Migrate more strings to translation keys (#11642)
This commit is contained in:
parent
c879882558
commit
faa7b1521f
87 changed files with 6443 additions and 6006 deletions
|
@ -40,9 +40,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
|
|||
|
||||
class EmailField extends PureComponent<IProps> {
|
||||
public static defaultProps = {
|
||||
label: _td("Email"),
|
||||
labelRequired: _td("Enter email address"),
|
||||
labelInvalid: _td("Doesn't look like a valid email address"),
|
||||
label: _td("auth|email_field_label"),
|
||||
labelRequired: _td("auth|email_field_label_required"),
|
||||
labelInvalid: _td("auth|email_field_label_invalid"),
|
||||
};
|
||||
|
||||
public readonly validate = withValidation({
|
||||
|
|
|
@ -169,7 +169,7 @@ export class PasswordAuthEntry extends React.Component<IAuthEntryProps, IPasswor
|
|||
|
||||
return (
|
||||
<div>
|
||||
<p>{_t("Confirm your identity by entering your account password below.")}</p>
|
||||
<p>{_t("auth|uia|password_prompt")}</p>
|
||||
<form onSubmit={this.onSubmit} className="mx_InteractiveAuthEntryComponents_passwordSection">
|
||||
<Field
|
||||
className={passwordBoxClass}
|
||||
|
@ -219,9 +219,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.",
|
||||
);
|
||||
errorText = _t("auth|uia|recaptcha_missing_params");
|
||||
} else {
|
||||
sitePublicKey = this.props.stageParams.public_key;
|
||||
}
|
||||
|
@ -352,7 +350,7 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
|
|||
if (allChecked) {
|
||||
this.props.submitAuthDict({ type: AuthType.Terms });
|
||||
} else {
|
||||
this.setState({ errorText: _t("Please review and accept all of the homeserver's policies") });
|
||||
this.setState({ errorText: _t("auth|uia|terms_invalid") });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -403,7 +401,7 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
|
|||
|
||||
return (
|
||||
<div className="mx_InteractiveAuthEntryComponents">
|
||||
<p>{_t("Please review and accept the policies of this homeserver:")}</p>
|
||||
<p>{_t("auth|uia|terms")}</p>
|
||||
{checkboxes}
|
||||
{errorSection}
|
||||
{submitButton}
|
||||
|
@ -474,19 +472,19 @@ export class EmailIdentityAuthEntry extends React.Component<
|
|||
return (
|
||||
<div className="mx_InteractiveAuthEntryComponents_emailWrapper">
|
||||
<AuthHeaderModifier
|
||||
title={_t("Check your email to continue")}
|
||||
icon={<img src={EmailPromptIcon} alt={_t("Unread email icon")} width={16} />}
|
||||
title={_t("auth|uia|email_auth_header")}
|
||||
icon={<img src={EmailPromptIcon} role="presentation" alt="" width={16} />}
|
||||
hideServerPicker={true}
|
||||
/>
|
||||
<p>
|
||||
{_t("To create your account, open the link in the email we just sent to %(emailAddress)s.", {
|
||||
{_t("auth|uia|email", {
|
||||
emailAddress: <b>{this.props.inputs.emailAddress}</b>,
|
||||
})}
|
||||
</p>
|
||||
{this.state.requesting ? (
|
||||
<p className="secondary">
|
||||
{_t(
|
||||
"Did not receive it? <a>Resend it</a>",
|
||||
"auth|uia|email_resend_prompt",
|
||||
{},
|
||||
{
|
||||
a: (text: string) => (
|
||||
|
@ -502,13 +500,15 @@ export class EmailIdentityAuthEntry extends React.Component<
|
|||
) : (
|
||||
<p className="secondary">
|
||||
{_t(
|
||||
"Did not receive it? <a>Resend it</a>",
|
||||
"auth|uia|email_resend_prompt",
|
||||
{},
|
||||
{
|
||||
a: (text: string) => (
|
||||
<AccessibleTooltipButton
|
||||
kind="link_inline"
|
||||
title={this.state.requested ? _t("Resent!") : _t("action|resend")}
|
||||
title={
|
||||
this.state.requested ? _t("auth|uia|email_resent") : _t("action|resend")
|
||||
}
|
||||
alignment={Alignment.Right}
|
||||
onHideTooltip={
|
||||
this.state.requested
|
||||
|
@ -642,7 +642,7 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
|
|||
});
|
||||
} else {
|
||||
this.setState({
|
||||
errorText: _t("Token incorrect"),
|
||||
errorText: _t("auth|uia|msisdn_token_incorrect"),
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -670,8 +670,8 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
|
|||
}
|
||||
return (
|
||||
<div>
|
||||
<p>{_t("A text message has been sent to %(msisdn)s", { msisdn: <i>{this.msisdn}</i> })}</p>
|
||||
<p>{_t("Please enter the code it contains:")}</p>
|
||||
<p>{_t("auth|uia|msisdn", { msisdn: <i>{this.msisdn}</i> })}</p>
|
||||
<p>{_t("auth|uia|msisdn_token_prompt")}</p>
|
||||
<div className="mx_InteractiveAuthEntryComponents_msisdnWrapper">
|
||||
<form onSubmit={this.onFormSubmit}>
|
||||
<input
|
||||
|
@ -761,13 +761,13 @@ export class RegistrationTokenAuthEntry extends React.Component<IAuthEntryProps,
|
|||
|
||||
return (
|
||||
<div>
|
||||
<p>{_t("Enter a registration token provided by the homeserver administrator.")}</p>
|
||||
<p>{_t("auth|uia|registration_token_prompt")}</p>
|
||||
<form onSubmit={this.onSubmit} className="mx_InteractiveAuthEntryComponents_registrationTokenSection">
|
||||
<Field
|
||||
className={registrationTokenBoxClass}
|
||||
type="text"
|
||||
name="registrationTokenField"
|
||||
label={_t("Registration token")}
|
||||
label={_t("auth|uia|registration_token_label")}
|
||||
autoFocus={true}
|
||||
value={this.state.registrationToken}
|
||||
onChange={this.onRegistrationTokenFieldChange}
|
||||
|
@ -895,7 +895,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
|
|||
} else if (this.state.attemptFailed) {
|
||||
errorSection = (
|
||||
<div className="error" role="alert">
|
||||
{_t("Something went wrong in confirming your identity. Cancel and try again.")}
|
||||
{_t("auth|uia|sso_failed")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -972,7 +972,7 @@ export class FallbackAuthEntry extends React.Component<IAuthEntryProps> {
|
|||
return (
|
||||
<div>
|
||||
<AccessibleButton kind="link" inputRef={this.fallbackButton} onClick={this.onShowFallbackClick}>
|
||||
{_t("Start authentication")}
|
||||
{_t("auth|uia|fallback_button")}
|
||||
</AccessibleButton>
|
||||
{errorSection}
|
||||
</div>
|
||||
|
|
|
@ -37,9 +37,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> {
|
|||
|
||||
class PassphraseConfirmField extends PureComponent<IProps> {
|
||||
public static defaultProps = {
|
||||
label: _td("Confirm password"),
|
||||
labelRequired: _td("Confirm password"),
|
||||
labelInvalid: _td("Passwords don't match"),
|
||||
label: _td("auth|change_password_confirm_label"),
|
||||
labelRequired: _td("auth|change_password_confirm_label"),
|
||||
labelInvalid: _td("auth|change_password_confirm_invalid"),
|
||||
};
|
||||
|
||||
private validate = withValidation({
|
||||
|
|
|
@ -46,9 +46,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
|
|||
class PassphraseField extends PureComponent<IProps> {
|
||||
public static defaultProps = {
|
||||
label: _td("common|password"),
|
||||
labelEnterPassword: _td("Enter password"),
|
||||
labelStrongPassword: _td("Nice, strong password!"),
|
||||
labelAllowedButUnsafe: _td("Password is allowed, but unsafe"),
|
||||
labelEnterPassword: _td("auth|password_field_label"),
|
||||
labelStrongPassword: _td("auth|password_field_strong_label"),
|
||||
labelAllowedButUnsafe: _td("auth|password_field_weak_label"),
|
||||
};
|
||||
|
||||
public readonly validate = withValidation<this, ZxcvbnResult | null>({
|
||||
|
@ -91,7 +91,7 @@ class PassphraseField extends PureComponent<IProps> {
|
|||
return null;
|
||||
}
|
||||
const { feedback } = complexity;
|
||||
return feedback.warning || feedback.suggestions[0] || _t("Keep going…");
|
||||
return feedback.warning || feedback.suggestions[0] || _t("auth|password_field_keep_going_prompt");
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -214,7 +214,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
test({ value, allowEmpty }) {
|
||||
return allowEmpty || !!value;
|
||||
},
|
||||
invalid: () => _t("Enter username"),
|
||||
invalid: () => _t("auth|username_field_required_invalid"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -236,12 +236,12 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
test({ value, allowEmpty }): boolean {
|
||||
return allowEmpty || !!value;
|
||||
},
|
||||
invalid: (): string => _t("Enter phone number"),
|
||||
invalid: (): string => _t("auth|msisdn_field_required_invalid"),
|
||||
},
|
||||
{
|
||||
key: "number",
|
||||
test: ({ value }): boolean => !value || PHONE_NUMBER_REGEX.test(value),
|
||||
invalid: (): string => _t("That phone number doesn't look quite right, please check and try again"),
|
||||
invalid: (): string => _t("auth|msisdn_field_number_invalid"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -259,7 +259,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
test({ value, allowEmpty }): boolean {
|
||||
return allowEmpty || !!value;
|
||||
},
|
||||
invalid: (): string => _t("Enter password"),
|
||||
invalid: (): string => _t("auth|password_field_label"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -341,7 +341,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
autoComplete="tel-national"
|
||||
key="phone_input"
|
||||
type="text"
|
||||
label={_t("Phone")}
|
||||
label={_t("auth|msisdn_field_label")}
|
||||
value={this.props.phoneNumber}
|
||||
prefixComponent={phoneCountry}
|
||||
onChange={this.onPhoneNumberChanged}
|
||||
|
@ -378,7 +378,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
kind="link"
|
||||
onClick={this.onForgotPasswordClick}
|
||||
>
|
||||
{_t("Forgot password?")}
|
||||
{_t("auth|reset_password_button")}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
if (!SdkConfig.get().disable_3pid_login) {
|
||||
loginType = (
|
||||
<div className="mx_Login_type_container">
|
||||
<label className="mx_Login_type_label">{_t("Sign in with")}</label>
|
||||
<label className="mx_Login_type_label">{_t("auth|identifier_label")}</label>
|
||||
<Field
|
||||
element="select"
|
||||
value={this.state.loginType}
|
||||
|
@ -410,7 +410,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
|||
{_t("Email address")}
|
||||
</option>
|
||||
<option key={LoginField.Password} value={LoginField.Password}>
|
||||
{_t("Phone")}
|
||||
{_t("auth|msisdn_field_label")}
|
||||
</option>
|
||||
</Field>
|
||||
</div>
|
||||
|
|
|
@ -267,7 +267,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
|||
};
|
||||
|
||||
private validateEmailRules = withValidation({
|
||||
description: () => _t("Use an email address to recover your account"),
|
||||
description: () => _t("auth|reset_password_email_field_description"),
|
||||
hideDescriptionIfValid: true,
|
||||
rules: [
|
||||
{
|
||||
|
@ -275,12 +275,12 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
|||
test(this: RegistrationForm, { value, allowEmpty }) {
|
||||
return allowEmpty || !this.authStepIsRequired("m.login.email.identity") || !!value;
|
||||
},
|
||||
invalid: () => _t("Enter email address (required on this homeserver)"),
|
||||
invalid: () => _t("auth|reset_password_email_field_required_invalid"),
|
||||
},
|
||||
{
|
||||
key: "email",
|
||||
test: ({ value }) => !value || Email.looksValid(value),
|
||||
invalid: () => _t("Doesn't look like a valid email address"),
|
||||
invalid: () => _t("auth|email_field_label_invalid"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -324,7 +324,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
|||
};
|
||||
|
||||
private validatePhoneNumberRules = withValidation({
|
||||
description: () => _t("Other users can invite you to rooms using your contact details"),
|
||||
description: () => _t("auth|msisdn_field_description"),
|
||||
hideDescriptionIfValid: true,
|
||||
rules: [
|
||||
{
|
||||
|
@ -332,12 +332,12 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
|||
test(this: RegistrationForm, { value, allowEmpty }) {
|
||||
return allowEmpty || !this.authStepIsRequired("m.login.msisdn") || !!value;
|
||||
},
|
||||
invalid: () => _t("Enter phone number (required on this homeserver)"),
|
||||
invalid: () => _t("auth|registration_msisdn_field_required_invalid"),
|
||||
},
|
||||
{
|
||||
key: "email",
|
||||
test: ({ value }) => !value || phoneNumberLooksValid(value),
|
||||
invalid: () => _t("That phone number doesn't look quite right, please check and try again"),
|
||||
invalid: () => _t("auth|msisdn_field_number_invalid"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -380,7 +380,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
|||
{
|
||||
key: "required",
|
||||
test: ({ value, allowEmpty }) => allowEmpty || !!value,
|
||||
invalid: () => _t("Enter username"),
|
||||
invalid: () => _t("auth|username_field_required_invalid"),
|
||||
},
|
||||
{
|
||||
key: "safeLocalpart",
|
||||
|
@ -451,7 +451,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
|||
if (!this.showEmail()) {
|
||||
return null;
|
||||
}
|
||||
const emailLabel = this.authStepIsRequired("m.login.email.identity") ? _td("Email") : _td("Email (optional)");
|
||||
const emailLabel = this.authStepIsRequired("m.login.email.identity")
|
||||
? _td("auth|email_field_label")
|
||||
: _td("Email (optional)");
|
||||
return (
|
||||
<EmailField
|
||||
fieldRef={(field) => (this[RegistrationField.Email] = field)}
|
||||
|
|
|
@ -179,7 +179,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
|
|||
tabs.push(
|
||||
new Tab(
|
||||
UserTab.Mjolnir,
|
||||
_td("Ignored users"),
|
||||
_td("labs_mjolnir|title"),
|
||||
"mx_UserSettingsDialog_mjolnirIcon",
|
||||
<MjolnirUserSettingsTab />,
|
||||
"UserSettingMjolnir",
|
||||
|
|
|
@ -63,8 +63,8 @@ const MAX_OPTION_LENGTH = 340;
|
|||
|
||||
function creatingInitialState(): IState {
|
||||
return {
|
||||
title: _t("Create poll"),
|
||||
actionLabel: _t("Create Poll"),
|
||||
title: _t("poll|create_poll_title"),
|
||||
actionLabel: _t("poll|create_poll_action"),
|
||||
canSubmit: false, // need to add a question and at least one option first
|
||||
question: "",
|
||||
options: arraySeed("", DEFAULT_NUM_OPTIONS),
|
||||
|
@ -79,7 +79,7 @@ function editingInitialState(editingMxEvent: MatrixEvent): IState {
|
|||
if (!poll?.isEquivalentTo(M_POLL_START)) return creatingInitialState();
|
||||
|
||||
return {
|
||||
title: _t("Edit poll"),
|
||||
title: _t("poll|edit_poll_title"),
|
||||
actionLabel: _t("action|done"),
|
||||
canSubmit: true,
|
||||
question: poll.question.text,
|
||||
|
@ -175,8 +175,8 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
|||
.catch((e) => {
|
||||
console.error("Failed to post poll:", e);
|
||||
Modal.createDialog(QuestionDialog, {
|
||||
title: _t("Failed to post poll"),
|
||||
description: _t("Sorry, the poll you tried to create was not posted."),
|
||||
title: _t("poll|failed_send_poll_title"),
|
||||
description: _t("poll|failed_send_poll_description"),
|
||||
button: _t("action|try_again"),
|
||||
cancelButton: _t("action|cancel"),
|
||||
onFinished: (tryAgain: boolean) => {
|
||||
|
@ -197,37 +197,37 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
|||
protected renderContent(): React.ReactNode {
|
||||
return (
|
||||
<div className="mx_PollCreateDialog">
|
||||
<h2>{_t("Poll type")}</h2>
|
||||
<h2>{_t("poll|type_heading")}</h2>
|
||||
<Field element="select" value={this.state.kind.name} onChange={this.onPollTypeChange}>
|
||||
<option key={M_POLL_KIND_DISCLOSED.name} value={M_POLL_KIND_DISCLOSED.name}>
|
||||
{_t("Open poll")}
|
||||
{_t("poll|type_open")}
|
||||
</option>
|
||||
<option key={M_POLL_KIND_UNDISCLOSED.name} value={M_POLL_KIND_UNDISCLOSED.name}>
|
||||
{_t("Closed poll")}
|
||||
{_t("poll|type_closed")}
|
||||
</option>
|
||||
</Field>
|
||||
<p>{pollTypeNotes(this.state.kind)}</p>
|
||||
<h2>{_t("What is your poll question or topic?")}</h2>
|
||||
<h2>{_t("poll|topic_heading")}</h2>
|
||||
<Field
|
||||
id="poll-topic-input"
|
||||
value={this.state.question}
|
||||
maxLength={MAX_QUESTION_LENGTH}
|
||||
label={_t("Question or topic")}
|
||||
placeholder={_t("Write something…")}
|
||||
label={_t("poll|topic_label")}
|
||||
placeholder={_t("poll|topic_placeholder")}
|
||||
onChange={this.onQuestionChange}
|
||||
usePlaceholderAsHint={true}
|
||||
disabled={this.state.busy}
|
||||
autoFocus={this.state.autoFocusTarget === FocusTarget.Topic}
|
||||
/>
|
||||
<h2>{_t("Create options")}</h2>
|
||||
<h2>{_t("poll|options_heading")}</h2>
|
||||
{this.state.options.map((op, i) => (
|
||||
<div key={`option_${i}`} className="mx_PollCreateDialog_option">
|
||||
<Field
|
||||
id={`pollcreate_option_${i}`}
|
||||
value={op}
|
||||
maxLength={MAX_OPTION_LENGTH}
|
||||
label={_t("Option %(number)s", { number: i + 1 })}
|
||||
placeholder={_t("Write an option")}
|
||||
label={_t("poll|options_label", { number: i + 1 })}
|
||||
placeholder={_t("poll|options_placeholder")}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => this.onOptionChange(i, e)}
|
||||
usePlaceholderAsHint={true}
|
||||
disabled={this.state.busy}
|
||||
|
@ -250,7 +250,7 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
|||
className="mx_PollCreateDialog_addOption"
|
||||
inputRef={this.addOptionRef}
|
||||
>
|
||||
{_t("Add option")}
|
||||
{_t("poll|options_add_button")}
|
||||
</AccessibleButton>
|
||||
{this.state.busy && (
|
||||
<div className="mx_PollCreateDialog_busy">
|
||||
|
@ -270,8 +270,8 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
|||
|
||||
function pollTypeNotes(kind: KnownPollKind): string {
|
||||
if (M_POLL_KIND_DISCLOSED.matches(kind.name)) {
|
||||
return _t("Voters see results as soon as they have voted");
|
||||
return _t("poll|disclosed_notes");
|
||||
} else {
|
||||
return _t("Results are only revealed when you end the poll");
|
||||
return _t("poll|notes");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
|
|||
dis.dispatch({ action: "open_room_settings" });
|
||||
}}
|
||||
>
|
||||
{_t("Edit topic")}
|
||||
{_t("room|edit_topic")}
|
||||
</AccessibleButton>
|
||||
)}
|
||||
</div>
|
||||
|
@ -119,7 +119,7 @@ export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
|
|||
onClick={onClick}
|
||||
dir="auto"
|
||||
tooltipTargetClassName={className}
|
||||
label={_t("Click to read topic")}
|
||||
label={_t("room|read_topic")}
|
||||
alignment={Alignment.Bottom}
|
||||
ignoreHover={ignoreHover}
|
||||
>
|
||||
|
|
|
@ -106,7 +106,7 @@ const EncryptionInfo: React.FC<IProps> = ({
|
|||
return (
|
||||
<React.Fragment>
|
||||
<div data-testid="encryption-info-description" className="mx_UserInfo_container">
|
||||
<h3>{_t("Encryption")}</h3>
|
||||
<h3>{_t("settings|security|encryption_section")}</h3>
|
||||
{description}
|
||||
</div>
|
||||
<div className="mx_UserInfo_container">
|
||||
|
|
|
@ -78,7 +78,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
|
|||
</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.",
|
||||
"room_settings|advanced|room_upgrade_warning",
|
||||
{},
|
||||
{
|
||||
b: (sub) => <b>{sub}</b>,
|
||||
|
@ -89,7 +89,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
|
|||
</div>
|
||||
<p className="mx_RoomUpgradeWarningBar_upgradelink">
|
||||
<AccessibleButton onClick={this.onUpgradeClick}>
|
||||
{_t("Upgrade this room to the recommended room version")}
|
||||
{_t("room_settings|advanced|room_upgrade_button")}
|
||||
</AccessibleButton>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
<span>{_t("room_settings|advanced|room_version")}</span>
|
||||
{room.getVersion()}
|
||||
</div>
|
||||
{oldRoomLink}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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>
|
||||
|
||||
{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>
|
||||
|
||||
<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}
|
||||
/>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -29,14 +29,10 @@ export default class VerificationComplete extends React.Component<IProps> {
|
|||
<div>
|
||||
<h2>{_t("encryption|verification|complete_title")}</h2>
|
||||
<p>{_t("encryption|verification|complete_description")}</p>
|
||||
<p>
|
||||
{_t(
|
||||
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.",
|
||||
)}
|
||||
</p>
|
||||
<p>{_t("encryption|verification|explainer")}</p>
|
||||
<DialogButtons
|
||||
onPrimaryButtonClick={this.props.onDone}
|
||||
primaryButton={_t("Got It")}
|
||||
primaryButton={_t("encryption|verification|complete_action")}
|
||||
hasCancel={false}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -133,18 +133,18 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
|
|||
</div>
|
||||
);
|
||||
sasCaption = this.props.isSelf
|
||||
? _t("Confirm the emoji below are displayed on both devices, in the same order:")
|
||||
: _t("Verify this user by confirming the following emoji appear on their screen.");
|
||||
? _t("encryption|verification|sas_emoji_caption_self")
|
||||
: _t("encryption|verification|sas_emoji_caption_user");
|
||||
} else if (this.props.sas.decimal) {
|
||||
const numberBlocks = this.props.sas.decimal.map((num, i) => <span key={i}>{num}</span>);
|
||||
sasDisplay = <div className="mx_VerificationShowSas_decimalSas">{numberBlocks}</div>;
|
||||
sasCaption = this.props.isSelf
|
||||
? _t("Verify this device by confirming the following number appears on its screen.")
|
||||
: _t("Verify this user by confirming the following number appears on their screen.");
|
||||
? _t("encryption|verification|sas_caption_self")
|
||||
: _t("encryption|verification|sas_caption_user");
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
{_t("Unable to find a supported verification method.")}
|
||||
{_t("encryption|verification|unsupported_method")}
|
||||
<AccessibleButton kind="primary" onClick={this.props.onCancel}>
|
||||
{_t("action|cancel")}
|
||||
</AccessibleButton>
|
||||
|
@ -159,21 +159,21 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
|
|||
// logged out during verification
|
||||
const otherDevice = this.props.otherDeviceDetails;
|
||||
if (otherDevice) {
|
||||
text = _t("Waiting for you to verify on your other device, %(deviceName)s (%(deviceId)s)…", {
|
||||
text = _t("encryption|verification|waiting_other_device_details", {
|
||||
deviceName: otherDevice.displayName,
|
||||
deviceId: otherDevice.deviceId,
|
||||
});
|
||||
} else {
|
||||
text = _t("Waiting for you to verify on your other device…");
|
||||
text = _t("encryption|verification|waiting_other_device");
|
||||
}
|
||||
confirm = <p>{text}</p>;
|
||||
} else if (this.state.pending || this.state.cancelling) {
|
||||
let text;
|
||||
if (this.state.pending) {
|
||||
const { displayName } = this.props;
|
||||
text = _t("Waiting for %(displayName)s to verify…", { displayName });
|
||||
text = _t("encryption|verification|waiting_other_user", { displayName });
|
||||
} else {
|
||||
text = _t("Cancelling…");
|
||||
text = _t("encryption|verification|cancelling");
|
||||
}
|
||||
confirm = <PendingActionSpinner text={text} />;
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue