From 58c3032bb275c81fa09bfaa24a580735573905be Mon Sep 17 00:00:00 2001
From: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Date: Thu, 17 Oct 2024 04:40:15 -0300
Subject: [PATCH] Rework PronounDB -> UserMessagesPronouns
---
src/plugins/pronoundb/api.ts | 172 ------------------
.../components/PronounsAboutComponent.tsx | 41 -----
src/plugins/pronoundb/index.ts | 78 --------
src/plugins/pronoundb/styles.css | 9 -
src/plugins/pronoundb/types.ts | 63 -------
.../PronounsChatComponent.tsx | 55 +++---
src/plugins/userMessagesPronouns/README.md | 5 +
src/plugins/userMessagesPronouns/index.ts | 54 ++++++
.../settings.ts | 32 +---
src/plugins/userMessagesPronouns/utils.ts | 35 ++++
10 files changed, 126 insertions(+), 418 deletions(-)
delete mode 100644 src/plugins/pronoundb/api.ts
delete mode 100644 src/plugins/pronoundb/components/PronounsAboutComponent.tsx
delete mode 100644 src/plugins/pronoundb/index.ts
delete mode 100644 src/plugins/pronoundb/styles.css
delete mode 100644 src/plugins/pronoundb/types.ts
rename src/plugins/{pronoundb/components => userMessagesPronouns}/PronounsChatComponent.tsx (68%)
create mode 100644 src/plugins/userMessagesPronouns/README.md
create mode 100644 src/plugins/userMessagesPronouns/index.ts
rename src/plugins/{pronoundb => userMessagesPronouns}/settings.ts (60%)
create mode 100644 src/plugins/userMessagesPronouns/utils.ts
diff --git a/src/plugins/pronoundb/api.ts b/src/plugins/pronoundb/api.ts
deleted file mode 100644
index 22821796..00000000
--- a/src/plugins/pronoundb/api.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 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 .
-*/
-
-import { getCurrentChannel } from "@utils/discord";
-import { useAwaiter } from "@utils/react";
-import { findStoreLazy } from "@webpack";
-import { UserProfileStore, UserStore } from "@webpack/common";
-
-import { settings } from "./settings";
-import { PronounMapping, Pronouns, PronounsCache, PronounSets, PronounsFormat, PronounSource, PronounsResponse } from "./types";
-
-const UserSettingsAccountStore = findStoreLazy("UserSettingsAccountStore");
-
-const EmptyPronouns = { pronouns: undefined, source: "", hasPendingPronouns: false } as const satisfies Pronouns;
-
-type RequestCallback = (pronounSets?: PronounSets) => void;
-
-const pronounCache: Record = {};
-const requestQueue: Record = {};
-let isProcessing = false;
-
-async function processQueue() {
- if (isProcessing) return;
- isProcessing = true;
-
- let ids = Object.keys(requestQueue);
- while (ids.length > 0) {
- const idsChunk = ids.splice(0, 50);
- const pronouns = await bulkFetchPronouns(idsChunk);
-
- for (const id of idsChunk) {
- const callbacks = requestQueue[id];
- for (const callback of callbacks) {
- callback(pronouns[id]?.sets);
- }
-
- delete requestQueue[id];
- }
-
- ids = Object.keys(requestQueue);
- await new Promise(r => setTimeout(r, 2000));
- }
-
- isProcessing = false;
-}
-
-function fetchPronouns(id: string): Promise {
- return new Promise(resolve => {
- if (pronounCache[id] != null) {
- resolve(extractPronouns(pronounCache[id].sets));
- return;
- }
-
- function handlePronouns(pronounSets?: PronounSets) {
- const pronouns = extractPronouns(pronounSets);
- resolve(pronouns);
- }
-
- if (requestQueue[id] != null) {
- requestQueue[id].push(handlePronouns);
- return;
- }
-
- requestQueue[id] = [handlePronouns];
- processQueue();
- });
-}
-
-async function bulkFetchPronouns(ids: string[]): Promise {
- const params = new URLSearchParams();
- params.append("platform", "discord");
- params.append("ids", ids.join(","));
-
- try {
- const req = await fetch("https://pronoundb.org/api/v2/lookup?" + String(params), {
- method: "GET",
- headers: {
- "Accept": "application/json",
- "X-PronounDB-Source": "WebExtension/0.14.5"
- }
- });
-
- if (!req.ok) throw new Error(`Status ${req.status}`);
- const res: PronounsResponse = await req.json();
-
- Object.assign(pronounCache, res);
- return res;
-
- } catch (e) {
- console.error("PronounDB request failed:", e);
- const dummyPronouns: PronounsResponse = Object.fromEntries(ids.map(id => [id, { sets: {} }]));
-
- Object.assign(pronounCache, dummyPronouns);
- return dummyPronouns;
- }
-}
-
-function extractPronouns(pronounSets?: PronounSets): string | undefined {
- if (pronounSets == null) return undefined;
- if (pronounSets.en == null) return PronounMapping.unspecified;
-
- const pronouns = pronounSets.en;
- if (pronouns.length === 0) return PronounMapping.unspecified;
-
- const { pronounsFormat } = settings.store;
-
- if (pronouns.length > 1) {
- const pronounString = pronouns.map(p => p[0].toUpperCase() + p.slice(1)).join("/");
- return pronounsFormat === PronounsFormat.Capitalized ? pronounString : pronounString.toLowerCase();
- }
-
- const pronoun = pronouns[0];
- // For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string
- if (pronounsFormat === PronounsFormat.Capitalized || ["any", "ask", "avoid", "other", "unspecified"].includes(pronoun)) {
- return PronounMapping[pronoun];
- } else {
- return PronounMapping[pronoun].toLowerCase();
- }
-}
-
-function getDiscordPronouns(id: string, useGlobalProfile: boolean = false): string | undefined {
- const globalPronouns = UserProfileStore.getUserProfile(id)?.pronouns;
- if (useGlobalProfile) return globalPronouns;
-
- return UserProfileStore.getGuildMemberProfile(id, getCurrentChannel()?.guild_id)?.pronouns || globalPronouns;
-}
-
-export function useFormattedPronouns(id: string, useGlobalProfile: boolean = false): Pronouns {
- const discordPronouns = getDiscordPronouns(id, useGlobalProfile)?.trim().replace(/\n+/g, "");
- const hasPendingPronouns = UserSettingsAccountStore.getPendingPronouns() != null;
-
- const [pronouns] = useAwaiter(() => fetchPronouns(id));
-
- if (settings.store.pronounSource === PronounSource.PreferDiscord && discordPronouns) {
- return { pronouns: discordPronouns, source: "Discord", hasPendingPronouns };
- }
-
- if (pronouns != null && pronouns !== PronounMapping.unspecified) {
- return { pronouns, source: "PronounDB", hasPendingPronouns };
- }
-
- return { pronouns: discordPronouns, source: "Discord", hasPendingPronouns };
-}
-
-export function useProfilePronouns(id: string, useGlobalProfile: boolean = false): Pronouns {
- try {
- const pronouns = useFormattedPronouns(id, useGlobalProfile);
-
- if (!settings.store.showInProfile) return EmptyPronouns;
- if (!settings.store.showSelf && id === UserStore.getCurrentUser()?.id) return EmptyPronouns;
-
- return pronouns;
- } catch (e) {
- console.error(e);
- return EmptyPronouns;
- }
-}
diff --git a/src/plugins/pronoundb/components/PronounsAboutComponent.tsx b/src/plugins/pronoundb/components/PronounsAboutComponent.tsx
deleted file mode 100644
index 255c6d35..00000000
--- a/src/plugins/pronoundb/components/PronounsAboutComponent.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 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 .
-*/
-
-import { Link } from "@components/Link";
-import { Forms, React } from "@webpack/common";
-
-export default function PronounsAboutComponent() {
- return (
-
- More Information
- To add your own pronouns, visit{" "}
- pronoundb.org
-
-
-
- The two pronoun formats are lowercase and capitalized. Example:
-
-
Lowercase: they/them
-
Capitalized: They/Them
-
- Text like "Ask me my pronouns" or "Any pronouns" will always be capitalized.
- You can also configure whether or not to display pronouns for the current user (since you probably already know them)
-
-
- );
-}
diff --git a/src/plugins/pronoundb/index.ts b/src/plugins/pronoundb/index.ts
deleted file mode 100644
index 511aeb1c..00000000
--- a/src/plugins/pronoundb/index.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 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 .
-*/
-
-import "./styles.css";
-
-import { Devs } from "@utils/constants";
-import definePlugin from "@utils/types";
-
-import { useProfilePronouns } from "./api";
-import PronounsAboutComponent from "./components/PronounsAboutComponent";
-import { CompactPronounsChatComponentWrapper, PronounsChatComponentWrapper } from "./components/PronounsChatComponent";
-import { settings } from "./settings";
-
-export default definePlugin({
- name: "PronounDB",
- authors: [Devs.Tyman, Devs.TheKodeToad, Devs.Ven, Devs.Elvyra],
- description: "Adds pronouns to user messages using pronoundb",
- patches: [
- {
- find: "showCommunicationDisabledStyles",
- replacement: [
- // Add next to username (compact mode)
- {
- match: /("span",{id:\i,className:\i,children:\i}\))/,
- replace: "$1, $self.CompactPronounsChatComponentWrapper(arguments[0])"
- },
- // Patch the chat timestamp element (normal mode)
- {
- match: /(?<=return\s*\(0,\i\.jsxs?\)\(.+!\i&&)(\(0,\i.jsxs?\)\(.+?\{.+?\}\))/,
- replace: "[$1, $self.PronounsChatComponentWrapper(arguments[0])]"
- }
- ]
- },
-
- {
- find: ".Messages.USER_PROFILE_PRONOUNS",
- group: true,
- replacement: [
- {
- match: /\.PANEL},/,
- replace: "$&{pronouns:vcPronoun,source:vcPronounSource,hasPendingPronouns:vcHasPendingPronouns}=$self.useProfilePronouns(arguments[0].user?.id),"
- },
- {
- match: /text:\i\.\i.Messages.USER_PROFILE_PRONOUNS/,
- replace: '$&+(vcPronoun==null||vcHasPendingPronouns?"":` (${vcPronounSource})`)'
- },
- {
- match: /(\.pronounsText.+?children:)(\i)/,
- replace: "$1(vcPronoun==null||vcHasPendingPronouns)?$2:vcPronoun"
- }
- ]
- }
- ],
-
- settings,
-
- settingsAboutComponent: PronounsAboutComponent,
-
- // Re-export the components on the plugin object so it is easily accessible in patches
- PronounsChatComponentWrapper,
- CompactPronounsChatComponentWrapper,
- useProfilePronouns
-});
diff --git a/src/plugins/pronoundb/styles.css b/src/plugins/pronoundb/styles.css
deleted file mode 100644
index a7d9eb9e..00000000
--- a/src/plugins/pronoundb/styles.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.vc-pronoundb-compact {
- display: none;
-}
-
-[class*="compact"] .vc-pronoundb-compact {
- display: inline-block;
- margin-left: -2px;
- margin-right: 0.25rem;
-}
diff --git a/src/plugins/pronoundb/types.ts b/src/plugins/pronoundb/types.ts
deleted file mode 100644
index 66bb13f0..00000000
--- a/src/plugins/pronoundb/types.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 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 .
-*/
-
-export interface UserProfileProps {
- userId: string;
-}
-
-export interface UserProfilePronounsProps {
- currentPronouns: string | null;
- hidePersonalInformation: boolean;
-}
-
-export type PronounSets = Record;
-export type PronounsResponse = Record;
-
-export interface PronounsCache {
- sets?: PronounSets;
-}
-
-export const PronounMapping = {
- he: "He/Him",
- it: "It/Its",
- she: "She/Her",
- they: "They/Them",
- any: "Any pronouns",
- other: "Other pronouns",
- ask: "Ask me my pronouns",
- avoid: "Avoid pronouns, use my name",
- unspecified: "No pronouns specified.",
-} as const satisfies Record;
-
-export type PronounCode = keyof typeof PronounMapping;
-
-export interface Pronouns {
- pronouns?: string;
- source: string;
- hasPendingPronouns: boolean;
-}
-
-export const enum PronounsFormat {
- Lowercase = "LOWERCASE",
- Capitalized = "CAPITALIZED"
-}
-
-export const enum PronounSource {
- PreferPDB,
- PreferDiscord
-}
diff --git a/src/plugins/pronoundb/components/PronounsChatComponent.tsx b/src/plugins/userMessagesPronouns/PronounsChatComponent.tsx
similarity index 68%
rename from src/plugins/pronoundb/components/PronounsChatComponent.tsx
rename to src/plugins/userMessagesPronouns/PronounsChatComponent.tsx
index 46c8a8a1..c2d7be2e 100644
--- a/src/plugins/pronoundb/components/PronounsChatComponent.tsx
+++ b/src/plugins/userMessagesPronouns/PronounsChatComponent.tsx
@@ -16,22 +16,22 @@
* along with this program. If not, see .
*/
+import { getUserSettingLazy } from "@api/UserSettings";
import ErrorBoundary from "@components/ErrorBoundary";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
-import { UserStore } from "@webpack/common";
+import { i18n, Tooltip, UserStore } from "@webpack/common";
import { Message } from "discord-types/general";
-import { useFormattedPronouns } from "../api";
-import { settings } from "../settings";
+import { settings } from "./settings";
+import { useFormattedPronouns } from "./utils";
const styles: Record = findByPropsLazy("timestampInline");
+const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact")!;
const AUTO_MODERATION_ACTION = 24;
function shouldShow(message: Message): boolean {
- if (!settings.store.showInMessages)
- return false;
if (message.author.bot || message.author.system || message.type === AUTO_MODERATION_ACTION)
return false;
if (!settings.store.showSelf && message.author.id === UserStore.getCurrentUser().id)
@@ -40,6 +40,21 @@ function shouldShow(message: Message): boolean {
return true;
}
+function PronounsChatComponent({ message }: { message: Message; }) {
+ const pronouns = useFormattedPronouns(message.author.id);
+
+ return pronouns && (
+
+ {tooltipProps => (
+ • {pronouns}
+ )}
+
+ );
+}
+
export const PronounsChatComponentWrapper = ErrorBoundary.wrap(({ message }: { message: Message; }) => {
return shouldShow(message)
?
@@ -47,27 +62,11 @@ export const PronounsChatComponentWrapper = ErrorBoundary.wrap(({ message }: { m
}, { noop: true });
export const CompactPronounsChatComponentWrapper = ErrorBoundary.wrap(({ message }: { message: Message; }) => {
- return shouldShow(message)
- ?
- : null;
-}, { noop: true });
-
-function PronounsChatComponent({ message }: { message: Message; }) {
- const { pronouns } = useFormattedPronouns(message.author.id);
-
- return pronouns && (
- • {pronouns}
- );
-}
-
-export const CompactPronounsChatComponent = ErrorBoundary.wrap(({ message }: { message: Message; }) => {
- const { pronouns } = useFormattedPronouns(message.author.id);
-
- return pronouns && (
- • {pronouns}
- );
+ const compact = MessageDisplayCompact.useSetting();
+
+ if (!compact || !shouldShow(message)) {
+ return null;
+ }
+
+ return ;
}, { noop: true });
diff --git a/src/plugins/userMessagesPronouns/README.md b/src/plugins/userMessagesPronouns/README.md
new file mode 100644
index 00000000..455f9c44
--- /dev/null
+++ b/src/plugins/userMessagesPronouns/README.md
@@ -0,0 +1,5 @@
+User Messages Pronouns
+
+Adds pronouns to chat user messages
+
+![](https://github.com/user-attachments/assets/34dc373d-faf4-4420-b49b-08b2647baa3b)
diff --git a/src/plugins/userMessagesPronouns/index.ts b/src/plugins/userMessagesPronouns/index.ts
new file mode 100644
index 00000000..27b162b9
--- /dev/null
+++ b/src/plugins/userMessagesPronouns/index.ts
@@ -0,0 +1,54 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 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 .
+*/
+
+import { migratePluginSettings } from "@api/Settings";
+import { Devs } from "@utils/constants";
+import definePlugin from "@utils/types";
+
+import { CompactPronounsChatComponentWrapper, PronounsChatComponentWrapper } from "./PronounsChatComponent";
+import { settings } from "./settings";
+
+migratePluginSettings("UserMessagesPronouns", "PronounDB");
+export default definePlugin({
+ name: "UserMessagesPronouns",
+ authors: [Devs.Tyman, Devs.TheKodeToad, Devs.Ven, Devs.Elvyra],
+ description: "Adds pronouns to chat user messages",
+ settings,
+
+ patches: [
+ {
+ find: "showCommunicationDisabledStyles",
+ replacement: {
+ // Add next to timestamp (normal mode)
+ match: /(?<=return\s*\(0,\i\.jsxs?\)\(.+!\i&&)(\(0,\i.jsxs?\)\(.+?\{.+?\}\))/,
+ replace: "[$1, $self.PronounsChatComponentWrapper(arguments[0])]"
+ }
+ },
+ {
+ find: '="SYSTEM_TAG"',
+ replacement: {
+ // Add next to username (compact mode)
+ match: /className:\i\(\)\(\i\.className(?:,\i\.clickable)?,\i\)}\),(?=\i)/g,
+ replace: "$&$self.CompactPronounsChatComponentWrapper(arguments[0]),"
+ }
+ }
+ ],
+
+ PronounsChatComponentWrapper,
+ CompactPronounsChatComponentWrapper,
+});
diff --git a/src/plugins/pronoundb/settings.ts b/src/plugins/userMessagesPronouns/settings.ts
similarity index 60%
rename from src/plugins/pronoundb/settings.ts
rename to src/plugins/userMessagesPronouns/settings.ts
index ebacfbc8..bbbd5085 100644
--- a/src/plugins/pronoundb/settings.ts
+++ b/src/plugins/userMessagesPronouns/settings.ts
@@ -19,7 +19,10 @@
import { definePluginSettings } from "@api/Settings";
import { OptionType } from "@utils/types";
-import { PronounsFormat, PronounSource } from "./types";
+export const enum PronounsFormat {
+ Lowercase = "LOWERCASE",
+ Capitalized = "CAPITALIZED"
+}
export const settings = definePluginSettings({
pronounsFormat: {
@@ -37,34 +40,9 @@ export const settings = definePluginSettings({
}
]
},
- pronounSource: {
- type: OptionType.SELECT,
- description: "Where to source pronouns from",
- options: [
- {
- label: "Prefer PronounDB, fall back to Discord",
- value: PronounSource.PreferPDB,
- default: true
- },
- {
- label: "Prefer Discord, fall back to PronounDB (might lead to inconsistency between pronouns in chat and profile)",
- value: PronounSource.PreferDiscord
- }
- ]
- },
showSelf: {
type: OptionType.BOOLEAN,
- description: "Enable or disable showing pronouns for the current user",
- default: true
- },
- showInMessages: {
- type: OptionType.BOOLEAN,
- description: "Show in messages",
- default: true
- },
- showInProfile: {
- type: OptionType.BOOLEAN,
- description: "Show in profile",
+ description: "Enable or disable showing pronouns for yourself",
default: true
}
});
diff --git a/src/plugins/userMessagesPronouns/utils.ts b/src/plugins/userMessagesPronouns/utils.ts
new file mode 100644
index 00000000..18a22772
--- /dev/null
+++ b/src/plugins/userMessagesPronouns/utils.ts
@@ -0,0 +1,35 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 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 .
+*/
+
+import { getCurrentChannel } from "@utils/discord";
+import { UserProfileStore, useStateFromStores } from "@webpack/common";
+
+import { PronounsFormat, settings } from "./settings";
+
+function useDiscordPronouns(id: string, useGlobalProfile: boolean = false): string | undefined {
+ const globalPronouns: string | undefined = useStateFromStores([UserProfileStore], () => UserProfileStore.getUserProfile(id)?.pronouns);
+ const guildPronouns: string | undefined = useStateFromStores([UserProfileStore], () => UserProfileStore.getGuildMemberProfile(id, getCurrentChannel()?.getGuildId())?.pronouns);
+
+ if (useGlobalProfile) return globalPronouns;
+ return guildPronouns || globalPronouns;
+}
+
+export function useFormattedPronouns(id: string, useGlobalProfile: boolean = false) {
+ const pronouns = useDiscordPronouns(id, useGlobalProfile)?.trim().replace(/\n+/g, "");
+ return settings.store.pronounsFormat === PronounsFormat.Lowercase ? pronouns?.toLowerCase() : pronouns;
+}