Fix instances of double translation and guard translation calls using typescript (#11443)

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
Michael Telatynski 2023-08-22 16:32:05 +01:00 committed by GitHub
parent d13b6e1b41
commit ac70f7ac9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
157 changed files with 554 additions and 780 deletions

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, { PureComponent, RefCallback, RefObject } from "react";
import Field, { IInputProps } from "../elements/Field";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
import * as Email from "../../../email";
@ -27,9 +27,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
value: string;
autoFocus?: boolean;
label?: string;
labelRequired?: string;
labelInvalid?: string;
label: TranslationKey;
labelRequired: TranslationKey;
labelInvalid: TranslationKey;
// When present, completely overrides the default validation rules.
validationRules?: (fieldState: IFieldState) => Promise<IValidationResult>;
@ -50,12 +50,12 @@ class EmailField extends PureComponent<IProps> {
{
key: "required",
test: ({ value, allowEmpty }) => allowEmpty || !!value,
invalid: () => _t(this.props.labelRequired!),
invalid: () => _t(this.props.labelRequired),
},
{
key: "email",
test: ({ value }) => !value || Email.looksValid(value),
invalid: () => _t(this.props.labelInvalid!),
invalid: () => _t(this.props.labelInvalid),
},
],
});
@ -80,7 +80,7 @@ class EmailField extends PureComponent<IProps> {
id={this.props.id}
ref={this.props.fieldRef}
type="text"
label={_t(this.props.label!)}
label={_t(this.props.label)}
value={this.props.value}
autoFocus={this.props.autoFocus}
onChange={this.props.onChange}

View file

@ -220,8 +220,7 @@ export class RecaptchaAuthEntry extends React.Component<IRecaptchaAuthEntryProps
let sitePublicKey: string | undefined;
if (!this.props.stageParams || !this.props.stageParams.public_key) {
errorText = _t(
"Missing captcha public key in homeserver configuration. Please report " +
"this to your homeserver administrator.",
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.",
);
} else {
sitePublicKey = this.props.stageParams.public_key;

View file

@ -18,7 +18,7 @@ import React, { PureComponent, RefCallback, RefObject } from "react";
import Field, { IInputProps } from "../elements/Field";
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> {
id?: string;
@ -27,9 +27,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> {
value: string;
password: string; // The password we're confirming
label: string;
labelRequired: string;
labelInvalid: string;
label: TranslationKey;
labelRequired: TranslationKey;
labelInvalid: TranslationKey;
onChange(ev: React.FormEvent<HTMLElement>): void;
onValidate?(result: IValidationResult): void;

View file

@ -20,7 +20,7 @@ import zxcvbn from "zxcvbn";
import SdkConfig from "../../../SdkConfig";
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import Field, { IInputProps } from "../elements/Field";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
@ -34,10 +34,10 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
// Additional strings such as a username used to catch bad passwords
userInputs?: string[];
label: string;
labelEnterPassword: string;
labelStrongPassword: string;
labelAllowedButUnsafe: string;
label: TranslationKey;
labelEnterPassword: TranslationKey;
labelStrongPassword: TranslationKey;
labelAllowedButUnsafe: TranslationKey;
onChange(ev: React.FormEvent<HTMLElement>): void;
onValidate?(result: IValidationResult): void;

View file

@ -19,9 +19,9 @@ import React, { useEffect, useState } from "react";
import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../MediaDeviceHandler";
import IconizedContextMenu, { IconizedContextMenuOptionList, IconizedContextMenuRadio } from "./IconizedContextMenu";
import { IProps as IContextMenuProps } from "../../structures/ContextMenu";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
const SECTION_NAMES: Record<MediaDeviceKindEnum, string> = {
const SECTION_NAMES: Record<MediaDeviceKindEnum, TranslationKey> = {
[MediaDeviceKindEnum.AudioInput]: _td("Input devices"),
[MediaDeviceKindEnum.AudioOutput]: _td("Output devices"),
[MediaDeviceKindEnum.VideoInput]: _td("Cameras"),

View file

@ -192,8 +192,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
Modal.createDialog(QuestionDialog, {
title: _t("Delete Widget"),
description: _t(
"Deleting a widget removes it for all users in this room." +
" Are you sure you want to delete this widget?",
"Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?",
),
button: _t("Delete widget"),
onFinished: (confirmed) => {

View file

@ -20,7 +20,7 @@ import { Room, EventType } from "matrix-js-sdk/src/matrix";
import { sleep } from "matrix-js-sdk/src/utils";
import { logger } from "matrix-js-sdk/src/logger";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import BaseDialog from "./BaseDialog";
import Dropdown from "../elements/Dropdown";
import SearchBox from "../../structures/SearchBox";
@ -357,7 +357,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
};
const defaultRendererFactory =
(title: string): Renderer =>
(title: TranslationKey): Renderer =>
(rooms, selectedToAdd, { scrollTop, height }, onChange) =>
(
<div className="mx_AddExistingToSpace_section">

View file

@ -78,9 +78,7 @@ export const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
<div className="mx_AnalyticsLearnMore_image_holder" />
<div className="mx_AnalyticsLearnMore_copy">
{_t(
"Help us identify issues and improve %(analyticsOwner)s by sharing anonymous usage data. " +
"To understand how people use multiple devices, we'll generate a random identifier, " +
"shared by your devices.",
"Help us identify issues and improve %(analyticsOwner)s by sharing anonymous usage data. To understand how people use multiple devices, we'll generate a random identifier, shared by your devices.",
{ analyticsOwner },
)}
</div>

View file

@ -224,10 +224,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
{warning}
<p>
{_t(
"Debug logs contain application usage data including your " +
"username, the IDs or aliases of the rooms you " +
"have visited, which UI elements you last interacted with, " +
"and the usernames of other users. They do not contain messages.",
"Debug logs contain application usage data including your username, the IDs or aliases of the rooms you have visited, which UI elements you last interacted with, and the usernames of other users. They do not contain messages.",
)}
</p>
<p>
@ -273,10 +270,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
onChange={this.onTextChange}
value={this.state.text}
placeholder={_t(
"If there is additional context that would help in " +
"analysing the issue, such as what you were doing at " +
"the time, room IDs, user IDs, etc., " +
"please include those things here.",
"If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.",
)}
/>
{progress}

View file

@ -114,16 +114,13 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
<div className="mx_Dialog_content" id="mx_Dialog_content">
<p>
{_t(
"You are about to remove %(count)s messages by %(user)s. " +
"This will remove them permanently for everyone in the conversation. " +
"Do you wish to continue?",
"You are about to remove %(count)s messages by %(user)s. This will remove them permanently for everyone in the conversation. Do you wish to continue?",
{ count, user },
)}
</p>
<p>
{_t(
"For a large amount of messages, this might take some time. " +
"Please don't refresh your client in the meantime.",
"For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.",
)}
</p>
<StyledCheckbox checked={keepStateEvents} onChange={(e) => setKeepStateEvents(e.target.checked)}>
@ -131,8 +128,7 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
</StyledCheckbox>
<div className="mx_BulkRedactDialog_checkboxMicrocopy">
{_t(
"Uncheck if you also want to remove system messages on this user " +
"(e.g. membership change, profile change…)",
"Uncheck if you also want to remove system messages on this user (e.g. membership change, profile change…)",
)}
</div>
</div>

View file

@ -26,8 +26,7 @@ export const createCantStartVoiceMessageBroadcastDialog = (): void => {
description: (
<p>
{_t(
"You can't start a voice message as you are currently recording a live broadcast. " +
"Please end your live broadcast in order to start recording a voice message.",
"You can't start a voice message as you are currently recording a live broadcast. Please end your live broadcast in order to start recording a voice message.",
)}
</p>
),

View file

@ -44,8 +44,7 @@ export default class ConfirmWipeDeviceDialog extends React.Component<IProps> {
<div className="mx_ConfirmWipeDeviceDialog_content">
<p>
{_t(
"Clearing all data from this session is permanent. Encrypted messages will be lost " +
"unless their keys have been backed up.",
"Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.",
)}
</p>
</div>

View file

@ -311,8 +311,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
}
} else {
microcopy = _t(
"Your server admin has disabled end-to-end encryption by default " +
"in private rooms & Direct Messages.",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
);
}
e2eeSection = (
@ -330,15 +329,13 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
}
let federateLabel = _t(
"You might enable this if the room will only be used for collaborating with internal " +
"teams on your homeserver. This cannot be changed later.",
"You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.",
);
if (SdkConfig.get().default_federate === false) {
// We only change the label if the default setting is different to avoid jarring text changes to the
// user. They will have read the implications of turning this off/on, so no need to rephrase for them.
federateLabel = _t(
"You might disable this if the room will be used for collaborating with external " +
"teams who have their own homeserver. This cannot be changed later.",
"You might disable this if the room will be used for collaborating with external teams who have their own homeserver. This cannot be changed later.",
);
}

View file

@ -36,9 +36,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
Modal.createDialog(QuestionDialog, {
title: _t("Sign out"),
description: _t(
"To avoid losing your chat history, you must export your room keys " +
"before logging out. You will need to go back to the newer version of " +
"%(brand)s to do this",
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this",
{ brand },
),
button: _t("Sign out"),
@ -53,9 +51,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
};
const description = _t(
"You've previously used a newer version of %(brand)s with this session. " +
"To use this version again with end to end encryption, you will " +
"need to sign out and back in again.",
"You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.",
{ brand },
);

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, { useState } from "react";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import BaseDialog from "./BaseDialog";
import { TimelineEventEditor } from "./devtools/Event";
@ -40,13 +40,13 @@ enum Category {
Other,
}
const categoryLabels: Record<Category, string> = {
const categoryLabels: Record<Category, TranslationKey> = {
[Category.Room]: _td("Room"),
[Category.Other]: _td("Other"),
};
export type Tool = React.FC<IDevtoolsProps> | ((props: IDevtoolsProps) => JSX.Element);
const Tools: Record<Category, [label: string, tool: Tool][]> = {
const Tools: Record<Category, [label: TranslationKey, tool: Tool][]> = {
[Category.Room]: [
[_td("Send custom timeline event"), TimelineEventEditor],
[_td("Explore room state"), RoomStateExplorer],

View file

@ -70,9 +70,7 @@ export default class EndPollDialog extends React.Component<IProps> {
<QuestionDialog
title={_t("End Poll")}
description={_t(
"Are you sure you want to end this poll? " +
"This will show the final results of the poll and " +
"stop people from being able to vote.",
"Are you sure you want to end this poll? This will show the final results of the poll and stop people from being able to vote.",
)}
button={_t("End Poll")}
onFinished={(endPoll: boolean) => this.onFinished(endPoll)}

View file

@ -96,8 +96,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
bugReports = (
<p className="mx_FeedbackDialog_section_microcopy">
{_t(
"PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> " +
"to help us track down the problem.",
"PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> to help us track down the problem.",
{},
{
debugLogsLink: (sub) => (
@ -125,8 +124,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
<h3>{_t("Report a bug")}</h3>
<p>
{_t(
"Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. " +
"No match? <newIssueLink>Start a new one</newIssueLink>.",
"Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. No match? <newIssueLink>Start a new one</newIssueLink>.",
{},
{
existingIssuesLink: (sub) => {

View file

@ -181,17 +181,14 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
const userDetailText = [
<p key="p1">
{_t(
"Verify this user to mark them as trusted. " +
"Trusting users gives you extra peace of mind when using " +
"end-to-end encrypted messages.",
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
)}
</p>,
<p key="p2">
{_t(
// NB. Below wording adjusted to singular 'session' until we have
// cross-signing
"Verifying this user will mark their session as trusted, and " +
"also mark your session as trusted to them.",
"Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
)}
</p>,
];
@ -199,15 +196,12 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
const selfDetailText = [
<p key="p1">
{_t(
"Verify this device to mark it as trusted. " +
"Trusting this device gives you and other users extra peace of mind when using " +
"end-to-end encrypted messages.",
"Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.",
)}
</p>,
<p key="p2">
{_t(
"Verifying this device will mark it as trusted, and users who have verified with " +
"you will trust this device.",
"Verifying this device will mark it as trusted, and users who have verified with you will trust this device.",
)}
</p>,
];

View file

@ -43,8 +43,7 @@ export default class IntegrationsImpossibleDialog extends React.Component<IProps
<div className="mx_IntegrationsImpossibleDialog_content">
<p>
{_t(
"Your %(brand)s doesn't allow you to use an integration manager to do this. " +
"Please contact an admin.",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.",
{ brand },
)}
</p>

View file

@ -1133,9 +1133,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
return (
<div className="mx_InviteDialog_identityServer">
{_t(
"Use an identity server to invite by email. " +
"<default>Use the default (%(defaultIdentityServerName)s)</default> " +
"or manage in <settings>Settings</settings>.",
"Use an identity server to invite by email. <default>Use the default (%(defaultIdentityServerName)s)</default> or manage in <settings>Settings</settings>.",
{
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
},
@ -1158,7 +1156,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
return (
<div className="mx_InviteDialog_identityServer">
{_t(
"Use an identity server to invite by email. " + "Manage in <settings>Settings</settings>.",
"Use an identity server to invite by email. Manage in <settings>Settings</settings>.",
{},
{
settings: (sub) => (
@ -1349,23 +1347,21 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
if (isSpace) {
if (identityServersEnabled) {
helpTextUntranslated = _td(
"Invite someone using their name, email address, username " +
"(like <userId/>) or <a>share this space</a>.",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this space</a>.",
);
} else {
helpTextUntranslated = _td(
"Invite someone using their name, username " + "(like <userId/>) or <a>share this space</a>.",
"Invite someone using their name, username (like <userId/>) or <a>share this space</a>.",
);
}
} else {
if (identityServersEnabled) {
helpTextUntranslated = _td(
"Invite someone using their name, email address, username " +
"(like <userId/>) or <a>share this room</a>.",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.",
);
} else {
helpTextUntranslated = _td(
"Invite someone using their name, username " + "(like <userId/>) or <a>share this room</a>.",
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.",
);
}
}

View file

@ -29,19 +29,14 @@ interface IProps {
const LazyLoadingDisabledDialog: React.FC<IProps> = (props) => {
const brand = SdkConfig.get().brand;
const description1 = _t(
"You've previously used %(brand)s on %(host)s with lazy loading of members enabled. " +
"In this version lazy loading is disabled. " +
"As the local cache is not compatible between these two settings, " +
"%(brand)s needs to resync your account.",
"You've previously used %(brand)s on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, %(brand)s needs to resync your account.",
{
brand,
host: props.host,
},
);
const description2 = _t(
"If the other version of %(brand)s is still open in another tab, " +
"please close it as using %(brand)s on the same host with both " +
"lazy loading enabled and disabled simultaneously will cause issues.",
"If the other version of %(brand)s is still open in another tab, please close it as using %(brand)s on the same host with both lazy loading enabled and disabled simultaneously will cause issues.",
{
brand,
},

View file

@ -28,9 +28,7 @@ interface IProps {
const LazyLoadingResyncDialog: React.FC<IProps> = (props) => {
const brand = SdkConfig.get().brand;
const description = _t(
"%(brand)s now uses 3-5x less memory, by only loading information " +
"about other users when needed. Please wait whilst we resynchronise " +
"with the server!",
"%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!",
{ brand },
);

View file

@ -63,15 +63,12 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
let onlyAdminWarning;
if (isOnlyAdmin(space)) {
onlyAdminWarning = _t(
"You're the only admin of this space. " + "Leaving it will mean no one has control over it.",
);
onlyAdminWarning = _t("You're the only admin of this space. Leaving it will mean no one has control over it.");
} else {
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdmin).length;
if (numChildrenOnlyAdminIn > 0) {
onlyAdminWarning = _t(
"You're the only admin of some of the rooms or spaces you wish to leave. " +
"Leaving them will leave them without any admins.",
"You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.",
);
}
}

View file

@ -138,16 +138,12 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
<div>
<p>
{_t(
"Encrypted messages are secured with end-to-end encryption. " +
"Only you and the recipient(s) have the keys to read these messages.",
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
)}
</p>
<p>
{_t(
"When you sign out, these keys will be deleted from this device, " +
"which means you won't be able to read encrypted messages unless you " +
"have the keys for them on your other devices, or backed them up to the " +
"server.",
"When you sign out, these keys will be deleted from this device, which means you won't be able to read encrypted messages unless you have the keys for them on your other devices, or backed them up to the server.",
)}
</p>
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p>

View file

@ -152,8 +152,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
>
<p>
{_t(
"Decide which spaces can access this room. " +
"If a space is selected, its members can find and join <RoomName/>.",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.",
{},
{
RoomName: () => <b>{room.name}</b>,

View file

@ -59,8 +59,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
<div className="mx_Dialog_content" id="mx_RegistrationEmailPromptDialog">
<p>
{_t(
"Just a heads up, if you don't add an email and forget your password, you could " +
"<b>permanently lose access to your account</b>.",
"Just a heads up, if you don't add an email and forget your password, you could <b>permanently lose access to your account</b>.",
{},
{
b: (sub) => <b>{sub}</b>,

View file

@ -317,54 +317,39 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
let subtitle: string;
switch (this.state.nature) {
case Nature.Disagreement:
subtitle = _t(
"What this user is writing is wrong.\n" + "This will be reported to the room moderators.",
);
subtitle = _t("What this user is writing is wrong.\nThis will be reported to the room moderators.");
break;
case Nature.Toxic:
subtitle = _t(
"This user is displaying toxic behaviour, " +
"for instance by insulting other users or sharing " +
"adult-only content in a family-friendly room " +
"or otherwise violating the rules of this room.\n" +
"This will be reported to the room moderators.",
"This user is displaying toxic behaviour, for instance by insulting other users or sharing adult-only content in a family-friendly room or otherwise violating the rules of this room.\nThis will be reported to the room moderators.",
);
break;
case Nature.Illegal:
subtitle = _t(
"This user is displaying illegal behaviour, " +
"for instance by doxing people or threatening violence.\n" +
"This will be reported to the room moderators who may escalate this to legal authorities.",
"This user is displaying illegal behaviour, for instance by doxing people or threatening violence.\nThis will be reported to the room moderators who may escalate this to legal authorities.",
);
break;
case Nature.Spam:
subtitle = _t(
"This user is spamming the room with ads, links to ads or to propaganda.\n" +
"This will be reported to the room moderators.",
"This user is spamming the room with ads, links to ads or to propaganda.\nThis will be reported to the room moderators.",
);
break;
case NonStandardValue.Admin:
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId()!)) {
subtitle = _t(
"This room is dedicated to illegal or toxic content " +
"or the moderators fail to moderate illegal or toxic content.\n" +
"This will be reported to the administrators of %(homeserver)s. " +
"The administrators will NOT be able to read the encrypted content of this room.",
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\nThis will be reported to the administrators of %(homeserver)s. The administrators will NOT be able to read the encrypted content of this room.",
{ homeserver: homeServerName },
);
} else {
subtitle = _t(
"This room is dedicated to illegal or toxic content " +
"or the moderators fail to moderate illegal or toxic content.\n" +
"This will be reported to the administrators of %(homeserver)s.",
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\nThis will be reported to the administrators of %(homeserver)s.",
{ homeserver: homeServerName },
);
}
break;
case Nature.Other:
subtitle = _t(
"Any other reason. Please describe the problem.\n" +
"This will be reported to the room moderators.",
"Any other reason. Please describe the problem.\nThis will be reported to the room moderators.",
);
break;
default:
@ -464,10 +449,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
<div className="mx_ReportEventDialog" id="mx_ReportEventDialog">
<p>
{_t(
"Reporting this message will send its unique 'event ID' to the administrator of " +
"your homeserver. If messages in this room are encrypted, your homeserver " +
"administrator will not be able to read the message text or view any files " +
"or images.",
"Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.",
)}
</p>
{adminMessage}

View file

@ -94,9 +94,7 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
>
<p>
{_t(
"Upgrading this room requires closing down the current " +
"instance of the room and creating a new room in its place. " +
"To give room members the best possible experience, we will:",
"Upgrading this room requires closing down the current instance of the room and creating a new room in its place. To give room members the best possible experience, we will:",
)}
</p>
<ol>
@ -104,14 +102,12 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
<li>{_t("Update any local room aliases to point to the new room")}</li>
<li>
{_t(
"Stop users from speaking in the old version of the room, " +
"and post a message advising users to move to the new room",
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room",
)}
</li>
<li>
{_t(
"Put a link back to the old room at the start of the new room " +
"so people can see old messages",
"Put a link back to the old room at the start of the new room so people can see old messages",
)}
</li>
</ol>

View file

@ -135,8 +135,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
let bugReports = (
<p>
{_t(
"This usually only affects how the room is processed on the server. If you're " +
"having problems with your %(brand)s, please report a bug.",
"This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.",
{ brand },
)}
</p>
@ -145,8 +144,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
bugReports = (
<p>
{_t(
"This usually only affects how the room is processed on the server. If you're " +
"having problems with your %(brand)s, please <a>report a bug</a>.",
"This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please <a>report a bug</a>.",
{
brand,
},
@ -195,14 +193,12 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
<p>
{this.props.description ||
_t(
"Upgrading a room is an advanced action and is usually recommended when a room " +
"is unstable due to bugs, missing features or security vulnerabilities.",
"Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.",
)}
</p>
<p>
{_t(
"<b>Please note upgrading will make a new version of the room</b>. " +
"All current messages will stay in this archived room.",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.",
{},
{
b: (sub) => <b>{sub}</b>,

View file

@ -107,8 +107,7 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
<div className="mx_ServerOfflineDialog_content">
<p>
{_t(
"Your server isn't responding to some of your requests. " +
"Below are some of the most likely reasons.",
"Your server isn't responding to some of your requests. Below are some of the most likely reasons.",
)}
</p>
<ul>

View file

@ -37,9 +37,7 @@ export default class SeshatResetDialog extends React.PureComponent<Props> {
{_t("You most likely do not want to reset your event index store")}
<br />
{_t(
"If you do, please note that none of your messages will be deleted, " +
"but the search experience might be degraded for a few moments " +
"whilst the index is recreated",
"If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated",
)}
</p>
</div>

View file

@ -101,17 +101,14 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
<p>
{_t(
"If you have previously used a more recent version of %(brand)s, your session " +
"may be incompatible with this version. Close this window and return " +
"to the more recent version.",
"If you have previously used a more recent version of %(brand)s, your session may be incompatible with this version. Close this window and return to the more recent version.",
{ brand },
)}
</p>
<p>
{_t(
"Clearing your browser's storage may fix the problem, but will sign you " +
"out and cause any encrypted chat history to become unreadable.",
"Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.",
)}
</p>
</div>

View file

@ -78,8 +78,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
Modal.createDialog(QuestionDialog, {
title: _t("Verification Pending"),
description: _t(
"Please check your email and click on the link it contains. Once this " +
"is done, click continue.",
"Please check your email and click on the link it contains. Once this is done, click continue.",
),
button: _t("Continue"),
onFinished: this.onEmailDialogFinished,

View file

@ -59,8 +59,7 @@ const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space
</StyledCheckbox>
<SettingsSubsectionText>
{_t(
"This groups your chats with members of this space. " +
"Turning this off will hide those chats from your view of %(spaceName)s.",
"This groups your chats with members of this space. Turning this off will hide those chats from your view of %(spaceName)s.",
{
spaceName: space.name,
},

View file

@ -65,9 +65,7 @@ export default class StorageEvictedDialog extends React.Component<IProps> {
<div className="mx_Dialog_content" id="mx_Dialog_content">
<p>
{_t(
"Some session data, including encrypted message keys, is " +
"missing. Sign out and sign in to fix this, restoring keys " +
"from backup.",
"Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.",
)}
</p>
<p>

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, { ChangeEvent, createRef } from "react";
import Field from "../elements/Field";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import { IFieldState, IValidationResult } from "../elements/Validation";
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
@ -28,7 +28,7 @@ interface IProps {
value: string;
placeholder?: string;
button?: string;
busyMessage: string; // pass _td string
busyMessage: TranslationKey;
focus: boolean;
hasCancel: boolean;
validator?: (fieldState: IFieldState) => Promise<IValidationResult>; // result of withValidation

View file

@ -49,8 +49,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
let buttons;
if (this.props.totalFiles === 1 && this.props.badFiles.length === 1) {
message = _t(
"This file is <b>too large</b> to upload. " +
"The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.",
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()),
sizeOfThisFile: fileSize(this.props.badFiles[0].size),
@ -69,7 +68,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
);
} else if (this.props.totalFiles === this.props.badFiles.length) {
message = _t(
"These files are <b>too large</b> to upload. " + "The file size limit is %(limit)s.",
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()),
},
@ -87,7 +86,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
);
} else {
message = _t(
"Some files are <b>too large</b> to be uploaded. " + "The file size limit is %(limit)s.",
"Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()),
},

View file

@ -18,7 +18,7 @@ limitations under the License.
import React, { ChangeEvent, ReactNode, useContext, useMemo, useRef, useState } from "react";
import { IContent, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { _t, _td } from "../../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../../languageHandler";
import Field from "../../elements/Field";
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
@ -37,7 +37,7 @@ interface IEventEditorProps extends Pick<IDevtoolsProps, "onBack"> {
interface IFieldDef {
id: string;
label: string; // _td
label: TranslationKey;
default?: string;
}

View file

@ -21,12 +21,12 @@ import { VerificationPhase as Phase, VerificationRequestEvent } from "matrix-js-
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { useTypedEventEmitter, useTypedEventEmitterState } from "../../../../hooks/useEventEmitter";
import { _t, _td } from "../../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../../languageHandler";
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
import { Tool } from "../DevtoolsDialog";
const PHASE_MAP: Record<Phase, string> = {
const PHASE_MAP: Record<Phase, TranslationKey> = {
[Phase.Unsent]: _td("Unsent"),
[Phase.Requested]: _td("Requested"),
[Phase.Ready]: _td("Ready"),

View file

@ -305,8 +305,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
<p>{_t("Only do this if you have no other device to complete verification with.")}</p>
<p>
{_t(
"If you reset everything, you will restart with no trusted sessions, no trusted users, and " +
"might not be able to see past messages.",
"If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.",
)}
</p>
<DialogButtons
@ -329,8 +328,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
<div className="mx_AccessSecretStorageDialog_keyStatus">
{"\uD83D\uDC4E "}
{_t(
"Unable to access secret storage. " +
"Please verify that you entered the correct Security Phrase.",
"Unable to access secret storage. Please verify that you entered the correct Security Phrase.",
)}
</div>
);

View file

@ -44,10 +44,7 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component<IP
<div className="mx_ConfirmDestroyCrossSigningDialog_content">
<p>
{_t(
"Deleting cross-signing keys is permanent. " +
"Anyone you have verified with will see security alerts. " +
"You almost certainly don't want to do this, unless " +
"you've lost every device you can cross-sign from.",
"Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.",
)}
</p>
</div>

View file

@ -351,8 +351,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
<div>
<p>
{_t(
"Backup could not be decrypted with this Security Key: " +
"please verify that you entered the correct Security Key.",
"Backup could not be decrypted with this Security Key: please verify that you entered the correct Security Key.",
)}
</p>
</div>
@ -363,8 +362,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
<div>
<p>
{_t(
"Backup could not be decrypted with this Security Phrase: " +
"please verify that you entered the correct Security Phrase.",
"Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.",
)}
</p>
</div>
@ -418,8 +416,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
</p>
<p>
{_t(
"Access your secure message history and set up secure " +
"messaging by entering your Security Phrase.",
"Access your secure message history and set up secure messaging by entering your Security Phrase.",
)}
</p>
@ -441,9 +438,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
/>
</form>
{_t(
"If you've forgotten your Security Phrase you can " +
"<button1>use your Security Key</button1> or " +
"<button2>set up new recovery options</button2>",
"If you've forgotten your Security Phrase you can <button1>use your Security Key</button1> or <button2>set up new recovery options</button2>",
{},
{
button1: (s) => (
@ -493,8 +488,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
</p>
<p>
{_t(
"Access your secure message history and set up secure " +
"messaging by entering your Security Key.",
"Access your secure message history and set up secure messaging by entering your Security Key.",
)}
</p>
@ -516,8 +510,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
/>
</div>
{_t(
"If you've forgotten your Security Key you can " +
"<button>set up new recovery options</button>",
"If you've forgotten your Security Key you can <button>set up new recovery options</button>",
{},
{
button: (s) => (

View file

@ -923,10 +923,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
<div className="mx_SpotlightDialog_section mx_SpotlightDialog_hiddenResults" role="group">
<h4>{_t("Some results may be hidden")}</h4>
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
{_t(
"If you can't find the room you're looking for, " +
"ask for an invite or create a new room.",
)}
{_t("If you can't find the room you're looking for, ask for an invite or create a new room.")}
</div>
<Option
id="mx_SpotlightDialog_button_createNewRoom"

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from "react";
import classNames from "classnames";
import { _t } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import BaseDialog from "..//dialogs/BaseDialog";
import DialogButtons from "./DialogButtons";
import AccessibleButton from "./AccessibleButton";
@ -135,7 +135,7 @@ export default class DesktopCapturerSourcePicker extends React.Component<PickerI
this.props.onFinished();
};
private getTab(type: TabId, label: string): Tab<TabId> {
private getTab(type: TabId, label: TranslationKey): Tab<TabId> {
const sources = this.state.sources
.filter((source) => source.id.startsWith(type))
.map((source) => {
@ -154,8 +154,8 @@ export default class DesktopCapturerSourcePicker extends React.Component<PickerI
public render(): React.ReactNode {
const tabs: NonEmptyArray<Tab<TabId>> = [
this.getTab("screen", _t("Share entire screen")),
this.getTab("window", _t("Application window")),
this.getTab("screen", _td("Share entire screen")),
this.getTab("window", _td("Application window")),
];
return (

View file

@ -85,8 +85,7 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
<React.Fragment>
<p>
{_t(
"Please <newIssueLink>create a new issue</newIssueLink> " +
"on GitHub so that we can investigate this bug.",
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.",
{},
{
newIssueLink: (sub) => {
@ -101,15 +100,10 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
</p>
<p>
{_t(
"If you've submitted a bug via GitHub, debug logs can help " +
"us track down the problem. ",
"If you've submitted a bug via GitHub, debug logs can help us track down the problem. ",
)}
{_t(
"Debug logs contain application " +
"usage data including your username, the IDs or aliases of " +
"the rooms you have visited, which UI elements you " +
"last interacted with, and the usernames of other users. " +
"They do not contain messages.",
"Debug logs contain application usage data including your username, the IDs or aliases of the rooms you have visited, which UI elements you last interacted with, and the usernames of other users. They do not contain messages.",
)}
</p>
<AccessibleButton onClick={this.onBugReport} kind="primary">

View file

@ -205,8 +205,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
header = (
<blockquote className="mx_ReplyChain mx_ReplyChain_error">
{_t(
"Unable to load event that was replied to, " +
"it either does not exist or you do not have permission to view it.",
"Unable to load event that was replied to, it either does not exist or you do not have permission to view it.",
)}
</blockquote>
);

View file

@ -47,9 +47,7 @@ const onHelpClick = (): void => {
{
title: _t("Server Options"),
description: _t(
"You can use the custom server options to sign into other Matrix servers by specifying " +
"a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on " +
"a different homeserver.",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.",
{ brand },
),
button: _t("Dismiss"),

View file

@ -29,7 +29,7 @@ interface IProps {
name: string;
level: SettingLevel;
roomId?: string; // for per-room settings
label?: string; // untranslated
label?: string;
isExplicit?: boolean;
// XXX: once design replaces all toggles make this the default
useCheckbox?: boolean;
@ -105,10 +105,7 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
if (!canChange && this.props.hideIfCannotSet) return null;
const label =
(this.props.label
? _t(this.props.label)
: SettingsStore.getDisplayName(this.props.name, this.props.level)) ?? undefined;
const label = this.props.label ?? SettingsStore.getDisplayName(this.props.name, this.props.level);
const description = SettingsStore.getDescription(this.props.name);
const shouldWarn = SettingsStore.shouldHaveWarning(this.props.name);
const disabled = this.state.disabled || !canChange;
@ -146,7 +143,7 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
onChange={this.onChange}
disabled={disabled}
tooltip={disabled ? SettingsStore.disabledMessage(this.props.name) : undefined}
title={label}
title={label ?? undefined}
/>
</div>
);

View file

@ -36,10 +36,7 @@ export const EnableLiveShare: React.FC<Props> = ({ onSubmit }) => {
</Heading>
<p className="mx_EnableLiveShare_description">
{_t(
"Please note: this is a labs feature using a temporary implementation. " +
"This means you will not be able to delete your location history, " +
"and advanced users will be able to see your location history " +
"even after you stop sharing your live location with this room.",
"Please note: this is a labs feature using a temporary implementation. This means you will not be able to delete your location history, and advanced users will be able to see your location history even after you stop sharing your live location with this room.",
)}
</p>
<LabelledToggleSwitch

View file

@ -167,16 +167,12 @@ export default class DateSeparator extends React.Component<IProps, IState> {
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.",
"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.",
);
} 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.",
"We were unable to find an event looking forwards from %(dateString)s. Try choosing an earlier date.",
{ dateString: formatFullDateNoDay(new Date(unixTimestamp)) },
);
} else {
@ -192,8 +188,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.",
"Please submit <debugLogsLink>debug logs</debugLogsLink> to help us track down the problem.",
{},
{
debugLogsLink: (sub) => (

View file

@ -22,7 +22,7 @@ import { Icon as DownloadIcon } from "../../../../res/img/download.svg";
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
import { RovingAccessibleTooltipButton } from "../../../accessibility/RovingTabIndex";
import Spinner from "../elements/Spinner";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import { FileDownloader } from "../../../utils/FileDownloader";
interface IProps {
@ -37,7 +37,7 @@ interface IProps {
interface IState {
loading: boolean;
blob?: Blob;
tooltip: string;
tooltip: TranslationKey;
}
export default class DownloadActionButton extends React.PureComponent<IProps, IState> {

View file

@ -53,16 +53,14 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp
} 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.",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their profile picture.",
{ displayName },
);
} else if (room && isLocalRoom(room)) {
subtitle = _t("Messages in this chat will be end-to-end encrypted.");
} 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.",
"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.",
);
}

View file

@ -106,9 +106,7 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
{!!guessedLink ? (
<>
{_t(
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been " +
"provided with 'via_servers' to look for it. It's possible that guessing the " +
"server from the room ID will work. If you want to try, click this link:",
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been provided with 'via_servers' to look for it. It's possible that guessing the server from the room ID will work. If you want to try, click this link:",
{
roomId: predecessor.roomId,
},
@ -117,8 +115,7 @@ export const RoomPredecessorTile: React.FC<IProps> = ({ mxEvent, timestamp }) =>
</>
) : (
_t(
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been " +
"provided with 'via_servers' to look for it.",
"Can't find the old version of this room (room ID: %(roomId)s), and we have not been provided with 'via_servers' to look for it.",
{
roomId: predecessor.roomId,
},

View file

@ -494,9 +494,7 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
description: (
<div>
{_t(
"You are about to be taken to a third-party site so you can " +
"authenticate your account for use with %(integrationsUrl)s. " +
"Do you wish to continue?",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
{ integrationsUrl: integrationsUrl },
)}
</div>

View file

@ -81,8 +81,7 @@ const EncryptionInfo: React.FC<IProps> = ({
<p>{_t("Messages in this room are end-to-end encrypted.")}</p>
<p>
{_t(
"Your messages are secured and only you and the recipient have " +
"the unique keys to unlock them.",
"Your messages are secured and only you and the recipient have the unique keys to unlock them.",
)}
</p>
</div>
@ -93,8 +92,7 @@ const EncryptionInfo: React.FC<IProps> = ({
<p>{_t("Messages in this room are not end-to-end encrypted.")}</p>
<p>
{_t(
"In encrypted rooms, your messages are secured and only you and the recipient have " +
"the unique keys to unlock them.",
"In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.",
)}
</p>
</div>

View file

@ -181,8 +181,7 @@ const PinnedMessagesCard: React.FC<IProps> = ({ room, onClose, permalinkCreator
{_t("Nothing pinned, yet")}
</Heading>
{_t(
"If you have permissions, open the menu on any message and select " +
"<b>Pin</b> to stick them here.",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.",
{},
{
b: (sub) => <b>{sub}</b>,

View file

@ -383,8 +383,7 @@ export const UserOptionsSection: React.FC<{
description: (
<div>
{_t(
"All messages and invites from this user will be hidden. " +
"Are you sure you want to ignore them?",
"All messages and invites from this user will be hidden. Are you sure you want to ignore them?",
)}
</div>
),
@ -523,14 +522,10 @@ export const warnSelfDemote = async (isSpace: boolean): Promise<boolean> => {
<div>
{isSpace
? _t(
"You will not be able to undo this change as you are demoting yourself, " +
"if you are the last privileged user in the space it will be impossible " +
"to regain privileges.",
"You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the space it will be impossible to regain privileges.",
)
: _t(
"You will not be able to undo this change as you are demoting yourself, " +
"if you are the last privileged user in the room it will be impossible " +
"to regain privileges.",
"You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.",
)}
</div>
),
@ -1185,8 +1180,7 @@ export const PowerLevelEditor: React.FC<{
description: (
<div>
{_t(
"You will not be able to undo this change as you are promoting the user " +
"to have the same power level as yourself.",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.",
)}
<br />
{_t("Are you sure?")}
@ -1355,9 +1349,7 @@ const BasicUserInfo: React.FC<{
description: (
<div>
{_t(
"Deactivating this user will log them out and prevent them from logging back in. Additionally, " +
"they will leave all the rooms they are in. This action cannot be reversed. Are you sure you " +
"want to deactivate this user?",
"Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?",
)}
</div>
),

View file

@ -93,9 +93,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
!showSAS && !showQR ? (
<p>
{_t(
"The device you are trying to verify doesn't support scanning a " +
"QR code or emoji verification, which is what %(brand)s supports. Try " +
"with a different client.",
"The device you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.",
{ brand },
)}
</p>

View file

@ -182,8 +182,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
Modal.createDialog(ErrorDialog, {
title: _t("Error updating main address"),
description: _t(
"There was an error updating the room's main address. It may not be allowed by the server " +
"or a temporary failure occurred.",
"There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.",
),
});
this.setState({ canonicalAlias: oldAlias });
@ -222,8 +221,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
Modal.createDialog(ErrorDialog, {
title: _t("Error updating main address"),
description: _t(
"There was an error updating the room's alternative addresses. " +
"It may not be allowed by the server or a temporary failure occurred.",
"There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.",
),
});
})
@ -258,8 +256,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
Modal.createDialog(ErrorDialog, {
title: _t("Error creating address"),
description: _t(
"There was an error creating that address. It may not be allowed by the server " +
"or a temporary failure occurred.",
"There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.",
),
});
});
@ -286,8 +283,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
description = _t("You don't have permission to delete the address.");
} else {
description = _t(
"There was an error removing that address. It may no longer exist or a temporary " +
"error occurred.",
"There was an error removing that address. It may no longer exist or a temporary error occurred.",
);
}
Modal.createDialog(ErrorDialog, {
@ -450,13 +446,11 @@ export default class AliasSettings extends React.Component<IProps, IState> {
description={
isSpaceRoom
? _t(
"Set addresses for this space so users can find this space " +
"through your homeserver (%(localDomain)s)",
"Set addresses for this space so users can find this space through your homeserver (%(localDomain)s)",
{ localDomain },
)
: _t(
"Set addresses for this room so users can find this room " +
"through your homeserver (%(localDomain)s)",
"Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)",
{ localDomain },
)
}

View file

@ -95,9 +95,7 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
}
} else {
previewsForAccount = _t(
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your " +
"homeserver (where the previews are generated) cannot gather information about links you see in " +
"this room.",
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.",
);
}
@ -114,8 +112,7 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
<>
<p>
{_t(
"When someone puts a URL in their message, a URL preview can be shown to give more " +
"information about that link such as the title, description, and an image from the website.",
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.",
)}
</p>
<p>{previewsForAccount}</p>

View file

@ -18,7 +18,7 @@ limitations under the License.
import React, { CSSProperties, useState } from "react";
import classNames from "classnames";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import Tooltip, { Alignment } from "../elements/Tooltip";
import { E2EStatus } from "../../../utils/ShieldUtils";
@ -32,12 +32,12 @@ export enum E2EState {
Unauthenticated = "unauthenticated",
}
const crossSigningUserTitles: { [key in E2EState]?: string } = {
const crossSigningUserTitles: { [key in E2EState]?: TranslationKey } = {
[E2EState.Warning]: _td("This user has not verified all of their sessions."),
[E2EState.Normal]: _td("You have not verified this user."),
[E2EState.Verified]: _td("You have verified this user. This user has verified all of their sessions."),
};
const crossSigningRoomTitles: { [key in E2EState]?: string } = {
const crossSigningRoomTitles: { [key in E2EState]?: TranslationKey } = {
[E2EState.Warning]: _td("Someone is using an unknown session"),
[E2EState.Normal]: _td("This room is end-to-end encrypted"),
[E2EState.Verified]: _td("Everyone in this room is verified"),
@ -85,7 +85,7 @@ const E2EIcon: React.FC<XOR<UserProps, RoomProps>> = ({
className,
);
let e2eTitle: string | undefined;
let e2eTitle: TranslationKey | undefined;
if (isUser) {
e2eTitle = crossSigningUserTitles[status];
} else {

View file

@ -20,7 +20,7 @@ import React from "react";
import classNames from "classnames";
import AccessibleButton from "../elements/AccessibleButton";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import E2EIcon, { E2EState } from "./E2EIcon";
import BaseAvatar from "../avatars/BaseAvatar";
import PresenceLabel from "./PresenceLabel";
@ -30,7 +30,7 @@ export enum PowerStatus {
Moderator = "moderator",
}
const PowerLabel: Record<PowerStatus, string> = {
const PowerLabel: Record<PowerStatus, TranslationKey> = {
[PowerStatus.Admin]: _td("Admin"),
[PowerStatus.Moderator]: _td("Mod"),
};

View file

@ -20,7 +20,7 @@ import { EventType, Room, User, MatrixClient } from "matrix-js-sdk/src/matrix";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomContext from "../../../contexts/RoomContext";
import DMRoomMap from "../../../utils/DMRoomMap";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import MiniAvatarUploader, { AVATAR_SIZE } from "../elements/MiniAvatarUploader";
import RoomAvatar from "../avatars/RoomAvatar";
@ -44,7 +44,7 @@ function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room):
return isPublic || !privateShouldBeEncrypted(matrixClient) || isEncrypted;
}
const determineIntroMessage = (room: Room, encryptedSingle3rdPartyInvite: boolean): string => {
const determineIntroMessage = (room: Room, encryptedSingle3rdPartyInvite: boolean): TranslationKey => {
if (room instanceof LocalRoom) {
return _td("Send your first message to invite <displayName/> to chat");
}
@ -270,9 +270,7 @@ const NewRoomIntro: React.FC = () => {
}
const subText = _t(
"Your private messages are normally encrypted, but this room isn't. " +
"Usually this is due to an unsupported device or method being used, " +
"like email invites.",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.",
);
let subButton: JSX.Element | undefined;

View file

@ -26,7 +26,7 @@ import { ActionPayload } from "../../../dispatcher/payloads";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import PosthogTrackers from "../../../PosthogTrackers";
import SettingsStore from "../../../settings/SettingsStore";
@ -93,7 +93,7 @@ export const TAG_ORDER: TagID[] = [
const ALWAYS_VISIBLE_TAGS: TagID[] = [DefaultTagID.DM, DefaultTagID.Untagged];
interface ITagAesthetics {
sectionLabel: string;
sectionLabel: TranslationKey;
sectionLabelRaw?: string;
AuxButtonComponent?: ComponentType<IAuxButtonProps>;
isInvite: boolean;

View file

@ -421,8 +421,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
}
const joinRule = this.joinRule();
const errCodeMessage = _t(
"An error (%(errcode)s) was returned while trying to validate your " +
"invite. You could try to pass this information on to the person who invited you.",
"An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to the person who invited you.",
{ errcode: this.state.threePidFetchError?.errcode || _t("unknown error code") },
);
switch (joinRule) {
@ -447,8 +446,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
case MessageCase.InvitedEmailNotFoundInAccount: {
if (roomName) {
title = _t(
"This invite to %(roomName)s was sent to %(email)s which is not " +
"associated with your account",
"This invite to %(roomName)s was sent to %(email)s which is not associated with your account",
{
roomName,
email: this.props.invitedEmail,
@ -585,9 +583,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
subTitle = [
_t("Try again later, or ask a room or space admin to check if you have access."),
_t(
"%(errcode)s was returned while trying to access the room or space. " +
"If you think you're seeing this message in error, please " +
"<issueLink>submit a bug report</issueLink>.",
"%(errcode)s was returned while trying to access the room or space. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.",
{ errcode: String(this.props.error?.errcode) },
{
issueLink: (label) => (

View file

@ -73,15 +73,12 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
<div className="mx_RoomUpgradeWarningBar_body">
<p>
{_t(
"Upgrading this room will shut down the current instance of the room and create " +
"an upgraded room with the same name.",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.",
)}
</p>
<p>
{_t(
"<b>Warning</b>: upgrading a room will <i>not automatically migrate room members " +
"to the new version of the room.</i> We'll post a link to the new room in the old " +
"version of the room - room members will have to click this link to join the new room.",
"<b>Warning</b>: upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.",
{},
{
b: (sub) => <b>{sub}</b>,
@ -111,8 +108,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
<div className="mx_RoomUpgradeWarningBar_wrapped">
<div className="mx_RoomUpgradeWarningBar_header">
{_t(
"This room is running room version <roomVersion />, which this homeserver has " +
"marked as <i>unstable</i>.",
"This room is running room version <roomVersion />, which this homeserver has marked as <i>unstable</i>.",
{},
{
roomVersion: () => <code>{this.props.room.getVersion()}</code>,

View file

@ -496,7 +496,10 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
return; // errored
}
if (content && [CommandCategories.messages, CommandCategories.effects].includes(cmd.category)) {
if (
content &&
[CommandCategories.messages as string, CommandCategories.effects as string].includes(cmd.category)
) {
// Attach any mentions which might be contained in the command content.
attachMentions(this.props.mxClient.getSafeUserId(), content, model, replyToEvent);
attachRelation(content, this.props.relation);

View file

@ -19,7 +19,7 @@ import { Room, ClientEvent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { IWidget } from "matrix-widget-api";
import { _t, _td } from "../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../languageHandler";
import AppTile from "../elements/AppTile";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import dis from "../../../dispatcher/dispatcher";
@ -159,7 +159,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
this.sendVisibilityToWidget(this.props.isStickerPickerOpen);
}
private imError(errorMsg: string, e: Error): void {
private imError(errorMsg: TranslationKey, e: Error): void {
logger.error(errorMsg, e);
this.setState({
imError: _t(errorMsg),

View file

@ -108,8 +108,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
Modal.createDialog(ErrorDialog, {
title: _t("Failed to revoke invite"),
description: _t(
"Could not revoke the invite. The server may be experiencing a temporary problem or " +
"you do not have sufficient permissions to revoke the invite.",
"Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.",
),
});
});

View file

@ -203,8 +203,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
summarisedStatus = (
<SettingsSubsectionText data-testid="summarised-status">
{_t(
"Your account has a cross-signing identity in secret storage, " +
"but it is not yet trusted by this session.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.",
)}
</SettingsSubsectionText>
);

View file

@ -149,8 +149,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
<>
<SettingsSubsectionText>
{_t(
"Securely cache encrypted messages locally for them " +
"to appear in search results, using %(size)s to store messages from %(rooms)s rooms.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.",
{
size: formatBytes(this.state.eventIndexSize, 0),
// This drives the singular / plural string
@ -188,10 +187,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
eventIndexingSettings = (
<SettingsSubsectionText>
{_t(
"%(brand)s is missing some components required for securely " +
"caching encrypted messages locally. If you'd like to " +
"experiment with this feature, build a custom %(brand)s Desktop " +
"with <nativeLink>search components added</nativeLink>.",
"%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.",
{
brand,
},
@ -209,9 +205,7 @@ export default class EventIndexPanel extends React.Component<{}, IState> {
eventIndexingSettings = (
<SettingsSubsectionText>
{_t(
"%(brand)s can't securely cache encrypted messages locally " +
"while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> " +
"for encrypted messages to appear in search results.",
"%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.",
{
brand,
},

View file

@ -323,9 +323,7 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
warning = (
<b>
{_t(
"This room is in some spaces you're not an admin of. " +
"In those spaces, the old room will still be shown, " +
"but people will be prompted to join the new one.",
"This room is in some spaces you're not an admin of. In those spaces, the old room will still be shown, but people will be prompted to join the new one.",
)}
</b>
);
@ -335,8 +333,7 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
targetVersion,
<>
{_t(
"This upgrade will allow members of selected spaces " +
"access to this room without an invite.",
"This upgrade will allow members of selected spaces access to this room without an invite.",
)}
{warning}
</>,

View file

@ -259,17 +259,14 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
<>
<SettingsSubsectionText>
{_t(
"This session is <b>not backing up your keys</b>, " +
"but you do have an existing backup you can restore from " +
"and add to going forward.",
"This session is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.",
{},
{ b: (sub) => <b>{sub}</b> },
)}
</SettingsSubsectionText>
<SettingsSubsectionText>
{_t(
"Connect this session to key backup before signing out to avoid " +
"losing any keys that may only be on this session.",
"Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.",
)}
</SettingsSubsectionText>
</>
@ -382,9 +379,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
<>
<SettingsSubsectionText>
{_t(
"Back up your encryption keys with your account data in case you " +
"lose access to your sessions. Your keys will be secured with a " +
"unique Security Key.",
"Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Security Key.",
)}
</SettingsSubsectionText>
{statusDescription}

View file

@ -296,9 +296,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
<div>
<p>
{_t(
"You should <b>remove your personal data</b> from identity server " +
"<idserver /> before disconnecting. Unfortunately, identity server " +
"<idserver /> is currently offline or cannot be reached.",
"You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.",
{},
messageElements,
)}
@ -307,8 +305,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
<ul>
<li>
{_t(
"check your browser plugins for anything that might block " +
"the identity server (such as Privacy Badger)",
"check your browser plugins for anything that might block the identity server (such as Privacy Badger)",
)}
</li>
<li>
@ -338,8 +335,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
</p>
<p>
{_t(
"We recommend that you remove your email addresses and phone numbers " +
"from the identity server before disconnecting.",
"We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.",
)}
</p>
</div>
@ -388,15 +384,13 @@ export default class SetIdServer extends React.Component<IProps, IState> {
if (idServerUrl) {
sectionTitle = _t("Identity server (%(server)s)", { server: abbreviateUrl(idServerUrl) });
bodyText = _t(
"You are currently using <server></server> to discover and be discoverable by " +
"existing contacts you know. You can change your identity server below.",
"You are currently using <server></server> to discover and be discoverable by existing contacts you know. You can change your identity server below.",
{},
{ server: (sub) => <b>{abbreviateUrl(idServerUrl)}</b> },
);
if (this.props.missingTerms) {
bodyText = _t(
"If you don't want to use <server /> to discover and be discoverable by existing " +
"contacts you know, enter another identity server below.",
"If you don't want to use <server /> to discover and be discoverable by existing contacts you know, enter another identity server below.",
{},
{ server: (sub) => <b>{abbreviateUrl(idServerUrl)}</b> },
);
@ -404,9 +398,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
} else {
sectionTitle = _t("Identity server");
bodyText = _t(
"You are not currently using an identity server. " +
"To discover and be discoverable by existing contacts you know, " +
"add one below.",
"You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.",
);
}
@ -414,15 +406,11 @@ export default class SetIdServer extends React.Component<IProps, IState> {
if (idServerUrl) {
let discoButtonContent: React.ReactNode = _t("Disconnect");
let discoBodyText = _t(
"Disconnecting from your identity server will mean you " +
"won't be discoverable by other users and you won't be " +
"able to invite others by email or phone.",
"Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.",
);
if (this.props.missingTerms) {
discoBodyText = _t(
"Using an identity server is optional. If you choose not to " +
"use an identity server, you won't be discoverable by other users " +
"and you won't be able to invite others by email or phone.",
"Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.",
);
discoButtonContent = _t("Do not use an identity server");
}

View file

@ -63,7 +63,7 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
if (currentManager) {
managerName = `(${currentManager.name})`;
bodyText = _t(
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, " + "and sticker packs.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.",
{ serverName: currentManager.name },
{ b: (sub) => <b>{sub}</b> },
);
@ -92,8 +92,7 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
<SettingsSubsectionText>{bodyText}</SettingsSubsectionText>
<SettingsSubsectionText>
{_t(
"Integration managers receive configuration data, and can modify widgets, " +
"send room invites, and set power levels on your behalf.",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.",
)}
</SettingsSubsectionText>
</label>

View file

@ -280,8 +280,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
<div>
<div>
{_t(
"A text message has been sent to +%(msisdn)s. " +
"Please enter the verification code it contains.",
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.",
{ msisdn: msisdn },
)}
<br />

View file

@ -84,14 +84,12 @@ const DeviceNameEditor: React.FC<Props & { stopEditing: () => void }> = ({ devic
<>
<p>
{_t(
`Other users in direct messages and rooms that you join ` +
`are able to view a full list of your sessions.`,
"Other users in direct messages and rooms that you join are able to view a full list of your sessions.",
)}
</p>
<p>
{_t(
`This provides them with confidence that they are really speaking to you, ` +
`but it also means they can see the session name you enter here.`,
"This provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.",
)}
</p>
</>

View file

@ -42,8 +42,7 @@ const securityCardContent: Record<
</p>
<p>
{_t(
`This means that you have all the keys needed to unlock your encrypted messages ` +
`and confirm to other users that you trust this session.`,
"This means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.",
)}
</p>
</>
@ -60,8 +59,7 @@ const securityCardContent: Record<
</p>
<p>
{_t(
`You should make especially certain that you recognise these sessions ` +
`as they could represent an unauthorised use of your account.`,
"You should make especially certain that you recognise these sessions as they could represent an unauthorised use of your account.",
)}
</p>
</>
@ -98,8 +96,7 @@ const securityCardContent: Record<
</p>
<p>
{_t(
`Removing inactive sessions improves security and performance, ` +
`and makes it easier for you to identify if a new session is suspicious.`,
"Removing inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious.",
)}
</p>
</>

View file

@ -88,8 +88,7 @@ const securityCardContent: Record<
[DeviceSecurityVariation.Unverified]: {
title: _t("Unverified sessions"),
description: _t(
`Verify your sessions for enhanced secure messaging or ` +
`sign out from those you don't recognize or use anymore.`,
"Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.",
),
},
[DeviceSecurityVariation.Unverifiable]: {
@ -99,7 +98,7 @@ const securityCardContent: Record<
[DeviceSecurityVariation.Inactive]: {
title: _t("Inactive sessions"),
description: _t(
`Consider signing out from old sessions ` + `(%(inactiveAgeDays)s days or older) you don't use anymore.`,
"Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore.",
{ inactiveAgeDays: INACTIVE_DEVICE_AGE_DAYS },
),
},

View file

@ -56,8 +56,7 @@ export default class LoginWithQRSection extends React.Component<IProps> {
<div className="mx_LoginWithQRSection">
<p className="mx_SettingsTab_subsectionText">
{_t(
"You can use this device to sign in a new device with a QR code. You will need to " +
"scan the QR code shown on this device with your device that's signed out.",
"You can use this device to sign in a new device with a QR code. You will need to scan the QR code shown on this device with your device that's signed out.",
)}
</p>
<AccessibleButton onClick={this.props.onShowQr} kind="primary">

View file

@ -63,8 +63,7 @@ const SecurityRecommendations: React.FC<Props> = ({ devices, currentDeviceId, go
description={
<>
{_t(
`Verify your sessions for enhanced secure messaging` +
` or sign out from those you don't recognize or use anymore.`,
"Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.",
)}
<DeviceSecurityLearnMore variation={DeviceSecurityVariation.Unverified} />
</>
@ -88,8 +87,7 @@ const SecurityRecommendations: React.FC<Props> = ({ devices, currentDeviceId, go
description={
<>
{_t(
`Consider signing out from old sessions ` +
`(%(inactiveAgeDays)s days or older) you don't use anymore.`,
"Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore.",
{ inactiveAgeDays },
)}
<DeviceSecurityLearnMore variation={DeviceSecurityVariation.Inactive} />

View file

@ -110,11 +110,7 @@ export default function NotificationSettings2(): JSX.Element {
onAction={() => reconcile(model!)}
>
{_t(
"<strong>Update:</strong>" +
"Weve simplified Notifications Settings to make options easier to find. " +
"Some custom settings youve chosen in the past are not shown here, but theyre still active. " +
"If you proceed, some of your settings may change. " +
"<a>Learn more</a>",
"<strong>Update:</strong>Weve simplified Notifications Settings to make options easier to find. Some custom settings youve chosen in the past are not shown here, but theyre still active. If you proceed, some of your settings may change. <a>Learn more</a>",
{},
{
strong: boldText,

View file

@ -120,9 +120,7 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
<div>
<p className="mx_SettingsTab_warningText">
{_t(
"<b>Warning</b>: upgrading a room will <i>not automatically migrate room members " +
"to the new version of the room.</i> We'll post a link to the new room in the old " +
"version of the room - room members will have to click this link to join the new room.",
"<b>Warning</b>: upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.",
{},
{
b: (sub) => <b>{sub}</b>,

View file

@ -63,7 +63,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
<div>
<p>
{_t(
"This room is bridging messages to the following platforms. " + "<a>Learn more.</a>",
"This room is bridging messages to the following platforms. <a>Learn more.</a>",
{},
{
// TODO: We don't have this link yet: this will prevent the translators
@ -85,7 +85,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
content = (
<p>
{_t(
"This room isn't bridging messages to any platforms. " + "<a>Learn more.</a>",
"This room isn't bridging messages to any platforms. <a>Learn more.</a>",
{},
{
// TODO: We don't have this link yet: this will prevent the translators

View file

@ -221,8 +221,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
{_t("@mentions & keywords")}
<div className="mx_NotificationSettingsTab_microCopy">
{_t(
"Get notified only with mentions and keywords " +
"as set up in your <a>settings</a>",
"Get notified only with mentions and keywords as set up in your <a>settings</a>",
{},
{
a: (sub) => (

View file

@ -20,7 +20,7 @@ import { logger } from "matrix-js-sdk/src/logger";
import { throttle, get } from "lodash";
import { compare } from "matrix-js-sdk/src/utils";
import { _t, _td } from "../../../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../../../languageHandler";
import AccessibleButton from "../../../elements/AccessibleButton";
import Modal from "../../../../../Modal";
import ErrorDialog from "../../../dialogs/ErrorDialog";
@ -207,8 +207,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
Modal.createDialog(ErrorDialog, {
title: _t("Error changing power level requirement"),
description: _t(
"An error occurred changing the room's power level requirements. Ensure you have sufficient " +
"permissions and try again.",
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.",
),
});
});
@ -233,8 +232,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
Modal.createDialog(ErrorDialog, {
title: _t("Error changing power level"),
description: _t(
"An error occurred changing the user's power level. Ensure you have sufficient " +
"permissions and try again.",
"An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.",
),
});
});
@ -249,7 +247,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
const plContent = plEvent ? plEvent.getContent() || {} : {};
const canChangeLevels = room.currentState.mayClientSendStateEvent(EventType.RoomPowerLevels, client);
const plEventsToLabels: Record<EventType | string, string | null> = {
const plEventsToLabels: Record<EventType | string, TranslationKey | null> = {
// These will be translated for us later.
[EventType.RoomAvatar]: isSpaceRoom ? _td("Change space avatar") : _td("Change room avatar"),
[EventType.RoomName]: isSpaceRoom ? _td("Change space name") : _td("Change room name"),
@ -458,10 +456,11 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
return null;
}
let label = plEventsToLabels[eventType];
if (label) {
const translationKeyForEvent = plEventsToLabels[eventType];
let label: string;
if (translationKeyForEvent) {
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;
label = _t(label, { brand });
label = _t(translationKeyForEvent, { brand });
} else {
label = _t("Send %(eventType)s events", { eventType });
}

View file

@ -122,11 +122,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
<p>
{" "}
{_t(
"<b>It's not recommended to add encryption to public rooms.</b> " +
"Anyone can find and join public rooms, so anyone can read messages in them. " +
"You'll get none of the benefits of encryption, and you won't be able to turn it " +
"off later. Encrypting messages in a public room will make receiving and sending " +
"messages slower.",
"<b>It's not recommended to add encryption to public rooms.</b> Anyone can find and join public rooms, so anyone can read messages in them. You'll get none of the benefits of encryption, and you won't be able to turn it off later. Encrypting messages in a public room will make receiving and sending messages slower.",
undefined,
{ b: (sub) => <b>{sub}</b> },
)}{" "}
@ -134,8 +130,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
<p>
{" "}
{_t(
"To avoid these issues, create a <a>new encrypted room</a> for " +
"the conversation you plan to have.",
"To avoid these issues, create a <a>new encrypted room</a> for the conversation you plan to have.",
undefined,
{
a: (sub) => (
@ -165,9 +160,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
Modal.createDialog(QuestionDialog, {
title: _t("Enable encryption?"),
description: _t(
"Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted " +
"room cannot be seen by the server, only by the participants of the room. Enabling encryption " +
"may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>",
"Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>",
{},
{
a: (sub) => <ExternalLink href={SdkConfig.get("help_encryption_url")}>{sub}</ExternalLink>,
@ -322,10 +315,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
<p>
{" "}
{_t(
"<b>It's not recommended to make encrypted rooms public.</b> " +
"It will mean anyone can find and join the room, so anyone can read messages. " +
"You'll get none of the benefits of encryption. Encrypting messages in a public " +
"room will make receiving and sending messages slower.",
"<b>It's not recommended to make encrypted rooms public.</b> It will mean anyone can find and join the room, so anyone can read messages. You'll get none of the benefits of encryption. Encrypting messages in a public room will make receiving and sending messages slower.",
undefined,
{ b: (sub) => <b>{sub}</b> },
)}{" "}
@ -333,8 +323,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
<p>
{" "}
{_t(
"To avoid these issues, create a <a>new public room</a> for the conversation " +
"you plan to have.",
"To avoid these issues, create a <a>new public room</a> for the conversation you plan to have.",
undefined,
{
a: (sub) => (
@ -398,8 +387,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
}
const description = _t(
"Changes to who can read history will only apply to future messages in this room. " +
"The visibility of existing history will be unchanged.",
"Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.",
);
return (
@ -435,8 +423,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
/>
<p>
{_t(
"People with supported clients will be able to join " +
"the room without having a registered account.",
"People with supported clients will be able to join the room without having a registered account.",
)}
</p>
</div>

View file

@ -82,10 +82,9 @@ const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
<LabelledToggleSwitch
data-testid="element-call-switch"
label={_t("Enable %(brand)s as an additional calling option in this room", { brand })}
caption={_t(
"%(brand)s is end-to-end encrypted, " + "but is currently limited to smaller numbers of users.",
{ brand },
)}
caption={_t("%(brand)s is end-to-end encrypted, but is currently limited to smaller numbers of users.", {
brand,
})}
value={elementCallEnabled}
onChange={onChange}
disabled={!maySend}

View file

@ -455,8 +455,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
const intro = (
<SettingsSubsectionText>
{_t(
"Agree to the identity server (%(serverName)s) Terms of Service to " +
"allow yourself to be discoverable by email address or phone number.",
"Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.",
{ serverName: this.state.idServerName },
)}
</SettingsSubsectionText>

View file

@ -136,8 +136,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
<ul>
<li>
{_t(
"The <photo>default cover photo</photo> is © " +
"<author>Jesús Roncero</author> used under the terms of <terms>CC-BY-SA 4.0</terms>.",
"The <photo>default cover photo</photo> is © <author>Jesús Roncero</author> used under the terms of <terms>CC-BY-SA 4.0</terms>.",
{},
{
photo: (sub) => (
@ -166,8 +165,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
</li>
<li>
{_t(
"The <colr>twemoji-colr</colr> font is © <author>Mozilla Foundation</author> " +
"used under the terms of <terms>Apache 2.0</terms>.",
"The <colr>twemoji-colr</colr> font is © <author>Mozilla Foundation</author> used under the terms of <terms>Apache 2.0</terms>.",
{},
{
colr: (sub) => (
@ -194,9 +192,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
</li>
<li>
{_t(
"The <twemoji>Twemoji</twemoji> emoji art is © " +
"<author>Twitter, Inc and other contributors</author> used under the terms of " +
"<terms>CC-BY 4.0</terms>.",
"The <twemoji>Twemoji</twemoji> emoji art is © <author>Twitter, Inc and other contributors</author> used under the terms of <terms>CC-BY 4.0</terms>.",
{},
{
twemoji: (sub) => (
@ -244,8 +240,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
faqText = (
<div>
{_t(
"For help with using %(brand)s, click <a>here</a> or start a chat with our " +
"bot using the button below.",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.",
{
brand,
},
@ -284,16 +279,11 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
<>
<SettingsSubsectionText>
{_t(
"If you've submitted a bug via GitHub, debug logs can help " +
"us track down the problem. ",
"If you've submitted a bug via GitHub, debug logs can help us track down the problem. ",
)}
</SettingsSubsectionText>
{_t(
"Debug logs contain application " +
"usage data including your username, the IDs or aliases of " +
"the rooms you have visited, which UI elements you " +
"last interacted with, and the usernames of other users. " +
"They do not contain messages.",
"Debug logs contain application usage data including your username, the IDs or aliases of the rooms you have visited, which UI elements you last interacted with, and the usernames of other users. They do not contain messages.",
)}
</>
}
@ -303,8 +293,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
</AccessibleButton>
<SettingsSubsectionText>
{_t(
"To report a Matrix-related security issue, please read the Matrix.org " +
"<a>Security Disclosure Policy</a>.",
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.",
{},
{
a: (sub) => (
@ -369,8 +358,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
<summary>{_t("Access Token")}</summary>
<b>
{_t(
"Your access token gives full access to your account." +
" Do not share it with anyone.",
"Your access token gives full access to your account. Do not share it with anyone.",
)}
</b>
<CopyableText getTextToCopy={() => this.context.getAccessToken()}>

View file

@ -113,9 +113,7 @@ export default class LabsUserSettingsTab extends React.Component<{}> {
<SettingsSection heading={_t("Upcoming features")}>
<SettingsSubsectionText>
{_t(
"What's next for %(brand)s? " +
"Labs are the best way to get things early, " +
"test out new features and help shape them before they actually launch.",
"What's next for %(brand)s? Labs are the best way to get things early, test out new features and help shape them before they actually launch.",
{ brand: SdkConfig.get("brand") },
)}
</SettingsSubsectionText>
@ -126,11 +124,7 @@ export default class LabsUserSettingsTab extends React.Component<{}> {
<SettingsSection heading={_t("Early previews")}>
<SettingsSubsectionText>
{_t(
"Feeling experimental? " +
"Try out our latest ideas in development. " +
"These features are not finalised; " +
"they may be unstable, may change, or may be dropped altogether. " +
"<a>Learn more</a>.",
"Feeling experimental? Try out our latest ideas in development. These features are not finalised; they may be unstable, may change, or may be dropped altogether. <a>Learn more</a>.",
{},
{
a: (sub) => {

View file

@ -259,28 +259,21 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
<span className="warning">{_t("⚠ These settings are meant for advanced users.")}</span>
<p>
{_t(
"Add users and servers you want to ignore here. Use asterisks " +
"to have %(brand)s match any characters. For example, <code>@bot:*</code> " +
"would ignore all users that have the name 'bot' on any server.",
"Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, <code>@bot:*</code> would ignore all users that have the name 'bot' on any server.",
{ brand },
{ code: (s) => <code>{s}</code> },
)}
</p>
<p>
{_t(
"Ignoring people is done through ban lists which contain rules for " +
"who to ban. Subscribing to a ban list means the users/servers blocked by " +
"that list will be hidden from you.",
"Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.",
)}
</p>
</SettingsSubsectionText>
<SettingsSubsection
heading={_t("Personal ban list")}
description={_t(
"Your personal ban list holds all the users/servers you personally don't " +
"want to see messages from. After ignoring your first user/server, a new room " +
"will show up in your room list named '%(myBanList)s' - stay in this room to keep " +
"the ban list in effect.",
"Your personal ban list holds all the users/servers you personally don't want to see messages from. After ignoring your first user/server, a new room will show up in your room list named '%(myBanList)s' - stay in this room to keep the ban list in effect.",
{
myBanList: _t("My Ban List"),
},

View file

@ -302,8 +302,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
warning = (
<div className="mx_SecurityUserSettingsTab_warning">
{_t(
"Your server admin has disabled end-to-end encryption by default " +
"in private rooms & Direct Messages.",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
)}
</div>
);

View file

@ -303,8 +303,7 @@ const SessionManagerTab: React.FC = () => {
/>
}
description={_t(
`For best security, verify your sessions and sign out ` +
`from any session that you don't recognize or use anymore.`,
"For best security, verify your sessions and sign out from any session that you don't recognize or use anymore.",
)}
data-testid="other-sessions-section"
stretchContent

View file

@ -68,8 +68,7 @@ const SidebarUserSettingsTab: React.FC = () => {
<SettingsSubsection
heading={_t("Spaces to show")}
description={_t(
"Spaces are ways to group rooms and people. " +
"Alongside the spaces you're in, you can use some pre-built ones too.",
"Spaces are ways to group rooms and people. Alongside the spaces you're in, you can use some pre-built ones too.",
)}
>
<StyledCheckbox

View file

@ -287,8 +287,7 @@ const SpaceCreateMenu: React.FC<{
<h2>{_t("Create a space")}</h2>
<p>
{_t(
"Spaces are a new way to group rooms and people. What kind of Space do you want to create? " +
"You can change this later.",
"Spaces are a new way to group rooms and people. What kind of Space do you want to create? You can change this later.",
)}
</p>

View file

@ -43,8 +43,7 @@ export function UserOnboardingHeader({ useCase }: Props): JSX.Element {
case UseCase.PersonalMessaging:
title = _t("Secure messaging for friends and family");
description = _t(
"With free end-to-end encrypted messaging, and unlimited voice and video calls, " +
"%(brand)s is a great way to stay in touch.",
"With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.",
{
brand: SdkConfig.get("brand"),
},
@ -55,8 +54,7 @@ export function UserOnboardingHeader({ useCase }: Props): JSX.Element {
case UseCase.WorkMessaging:
title = _t("Secure messaging for work");
description = _t(
"With free end-to-end encrypted messaging, and unlimited voice and video calls," +
" %(brand)s is a great way to stay in touch.",
"With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.",
{
brand: SdkConfig.get("brand"),
},
@ -67,8 +65,7 @@ export function UserOnboardingHeader({ useCase }: Props): JSX.Element {
case UseCase.CommunityMessaging:
title = _t("Community ownership");
description = _t(
"Keep ownership and control of community discussion.\n" +
"Scale to support millions, with powerful moderation and interoperability.",
"Keep ownership and control of community discussion.\nScale to support millions, with powerful moderation and interoperability.",
);
image = require("../../../../res/img/user-onboarding/CommunityMessaging.png");
actionLabel = _t("Find your people");
@ -78,8 +75,7 @@ export function UserOnboardingHeader({ useCase }: Props): JSX.Element {
brand: SdkConfig.get("brand"),
});
description = _t(
"With free end-to-end encrypted messaging, and unlimited voice and video calls," +
" %(brand)s is a great way to stay in touch.",
"With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.",
{
brand: SdkConfig.get("brand"),
},

View file

@ -31,8 +31,7 @@ export default class VerificationComplete extends React.Component<IProps> {
<p>{_t("You've successfully verified this user.")}</p>
<p>
{_t(
"Secure messages with this user are end-to-end encrypted and not able to be " +
"read by third parties.",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.",
)}
</p>
<DialogButtons