Migrate more strings to translation keys (#11642)

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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