Merge branch 'develop' into germain-gg/facepile-offset
This commit is contained in:
commit
d99618263a
144 changed files with 12828 additions and 10514 deletions
|
@ -1277,7 +1277,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
const errCode = err.errcode || _td("unknown error code");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Failed to forget room %(errCode)s", { errCode }),
|
||||
description: err && err.message ? err.message : _t("Operation failed"),
|
||||
description: err && err.message ? err.message : _t("invite|failed_generic"),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ export default class UserView extends React.Component<IProps, IState> {
|
|||
} catch (err) {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Could not load user profile"),
|
||||
description: err instanceof Error ? err.message : _t("Operation failed"),
|
||||
description: err instanceof Error ? err.message : _t("invite|failed_generic"),
|
||||
});
|
||||
this.setState({ loading: false });
|
||||
return;
|
||||
|
|
|
@ -177,10 +177,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
|||
|
||||
if (err?.name === "ConnectionError") {
|
||||
this.setState({
|
||||
errorText:
|
||||
_t("Cannot reach homeserver") +
|
||||
": " +
|
||||
_t("Ensure you have a stable internet connection, or get in touch with the server admin"),
|
||||
errorText: _t("cannot_reach_homeserver") + ": " + _t("cannot_reach_homeserver_detail"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
|
|||
private getDefaultDialogAesthetics(): DialogAesthetics {
|
||||
const ssoAesthetics = {
|
||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||
title: _t("Use Single Sign On to continue"),
|
||||
title: _t("auth|uia|sso_title"),
|
||||
body: _t("To continue, use Single Sign On to prove your identity."),
|
||||
continueText: _t("auth|sso"),
|
||||
continueKind: "primary",
|
||||
|
|
|
@ -1337,7 +1337,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
|||
const room = MatrixClientPeg.get()?.getRoom(roomId);
|
||||
const isSpace = room?.isSpaceRoom();
|
||||
title = isSpace
|
||||
? _t("Invite to %(spaceName)s", {
|
||||
? _t("invite|to_space", {
|
||||
spaceName: room?.name || _t("common|unnamed_space"),
|
||||
})
|
||||
: _t("Invite to %(roomName)s", {
|
||||
|
|
|
@ -165,9 +165,9 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
|||
} else {
|
||||
content = (
|
||||
<p className="mx_MessageEditHistoryDialog_error">
|
||||
{_t("Cannot reach homeserver")}
|
||||
{_t("cannot_reach_homeserver")}
|
||||
<br />
|
||||
{_t("Ensure you have a stable internet connection, or get in touch with the server admin")}
|
||||
{_t("cannot_reach_homeserver_detail")}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
|||
logger.error("Unable to add email address " + emailAddress + " " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to add email address"),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
@ -138,7 +138,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
|||
logger.error("Unable to verify email address: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to verify email address."),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -239,7 +239,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
|||
await cli.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => {
|
||||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||
title: _t("Setting up keys"),
|
||||
title: _t("encryption|bootstrap_title"),
|
||||
matrixClient: cli,
|
||||
makeRequest,
|
||||
});
|
||||
|
|
|
@ -112,7 +112,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
|||
} else {
|
||||
const dialogAesthetics = {
|
||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||
title: _t("Use Single Sign On to continue"),
|
||||
title: _t("auth|uia|sso_title"),
|
||||
body: _t("To continue, use Single Sign On to prove your identity."),
|
||||
continueText: _t("auth|sso"),
|
||||
continueKind: "primary",
|
||||
|
@ -126,7 +126,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
|||
};
|
||||
|
||||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||
title: _t("Setting up keys"),
|
||||
title: _t("encryption|bootstrap_title"),
|
||||
matrixClient: MatrixClientPeg.safeGet(),
|
||||
makeRequest,
|
||||
aestheticsForStagePhases: {
|
||||
|
@ -195,7 +195,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
|||
<BaseDialog
|
||||
className="mx_CreateCrossSigningDialog"
|
||||
onFinished={this.props.onFinished}
|
||||
title={_t("Setting up keys")}
|
||||
title={_t("encryption|bootstrap_title")}
|
||||
hasCancel={false}
|
||||
fixedWidth={false}
|
||||
>
|
||||
|
|
|
@ -221,7 +221,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
|||
// in which case we show the error code)
|
||||
reason = _t("An unknown error occurred");
|
||||
} else if (hangupReason === CallErrorCode.UserBusy) {
|
||||
reason = _t("The user you called is busy.");
|
||||
reason = _t("voip|user_busy_description");
|
||||
} else {
|
||||
reason = _t("Unknown failure: %(reason)s", { reason: hangupReason });
|
||||
}
|
||||
|
|
|
@ -467,18 +467,19 @@ export const UserOptionsSection: React.FC<{
|
|||
if (errorStringFromInviterUtility) {
|
||||
throw new Error(errorStringFromInviterUtility);
|
||||
} else {
|
||||
throw new UserFriendlyError(
|
||||
`User (%(user)s) did not end up as invited to %(roomId)s but no error was given from the inviter utility`,
|
||||
{ user: member.userId, roomId, cause: undefined },
|
||||
);
|
||||
throw new UserFriendlyError("slash_command|invite_failed", {
|
||||
user: member.userId,
|
||||
roomId,
|
||||
cause: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
const description = err instanceof Error ? err.message : _t("Operation failed");
|
||||
const description = err instanceof Error ? err.message : _t("invite|failed_generic");
|
||||
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Failed to invite"),
|
||||
title: _t("invite|failed_title"),
|
||||
description,
|
||||
});
|
||||
}
|
||||
|
@ -1367,7 +1368,7 @@ const BasicUserInfo: React.FC<{
|
|||
logger.error("Failed to deactivate user");
|
||||
logger.error(err);
|
||||
|
||||
const description = err instanceof Error ? err.message : _t("Operation failed");
|
||||
const description = err instanceof Error ? err.message : _t("invite|failed_generic");
|
||||
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Failed to deactivate user"),
|
||||
|
|
|
@ -270,7 +270,7 @@ const startVoiceBroadcastButton: React.FC<IProps> = (props: IProps): ReactElemen
|
|||
className="mx_MessageComposer_button"
|
||||
iconClassName="mx_MessageComposer_voiceBroadcast"
|
||||
onClick={props.onStartVoiceBroadcastClick}
|
||||
title={_t("Voice broadcast")}
|
||||
title={_t("voice_broadcast|action")}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
|
|
@ -190,7 +190,7 @@ const NewRoomIntro: React.FC = () => {
|
|||
showSpaceInvite(parentSpace!);
|
||||
}}
|
||||
>
|
||||
{_t("Invite to %(spaceName)s", { spaceName: parentSpace.name })}
|
||||
{_t("invite|to_space", { spaceName: parentSpace.name })}
|
||||
</AccessibleButton>
|
||||
{room.canInvite(cli.getSafeUserId()) && (
|
||||
<AccessibleButton
|
||||
|
|
|
@ -543,7 +543,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
|
||||
private renderSuggestedRooms(): ReactComponentElement<typeof ExtraTile>[] {
|
||||
return this.state.suggestedRooms.map((room) => {
|
||||
const name = room.name || room.canonical_alias || room.aliases?.[0] || _t("Empty room");
|
||||
const name = room.name || room.canonical_alias || room.aliases?.[0] || _t("empty_room");
|
||||
const avatar = (
|
||||
<RoomAvatar
|
||||
oobData={{
|
||||
|
|
|
@ -133,7 +133,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
|
|||
await cli.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => {
|
||||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||
title: _t("Setting up keys"),
|
||||
title: _t("encryption|bootstrap_title"),
|
||||
matrixClient: cli,
|
||||
makeRequest,
|
||||
});
|
||||
|
|
|
@ -47,7 +47,7 @@ interface IState {
|
|||
|
||||
export default class FontScalingPanel extends React.Component<IProps, IState> {
|
||||
private readonly MESSAGE_PREVIEW_TEXT = _t("common|preview_message");
|
||||
|
||||
private layoutWatcherRef?: string;
|
||||
private unmounted = false;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
|
@ -65,6 +65,15 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
|
|||
const client = MatrixClientPeg.safeGet();
|
||||
const userId = client.getSafeUserId();
|
||||
const profileInfo = await client.getProfileInfo(userId);
|
||||
this.layoutWatcherRef = SettingsStore.watchSetting("layout", null, () => {
|
||||
// Update the layout for the preview window according to the user selection
|
||||
const value = SettingsStore.getValue("layout");
|
||||
if (this.state.layout !== value) {
|
||||
this.setState({
|
||||
layout: value,
|
||||
});
|
||||
}
|
||||
});
|
||||
if (this.unmounted) return;
|
||||
|
||||
this.setState({
|
||||
|
@ -76,6 +85,9 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
|
|||
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
if (this.layoutWatcherRef) {
|
||||
SettingsStore.unwatchSetting(this.layoutWatcherRef);
|
||||
}
|
||||
}
|
||||
|
||||
private onFontSizeChanged = (size: number): void => {
|
||||
|
|
|
@ -16,10 +16,9 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { ReactNode } from "react";
|
||||
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
|
||||
import { TrustInfo } from "matrix-js-sdk/src/crypto/backup";
|
||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { BackupTrustInfo, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
||||
|
||||
import type CreateKeyBackupDialog from "../../../async-components/views/dialogs/security/CreateKeyBackupDialog";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
@ -41,9 +40,34 @@ interface IState {
|
|||
backupKeyWellFormed: boolean | null;
|
||||
secretStorageKeyInAccount: boolean | null;
|
||||
secretStorageReady: boolean | null;
|
||||
backupInfo: IKeyBackupInfo | null;
|
||||
backupSigStatus: TrustInfo | null;
|
||||
sessionsRemaining: number;
|
||||
|
||||
/** Information on the current key backup version, as returned by the server.
|
||||
*
|
||||
* `null` could mean any of:
|
||||
* * we haven't yet requested the data from the server.
|
||||
* * we were unable to reach the server.
|
||||
* * the server returned key backup version data we didn't understand or was malformed.
|
||||
* * there is actually no backup on the server.
|
||||
*/
|
||||
backupInfo: KeyBackupInfo | null;
|
||||
|
||||
/**
|
||||
* Information on whether the backup in `backupInfo` is correctly signed, and whether we have the right key to
|
||||
* decrypt it.
|
||||
*
|
||||
* `undefined` if `backupInfo` is null, or if crypto is not enabled in the client.
|
||||
*/
|
||||
backupTrustInfo: BackupTrustInfo | undefined;
|
||||
|
||||
/**
|
||||
* If key backup is currently enabled, the backup version we are backing up to.
|
||||
*/
|
||||
activeBackupVersion: string | null;
|
||||
|
||||
/**
|
||||
* Number of sessions remaining to be backed up. `null` if we have no information on this.
|
||||
*/
|
||||
sessionsRemaining: number | null;
|
||||
}
|
||||
|
||||
export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
||||
|
@ -61,8 +85,9 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
secretStorageKeyInAccount: null,
|
||||
secretStorageReady: null,
|
||||
backupInfo: null,
|
||||
backupSigStatus: null,
|
||||
sessionsRemaining: 0,
|
||||
backupTrustInfo: undefined,
|
||||
activeBackupVersion: null,
|
||||
sessionsRemaining: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -101,14 +126,19 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
this.setState({ loading: true });
|
||||
this.getUpdatedDiagnostics();
|
||||
try {
|
||||
const backupInfo = await MatrixClientPeg.safeGet().getKeyBackupVersion();
|
||||
const backupSigStatus = backupInfo ? await MatrixClientPeg.safeGet().isKeyBackupTrusted(backupInfo) : null;
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
const backupInfo = await cli.getKeyBackupVersion();
|
||||
const backupTrustInfo = backupInfo ? await cli.getCrypto()?.isKeyBackupTrusted(backupInfo) : undefined;
|
||||
|
||||
const activeBackupVersion = (await cli.getCrypto()?.getActiveSessionBackupVersion()) ?? null;
|
||||
|
||||
if (this.unmounted) return;
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: false,
|
||||
backupInfo,
|
||||
backupSigStatus,
|
||||
backupTrustInfo,
|
||||
activeBackupVersion,
|
||||
});
|
||||
} catch (e) {
|
||||
logger.log("Unable to fetch key backup status", e);
|
||||
|
@ -117,7 +147,8 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
loading: false,
|
||||
error: true,
|
||||
backupInfo: null,
|
||||
backupSigStatus: null,
|
||||
backupTrustInfo: undefined,
|
||||
activeBackupVersion: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -173,8 +204,10 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
onFinished: (proceed) => {
|
||||
if (!proceed) return;
|
||||
this.setState({ loading: true });
|
||||
const versionToDelete = this.state.backupInfo!.version!;
|
||||
MatrixClientPeg.safeGet()
|
||||
.deleteKeyBackupVersion(this.state.backupInfo!.version!)
|
||||
.getCrypto()
|
||||
?.deleteKeyBackupVersion(versionToDelete)
|
||||
.then(() => {
|
||||
this.loadBackupStatus();
|
||||
});
|
||||
|
@ -209,7 +242,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
secretStorageKeyInAccount,
|
||||
secretStorageReady,
|
||||
backupInfo,
|
||||
backupSigStatus,
|
||||
backupTrustInfo,
|
||||
sessionsRemaining,
|
||||
} = this.state;
|
||||
|
||||
|
@ -228,7 +261,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
} else if (backupInfo) {
|
||||
let restoreButtonCaption = _t("Restore from Backup");
|
||||
|
||||
if (MatrixClientPeg.safeGet().getKeyBackupEnabled()) {
|
||||
if (this.state.activeBackupVersion !== null) {
|
||||
statusDescription = (
|
||||
<SettingsSubsectionText>✅ {_t("This session is backing up your keys.")}</SettingsSubsectionText>
|
||||
);
|
||||
|
@ -253,7 +286,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
}
|
||||
|
||||
let uploadStatus: ReactNode;
|
||||
if (!MatrixClientPeg.safeGet().getKeyBackupEnabled()) {
|
||||
if (sessionsRemaining === null) {
|
||||
// No upload status to show when backup disabled.
|
||||
uploadStatus = "";
|
||||
} else if (sessionsRemaining > 0) {
|
||||
|
@ -271,19 +304,21 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
|
|||
}
|
||||
|
||||
let trustedLocally: string | undefined;
|
||||
if (backupSigStatus?.trusted_locally) {
|
||||
trustedLocally = _t("This backup is trusted because it has been restored on this session");
|
||||
if (backupTrustInfo?.matchesDecryptionKey) {
|
||||
trustedLocally = _t("This backup can be restored on this session");
|
||||
}
|
||||
|
||||
extraDetailsTableRows = (
|
||||
<>
|
||||
<tr>
|
||||
<th scope="row">{_t("Backup version:")}</th>
|
||||
<td>{backupInfo.version}</td>
|
||||
<th scope="row">{_t("Latest backup version on server:")}</th>
|
||||
<td>
|
||||
{backupInfo.version} ({_t("Algorithm:")} <code>{backupInfo.algorithm}</code>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{_t("Algorithm:")}</th>
|
||||
<td>{backupInfo.algorithm}</td>
|
||||
<th scope="row">{_t("Active backup version:")}</th>
|
||||
<td>{this.state.activeBackupVersion === null ? _t("None") : this.state.activeBackupVersion}</td>
|
||||
</tr>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -223,13 +223,13 @@ export default class SetIdServer extends React.Component<IProps, IState> {
|
|||
|
||||
private showNoTermsWarning(fullUrl: string): Promise<[ok?: boolean]> {
|
||||
const { finished } = Modal.createDialog(QuestionDialog, {
|
||||
title: _t("Identity server has no terms of service"),
|
||||
title: _t("terms|identity_server_no_terms_title"),
|
||||
description: (
|
||||
<div>
|
||||
<span className="warning">
|
||||
{_t("The identity server you have chosen does not have any terms of service.")}
|
||||
</span>
|
||||
<span> {_t("Only continue if you trust the owner of the server.")}</span>
|
||||
<span> {_t("terms|identity_server_no_terms_description_2")}</span>
|
||||
</div>
|
||||
),
|
||||
button: _t("action|continue"),
|
||||
|
|
|
@ -89,7 +89,7 @@ export class ExistingEmailAddress extends React.Component<IExistingEmailAddressP
|
|||
logger.error("Unable to remove contact information: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to remove contact information"),
|
||||
description: err && err.message ? err.message : _t("Operation failed"),
|
||||
description: err && err.message ? err.message : _t("invite|failed_generic"),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -200,7 +200,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
|
|||
this.setState({ verifying: false, continueDisabled: false, addTask: null });
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to add email address"),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -247,7 +247,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
|
|||
} else {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to verify email address."),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -85,7 +85,7 @@ export class ExistingPhoneNumber extends React.Component<IExistingPhoneNumberPro
|
|||
logger.error("Unable to remove contact information: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to remove contact information"),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -202,7 +202,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
|
|||
this.setState({ verifying: false, continueDisabled: false, addTask: null });
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("common|error"),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -245,7 +245,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
|
|||
if (underlyingError.errcode !== "M_THREEPID_AUTH_FAILED") {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to verify phone number."),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
} else {
|
||||
this.setState({ verifyError: _t("Incorrect verification code") });
|
||||
|
|
|
@ -52,7 +52,7 @@ export const deleteDevicesWithInteractiveAuth = async (
|
|||
const numDevices = deviceIds.length;
|
||||
const dialogAesthetics = {
|
||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||
title: _t("Use Single Sign On to continue"),
|
||||
title: _t("auth|uia|sso_title"),
|
||||
body: _t("settings|sessions|confirm_sign_out_sso", {
|
||||
count: numDevices,
|
||||
}),
|
||||
|
|
|
@ -105,7 +105,7 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
|
|||
});
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: errorTitle,
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
|
|||
logger.error("Unable to verify email address: " + err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to verify email address."),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -106,7 +106,7 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
|
|||
});
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: errorTitle,
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
|
|||
if (underlyingError instanceof MatrixError && underlyingError.errcode !== "M_THREEPID_AUTH_FAILED") {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to verify phone number."),
|
||||
description: extractErrorMessageFromError(err, _t("Operation failed")),
|
||||
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
|
||||
});
|
||||
} else {
|
||||
this.setState({ verifyError: _t("Incorrect verification code") });
|
||||
|
|
|
@ -110,7 +110,7 @@ export class BannedUser extends React.Component<IBannedUserProps> {
|
|||
kind="danger_sm"
|
||||
onClick={this.onUnbanClick}
|
||||
>
|
||||
{_t("Unban")}
|
||||
{_t("action|unban")}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
|
|||
if (description === userId) {
|
||||
const user = client.getUser(userId);
|
||||
if (user && user.displayName) {
|
||||
description = _t("%(name)s (%(userId)s)", { name: user.displayName, userId });
|
||||
description = _t("name_and_id", { name: user.displayName, userId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue