Preparations for React 18 (#12860)
* Add missing types Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Eagerly add `children` to props in prep for React 18 Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Avoid assuming that setState immediately sets `this.state` values Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add missing context declaration Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix UserFriendlyError types to work with React 18 Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
accbe07439
commit
090586439f
17 changed files with 63 additions and 44 deletions
|
@ -97,6 +97,12 @@ type WithKeyFunction<T> = T extends Key
|
||||||
toKey: (key: T) => Key;
|
toKey: (key: T) => Key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface AdditionalOptionsProps {
|
||||||
|
menuDisplayed: boolean;
|
||||||
|
closeMenu: () => void;
|
||||||
|
openMenu: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
type IProps<T> = WithKeyFunction<T> & {
|
type IProps<T> = WithKeyFunction<T> & {
|
||||||
value: T;
|
value: T;
|
||||||
options: readonly GenericDropdownMenuOption<T>[] | readonly GenericDropdownMenuGroup<T>[];
|
options: readonly GenericDropdownMenuOption<T>[] | readonly GenericDropdownMenuGroup<T>[];
|
||||||
|
@ -105,11 +111,7 @@ type IProps<T> = WithKeyFunction<T> & {
|
||||||
onOpen?: (ev: ButtonEvent) => void;
|
onOpen?: (ev: ButtonEvent) => void;
|
||||||
onClose?: (ev: ButtonEvent) => void;
|
onClose?: (ev: ButtonEvent) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
AdditionalOptions?: FunctionComponent<{
|
AdditionalOptions?: FunctionComponent<AdditionalOptionsProps>;
|
||||||
menuDisplayed: boolean;
|
|
||||||
closeMenu: () => void;
|
|
||||||
openMenu: () => void;
|
|
||||||
}>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function GenericDropdownMenu<T>({
|
export function GenericDropdownMenu<T>({
|
||||||
|
|
|
@ -117,7 +117,7 @@ export const ThreadPanelHeader: React.FC<{
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
const onMarkAllThreadsReadClick = React.useCallback(
|
const onMarkAllThreadsReadClick = React.useCallback(
|
||||||
(e) => {
|
(e: React.MouseEvent) => {
|
||||||
PosthogTrackers.trackInteraction("WebThreadsMarkAllReadButton", e);
|
PosthogTrackers.trackInteraction("WebThreadsMarkAllReadButton", e);
|
||||||
if (!roomContext.room) {
|
if (!roomContext.room) {
|
||||||
logger.error("No room in context to mark all threads read");
|
logger.error("No room in context to mark all threads read");
|
||||||
|
|
|
@ -248,15 +248,20 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
logger.error("Failed to get login flows to check for SSO support", e);
|
logger.error("Failed to get login flows to check for SSO support", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(({ flows }) => ({
|
await new Promise<void>((resolve) => {
|
||||||
matrixClient: cli,
|
this.setState(
|
||||||
ssoFlow,
|
({ flows }) => ({
|
||||||
oidcNativeFlow,
|
matrixClient: cli,
|
||||||
// if we are using oidc native we won't continue with flow discovery on HS
|
ssoFlow,
|
||||||
// so set an empty array to indicate flows are no longer loading
|
oidcNativeFlow,
|
||||||
flows: oidcNativeFlow ? [] : flows,
|
// if we are using oidc native we won't continue with flow discovery on HS
|
||||||
busy: false,
|
// so set an empty array to indicate flows are no longer loading
|
||||||
}));
|
flows: oidcNativeFlow ? [] : flows,
|
||||||
|
busy: false,
|
||||||
|
}),
|
||||||
|
resolve,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// don't need to check with homeserver for login flows
|
// don't need to check with homeserver for login flows
|
||||||
// since we are going to use OIDC native flow
|
// since we are going to use OIDC native flow
|
||||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { forwardRef, useCallback, useContext, useEffect, useState } from "react";
|
import React, { forwardRef, useCallback, useContext, useEffect, useState } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { ClientEvent } from "matrix-js-sdk/src/matrix";
|
import { ClientEvent, SyncState } from "matrix-js-sdk/src/matrix";
|
||||||
import { Avatar } from "@vector-im/compound-web";
|
import { Avatar } from "@vector-im/compound-web";
|
||||||
|
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
@ -80,7 +80,7 @@ const useImageUrl = ({ url, urls }: { url?: string | null; urls?: string[] }): [
|
||||||
}, [url, JSON.stringify(urls)]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [url, JSON.stringify(urls)]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
const onClientSync = useCallback((syncState, prevState) => {
|
const onClientSync = useCallback((syncState: SyncState, prevState: SyncState | null) => {
|
||||||
// Consider the client reconnected if there is no error with syncing.
|
// Consider the client reconnected if there is no error with syncing.
|
||||||
// This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP.
|
// This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP.
|
||||||
const reconnected = syncState !== "ERROR" && prevState !== syncState;
|
const reconnected = syncState !== "ERROR" && prevState !== syncState;
|
||||||
|
|
|
@ -26,6 +26,7 @@ interface OptionProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick: ((ev: ButtonEvent) => void) | null;
|
onClick: ((ev: ButtonEvent) => void) | null;
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Option: React.FC<OptionProps> = ({ inputRef, children, endAdornment, className, ...props }) => {
|
export const Option: React.FC<OptionProps> = ({ inputRef, children, endAdornment, className, ...props }) => {
|
||||||
|
|
|
@ -26,7 +26,11 @@ import SdkConfig from "../../../SdkConfig";
|
||||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { Protocols } from "../../../utils/DirectoryUtils";
|
import { Protocols } from "../../../utils/DirectoryUtils";
|
||||||
import { GenericDropdownMenu, GenericDropdownMenuItem } from "../../structures/GenericDropdownMenu";
|
import {
|
||||||
|
AdditionalOptionsProps,
|
||||||
|
GenericDropdownMenu,
|
||||||
|
GenericDropdownMenuItem,
|
||||||
|
} from "../../structures/GenericDropdownMenu";
|
||||||
import TextInputDialog from "../dialogs/TextInputDialog";
|
import TextInputDialog from "../dialogs/TextInputDialog";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import withValidation from "../elements/Validation";
|
import withValidation from "../elements/Validation";
|
||||||
|
@ -181,7 +185,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const addNewServer = useCallback(
|
const addNewServer = useCallback(
|
||||||
({ closeMenu }) => (
|
({ closeMenu }: AdditionalOptionsProps) => (
|
||||||
<>
|
<>
|
||||||
<span className="mx_GenericDropdownMenu_divider" />
|
<span className="mx_GenericDropdownMenu_divider" />
|
||||||
<MenuItemRadio
|
<MenuItemRadio
|
||||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ContextType, CSSProperties, MutableRefObject } from "react";
|
import React, { ContextType, CSSProperties, MutableRefObject, ReactNode } from "react";
|
||||||
import { Room } from "matrix-js-sdk/src/matrix";
|
import { Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import WidgetUtils from "../../../utils/WidgetUtils";
|
import WidgetUtils from "../../../utils/WidgetUtils";
|
||||||
|
@ -28,6 +28,7 @@ interface IProps {
|
||||||
persistentRoomId: string;
|
persistentRoomId: string;
|
||||||
pointerEvents?: CSSProperties["pointerEvents"];
|
pointerEvents?: CSSProperties["pointerEvents"];
|
||||||
movePersistedElement: MutableRefObject<(() => void) | undefined>;
|
movePersistedElement: MutableRefObject<(() => void) | undefined>;
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PersistentApp extends React.Component<IProps> {
|
export default class PersistentApp extends React.Component<IProps> {
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useCallback, useContext } from "react";
|
import React, { useCallback, useContext } from "react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent, Room, RoomState } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
|
@ -52,7 +52,7 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
|
||||||
const predecessor = useRoomState(
|
const predecessor = useRoomState(
|
||||||
roomContext.room,
|
roomContext.room,
|
||||||
useCallback(
|
useCallback(
|
||||||
(state) => state.findPredecessor(msc3946ProcessDynamicPredecessor),
|
(state: RoomState) => state.findPredecessor(msc3946ProcessDynamicPredecessor),
|
||||||
[msc3946ProcessDynamicPredecessor],
|
[msc3946ProcessDynamicPredecessor],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -63,9 +63,9 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
|
||||||
|
|
||||||
dis.dispatch<ViewRoomPayload>({
|
dis.dispatch<ViewRoomPayload>({
|
||||||
action: Action.ViewRoom,
|
action: Action.ViewRoom,
|
||||||
event_id: predecessor.eventId,
|
event_id: predecessor?.eventId,
|
||||||
highlighted: true,
|
highlighted: true,
|
||||||
room_id: predecessor.roomId,
|
room_id: predecessor?.roomId,
|
||||||
metricsTrigger: "Predecessor",
|
metricsTrigger: "Predecessor",
|
||||||
metricsViaKeyboard: e.type !== "click",
|
metricsViaKeyboard: e.type !== "click",
|
||||||
});
|
});
|
||||||
|
@ -126,7 +126,7 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
|
||||||
|
|
||||||
const predecessorPermalink = prevRoom
|
const predecessorPermalink = prevRoom
|
||||||
? createLinkWithRoom(prevRoom, predecessor.roomId, predecessor.eventId)
|
? createLinkWithRoom(prevRoom, predecessor.roomId, predecessor.eventId)
|
||||||
: createLinkWithoutRoom(predecessor.roomId, predecessor.viaServers, predecessor.eventId);
|
: createLinkWithoutRoom(predecessor.roomId, predecessor?.viaServers ?? [], predecessor.eventId);
|
||||||
|
|
||||||
const link = (
|
const link = (
|
||||||
<a href={predecessorPermalink} onClick={onLinkClicked}>
|
<a href={predecessorPermalink} onClick={onLinkClicked}>
|
||||||
|
|
|
@ -27,6 +27,7 @@ interface IProps {
|
||||||
|
|
||||||
export default class TextualEvent extends React.Component<IProps> {
|
export default class TextualEvent extends React.Component<IProps> {
|
||||||
public static contextType = RoomContext;
|
public static contextType = RoomContext;
|
||||||
|
public declare context: React.ContextType<typeof RoomContext>;
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const text = TextForEvent.textForEvent(
|
const text = TextForEvent.textForEvent(
|
||||||
|
|
|
@ -14,10 +14,11 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum SeparatorKind {
|
export const enum SeparatorKind {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import { WidgetType } from "../../../widgets/WidgetType";
|
||||||
import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore";
|
import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore";
|
||||||
import WidgetUtils from "../../../utils/WidgetUtils";
|
import WidgetUtils from "../../../utils/WidgetUtils";
|
||||||
import { ElementWidgetActions } from "../../../stores/widgets/ElementWidgetActions";
|
import { ElementWidgetActions } from "../../../stores/widgets/ElementWidgetActions";
|
||||||
|
import { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
|
@ -62,7 +63,7 @@ export const WidgetPip: FC<Props> = ({ widgetId, room, viewingRoom, onStartMovin
|
||||||
const call = useCallForWidget(widgetId, room.roomId);
|
const call = useCallForWidget(widgetId, room.roomId);
|
||||||
|
|
||||||
const onBackClick = useCallback(
|
const onBackClick = useCallback(
|
||||||
(ev) => {
|
(ev: ButtonEvent) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ export const WidgetPip: FC<Props> = ({ widgetId, room, viewingRoom, onStartMovin
|
||||||
);
|
);
|
||||||
|
|
||||||
const onLeaveClick = useCallback(
|
const onLeaveClick = useCallback(
|
||||||
(ev) => {
|
(ev: ButtonEvent) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
|
|
@ -424,6 +424,7 @@ export const UserOptionsSection: React.FC<{
|
||||||
member: Member;
|
member: Member;
|
||||||
canInvite: boolean;
|
canInvite: boolean;
|
||||||
isSpace?: boolean;
|
isSpace?: boolean;
|
||||||
|
children?: ReactNode;
|
||||||
}> = ({ member, canInvite, isSpace, children }) => {
|
}> = ({ member, canInvite, isSpace, children }) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
|
@ -1036,7 +1037,7 @@ const IgnoreToggleButton: React.FC<{
|
||||||
}, [cli, member.userId]);
|
}, [cli, member.userId]);
|
||||||
// Recheck also if we receive new accountData m.ignored_user_list
|
// Recheck also if we receive new accountData m.ignored_user_list
|
||||||
const accountDataHandler = useCallback(
|
const accountDataHandler = useCallback(
|
||||||
(ev) => {
|
(ev: MatrixEvent) => {
|
||||||
if (ev.getType() === "m.ignored_user_list") {
|
if (ev.getType() === "m.ignored_user_list") {
|
||||||
setIsIgnored(cli.isUserIgnored(member.userId));
|
setIsIgnored(cli.isUserIgnored(member.userId));
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,10 @@ export default function RoomHeader({
|
||||||
|
|
||||||
const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
|
const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
|
||||||
|
|
||||||
const videoClick = useCallback((ev) => videoCallClick(ev, callOptions[0]), [callOptions, videoCallClick]);
|
const videoClick = useCallback(
|
||||||
|
(ev: React.MouseEvent) => videoCallClick(ev, callOptions[0]),
|
||||||
|
[callOptions, videoCallClick],
|
||||||
|
);
|
||||||
|
|
||||||
const toggleCallButton = (
|
const toggleCallButton = (
|
||||||
<Tooltip label={isViewingCall ? _t("voip|minimise_call") : _t("voip|maximise_call")}>
|
<Tooltip label={isViewingCall ? _t("voip|minimise_call") : _t("voip|maximise_call")}>
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react";
|
import React, { ChangeEvent, ReactNode, useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web";
|
import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web";
|
||||||
import { Icon as PopOutIcon } from "@vector-im/compound-design-tokens/icons/pop-out.svg";
|
import { Icon as PopOutIcon } from "@vector-im/compound-design-tokens/icons/pop-out.svg";
|
||||||
|
@ -37,7 +37,7 @@ import Modal from "../../../Modal";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import { Flex } from "../../utils/Flex";
|
import { Flex } from "../../utils/Flex";
|
||||||
|
|
||||||
const SpinnerToast: React.FC = ({ children }) => (
|
const SpinnerToast: React.FC<{ children?: ReactNode }> = ({ children }) => (
|
||||||
<>
|
<>
|
||||||
<InlineSpinner />
|
<InlineSpinner />
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -45,7 +45,7 @@ const QuickSettingsButton: React.FC<{
|
||||||
useSettingValue<Record<MetaSpace, boolean>>("Spaces.enabledMetaSpaces");
|
useSettingValue<Record<MetaSpace, boolean>>("Spaces.enabledMetaSpaces");
|
||||||
|
|
||||||
const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||||
const developerModeEnabled = useSettingValue("developerMode");
|
const developerModeEnabled = useSettingValue<boolean>("developerMode");
|
||||||
|
|
||||||
let contextMenu: JSX.Element | undefined;
|
let contextMenu: JSX.Element | undefined;
|
||||||
if (menuDisplayed && handle.current) {
|
if (menuDisplayed && handle.current) {
|
||||||
|
|
|
@ -26,9 +26,9 @@ export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: strin
|
||||||
const [value, setValue] = useState<T | undefined>(() => tryGetContent<T>(cli.getAccountData(eventType)));
|
const [value, setValue] = useState<T | undefined>(() => tryGetContent<T>(cli.getAccountData(eventType)));
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
(event) => {
|
(event: MatrixEvent) => {
|
||||||
if (event.getType() !== eventType) return;
|
if (event.getType() !== eventType) return;
|
||||||
setValue(event.getContent());
|
setValue(event.getContent<T>());
|
||||||
},
|
},
|
||||||
[eventType],
|
[eventType],
|
||||||
);
|
);
|
||||||
|
|
|
@ -53,7 +53,7 @@ const FALLBACK_LOCALE = "en";
|
||||||
counterpart.setFallbackLocale(FALLBACK_LOCALE);
|
counterpart.setFallbackLocale(FALLBACK_LOCALE);
|
||||||
|
|
||||||
export interface ErrorOptions {
|
export interface ErrorOptions {
|
||||||
// Because we're mixing the subsitution variables and `cause` into the same object
|
// Because we're mixing the substitution variables and `cause` into the same object
|
||||||
// below, we want them to always explicitly say whether there is an underlying error
|
// below, we want them to always explicitly say whether there is an underlying error
|
||||||
// or not to avoid typos of "cause" slipping through unnoticed.
|
// or not to avoid typos of "cause" slipping through unnoticed.
|
||||||
cause: unknown | undefined;
|
cause: unknown | undefined;
|
||||||
|
@ -78,16 +78,15 @@ export interface ErrorOptions {
|
||||||
export class UserFriendlyError extends Error {
|
export class UserFriendlyError extends Error {
|
||||||
public readonly translatedMessage: string;
|
public readonly translatedMessage: string;
|
||||||
|
|
||||||
public constructor(message: TranslationKey, substitutionVariablesAndCause?: IVariables & ErrorOptions) {
|
public constructor(
|
||||||
const errorOptions = {
|
message: TranslationKey,
|
||||||
cause: substitutionVariablesAndCause?.cause,
|
substitutionVariablesAndCause?: Omit<IVariables, keyof ErrorOptions> | ErrorOptions,
|
||||||
};
|
) {
|
||||||
// Prevent "Could not find /%\(cause\)s/g in x" logs to the console by removing it from the list
|
// Prevent "Could not find /%\(cause\)s/g in x" logs to the console by removing it from the list
|
||||||
const substitutionVariables = { ...substitutionVariablesAndCause };
|
const { cause, ...substitutionVariables } = substitutionVariablesAndCause ?? {};
|
||||||
delete substitutionVariables["cause"];
|
const errorOptions = { cause };
|
||||||
|
|
||||||
// Create the error with the English version of the message that we want to show
|
// Create the error with the English version of the message that we want to show up in the logs
|
||||||
// up in the logs
|
|
||||||
const englishTranslatedMessage = _t(message, { ...substitutionVariables, locale: "en" });
|
const englishTranslatedMessage = _t(message, { ...substitutionVariables, locale: "en" });
|
||||||
super(englishTranslatedMessage, errorOptions);
|
super(englishTranslatedMessage, errorOptions);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue