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
|
@ -1607,8 +1607,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Signed Out"),
|
||||
description: _t("For security, this session has been signed out. Please sign in again."),
|
||||
title: _t("auth|session_logged_out_title"),
|
||||
description: _t("auth|session_logged_out_description"),
|
||||
});
|
||||
|
||||
dis.dispatch({
|
||||
|
@ -1619,19 +1619,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
Modal.createDialog(
|
||||
QuestionDialog,
|
||||
{
|
||||
title: _t("Terms and Conditions"),
|
||||
title: _t("terms|tac_title"),
|
||||
description: (
|
||||
<div>
|
||||
<p>
|
||||
{" "}
|
||||
{_t(
|
||||
"To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.",
|
||||
{ homeserverDomain: cli.getDomain() },
|
||||
)}
|
||||
</p>
|
||||
<p> {_t("terms|tac_description", { homeserverDomain: cli.getDomain() })}</p>
|
||||
</div>
|
||||
),
|
||||
button: _t("Review terms and conditions"),
|
||||
button: _t("terms|tac_button"),
|
||||
cancelButton: _t("action|dismiss"),
|
||||
onFinished: (confirmed) => {
|
||||
if (confirmed) {
|
||||
|
@ -1672,11 +1666,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
switch (type) {
|
||||
case "CRYPTO_WARNING_OLD_VERSION_DETECTED":
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Old cryptography data detected"),
|
||||
description: _t(
|
||||
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.",
|
||||
{ brand: SdkConfig.get().brand },
|
||||
),
|
||||
title: _t("encryption|old_version_detected_title"),
|
||||
description: _t("encryption|old_version_detected_description", {
|
||||
brand: SdkConfig.get().brand,
|
||||
}),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -1732,7 +1725,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
} else if (request.pending) {
|
||||
ToastStore.sharedInstance().addOrReplaceToast({
|
||||
key: "verifreq_" + request.transactionId,
|
||||
title: _t("Verification requested"),
|
||||
title: _t("encryption|verification_requested_toast_title"),
|
||||
icon: "verification",
|
||||
props: { request },
|
||||
component: VerificationRequestToast,
|
||||
|
|
|
@ -2335,7 +2335,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
className="mx_RoomView_auxPanel_hiddenHighlights"
|
||||
onClick={this.onHiddenHighlightsClick}
|
||||
>
|
||||
{_t("You have %(count)s unread notifications in a prior version of this room.", {
|
||||
{_t("room|unread_notifications_predecessor", {
|
||||
count: hiddenHighlightCount,
|
||||
})}
|
||||
</AccessibleButton>
|
||||
|
|
|
@ -487,7 +487,7 @@ const validateEmailRules = withValidation({
|
|||
{
|
||||
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"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -509,7 +509,7 @@ const SpaceSetupPrivateInvite: React.FC<{
|
|||
name={name}
|
||||
type="text"
|
||||
label={_t("Email address")}
|
||||
placeholder={_t("Email")}
|
||||
placeholder={_t("auth|email_field_label")}
|
||||
value={emailAddresses[i]}
|
||||
onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
|
||||
ref={fieldRefs[i]}
|
||||
|
|
|
@ -93,7 +93,7 @@ export default class ViewSource extends React.Component<IProps, IState> {
|
|||
</details>
|
||||
<details className="mx_ViewSource_details">
|
||||
<summary>
|
||||
<span className="mx_ViewSource_heading">{_t("Original event source")}</span>
|
||||
<span className="mx_ViewSource_heading">{_t("devtools|original_event_source")}</span>
|
||||
</summary>
|
||||
<CopyableText getTextToCopy={copyOriginalFunc}>
|
||||
<SyntaxHighlight language="json">{stringify(originalEventSource)}</SyntaxHighlight>
|
||||
|
@ -104,7 +104,7 @@ export default class ViewSource extends React.Component<IProps, IState> {
|
|||
} else {
|
||||
return (
|
||||
<>
|
||||
<div className="mx_ViewSource_heading">{_t("Original event source")}</div>
|
||||
<div className="mx_ViewSource_heading">{_t("devtools|original_event_source")}</div>
|
||||
<CopyableText getTextToCopy={copyOriginalFunc}>
|
||||
<SyntaxHighlight language="json">{stringify(originalEventSource)}</SyntaxHighlight>
|
||||
</CopyableText>
|
||||
|
|
|
@ -396,7 +396,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
|||
<PassphraseField
|
||||
name="reset_password"
|
||||
type="password"
|
||||
label={_td("New Password")}
|
||||
label={_td("auth|change_password_new_label")}
|
||||
value={this.state.password}
|
||||
minScore={PASSWORD_MIN_SCORE}
|
||||
fieldRef={(field) => (this.fieldPassword = field)}
|
||||
|
|
|
@ -53,7 +53,7 @@ export const CheckEmail: React.FC<CheckEmailProps> = ({
|
|||
return (
|
||||
<>
|
||||
<EMailPromptIcon className="mx_AuthBody_emailPromptIcon--shifted" />
|
||||
<h1>{_t("Check your email to continue")}</h1>
|
||||
<h1>{_t("auth|uia|email_auth_header")}</h1>
|
||||
<div className="mx_AuthBody_text">
|
||||
<p>{_t("auth|check_email_explainer", { email: email }, { b: (t) => <b>{t}</b> })}</p>
|
||||
<div className="mx_AuthBody_did-not-receive">
|
||||
|
|
|
@ -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