Migrate more strings to translation keys (#11683)
This commit is contained in:
parent
632d8f4bc7
commit
41a2325a2a
86 changed files with 4744 additions and 4051 deletions
|
@ -147,7 +147,7 @@ const EmptyThread: React.FC<EmptyThreadIProps> = ({ hasThreads, filterOption, sh
|
|||
<>
|
||||
<p>
|
||||
{_t("threads|empty_has_threads_tip", {
|
||||
replyInThread: _t("Reply in thread"),
|
||||
replyInThread: _t("action|reply_in_thread"),
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
|
@ -168,7 +168,7 @@ const EmptyThread: React.FC<EmptyThreadIProps> = ({ hasThreads, filterOption, sh
|
|||
{_t(
|
||||
"threads|empty_tip",
|
||||
{
|
||||
replyInThread: _t("Reply in thread"),
|
||||
replyInThread: _t("action|reply_in_thread"),
|
||||
},
|
||||
{
|
||||
b: (sub) => <b>{sub}</b>,
|
||||
|
|
|
@ -112,7 +112,7 @@ export default class LoginWithQRFlow extends React.Component<IProps> {
|
|||
cancellationMessage = _t("auth|qr_code_login|error_request_cancelled");
|
||||
break;
|
||||
}
|
||||
title = _t("Connection failed");
|
||||
title = _t("timeline|m.call.invite|failed_connection");
|
||||
centreTitle = true;
|
||||
titleIcon = <WarningBadge className="error" />;
|
||||
backButton = false;
|
||||
|
|
|
@ -97,7 +97,7 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent, closeMen
|
|||
return (
|
||||
<IconizedContextMenuOption
|
||||
iconClassName="mx_MessageContextMenu_iconReplyInThread"
|
||||
label={_t("Reply in thread")}
|
||||
label={_t("action|reply_in_thread")}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -172,7 +172,7 @@ export const CallEvent = forwardRef<any, CallEventProps>(({ mxEvent }, ref) => {
|
|||
<div className="mx_CallEvent_wrapper" ref={ref}>
|
||||
<div className="mx_CallEvent mx_CallEvent_inactive">
|
||||
<div className="mx_CallEvent_columns">
|
||||
<span className="mx_CallEvent_title">{_t("Video call ended")}</span>
|
||||
<span className="mx_CallEvent_title">{_t("timeline|m.call|video_call_ended")}</span>
|
||||
<CallDuration delta={latestEvent.getTs() - mxEvent.getTs()} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -170,17 +170,14 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
let friendlyErrorMessage = "An error occured while trying to find and jump to the given date.";
|
||||
let submitDebugLogsContent: JSX.Element = <></>;
|
||||
if (err instanceof ConnectionError) {
|
||||
friendlyErrorMessage = _t(
|
||||
"A network error occurred while trying to find and jump to the given date. Your homeserver might be down or there was just a temporary problem with your internet connection. Please try again. If this continues, please contact your homeserver administrator.",
|
||||
);
|
||||
friendlyErrorMessage = _t("room|error_jump_to_date_connection");
|
||||
} else if (err instanceof MatrixError) {
|
||||
if (err?.errcode === "M_NOT_FOUND") {
|
||||
friendlyErrorMessage = _t(
|
||||
"We were unable to find an event looking forwards from %(dateString)s. Try choosing an earlier date.",
|
||||
{ dateString: formatFullDateNoDay(new Date(unixTimestamp)) },
|
||||
);
|
||||
friendlyErrorMessage = _t("room|error_jump_to_date_not_found", {
|
||||
dateString: formatFullDateNoDay(new Date(unixTimestamp)),
|
||||
});
|
||||
} else {
|
||||
friendlyErrorMessage = _t("Server returned %(statusCode)s with error code %(errorCode)s", {
|
||||
friendlyErrorMessage = _t("room|error_jump_to_date", {
|
||||
statusCode: err?.httpStatus || _t("unknown status code"),
|
||||
errorCode: err?.errcode || _t("unavailable"),
|
||||
});
|
||||
|
@ -192,7 +189,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
submitDebugLogsContent = (
|
||||
<p>
|
||||
{_t(
|
||||
"Please submit <debugLogsLink>debug logs</debugLogsLink> to help us track down the problem.",
|
||||
"room|error_jump_to_date_send_logs_prompt",
|
||||
{},
|
||||
{
|
||||
debugLogsLink: (sub) => (
|
||||
|
@ -215,13 +212,13 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to find event at that date"),
|
||||
title: _t("room|error_jump_to_date_title"),
|
||||
description: (
|
||||
<div data-testid="jump-to-date-error-content">
|
||||
<p>{friendlyErrorMessage}</p>
|
||||
{submitDebugLogsContent}
|
||||
<details>
|
||||
<summary>{_t("Error details")}</summary>
|
||||
<summary>{_t("room|error_jump_to_date_details")}</summary>
|
||||
<p>{String(err)}</p>
|
||||
</details>
|
||||
</div>
|
||||
|
@ -285,7 +282,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
data-testid="jump-to-date-last-month"
|
||||
/>
|
||||
<IconizedContextMenuOption
|
||||
label={_t("The beginning of the room")}
|
||||
label={_t("room|jump_to_date_beginning")}
|
||||
onClick={this.onTheBeginningClicked}
|
||||
data-testid="jump-to-date-beginning"
|
||||
/>
|
||||
|
@ -304,7 +301,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
|||
data-testid="jump-to-date-separator-button"
|
||||
onClick={this.onContextMenuOpenClick}
|
||||
isExpanded={!!this.state.contextMenuPosition}
|
||||
title={_t("Jump to date")}
|
||||
title={_t("room|jump_to_date")}
|
||||
>
|
||||
<h2 className="mx_DateSeparator_dateHeading" aria-hidden="true">
|
||||
{this.getLabel()}
|
||||
|
|
|
@ -22,7 +22,7 @@ import { IBodyProps } from "./IBodyProps";
|
|||
|
||||
function getErrorMessage(mxEvent?: MatrixEvent): string {
|
||||
return mxEvent?.isEncryptedDisabledForUnverifiedDevices
|
||||
? _t("The sender has blocked you from receiving this message")
|
||||
? _t("timeline|decryption_failure_blocked")
|
||||
: _t("threads|unable_to_decrypt");
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ export default class DisambiguatedProfile extends React.Component<IProps> {
|
|||
if (member?.disambiguate) {
|
||||
mxidElement = <span className="mx_DisambiguatedProfile_mxid">{identifier}</span>;
|
||||
}
|
||||
title = _t("%(displayName)s (%(matrixId)s)", {
|
||||
title = _t("timeline|disambiguated_profile", {
|
||||
displayName: rawDisplayName,
|
||||
matrixId: identifier,
|
||||
});
|
||||
|
|
|
@ -48,7 +48,7 @@ export default class DownloadActionButton extends React.PureComponent<IProps, IS
|
|||
|
||||
this.state = {
|
||||
loading: false,
|
||||
tooltip: _td("Downloading"),
|
||||
tooltip: _td("timeline|download_action_downloading"),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ export default class DownloadActionButton extends React.PureComponent<IProps, IS
|
|||
if (this.state.loading || !mediaEventHelper) return;
|
||||
|
||||
if (mediaEventHelper.media.isEncrypted) {
|
||||
this.setState({ tooltip: _td("Decrypting") });
|
||||
this.setState({ tooltip: _td("timeline|download_action_decrypting") });
|
||||
}
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
|
|
@ -49,19 +49,14 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp
|
|||
const dmPartner = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
||||
const room = cli?.getRoom(roomId);
|
||||
if (prevContent.algorithm === ALGORITHM) {
|
||||
subtitle = _t("Some encryption parameters have been changed.");
|
||||
subtitle = _t("timeline|m.room.encryption|parameters_changed");
|
||||
} else if (dmPartner) {
|
||||
const displayName = room?.getMember(dmPartner)?.rawDisplayName || dmPartner;
|
||||
subtitle = _t(
|
||||
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their profile picture.",
|
||||
{ displayName },
|
||||
);
|
||||
subtitle = _t("timeline|m.room.encryption|enabled_dm", { displayName });
|
||||
} else if (room && isLocalRoom(room)) {
|
||||
subtitle = _t("Messages in this chat will be end-to-end encrypted.");
|
||||
subtitle = _t("timeline|m.room.encryption|enabled_local");
|
||||
} else {
|
||||
subtitle = _t(
|
||||
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their profile picture.",
|
||||
);
|
||||
subtitle = _t("timeline|m.room.encryption|enabled");
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -79,7 +74,7 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp
|
|||
<EventTileBubble
|
||||
className="mx_cryptoEvent mx_cryptoEvent_icon"
|
||||
title={_t("common|encryption_enabled")}
|
||||
subtitle={_t("Ignored attempt to disable encryption")}
|
||||
subtitle={_t("timeline|m.room.encryption|disable_attempt")}
|
||||
timestamp={timestamp}
|
||||
/>
|
||||
);
|
||||
|
@ -88,8 +83,8 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp
|
|||
return (
|
||||
<EventTileBubble
|
||||
className="mx_cryptoEvent mx_cryptoEvent_icon mx_cryptoEvent_icon_warning"
|
||||
title={_t("Encryption not enabled")}
|
||||
subtitle={_t("The encryption used by this room isn't supported.")}
|
||||
title={_t("timeline|m.room.encryption|disabled")}
|
||||
subtitle={_t("timeline|m.room.encryption|unsupported")}
|
||||
ref={ref}
|
||||
timestamp={timestamp}
|
||||
/>
|
||||
|
|
|
@ -38,9 +38,9 @@ const HiddenBody = React.forwardRef<any, IProps | IBodyProps>(({ mxEvent }, ref)
|
|||
throw new Error("HiddenBody should only be applied to hidden messages");
|
||||
case false:
|
||||
if (visibility.reason) {
|
||||
text = _t("Message pending moderation: %(reason)s", { reason: visibility.reason });
|
||||
text = _t("timeline|pending_moderation_reason", { reason: visibility.reason });
|
||||
} else {
|
||||
text = _t("Message pending moderation");
|
||||
text = _t("timeline|pending_moderation");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ const JumpToDatePicker: React.FC<IProps> = ({ ts, onDatePicked }: IProps) => {
|
|||
|
||||
return (
|
||||
<form className="mx_JumpToDatePicker_form" onSubmit={onJumpToDateSubmit}>
|
||||
<span className="mx_JumpToDatePicker_label">{_t("Jump to date")}</span>
|
||||
<span className="mx_JumpToDatePicker_label">{_t("room|jump_to_date")}</span>
|
||||
<Field
|
||||
element="input"
|
||||
type="date"
|
||||
|
@ -51,7 +51,7 @@ const JumpToDatePicker: React.FC<IProps> = ({ ts, onDatePicked }: IProps) => {
|
|||
// events there anyway).
|
||||
max={formatDateForInput(new Date())}
|
||||
className="mx_JumpToDatePicker_datePicker"
|
||||
label={_t("Pick a date to jump to")}
|
||||
label={_t("room|jump_to_date_prompt")}
|
||||
onFocus={onFocus}
|
||||
inputRef={ref}
|
||||
tabIndex={isActive ? 0 : -1}
|
||||
|
|
|
@ -157,23 +157,23 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
|||
if (gotRejected) {
|
||||
return (
|
||||
<div className="mx_LegacyCallEvent_content">
|
||||
{_t("Call declined")}
|
||||
{this.renderCallBackButton(_t("Call back"))}
|
||||
{_t("timeline|m.call.invite|declined")}
|
||||
{this.renderCallBackButton(_t("timeline|m.call.invite|call_back_prompt"))}
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
);
|
||||
} else if (hangupReason === CallErrorCode.AnsweredElsewhere) {
|
||||
return (
|
||||
<div className="mx_LegacyCallEvent_content">
|
||||
{_t("Answered elsewhere")}
|
||||
{_t("timeline|m.call.invite|answered_elsewhere")}
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.callEventGrouper.callWasMissed) {
|
||||
return (
|
||||
<div className="mx_LegacyCallEvent_content">
|
||||
{_t("Missed call")}
|
||||
{this.renderCallBackButton(_t("Call back"))}
|
||||
{_t("timeline|m.call.invite|missed_call")}
|
||||
{this.renderCallBackButton(_t("timeline|m.call.invite|call_back_prompt"))}
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
);
|
||||
|
@ -198,8 +198,8 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
|||
} else if (hangupReason === CallErrorCode.InviteTimeout) {
|
||||
return (
|
||||
<div className="mx_LegacyCallEvent_content">
|
||||
{_t("No answer")}
|
||||
{this.renderCallBackButton(_t("Call back"))}
|
||||
{_t("timeline|m.call.invite|no_answer")}
|
||||
{this.renderCallBackButton(_t("timeline|m.call.invite|call_back_prompt"))}
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
);
|
||||
|
@ -208,22 +208,22 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
|||
let reason;
|
||||
if (hangupReason === CallErrorCode.IceFailed) {
|
||||
// We couldn't establish a connection at all
|
||||
reason = _t("Could not connect media");
|
||||
reason = _t("timeline|m.call.invite|failed_connect_media");
|
||||
} else if (hangupReason === "ice_timeout") {
|
||||
// We established a connection but it died
|
||||
reason = _t("Connection failed");
|
||||
reason = _t("timeline|m.call.invite|failed_connection");
|
||||
} else if (hangupReason === CallErrorCode.NoUserMedia) {
|
||||
// The other side couldn't open capture devices
|
||||
reason = _t("Their device couldn't start the camera or microphone");
|
||||
reason = _t("timeline|m.call.invite|failed_opponent_media");
|
||||
} else if (hangupReason === "unknown_error") {
|
||||
// An error code the other side doesn't have a way to express
|
||||
// (as opposed to an error code they gave but we don't know about,
|
||||
// in which case we show the error code)
|
||||
reason = _t("An unknown error occurred");
|
||||
reason = _t("timeline|m.call.invite|unknown_error");
|
||||
} else if (hangupReason === CallErrorCode.UserBusy) {
|
||||
reason = _t("voip|user_busy_description");
|
||||
} else {
|
||||
reason = _t("Unknown failure: %(reason)s", { reason: hangupReason });
|
||||
reason = _t("timeline|m.call.invite|unknown_failure", { reason: hangupReason });
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -233,7 +233,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
|||
className="mx_LegacyCallEvent_content_tooltip"
|
||||
kind={InfoTooltipKind.Warning}
|
||||
/>
|
||||
{_t("Connection failed")}
|
||||
{_t("timeline|m.call.invite|failed_connection")}
|
||||
{this.renderCallBackButton(_t("action|retry"))}
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
|
@ -258,7 +258,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
|
|||
|
||||
return (
|
||||
<div className="mx_LegacyCallEvent_content">
|
||||
{_t("The call is in an unknown state!")}
|
||||
{_t("timeline|m.call.invite|unknown_state")}
|
||||
{this.props.timestamp}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -98,7 +98,7 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
|
|||
if (this.state.error) {
|
||||
return (
|
||||
<MediaProcessingError className="mx_MAudioBody">
|
||||
{_t("Error processing audio message")}
|
||||
{_t("timeline|m.audio|error_processing_audio")}
|
||||
</MediaProcessingError>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ const MBeaconBody = React.forwardRef<HTMLDivElement, IBodyProps>(({ mxEvent, get
|
|||
className="mx_MBeaconBody_chin"
|
||||
beacon={beacon}
|
||||
displayStatus={displayStatus}
|
||||
label={_t("View live location")}
|
||||
label={_t("timeline|m.beacon_info|view_live_location")}
|
||||
withIcon
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -150,7 +150,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
imgSrc: DOWNLOAD_ICON_URL,
|
||||
imgStyle: null,
|
||||
style: computedStyle(this.dummyLink.current),
|
||||
textContent: _t("Download %(text)s", { text }),
|
||||
textContent: _t("timeline|m.file|download_label", { text }),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
logger.warn("Unable to decrypt attachment: ", err);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("common|error"),
|
||||
description: _t("Error decrypting attachment"),
|
||||
description: _t("timeline|m.file|error_decrypting"),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -248,7 +248,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
{showDownloadLink && (
|
||||
<div className="mx_MFileBody_download">
|
||||
<AccessibleButton onClick={this.decryptFile}>
|
||||
{_t("Decrypt %(text)s", { text: this.linkText })}
|
||||
{_t("timeline|m.file|decrypt_label", { text: this.linkText })}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
)}
|
||||
|
@ -346,7 +346,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
<div className="mx_MFileBody_download">
|
||||
<a {...downloadProps}>
|
||||
<span className="mx_MFileBody_download_icon" />
|
||||
{_t("Download %(text)s", { text: this.linkText })}
|
||||
{_t("timeline|m.file|download_label", { text: this.linkText })}
|
||||
</a>
|
||||
{this.context.timelineRenderingType === TimelineRenderingType.File && (
|
||||
<div className="mx_MImageBody_size">
|
||||
|
@ -362,7 +362,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
|||
return (
|
||||
<span className="mx_MFileBody">
|
||||
{placeholder}
|
||||
{_t("Invalid file%(extra)s", { extra: extra })}
|
||||
{_t("timeline|m.file|error_invalid", { extra: extra })}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -604,11 +604,11 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
const content = this.props.mxEvent.getContent<ImageContent>();
|
||||
|
||||
if (this.state.error) {
|
||||
let errorText = _t("Unable to show image due to error");
|
||||
let errorText = _t("timeline|m.image|error");
|
||||
if (this.state.error instanceof DecryptError) {
|
||||
errorText = _t("Error decrypting image");
|
||||
errorText = _t("timeline|m.image|error_decrypting");
|
||||
} else if (this.state.error instanceof DownloadError) {
|
||||
errorText = _t("Error downloading image");
|
||||
errorText = _t("timeline|m.image|error_downloading");
|
||||
}
|
||||
|
||||
return <MediaProcessingError className="mx_MImageBody">{errorText}</MediaProcessingError>;
|
||||
|
@ -651,7 +651,7 @@ export class HiddenImagePlaceholder extends React.PureComponent<PlaceholderIProp
|
|||
<div className={className} style={{ maxWidth: `min(100%, ${maxWidth}px)` }}>
|
||||
<div className="mx_HiddenImagePlaceholder_button">
|
||||
<span className="mx_HiddenImagePlaceholder_eye" />
|
||||
<span>{_t("Show image")}</span>
|
||||
<span>{_t("timeline|m.image|show_image")}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -42,9 +42,9 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
|
|||
const widgetId = this.props.mxEvent.getStateKey();
|
||||
const widget = WidgetStore.instance.getRoom(room.roomId, true).widgets.find((w) => w.id === widgetId);
|
||||
|
||||
let joinCopy: string | null = _t("Join the conference at the top of this room");
|
||||
let joinCopy: string | null = _t("timeline|m.widget|jitsi_join_top_prompt");
|
||||
if (widget && WidgetLayoutStore.instance.isInContainer(room, widget, Container.Right)) {
|
||||
joinCopy = _t("Join the conference from the room information card on the right");
|
||||
joinCopy = _t("timeline|m.widget|jitsi_join_right_prompt");
|
||||
} else if (!widget) {
|
||||
joinCopy = null;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
|
|||
return (
|
||||
<EventTileBubble
|
||||
className="mx_MJitsiWidgetEvent"
|
||||
title={_t("Video conference ended by %(senderName)s", { senderName })}
|
||||
title={_t("timeline|m.widget|jitsi_ended", { senderName })}
|
||||
timestamp={this.props.timestamp}
|
||||
/>
|
||||
);
|
||||
|
@ -63,7 +63,7 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
|
|||
return (
|
||||
<EventTileBubble
|
||||
className="mx_MJitsiWidgetEvent"
|
||||
title={_t("Video conference updated by %(senderName)s", { senderName })}
|
||||
title={_t("timeline|m.widget|jitsi_updated", { senderName })}
|
||||
subtitle={joinCopy}
|
||||
timestamp={this.props.timestamp}
|
||||
/>
|
||||
|
@ -73,7 +73,7 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
|
|||
return (
|
||||
<EventTileBubble
|
||||
className="mx_MJitsiWidgetEvent"
|
||||
title={_t("Video conference started by %(senderName)s", { senderName })}
|
||||
title={_t("timeline|m.widget|jitsi_started", { senderName })}
|
||||
subtitle={joinCopy}
|
||||
timestamp={this.props.timestamp}
|
||||
/>
|
||||
|
|
|
@ -109,17 +109,17 @@ export default class MKeyVerificationConclusion extends React.Component<IProps>
|
|||
let title: string | undefined;
|
||||
|
||||
if (request.phase === VerificationPhase.Done) {
|
||||
title = _t("You verified %(name)s", {
|
||||
title = _t("timeline|m.key.verification.done", {
|
||||
name: getNameForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!),
|
||||
});
|
||||
} else if (request.phase === VerificationPhase.Cancelled) {
|
||||
const userId = request.cancellingUserId;
|
||||
if (userId === myUserId) {
|
||||
title = _t("You cancelled verifying %(name)s", {
|
||||
title = _t("timeline|m.key.verification.cancel|you_cancelled", {
|
||||
name: getNameForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!),
|
||||
});
|
||||
} else if (userId) {
|
||||
title = _t("%(name)s cancelled verifying", {
|
||||
title = _t("timeline|m.key.verification.cancel|user_cancelled", {
|
||||
name: getNameForEventRoom(client, userId, mxEvent.getRoomId()!),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
|
|||
const client = MatrixClientPeg.safeGet();
|
||||
const myUserId = client.getUserId();
|
||||
if (userId === myUserId) {
|
||||
return _t("You accepted");
|
||||
return _t("timeline|m.key.verification.request|you_accepted");
|
||||
} else {
|
||||
return _t("%(name)s accepted", {
|
||||
name: getNameForEventRoom(client, userId, this.props.mxEvent.getRoomId()!),
|
||||
|
@ -110,9 +110,9 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
|
|||
const declined = cancellationCode === "m.user";
|
||||
if (userId === myUserId) {
|
||||
if (declined) {
|
||||
return _t("You declined");
|
||||
return _t("timeline|m.key.verification.request|you_declined");
|
||||
} else {
|
||||
return _t("You cancelled");
|
||||
return _t("timeline|m.key.verification.request|you_cancelled");
|
||||
}
|
||||
} else {
|
||||
if (declined) {
|
||||
|
@ -157,7 +157,7 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
|
|||
} else if (request.accepting) {
|
||||
stateLabel = _t("encryption|verification|accepting");
|
||||
} else if (request.declining) {
|
||||
stateLabel = _t("Declining…");
|
||||
stateLabel = _t("timeline|m.key.verification.request|declining");
|
||||
}
|
||||
stateNode = <div className="mx_cryptoEvent_state">{stateLabel}</div>;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
|
|||
}
|
||||
} else {
|
||||
// request sent by us
|
||||
title = _t("You sent a verification request");
|
||||
title = _t("timeline|m.key.verification.request|you_started");
|
||||
subtitle = userLabelForEventRoom(client, request.otherUserId, mxEvent.getRoomId()!);
|
||||
}
|
||||
|
||||
|
|
|
@ -126,8 +126,8 @@ export function launchPollEditor(mxEvent: MatrixEvent, getRelationsForEvent?: Ge
|
|||
const room = MatrixClientPeg.safeGet().getRoom(mxEvent.getRoomId());
|
||||
if (pollAlreadyHasVotes(mxEvent, getRelationsForEvent)) {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Can't edit poll"),
|
||||
description: _t("Sorry, you can't edit a poll after votes have been cast."),
|
||||
title: _t("poll|unable_edit_title"),
|
||||
description: _t("poll|unable_edit_description"),
|
||||
});
|
||||
} else if (room) {
|
||||
Modal.createDialog(
|
||||
|
@ -229,8 +229,8 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
|||
console.error("Failed to submit poll response event:", e);
|
||||
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Vote not registered"),
|
||||
description: _t("Sorry, your vote was not registered. Please try again."),
|
||||
title: _t("poll|error_voting_title"),
|
||||
description: _t("poll|error_voting_description"),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -306,19 +306,19 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
|
|||
|
||||
let totalText: string;
|
||||
if (showResults && poll.undecryptableRelationsCount) {
|
||||
totalText = _t("Due to decryption errors, some votes may not be counted");
|
||||
totalText = _t("poll|total_decryption_errors");
|
||||
} else if (poll.isEnded) {
|
||||
totalText = _t("Final result based on %(count)s votes", { count: totalVotes });
|
||||
totalText = _t("right_panel|poll|final_result", { count: totalVotes });
|
||||
} else if (!disclosed) {
|
||||
totalText = _t("Results will be visible when the poll is ended");
|
||||
totalText = _t("poll|total_not_ended");
|
||||
} else if (myVote === undefined) {
|
||||
if (totalVotes === 0) {
|
||||
totalText = _t("No votes cast");
|
||||
totalText = _t("poll|total_no_votes");
|
||||
} else {
|
||||
totalText = _t("%(count)s votes cast. Vote to see the results", { count: totalVotes });
|
||||
totalText = _t("poll|total_n_votes", { count: totalVotes });
|
||||
}
|
||||
} else {
|
||||
totalText = _t("Based on %(count)s votes", { count: totalVotes });
|
||||
totalText = _t("poll|total_n_votes_voted", { count: totalVotes });
|
||||
}
|
||||
|
||||
const editedSpan = this.props.mxEvent.replacingEvent() ? (
|
||||
|
|
|
@ -109,7 +109,7 @@ export const MPollEndBody = React.forwardRef<any, IBodyProps>(({ mxEvent, ...pro
|
|||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<Caption>{_t("Ended a poll")}</Caption>
|
||||
<Caption>{_t("timeline|m.poll.end|ended")}</Caption>
|
||||
<MPollBody mxEvent={pollStartEvent} {...props} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -250,7 +250,9 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
|
|||
|
||||
if (this.state.error !== null) {
|
||||
return (
|
||||
<MediaProcessingError className="mx_MVideoBody">{_t("Error decrypting video")}</MediaProcessingError>
|
||||
<MediaProcessingError className="mx_MVideoBody">
|
||||
{_t("timeline|m.video|error_decrypting")}
|
||||
</MediaProcessingError>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ export default class MVoiceMessageBody extends MAudioBody {
|
|||
if (this.state.error) {
|
||||
return (
|
||||
<MediaProcessingError className="mx_MVoiceMessageBody">
|
||||
{_t("Error processing voice message")}
|
||||
{_t("timeline|m.audio|error_processing_voice_message")}
|
||||
</MediaProcessingError>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -237,16 +237,12 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent }) => {
|
|||
<>
|
||||
<div className="mx_Tooltip_title">
|
||||
{!hasARelation
|
||||
? _t("Reply in thread")
|
||||
: _t("Can't create a thread from an event with an existing relation")}
|
||||
? _t("action|reply_in_thread")
|
||||
: _t("threads|error_start_thread_existing_relation")}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
title={
|
||||
!hasARelation
|
||||
? _t("Reply in thread")
|
||||
: _t("Can't create a thread from an event with an existing relation")
|
||||
}
|
||||
title={!hasARelation ? _t("action|reply_in_thread") : _t("threads|error_start_thread_existing_relation")}
|
||||
onClick={onClick}
|
||||
onContextMenu={onClick}
|
||||
>
|
||||
|
@ -515,15 +511,23 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
|
|||
const tooltip = (
|
||||
<>
|
||||
<div className="mx_Tooltip_title">
|
||||
{this.props.isQuoteExpanded ? _t("Collapse quotes") : _t("Expand quotes")}
|
||||
{this.props.isQuoteExpanded
|
||||
? _t("timeline|mab|collapse_reply_chain")
|
||||
: _t("timeline|mab|expand_reply_chain")}
|
||||
</div>
|
||||
<div className="mx_Tooltip_sub">
|
||||
{_t(ALTERNATE_KEY_NAME[Key.SHIFT]) + " + " + _t("action|click")}
|
||||
</div>
|
||||
<div className="mx_Tooltip_sub">{_t(ALTERNATE_KEY_NAME[Key.SHIFT]) + " + " + _t("Click")}</div>
|
||||
</>
|
||||
);
|
||||
toolbarOpts.push(
|
||||
<RovingAccessibleTooltipButton
|
||||
className={expandClassName}
|
||||
title={this.props.isQuoteExpanded ? _t("Collapse quotes") : _t("Expand quotes")}
|
||||
title={
|
||||
this.props.isQuoteExpanded
|
||||
? _t("timeline|mab|collapse_reply_chain")
|
||||
: _t("timeline|mab|expand_reply_chain")
|
||||
}
|
||||
tooltip={tooltip}
|
||||
onClick={this.props.toggleThreadExpanded}
|
||||
key="expand"
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class MjolnirBody extends React.Component<IBodyProps> {
|
|||
<div className="mx_MjolnirBody">
|
||||
<i>
|
||||
{_t(
|
||||
"You have ignored this user, so their message is hidden. <a>Show anyways.</a>",
|
||||
"timeline|mjolnir|message_hidden",
|
||||
{},
|
||||
{
|
||||
a: (sub) => (
|
||||
|
|
|
@ -555,9 +555,9 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
|
|||
throw new Error("renderPendingModerationMarker should only be applied to hidden messages");
|
||||
case false:
|
||||
if (visibility.reason) {
|
||||
text = _t("Message pending moderation: %(reason)s", { reason: visibility.reason });
|
||||
text = _t("timeline|pending_moderation_reason", { reason: visibility.reason });
|
||||
} else {
|
||||
text = _t("Message pending moderation");
|
||||
text = _t("timeline|pending_moderation");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ export const PollDetail: React.FC<Props> = ({ poll, permalinkCreator, requestMod
|
|||
onClick={onLinkClick}
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
{_t("View poll in timeline")}
|
||||
{_t("right_panel|poll|view_in_timeline")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -30,7 +30,7 @@ export const PollDetailHeader: React.FC<Props> = ({ filter, onNavigateBack }) =>
|
|||
return (
|
||||
<AccessibleButton kind="content_inline" onClick={onNavigateBack} className="mx_PollDetailHeader">
|
||||
<LeftCaretIcon className="mx_PollDetailHeader_icon" />
|
||||
{filter === "ACTIVE" ? _t("Active polls") : _t("Past polls")}
|
||||
{filter === "ACTIVE" ? _t("right_panel|poll|active_heading") : _t("right_panel|poll|past_heading")}
|
||||
</AccessibleButton>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ const LoadingPolls: React.FC<{ noResultsYet?: boolean }> = ({ noResultsYet }) =>
|
|||
})}
|
||||
>
|
||||
<InlineSpinner />
|
||||
{_t("Loading polls")}
|
||||
{_t("right_panel|poll|loading")}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -44,7 +44,7 @@ const LoadMorePolls: React.FC<{ loadMorePolls?: () => void; isLoading?: boolean
|
|||
kind="link_inline"
|
||||
onClick={() => loadMorePolls()}
|
||||
>
|
||||
{_t("Load more polls")}
|
||||
{_t("right_panel|poll|load_more")}
|
||||
{isLoading && <InlineSpinner />}
|
||||
</AccessibleButton>
|
||||
) : null;
|
||||
|
@ -56,25 +56,20 @@ const getNoResultsMessage = (
|
|||
loadMorePolls?: () => void,
|
||||
): string => {
|
||||
if (!loadMorePolls) {
|
||||
return filter === "ACTIVE"
|
||||
? _t("There are no active polls in this room")
|
||||
: _t("There are no past polls in this room");
|
||||
return filter === "ACTIVE" ? _t("right_panel|poll|empty_active") : _t("right_panel|poll|empty_past");
|
||||
}
|
||||
|
||||
// we don't know how much history has been fetched
|
||||
if (!oldestEventTimestamp) {
|
||||
return filter === "ACTIVE"
|
||||
? _t("There are no active polls. Load more polls to view polls for previous months")
|
||||
: _t("There are no past polls. Load more polls to view polls for previous months");
|
||||
? _t("right_panel|poll|empty_active_load_more")
|
||||
: _t("right_panel|poll|empty_past_load_more");
|
||||
}
|
||||
|
||||
const fetchedHistoryDaysCount = Math.ceil((Date.now() - oldestEventTimestamp) / ONE_DAY_MS);
|
||||
return filter === "ACTIVE"
|
||||
? _t(
|
||||
"There are no active polls for the past %(count)s days. Load more polls to view polls for previous months",
|
||||
{ count: fetchedHistoryDaysCount },
|
||||
)
|
||||
: _t("There are no past polls for the past %(count)s days. Load more polls to view polls for previous months", {
|
||||
? _t("right_panel|poll|empty_active_load_more_n_days", { count: fetchedHistoryDaysCount })
|
||||
: _t("right_panel|poll|empty_past_load_more_n_days", {
|
||||
count: fetchedHistoryDaysCount,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ export const PollListItem: React.FC<Props> = ({ event, onClick }) => {
|
|||
const formattedDate = formatLocalDateShort(event.getTs());
|
||||
return (
|
||||
<li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItem" onClick={onClick}>
|
||||
<TooltipTarget label={_t("View poll")} alignment={Alignment.Top}>
|
||||
<TooltipTarget label={_t("right_panel|poll|view_poll")} alignment={Alignment.Top}>
|
||||
<div className="mx_PollListItem_content">
|
||||
<span>{formattedDate}</span>
|
||||
<PollIcon className="mx_PollListItem_icon" />
|
||||
|
|
|
@ -100,7 +100,7 @@ export const PollListItemEnded: React.FC<Props> = ({ event, poll, onClick }) =>
|
|||
|
||||
return (
|
||||
<li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItemEnded" onClick={onClick}>
|
||||
<TooltipTarget label={_t("View poll")} alignment={Alignment.Top}>
|
||||
<TooltipTarget label={_t("right_panel|poll|view_poll")} alignment={Alignment.Top}>
|
||||
<div className="mx_PollListItemEnded_content">
|
||||
<div className="mx_PollListItemEnded_title">
|
||||
<PollIcon className="mx_PollListItemEnded_icon" />
|
||||
|
@ -124,7 +124,7 @@ export const PollListItemEnded: React.FC<Props> = ({ event, poll, onClick }) =>
|
|||
</div>
|
||||
)}
|
||||
<div className="mx_PollListItemEnded_voteCount">
|
||||
<Caption>{_t("Final result based on %(count)s votes", { count: totalVoteCount })}</Caption>
|
||||
<Caption>{_t("right_panel|poll|final_result", { count: totalVoteCount })}</Caption>
|
||||
</div>
|
||||
</div>
|
||||
</TooltipTarget>
|
||||
|
|
|
@ -1423,7 +1423,7 @@ const BasicUserInfo: React.FC<{
|
|||
let text;
|
||||
if (!isRoomEncrypted) {
|
||||
if (!cryptoEnabled) {
|
||||
text = _t("This client does not support end-to-end encryption.");
|
||||
text = _t("encryption|unsupported");
|
||||
} else if (room && !room.isSpaceRoom()) {
|
||||
text = _t("user_info|room_unencrypted");
|
||||
}
|
||||
|
@ -1487,7 +1487,7 @@ const BasicUserInfo: React.FC<{
|
|||
});
|
||||
}}
|
||||
>
|
||||
{_t("Edit devices")}
|
||||
{_t("user_info|edit_own_devices")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -147,9 +147,9 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
if (showQR) {
|
||||
qrBlock = (
|
||||
<div className="mx_UserInfo_container">
|
||||
<h3>{_t("Verify by scanning")}</h3>
|
||||
<h3>{_t("encryption|verification|scan_qr")}</h3>
|
||||
<p>
|
||||
{_t("Ask %(displayName)s to scan your code:", {
|
||||
{_t("encryption|verification|scan_qr_explainer", {
|
||||
displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
|
||||
})}
|
||||
</p>
|
||||
|
@ -165,13 +165,13 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
if (showSAS) {
|
||||
const disabled = this.state.emojiButtonClicked;
|
||||
const sasLabel = showQR
|
||||
? _t("If you can't scan the code above, verify by comparing unique emoji.")
|
||||
: _t("Verify by comparing unique emoji.");
|
||||
? _t("encryption|verification|verify_emoji_prompt_qr")
|
||||
: _t("encryption|verification|verify_emoji_prompt");
|
||||
|
||||
// Note: mx_VerificationPanel_verifyByEmojiButton is for the end-to-end tests
|
||||
sasBlock = (
|
||||
<div className="mx_UserInfo_container">
|
||||
<h3>{_t("Verify by emoji")}</h3>
|
||||
<h3>{_t("encryption|verification|verify_emoji")}</h3>
|
||||
<p>{sasLabel}</p>
|
||||
<AccessibleButton
|
||||
disabled={disabled}
|
||||
|
@ -179,7 +179,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
className="mx_UserInfo_wideButton mx_VerificationPanel_verifyByEmojiButton"
|
||||
onClick={this.startSAS}
|
||||
>
|
||||
{_t("Verify by emoji")}
|
||||
{_t("encryption|verification|verify_emoji")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
);
|
||||
|
@ -230,8 +230,8 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
private renderQRReciprocatePhase(): JSX.Element {
|
||||
const { member, request } = this.props;
|
||||
const description = request.isSelfVerification
|
||||
? _t("Almost there! Is your other device showing the same shield?")
|
||||
: _t("Almost there! Is %(displayName)s showing the same shield?", {
|
||||
? _t("encryption|verification|qr_reciprocate_same_shield_device")
|
||||
: _t("encryption|verification|qr_reciprocate_same_shield_user", {
|
||||
displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
|
||||
});
|
||||
let body: JSX.Element;
|
||||
|
@ -268,7 +268,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
}
|
||||
return (
|
||||
<div className="mx_UserInfo_container mx_VerificationPanel_reciprocate_section">
|
||||
<h3>{_t("Verify by scanning")}</h3>
|
||||
<h3>{_t("encryption|verification|scan_qr")}</h3>
|
||||
{body}
|
||||
</div>
|
||||
);
|
||||
|
@ -280,9 +280,9 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
let text: string | undefined;
|
||||
if (!request.isSelfVerification) {
|
||||
if (this.props.isRoomEncrypted) {
|
||||
text = _t("Verify all users in a room to ensure it's secure.");
|
||||
text = _t("encryption|verification|prompt_encrypted");
|
||||
} else {
|
||||
text = _t("In encrypted rooms, verify all users to ensure it's secure.");
|
||||
text = _t("encryption|verification|prompt_unencrypted");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,15 +293,15 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
// This can happen if the device is logged out while we're still showing verification
|
||||
// UI for it.
|
||||
logger.warn("Verified device we don't know about: " + this.props.request.otherDeviceId);
|
||||
description = _t("You've successfully verified your device!");
|
||||
description = _t("encryption|verification|successful_own_device");
|
||||
} else {
|
||||
description = _t("You've successfully verified %(deviceName)s (%(deviceId)s)!", {
|
||||
description = _t("encryption|verification|successful_device", {
|
||||
deviceName: device.displayName,
|
||||
deviceId: device.deviceId,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
description = _t("You've successfully verified %(displayName)s!", {
|
||||
description = _t("encryption|verification|successful_user", {
|
||||
displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
|
||||
});
|
||||
}
|
||||
|
@ -323,25 +323,25 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
|
|||
|
||||
let startAgainInstruction: string;
|
||||
if (request.isSelfVerification) {
|
||||
startAgainInstruction = _t("Start verification again from the notification.");
|
||||
startAgainInstruction = _t("encryption|verification|prompt_self");
|
||||
} else {
|
||||
startAgainInstruction = _t("Start verification again from their profile.");
|
||||
startAgainInstruction = _t("encryption|verification|prompt_user");
|
||||
}
|
||||
|
||||
let text: string;
|
||||
if (request.cancellationCode === "m.timeout") {
|
||||
text = _t("Verification timed out.") + ` ${startAgainInstruction}`;
|
||||
text = _t("encryption|verification|timed_out") + ` ${startAgainInstruction}`;
|
||||
} else if (request.cancellingUserId === request.otherUserId) {
|
||||
if (request.isSelfVerification) {
|
||||
text = _t("You cancelled verification on your other device.");
|
||||
text = _t("encryption|verification|cancelled_self");
|
||||
} else {
|
||||
text = _t("%(displayName)s cancelled verification.", {
|
||||
text = _t("encryption|verification|cancelled_user", {
|
||||
displayName: (member as User).displayName || (member as RoomMember).name || member.userId,
|
||||
});
|
||||
}
|
||||
text = `${text} ${startAgainInstruction}`;
|
||||
} else {
|
||||
text = _t("You cancelled verification.") + ` ${startAgainInstruction}`;
|
||||
text = _t("encryption|verification|cancelled") + ` ${startAgainInstruction}`;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue