Migrate more strings to translation keys (#11683)

This commit is contained in:
Michael Telatynski 2023-10-02 13:52:27 +01:00 committed by GitHub
parent 632d8f4bc7
commit 41a2325a2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
86 changed files with 4744 additions and 4051 deletions

View file

@ -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>,

View file

@ -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;

View file

@ -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}
/>
);

View file

@ -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>

View file

@ -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()}

View file

@ -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");
}

View file

@ -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,
});

View file

@ -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 });

View file

@ -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}
/>

View file

@ -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;
}

View file

@ -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}

View file

@ -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>
);

View file

@ -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>
);
}

View file

@ -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
/>
)}

View file

@ -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>
);
}

View file

@ -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>
);

View file

@ -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}
/>

View file

@ -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()!),
});
}

View file

@ -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()!);
}

View file

@ -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() ? (

View file

@ -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>
);

View file

@ -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>
);
}

View file

@ -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>
);
}

View file

@ -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"

View file

@ -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) => (

View file

@ -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;
}

View file

@ -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>
</>

View file

@ -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>
);
};

View file

@ -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,
});
};

View file

@ -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" />

View file

@ -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>

View file

@ -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>
);

View file

@ -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 (