Migrate more strings to translation keys (#11642)

This commit is contained in:
Michael Telatynski 2023-09-21 18:16:04 +01:00 committed by GitHub
parent c879882558
commit faa7b1521f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 6443 additions and 6006 deletions

View file

@ -89,7 +89,7 @@ export default class BridgeTile extends React.PureComponent<IProps> {
creator = (
<li>
{_t(
"This bridge was provisioned by <user />.",
"labs|bridge_state_creator",
{},
{
user: () => (
@ -109,7 +109,7 @@ export default class BridgeTile extends React.PureComponent<IProps> {
const bot = (
<li>
{_t(
"This bridge is managed by <user />.",
"labs|bridge_state_manager",
{},
{
user: () => (
@ -154,7 +154,7 @@ export default class BridgeTile extends React.PureComponent<IProps> {
);
}
networkItem = _t(
"Workspace: <networkLink/>",
"labs|bridge_state_workspace",
{},
{
networkLink: () => networkLink,
@ -181,7 +181,7 @@ export default class BridgeTile extends React.PureComponent<IProps> {
{networkItem}
<span className="mx_RoomSettingsDialog_channel">
{_t(
"Channel: <channelLink/>",
"labs|bridge_state_channel",
{},
{
channelLink: () => channelLink,

View file

@ -127,7 +127,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
this.props.onError(err);
} else {
this.props.onError(
new UserFriendlyError("Error while changing password: %(error)s", {
new UserFriendlyError("auth|change_password_error", {
error: String(err),
cause: undefined,
}),
@ -155,16 +155,16 @@ export default class ChangePassword extends React.Component<IProps, IState> {
*/
private checkPassword(oldPass: string, newPass: string, confirmPass: string): void {
if (newPass !== confirmPass) {
throw new UserFriendlyError("New passwords don't match");
throw new UserFriendlyError("auth|change_password_mismatch");
} else if (!newPass || newPass.length === 0) {
throw new UserFriendlyError("Passwords can't be empty");
throw new UserFriendlyError("auth|change_password_empty");
}
}
private optionallySetEmail(): Promise<boolean> {
// Ask for an email otherwise the user has no way to reset their password
const modal = Modal.createDialog(SetEmailDialog, {
title: _t("Do you want to set an email address?"),
title: _t("auth|set_email_prompt"),
});
return modal.finished.then(([confirmed]) => !!confirmed);
}
@ -194,7 +194,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
{
key: "required",
test: ({ value, allowEmpty }) => allowEmpty || !!value,
invalid: () => _t("Passwords can't be empty"),
invalid: () => _t("auth|change_password_empty"),
},
],
});
@ -226,14 +226,14 @@ export default class ChangePassword extends React.Component<IProps, IState> {
{
key: "required",
test: ({ value, allowEmpty }) => allowEmpty || !!value,
invalid: () => _t("Confirm password"),
invalid: () => _t("auth|change_password_confirm_label"),
},
{
key: "match",
test({ value }) {
return !value || value === this.state.newPassword;
},
invalid: () => _t("Passwords don't match"),
invalid: () => _t("auth|change_password_confirm_invalid"),
},
],
});
@ -261,7 +261,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
this.props.onError(err);
} else {
this.props.onError(
new UserFriendlyError("Error while changing password: %(error)s", {
new UserFriendlyError("auth|change_password_error", {
error: String(err),
cause: undefined,
}),
@ -344,7 +344,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
<Field
ref={(field) => (this[FIELD_OLD_PASSWORD] = field)}
type="password"
label={_t("Current password")}
label={_t("auth|change_password_current_label")}
value={this.state.oldPassword}
onChange={this.onChangeOldPassword}
onValidate={this.onOldPasswordValidate}
@ -354,7 +354,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
<PassphraseField
fieldRef={(field) => (this[FIELD_NEW_PASSWORD] = field)}
type="password"
label={_td("New Password")}
label={_td("auth|change_password_new_label")}
minScore={PASSWORD_MIN_SCORE}
value={this.state.newPassword}
autoFocus={this.props.autoFocusNewPasswordInput}
@ -367,7 +367,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
<Field
ref={(field) => (this[FIELD_NEW_PASSWORD_CONFIRM] = field)}
type="password"
label={_t("Confirm password")}
label={_t("auth|change_password_confirm_label")}
value={this.state.newPasswordConfirm}
onChange={this.onChangeNewPasswordConfirm}
onValidate={this.onNewPasswordConfirmValidate}
@ -379,7 +379,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
kind={this.props.buttonKind}
onClick={this.onClickChange}
>
{this.props.buttonLabel || _t("Change Password")}
{this.props.buttonLabel || _t("auth|change_password_action")}
</AccessibleButton>
</form>
);

View file

@ -263,32 +263,52 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
<summary>{_t("Advanced")}</summary>
<table className="mx_CrossSigningPanel_statusList">
<tr>
<th scope="row">{_t("Cross-signing public keys:")}</th>
<td>{crossSigningPublicKeysOnDevice ? _t("in memory") : _t("not found")}</td>
</tr>
<tr>
<th scope="row">{_t("Cross-signing private keys:")}</th>
<th scope="row">{_t("settings|security|cross_signing_public_keys")}</th>
<td>
{crossSigningPrivateKeysInStorage
? _t("in secret storage")
: _t("not found in storage")}
{crossSigningPublicKeysOnDevice
? _t("settings|security|cross_signing_in_memory")
: _t("settings|security|cross_signing_not_found")}
</td>
</tr>
<tr>
<th scope="row">{_t("Master private key:")}</th>
<td>{masterPrivateKeyCached ? _t("cached locally") : _t("not found locally")}</td>
<th scope="row">{_t("settings|security|cross_signing_private_keys")}</th>
<td>
{crossSigningPrivateKeysInStorage
? _t("settings|security|cross_signing_in_4s")
: _t("settings|security|cross_signing_not_in_4s")}
</td>
</tr>
<tr>
<th scope="row">{_t("Self signing private key:")}</th>
<td>{selfSigningPrivateKeyCached ? _t("cached locally") : _t("not found locally")}</td>
<th scope="row">{_t("settings|security|cross_signing_master_private_Key")}</th>
<td>
{masterPrivateKeyCached
? _t("settings|security|cross_signing_cached")
: _t("settings|security|cross_signing_not_cached")}
</td>
</tr>
<tr>
<th scope="row">{_t("User signing private key:")}</th>
<td>{userSigningPrivateKeyCached ? _t("cached locally") : _t("not found locally")}</td>
<th scope="row">{_t("settings|security|cross_signing_self_signing_private_key")}</th>
<td>
{selfSigningPrivateKeyCached
? _t("settings|security|cross_signing_cached")
: _t("settings|security|cross_signing_not_cached")}
</td>
</tr>
<tr>
<th scope="row">{_t("Homeserver feature support:")}</th>
<td>{homeserverSupportsCrossSigning ? _t("exists") : _t("not found")}</td>
<th scope="row">{_t("settings|security|cross_signing_user_signing_private_key")}</th>
<td>
{userSigningPrivateKeyCached
? _t("settings|security|cross_signing_cached")
: _t("settings|security|cross_signing_not_cached")}
</td>
</tr>
<tr>
<th scope="row">{_t("settings|security|cross_signing_homeserver_support")}</th>
<td>
{homeserverSupportsCrossSigning
? _t("settings|security|cross_signing_homeserver_support_exists")
: _t("settings|security|cross_signing_not_found")}
</td>
</tr>
</table>
</details>

View file

@ -52,10 +52,10 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
importExportButtons = (
<div className="mx_CryptographyPanel_importExportButtons">
<AccessibleButton kind="primary" onClick={this.onExportE2eKeysClicked}>
{_t("Export E2E room keys")}
{_t("settings|security|export_megolm_keys")}
</AccessibleButton>
<AccessibleButton kind="primary" onClick={this.onImportE2eKeysClicked}>
{_t("Import E2E room keys")}
{_t("settings|security|import_megolm_keys")}
</AccessibleButton>
</div>
);
@ -73,17 +73,17 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
}
return (
<SettingsSubsection heading={_t("Cryptography")}>
<SettingsSubsection heading={_t("settings|security|cryptography_section")}>
<SettingsSubsectionText>
<table className="mx_CryptographyPanel_sessionInfo">
<tr>
<th scope="row">{_t("Session ID:")}</th>
<th scope="row">{_t("settings|security|session_id")}</th>
<td>
<code>{deviceId}</code>
</td>
</tr>
<tr>
<th scope="row">{_t("Session key:")}</th>
<th scope="row">{_t("settings|security|session_key")}</th>
<td>
<code>
<b>{identityKey}</b>

View file

@ -26,7 +26,7 @@ const SETTING_MANUALLY_VERIFY_ALL_SESSIONS = "e2ee.manuallyVerifyAllSessions";
const E2eAdvancedPanel: React.FC = () => {
return (
<SettingsSubsection heading={_t("Encryption")}>
<SettingsSubsection heading={_t("settings|security|encryption_section")}>
<SettingsFlag name={SETTING_MANUALLY_VERIFY_ALL_SESSIONS} level={SettingLevel.DEVICE} />
<SettingsSubsectionText>
{_t(

View file

@ -366,18 +366,28 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
<table className="mx_SecureBackupPanel_statusList">
<tr>
<th scope="row">{_t("Backup key stored:")}</th>
<td>{backupKeyStored === true ? _t("in secret storage") : _t("not stored")}</td>
<td>
{backupKeyStored === true
? _t("settings|security|cross_signing_in_4s")
: _t("not stored")}
</td>
</tr>
<tr>
<th scope="row">{_t("Backup key cached:")}</th>
<td>
{backupKeyCached ? _t("cached locally") : _t("not found locally")}
{backupKeyCached
? _t("settings|security|cross_signing_cached")
: _t("settings|security|cross_signing_not_cached")}
{backupKeyWellFormedText}
</td>
</tr>
<tr>
<th scope="row">{_t("Secret storage public key:")}</th>
<td>{secretStorageKeyInAccount ? _t("in account data") : _t("not found")}</td>
<td>
{secretStorageKeyInAccount
? _t("in account data")
: _t("settings|security|cross_signing_not_found")}
</td>
</tr>
<tr>
<th scope="row">{_t("Secret storage:")}</th>

View file

@ -33,16 +33,16 @@ function installUpdate(): void {
function getStatusText(status: UpdateCheckStatus, errorDetail?: string): ReactNode {
switch (status) {
case UpdateCheckStatus.Error:
return _t("Error encountered (%(errorDetail)s).", { errorDetail });
return _t("update|error_encountered", { errorDetail });
case UpdateCheckStatus.Checking:
return _t("Checking for an update…");
return _t("update|checking");
case UpdateCheckStatus.NotAvailable:
return _t("No update available.");
return _t("update|no_update");
case UpdateCheckStatus.Downloading:
return _t("Downloading update…");
return _t("update|downloading");
case UpdateCheckStatus.Ready:
return _t(
"New version available. <a>Update now.</a>",
"update|new_version_available",
{},
{
a: (sub) => (
@ -86,7 +86,7 @@ const UpdateCheckButton: React.FC = () => {
return (
<React.Fragment>
<AccessibleButton onClick={onCheckForUpdateClick} kind="primary" disabled={busy}>
{_t("Check for update")}
{_t("update|check_action")}
</AccessibleButton>
{suffix}
</React.Fragment>

View file

@ -111,7 +111,7 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
let unfederatableSection: JSX.Element | undefined;
if (room.currentState.getStateEvents(EventType.RoomCreate, "")?.getContent()["m.federate"] === false) {
unfederatableSection = <div>{_t("This room is not accessible by remote Matrix servers")}</div>;
unfederatableSection = <div>{_t("room_settings|advanced|unfederated")}</div>;
}
let roomUpgradeButton;
@ -120,7 +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.",
"room_settings|advanced|room_upgrade_warning",
{},
{
b: (sub) => <b>{sub}</b>,
@ -130,8 +130,8 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
</p>
<AccessibleButton onClick={this.upgradeRoom} kind="primary">
{isSpace
? _t("Upgrade this space to the recommended room version")
: _t("Upgrade this room to the recommended room version")}
? _t("room_settings|advanced|space_upgrade_button")
: _t("room_settings|advanced|room_upgrade_button")}
</AccessibleButton>
</div>
);
@ -141,9 +141,9 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
if (this.state.oldRoomId) {
let copy: string;
if (isSpace) {
copy = _t("View older version of %(spaceName)s.", { spaceName: room.name ?? this.state.oldRoomId });
copy = _t("room_settings|advanced|space_predecessor", { spaceName: room.name ?? this.state.oldRoomId });
} else {
copy = _t("View older messages in %(roomName)s.", { roomName: room.name ?? this.state.oldRoomId });
copy = _t("room_settings|advanced|room_predecessor", { roomName: room.name ?? this.state.oldRoomId });
}
oldRoomLink = (
@ -158,16 +158,16 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
<SettingsSection heading={_t("Advanced")}>
<SettingsSubsection heading={room.isSpaceRoom() ? _t("Space information") : _t("Room information")}>
<div>
<span>{_t("Internal room ID")}</span>
<span>{_t("room_settings|advanced|room_id")}</span>
<CopyableText getTextToCopy={() => this.props.room.roomId}>
{this.props.room.roomId}
</CopyableText>
</div>
{unfederatableSection}
</SettingsSubsection>
<SettingsSubsection heading={_t("Room version")}>
<SettingsSubsection heading={_t("room_settings|advanced|room_version_section")}>
<div>
<span>{_t("Room version:")}</span>&nbsp;
<span>{_t("room_settings|advanced|room_version")}</span>&nbsp;
{room.getVersion()}
</div>
{oldRoomLink}

View file

@ -444,7 +444,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
<SettingsTab>
<SettingsSection heading={_t("room_settings|security|title")}>
<SettingsFieldset
legend={_t("Encryption")}
legend={_t("settings|security|encryption_section")}
description={
isEncryptionForceDisabled && !isEncrypted
? undefined

View file

@ -402,14 +402,18 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
href={this.state.externalAccountManagementUrl}
data-testid="external-account-management-link"
>
{_t("Manage account")}
{_t("settings|general|oidc_manage_button")}
</AccessibleButton>
</>
);
}
return (
<>
<SettingsSubsection heading={_t("Account")} stretchContent data-testid="accountSection">
<SettingsSubsection
heading={_t("settings|general|account_section")}
stretchContent
data-testid="accountSection"
>
{externalAccountManagement}
{passwordChangeSection}
</SettingsSubsection>
@ -421,7 +425,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
private renderLanguageSection(): JSX.Element {
// TODO: Convert to new-styled Field
return (
<SettingsSubsection heading={_t("Language and region")} stretchContent>
<SettingsSubsection heading={_t("settings|general|language_section")} stretchContent>
<LanguageDropdown
className="mx_GeneralUserSettingsTab_section_languageInput"
onOptionChange={this.onLanguageChange}
@ -433,7 +437,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
private renderSpellCheckSection(): JSX.Element {
const heading = (
<SettingsSubsectionHeading heading={_t("Spell check")}>
<SettingsSubsectionHeading heading={_t("settings|general|spell_check_section")}>
<ToggleSwitch checked={!!this.state.spellCheckEnabled} onChange={this.onSpellCheckEnabledChange} />
</SettingsSubsectionHeading>
);

View file

@ -110,21 +110,18 @@ export default class LabsUserSettingsTab extends React.Component<{}> {
return (
<SettingsTab>
<SettingsSection heading={_t("Upcoming features")}>
<SettingsSection heading={_t("labs|beta_section")}>
<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.",
{ brand: SdkConfig.get("brand") },
)}
{_t("labs|beta_description", { brand: SdkConfig.get("brand") })}
</SettingsSubsectionText>
{betaSection}
</SettingsSection>
{labsSections && (
<SettingsSection heading={_t("Early previews")}>
<SettingsSection heading={_t("labs|experimental_section")}>
<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>.",
"labs|experimental_description",
{},
{
a: (sub) => {

View file

@ -69,14 +69,14 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
this.setState({ busy: true });
try {
const list = await Mjolnir.sharedInstance().getOrCreatePersonalList();
await list.banEntity(kind, this.state.newPersonalRule, _t("Ignored/Blocked"));
await list.banEntity(kind, this.state.newPersonalRule, _t("labs_mjolnir|ban_reason"));
this.setState({ newPersonalRule: "" }); // this will also cause the new rule to be rendered
} catch (e) {
logger.error(e);
Modal.createDialog(ErrorDialog, {
title: _t("Error adding ignored user/server"),
description: _t("Something went wrong. Please try again or view your console for hints."),
title: _t("labs_mjolnir|error_adding_ignore"),
description: _t("labs_mjolnir|something_went_wrong"),
});
} finally {
this.setState({ busy: false });
@ -96,8 +96,8 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
logger.error(e);
Modal.createDialog(ErrorDialog, {
title: _t("Error subscribing to list"),
description: _t("Please verify the room ID or address and try again."),
title: _t("labs_mjolnir|error_adding_list_title"),
description: _t("labs_mjolnir|error_adding_list_description"),
});
} finally {
this.setState({ busy: false });
@ -113,8 +113,8 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
logger.error(e);
Modal.createDialog(ErrorDialog, {
title: _t("Error removing ignored user/server"),
description: _t("Something went wrong. Please try again or view your console for hints."),
title: _t("labs_mjolnir|error_removing_ignore"),
description: _t("labs_mjolnir|something_went_wrong"),
});
} finally {
this.setState({ busy: false });
@ -130,8 +130,8 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
logger.error(e);
Modal.createDialog(ErrorDialog, {
title: _t("Error unsubscribing from list"),
description: _t("Please try again or view your console for hints."),
title: _t("labs_mjolnir|error_removing_list_title"),
description: _t("labs_mjolnir|error_removing_list_description"),
});
} finally {
this.setState({ busy: false });
@ -157,12 +157,12 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
};
Modal.createDialog(QuestionDialog, {
title: _t("Ban list rules - %(roomName)s", { roomName: name }),
title: _t("labs_mjolnir|rules_title", { roomName: name }),
description: (
<div>
<h3>{_t("Server rules")}</h3>
<h3>{_t("labs_mjolnir|rules_server")}</h3>
{renderRules(list.serverRules)}
<h3>{_t("User rules")}</h3>
<h3>{_t("labs_mjolnir|rules_user")}</h3>
{renderRules(list.userRules)}
</div>
),
@ -174,7 +174,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
private renderPersonalBanListRules(): JSX.Element {
const list = Mjolnir.sharedInstance().getPersonalList();
const rules = list ? [...list.userRules, ...list.serverRules] : [];
if (!list || rules.length <= 0) return <i>{_t("You have not ignored anyone.")}</i>;
if (!list || rules.length <= 0) return <i>{_t("labs_mjolnir|personal_empty")}</i>;
const tiles: JSX.Element[] = [];
for (const rule of rules) {
@ -195,7 +195,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
return (
<div>
<p>{_t("You are currently ignoring:")}</p>
<p>{_t("labs_mjolnir|personal_section")}</p>
<ul>{tiles}</ul>
</div>
);
@ -206,7 +206,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
const lists = Mjolnir.sharedInstance().lists.filter((b) => {
return personalList ? personalList.roomId !== b.roomId : true;
});
if (!lists || lists.length <= 0) return <i>{_t("You are not subscribed to any lists")}</i>;
if (!lists || lists.length <= 0) return <i>{_t("labs_mjolnir|no_lists")}</i>;
const tiles: JSX.Element[] = [];
for (const list of lists) {
@ -233,7 +233,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
onClick={() => this.viewListRules(list)}
disabled={this.state.busy}
>
{_t("View rules")}
{_t("labs_mjolnir|view_rules")}
</AccessibleButton>
&nbsp;
{name}
@ -243,7 +243,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
return (
<div>
<p>{_t("You are currently subscribed to:")}</p>
<p>{_t("labs_mjolnir|lists")}</p>
<ul>{tiles}</ul>
</div>
);
@ -254,37 +254,24 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
return (
<SettingsTab>
<SettingsSection heading={_t("Ignored users")}>
<SettingsSection heading={_t("labs_mjolnir|title")}>
<SettingsSubsectionText>
<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.",
{ 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.",
)}
</p>
<span className="warning">{_t("labs_mjolnir|advanced_warning")}</span>
<p>{_t("labs_mjolnir|explainer_1", { brand }, { code: (s) => <code>{s}</code> })}</p>
<p>{_t("labs_mjolnir|explainer_2")}</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.",
{
myBanList: _t("labs_mjolnir|room_name"),
},
)}
heading={_t("labs_mjolnir|personal_heading")}
description={_t("labs_mjolnir|personal_description", {
myBanList: _t("labs_mjolnir|room_name"),
})}
>
{this.renderPersonalBanListRules()}
<form onSubmit={this.onAddPersonalRule} autoComplete="off">
<Field
type="text"
label={_t("Server or user ID to ignore")}
placeholder={_t("eg: @bot:* or example.org")}
label={_t("labs_mjolnir|personal_new_label")}
placeholder={_t("labs_mjolnir|personal_new_placeholder")}
value={this.state.newPersonalRule}
onChange={this.onPersonalRuleChanged}
/>
@ -299,16 +286,12 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
</form>
</SettingsSubsection>
<SettingsSubsection
heading={_t("Subscribed lists")}
heading={_t("labs_mjolnir|lists_heading")}
description={
<>
<span className="warning">
{_t("Subscribing to a ban list will cause you to join it!")}
</span>
<span className="warning">{_t("labs_mjolnir|lists_description_1")}</span>
&nbsp;
<span>
{_t("If this isn't what you want, please use a different tool to ignore users.")}
</span>
<span>{_t("labs_mjolnir|lists_description_2")}</span>
</>
}
>
@ -316,7 +299,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
<form onSubmit={this.onSubscribeList} autoComplete="off">
<Field
type="text"
label={_t("Room ID or address of ban list")}
label={_t("labs_mjolnir|lists_new_label")}
value={this.state.newList}
onChange={this.onNewListChanged}
/>

View file

@ -358,7 +358,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
return (
<SettingsTab>
{warning}
<SettingsSection heading={_t("Encryption")}>
<SettingsSection heading={_t("settings|security|encryption_section")}>
{secureBackup}
{eventIndex}
{crossSigning}