Migrate more strings to translation keys (#11671)

This commit is contained in:
Michael Telatynski 2023-09-26 18:35:55 +01:00 committed by GitHub
parent 13aed62a91
commit 4d0d024e86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
125 changed files with 7066 additions and 6607 deletions

View file

@ -345,7 +345,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
<AccessibleTooltipButton
className="mx_LeftPanel_exploreButton"
onClick={this.onExplore}
title={_t("Explore rooms")}
title={_t("action|explore_rooms")}
/>
);
}

View file

@ -384,7 +384,7 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
oob_data: {
avatarUrl: room?.avatar_url,
// XXX: This logic is duplicated from the JS SDK which would normally decide what the name is.
name: room?.name || roomAlias || _t("Unnamed room"),
name: room?.name || roomAlias || _t("common|unnamed_room"),
roomType,
} as IOOBData,
metricsTrigger: "RoomDirectory",

View file

@ -124,7 +124,7 @@ const SpaceLandingAddButton: React.FC<{ space: Room }> = ({ space }) => {
{canCreateRoom && (
<>
<IconizedContextMenuOption
label={_t("New room")}
label={_t("action|new_room")}
iconClassName="mx_RoomList_iconNewRoom"
onClick={async (e): Promise<void> => {
e.preventDefault();
@ -139,7 +139,7 @@ const SpaceLandingAddButton: React.FC<{ space: Room }> = ({ space }) => {
/>
{videoRoomsEnabled && (
<IconizedContextMenuOption
label={_t("New video room")}
label={_t("action|new_video_room")}
iconClassName="mx_RoomList_iconNewVideoRoom"
onClick={async (e): Promise<void> => {
e.preventDefault();
@ -164,7 +164,7 @@ const SpaceLandingAddButton: React.FC<{ space: Room }> = ({ space }) => {
</>
)}
<IconizedContextMenuOption
label={_t("Add existing room")}
label={_t("action|add_existing_room")}
iconClassName="mx_RoomList_iconAddExistingRoom"
onClick={(e) => {
e.preventDefault();

View file

@ -174,11 +174,11 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
let iconClassName: string | undefined;
switch (echoChamber.notificationVolume) {
case RoomNotifState.AllMessages:
notificationLabel = _t("Default");
notificationLabel = _t("notifications|default");
iconClassName = "mx_RoomTile_iconNotificationsDefault";
break;
case RoomNotifState.AllMessagesLoud:
notificationLabel = _t("All messages");
notificationLabel = _t("notifications|all_messages");
iconClassName = "mx_RoomTile_iconNotificationsAllMessages";
break;
case RoomNotifState.MentionsOnly:

View file

@ -61,7 +61,7 @@ export const RoomNotificationContextMenu: React.FC<IProps> = ({ room, onFinished
const allMessagesOption: JSX.Element = (
<IconizedContextMenuRadio
label={_t("All messages")}
label={_t("notifications|all_messages")}
active={notificationState === RoomNotifState.AllMessagesLoud}
iconClassName="mx_RoomNotificationContextMenu_iconBellDot"
onClick={wrapHandler(() => setNotificationState(RoomNotifState.AllMessagesLoud))}

View file

@ -187,7 +187,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
<IconizedContextMenuOption
data-testid="new-video-room-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Video room")}
label={_t("common|video_room")}
onClick={onNewVideoRoomClick}
>
<BetaPill />

View file

@ -95,7 +95,7 @@ export default class ConfirmUserActionDialog extends React.Component<IProps, ISt
onChange={this.onReasonChange}
value={this.state.reason}
className="mx_ConfirmUserActionDialog_reasonField"
label={_t("Reason")}
label={_t("room_settings|permissions|ban_reason")}
autoFocus={true}
/>
</form>

View file

@ -353,9 +353,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
microcopy = _t("create_room|encryption_forced");
}
} else {
microcopy = _t(
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
);
microcopy = _t("settings|security|e2ee_default_disabled_warning");
}
e2eeSection = (
<React.Fragment>
@ -420,7 +418,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
labelKnock={
this.askToJoinEnabled ? _t("room_settings|security|join_rule_knock") : undefined
}
labelPublic={_t("Public room")}
labelPublic={_t("common|public_room")}
labelRestricted={
this.supportsRestricted ? _t("create_room|join_rule_restricted") : undefined
}

View file

@ -163,7 +163,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
<JoinRuleDropdown
label={_t("Space visibility")}
labelInvite={_t("Private space (invite only)")}
labelPublic={_t("Public space")}
labelPublic={_t("common|public_space")}
labelRestricted={_t("create_room|join_rule_restricted")}
width={478}
value={joinRule}

View file

@ -214,7 +214,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
className="mx_DeactivateAccountDialog"
onFinished={this.props.onFinished}
titleClass="danger"
title={_t("Deactivate Account")}
title={_t("settings|general|deactivate_section")}
screenName="DeactivateAccount"
>
<div className="mx_Dialog_content">

View file

@ -47,7 +47,7 @@ export default class IntegrationsDisabledDialog extends React.Component<IProps>
<div className="mx_IntegrationsDisabledDialog_content">
<p>
{_t("Enable '%(manageIntegrations)s' in Settings to do this.", {
manageIntegrations: _t("Manage integrations"),
manageIntegrations: _t("integration_manager|manage_title"),
})}
</p>
</div>

View file

@ -143,7 +143,7 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
// Let's pick a title, body, and other params text that we'll show to the user. The order
// is most specific first, so stagePhase > our props > defaults.
let title = this.state.authError ? "Error" : this.props.title || _t("Authentication");
let title = this.state.authError ? "Error" : this.props.title || _t("common|authentication");
let body = this.state.authError ? null : this.props.body;
let continueText: string | undefined;
let continueKind: string | undefined;

View file

@ -417,7 +417,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
<Field
className="mx_ReportEventDialog_reason"
element="textarea"
label={_t("Reason")}
label={_t("room_settings|permissions|ban_reason")}
rows={5}
onChange={this.onReasonChange}
value={this.state.reason}
@ -456,7 +456,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
<Field
className="mx_ReportEventDialog_reason"
element="textarea"
label={_t("Reason")}
label={_t("room_settings|permissions|ban_reason")}
rows={5}
onChange={this.onReasonChange}
value={this.state.reason}

View file

@ -154,7 +154,7 @@ class RoomSettingsDialog extends React.Component<IProps, IState> {
tabs.push(
new Tab(
RoomSettingsTab.Voip,
_td("Voice & Video"),
_td("settings|voip|title"),
"mx_RoomSettingsDialog_voiceIcon",
<VoipRoomSettingsTab room={this.state.room} />,
),
@ -197,7 +197,7 @@ class RoomSettingsDialog extends React.Component<IProps, IState> {
tabs.push(
new Tab(
RoomSettingsTab.Bridges,
_td("Bridges"),
_td("room_settings|bridges|title"),
"mx_RoomSettingsDialog_bridgesIcon",
<BridgeSettingsTab room={this.state.room} />,
"RoomSettingsBridges",

View file

@ -67,8 +67,8 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
const emailAddress = this.state.emailAddress;
if (!Email.looksValid(emailAddress)) {
Modal.createDialog(ErrorDialog, {
title: _t("Invalid Email Address"),
description: _t("This doesn't appear to be a valid email address"),
title: _t("settings|general|error_invalid_email"),
description: _t("settings|general|error_invalid_email_detail"),
});
return;
}
@ -88,7 +88,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
this.setState({ emailBusy: false });
logger.error("Unable to add email address " + emailAddress + " " + err);
Modal.createDialog(ErrorDialog, {
title: _t("Unable to add email address"),
title: _t("settings|general|error_add_email"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
},
@ -123,7 +123,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
if (underlyingError instanceof MatrixError && underlyingError.errcode === "M_THREEPID_AUTH_FAILED") {
const message =
_t("Unable to verify email address.") +
_t("settings|general|error_email_verification") +
" " +
_t(
"Please check your email and click on the link it contains. Once this is done, click continue.",
@ -137,7 +137,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
} else {
logger.error("Unable to verify email address: " + err);
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify email address."),
title: _t("settings|general|error_email_verification"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
}

View file

@ -133,7 +133,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
tabs.push(
new Tab(
UserTab.Voice,
_td("Voice & Video"),
_td("settings|voip|title"),
"mx_UserSettingsDialog_voiceIcon",
<VoiceUserSettingsTab />,
"UserSettingsVoiceVideo",

View file

@ -33,7 +33,9 @@ interface Props {
export function PublicRoomResultDetails({ room, labelId, descriptionId, detailsId }: Props): JSX.Element {
let name =
room.name || getDisplayAliasForAliasSet(room.canonical_alias ?? "", room.aliases ?? []) || _t("Unnamed room");
room.name ||
getDisplayAliasForAliasSet(room.canonical_alias ?? "", room.aliases ?? []) ||
_t("common|unnamed_room");
if (name.length > MAX_NAME_LENGTH) {
name = `${name.substring(0, MAX_NAME_LENGTH)}...`;
}

View file

@ -409,7 +409,7 @@ export const UserOptionsSection: React.FC<{
kind="link"
className={classNames("mx_UserInfo_field", { mx_UserInfo_destructive: !isIgnored })}
>
{isIgnored ? _t("Unignore") : _t("action|ignore")}
{isIgnored ? _t("action|unignore") : _t("action|ignore")}
</AccessibleButton>
);

View file

@ -762,7 +762,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
const buttons = this.props.showButtons ? this.renderButtons(isVideoRoom) : null;
let oobName = _t("Unnamed room");
let oobName = _t("common|unnamed_room");
if (this.props.oobData && this.props.oobData.name) {
oobName = this.props.oobData.name;
}

View file

@ -59,7 +59,7 @@ const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick, onH
<AccessibleButton onClick={toggleExpanded}>
{expanded
? _t("action|collapse")
: _t("Show %(count)s other previews", { count: previews.length - showPreviews.length })}
: _t("timeline|url_preview|show_n_more", { count: previews.length - showPreviews.length })}
</AccessibleButton>
);
}
@ -72,7 +72,7 @@ const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick, onH
<AccessibleButton
className="mx_LinkPreviewGroup_hide"
onClick={onCancelClick}
aria-label={_t("Close preview")}
aria-label={_t("timeline|url_preview|close")}
>
<img
className="mx_filterFlipColor"

View file

@ -354,9 +354,9 @@ export default class MemberList extends React.Component<IProps, IState> {
let inviteButton: JSX.Element | undefined;
if (room?.getMyMembership() === "join" && shouldShowComponent(UIComponent.InviteUsers)) {
let inviteButtonText = _t("Invite to this room");
let inviteButtonText = _t("room|invite_this_room");
if (room.isSpaceRoom()) {
inviteButtonText = _t("Invite to this space");
inviteButtonText = _t("space|invite_this_space");
}
if (this.state.canInvite) {

View file

@ -215,7 +215,7 @@ const NewRoomIntro: React.FC = () => {
defaultDispatcher.dispatch({ action: "view_invite", roomId });
}}
>
{_t("Invite to this room")}
{_t("room|invite_this_room")}
</AccessibleButton>
</div>
);

View file

@ -50,7 +50,7 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v
<AccessibleTooltipButton
className="mx_RoomBreadcrumbs_crumb"
onClick={onClick}
aria-label={_t("Room %(name)s", { name: room.name })}
aria-label={_t("a11y|room_name", { name: room.name })}
title={room.name}
tooltipClassName="mx_RoomBreadcrumbs_Tooltip"
onFocus={onFocus}
@ -123,7 +123,7 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
// NOTE: The CSSTransition timeout MUST match the timeout in our CSS!
return (
<CSSTransition appear={true} in={this.state.doAnimation} timeout={640} classNames="mx_RoomBreadcrumbs">
<Toolbar className="mx_RoomBreadcrumbs" aria-label={_t("Recently visited rooms")}>
<Toolbar className="mx_RoomBreadcrumbs" aria-label={_t("room_list|breadcrumbs_label")}>
{tiles.slice(this.state.skipFirst ? 1 : 0)}
</Toolbar>
</CSSTransition>
@ -131,7 +131,7 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
} else {
return (
<div className="mx_RoomBreadcrumbs">
<div className="mx_RoomBreadcrumbs_placeholder">{_t("No recently visited rooms")}</div>
<div className="mx_RoomBreadcrumbs_placeholder">{_t("room_list|breadcrumbs_empty")}</div>
</div>
);
}

View file

@ -131,12 +131,12 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
{roomName}
{!isDirectMessage && roomState.getJoinRule() === JoinRule.Public && (
<Tooltip label={_t("Public room")}>
<Tooltip label={_t("common|public_room")}>
<PublicIcon
width="16px"
height="16px"
className="text-secondary"
aria-label={_t("Public room")}
aria-label={_t("common|public_room")}
/>
</Tooltip>
)}
@ -153,12 +153,12 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
)}
{isDirectMessage && e2eStatus === E2EStatus.Warning && (
<Tooltip label={_t("Untrusted")}>
<Tooltip label={_t("room|header_untrusted_label")}>
<ErrorIcon
width="16px"
height="16px"
className="mx_Untrusted"
aria-label={_t("Untrusted")}
aria-label={_t("room|header_untrusted_label")}
/>
</Tooltip>
)}

View file

@ -51,13 +51,13 @@ const RoomInfoLine: FC<IProps> = ({ room }) => {
let roomType: string;
if (isVideoRoom) {
iconClass = "mx_RoomInfoLine_video";
roomType = _t("Video room");
roomType = _t("common|video_room");
} else if (joinRule === JoinRule.Public) {
iconClass = "mx_RoomInfoLine_public";
roomType = room.isSpaceRoom() ? _t("Public space") : _t("Public room");
roomType = room.isSpaceRoom() ? _t("common|public_space") : _t("common|public_room");
} else {
iconClass = "mx_RoomInfoLine_private";
roomType = room.isSpaceRoom() ? _t("Private space") : _t("Private room");
roomType = room.isSpaceRoom() ? _t("common|private_space") : _t("common|private_room");
}
let members: JSX.Element | undefined;

View file

@ -132,7 +132,7 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
<IconizedContextMenuOptionList first>
{showCreateRooms && (
<IconizedContextMenuOption
label={_t("Start new chat")}
label={_t("action|start_new_chat")}
iconClassName="mx_RoomList_iconStartChat"
onClick={(e) => {
e.preventDefault();
@ -148,7 +148,7 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
)}
{showInviteUsers && (
<IconizedContextMenuOption
label={_t("Invite to space")}
label={_t("action|invite_to_space")}
iconClassName="mx_RoomList_iconInvite"
onClick={(e) => {
e.preventDefault();
@ -172,8 +172,8 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
onClick={openMenu}
className="mx_RoomSublist_auxButton"
tooltipClassName="mx_RoomSublist_addRoomTooltip"
aria-label={_t("Add people")}
title={_t("Add people")}
aria-label={_t("action|add_people")}
title={_t("action|add_people")}
isExpanded={menuDisplayed}
inputRef={handle}
/>
@ -222,7 +222,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
contextMenuContent = (
<IconizedContextMenuOptionList first>
<IconizedContextMenuOption
label={_t("Explore rooms")}
label={_t("action|explore_rooms")}
iconClassName="mx_RoomList_iconExplore"
onClick={(e) => {
e.preventDefault();
@ -239,7 +239,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
{showCreateRoom ? (
<>
<IconizedContextMenuOption
label={_t("New room")}
label={_t("action|new_room")}
iconClassName="mx_RoomList_iconNewRoom"
onClick={(e) => {
e.preventDefault();
@ -253,7 +253,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
/>
{videoRoomsEnabled && (
<IconizedContextMenuOption
label={_t("New video room")}
label={_t("action|new_video_room")}
iconClassName="mx_RoomList_iconNewVideoRoom"
onClick={(e) => {
e.preventDefault();
@ -271,7 +271,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
</IconizedContextMenuOption>
)}
<IconizedContextMenuOption
label={_t("Add existing room")}
label={_t("action|add_existing_room")}
iconClassName="mx_RoomList_iconAddExistingRoom"
onClick={(e) => {
e.preventDefault();
@ -292,7 +292,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
{showCreateRoom && (
<>
<IconizedContextMenuOption
label={_t("New room")}
label={_t("action|new_room")}
iconClassName="mx_RoomList_iconNewRoom"
onClick={(e) => {
e.preventDefault();
@ -304,7 +304,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
/>
{videoRoomsEnabled && (
<IconizedContextMenuOption
label={_t("New video room")}
label={_t("action|new_video_room")}
iconClassName="mx_RoomList_iconNewVideoRoom"
onClick={(e) => {
e.preventDefault();
@ -325,7 +325,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
)}
{showExploreRooms ? (
<IconizedContextMenuOption
label={_t("Explore public rooms")}
label={_t("action|explore_public_rooms")}
iconClassName="mx_RoomList_iconExplore"
onClick={(e) => {
e.preventDefault();

View file

@ -203,7 +203,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
<>
<IconizedContextMenuOption
iconClassName="mx_RoomListHeader_iconNewRoom"
label={_t("New room")}
label={_t("action|new_room")}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@ -215,7 +215,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
{videoRoomsEnabled && (
<IconizedContextMenuOption
iconClassName="mx_RoomListHeader_iconNewVideoRoom"
label={_t("New video room")}
label={_t("action|new_video_room")}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@ -243,7 +243,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
{inviteOption}
{newRoomOptions}
<IconizedContextMenuOption
label={_t("Explore rooms")}
label={_t("action|explore_rooms")}
iconClassName="mx_RoomListHeader_iconExplore"
onClick={(e) => {
e.preventDefault();
@ -258,7 +258,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
}}
/>
<IconizedContextMenuOption
label={_t("Add existing room")}
label={_t("action|add_existing_room")}
iconClassName="mx_RoomListHeader_iconPlus"
onClick={(e) => {
e.preventDefault();
@ -296,7 +296,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
newRoomOpts = (
<>
<IconizedContextMenuOption
label={_t("Start new chat")}
label={_t("action|start_new_chat")}
iconClassName="mx_RoomListHeader_iconStartChat"
onClick={(e) => {
e.preventDefault();
@ -307,7 +307,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
}}
/>
<IconizedContextMenuOption
label={_t("New room")}
label={_t("action|new_room")}
iconClassName="mx_RoomListHeader_iconNewRoom"
onClick={(e) => {
e.preventDefault();
@ -319,7 +319,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
/>
{videoRoomsEnabled && (
<IconizedContextMenuOption
label={_t("New video room")}
label={_t("action|new_video_room")}
iconClassName="mx_RoomListHeader_iconNewVideoRoom"
onClick={(e) => {
e.preventDefault();

View file

@ -311,7 +311,11 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
</tr>
<tr>
<th scope="row">{_t("settings|security|key_backup_active_version")}</th>
<td>{this.state.activeBackupVersion === null ? _t("None") : this.state.activeBackupVersion}</td>
<td>
{this.state.activeBackupVersion === null
? _t("settings|security|key_backup_active_version_none")
: this.state.activeBackupVersion}
</td>
</tr>
</>
);

View file

@ -47,7 +47,7 @@ const REACHABILITY_TIMEOUT = 10000; // ms
async function checkIdentityServerUrl(u: string): Promise<string | null> {
const parsedUrl = parseUrl(u);
if (parsedUrl.protocol !== "https:") return _t("Identity server URL must be HTTPS");
if (parsedUrl.protocol !== "https:") return _t("identity_server|url_not_https");
// XXX: duplicated logic from js-sdk but it's quite tied up in the validation logic in the
// js-sdk so probably as easy to duplicate it than to separate it out so we can reuse it
@ -56,12 +56,12 @@ async function checkIdentityServerUrl(u: string): Promise<string | null> {
if (response.ok) {
return null;
} else if (response.status < 200 || response.status >= 300) {
return _t("Not a valid identity server (status code %(code)s)", { code: response.status });
return _t("identity_server|error_invalid", { code: response.status });
} else {
return _t("Could not connect to identity server");
return _t("identity_server|error_connection");
}
} catch (e) {
return _t("Could not connect to identity server");
return _t("identity_server|error_connection");
}
}
@ -133,7 +133,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
return (
<div>
<InlineSpinner />
{_t("Checking server")}
{_t("identity_server|checking")}
</div>
);
} else if (this.state.error) {
@ -191,9 +191,9 @@ export default class SetIdServer extends React.Component<IProps, IState> {
// 3PIDs that would be left behind.
if (save && currentClientIdServer && fullUrl !== currentClientIdServer) {
const [confirmed] = await this.showServerChangeWarning({
title: _t("Change identity server"),
title: _t("identity_server|change"),
unboundMessage: _t(
"Disconnect from the identity server <current /> and connect to <new /> instead?",
"identity_server|change_prompt",
{},
{
current: (sub) => <b>{abbreviateUrl(currentClientIdServer)}</b>,
@ -210,7 +210,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
}
} catch (e) {
logger.error(e);
errStr = _t("Terms of service not accepted or the identity server is invalid.");
errStr = _t("identity_server|error_invalid_or_terms");
}
}
this.setState({
@ -226,9 +226,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
title: _t("terms|identity_server_no_terms_title"),
description: (
<div>
<span className="warning">
{_t("The identity server you have chosen does not have any terms of service.")}
</span>
<span className="warning">{_t("identity_server|no_terms")}</span>
<span>&nbsp;{_t("terms|identity_server_no_terms_description_2")}</span>
</div>
),
@ -241,9 +239,9 @@ export default class SetIdServer extends React.Component<IProps, IState> {
this.setState({ disconnectBusy: true });
try {
const [confirmed] = await this.showServerChangeWarning({
title: _t("Disconnect identity server"),
title: _t("identity_server|disconnect"),
unboundMessage: _t(
"Disconnect from the identity server <idserver />?",
"identity_server|disconnect_server",
{},
{ idserver: (sub) => <b>{abbreviateUrl(this.state.currentClientIdServer)}</b> },
),
@ -294,54 +292,34 @@ export default class SetIdServer extends React.Component<IProps, IState> {
if (!currentServerReachable) {
message = (
<div>
<p>
{_t(
"You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.",
{},
messageElements,
)}
</p>
<p>{_t("You should:")}</p>
<p>{_t("identity_server|disconnect_offline_warning", {}, messageElements)}</p>
<p>{_t("identity_server|suggestions")}</p>
<ul>
<li>{_t("identity_server|suggestions_1")}</li>
<li>
{_t(
"check your browser plugins for anything that might block the identity server (such as Privacy Badger)",
)}
</li>
<li>
{_t(
"contact the administrators of identity server <idserver />",
"identity_server|suggestions_2",
{},
{
idserver: messageElements.idserver,
},
)}
</li>
<li>{_t("wait and try again later")}</li>
<li>{_t("identity_server|suggestions_3")}</li>
</ul>
</div>
);
danger = true;
button = _t("Disconnect anyway");
button = _t("identity_server|disconnect_anyway");
} else if (boundThreepids.length) {
message = (
<div>
<p>
{_t(
"You are still <b>sharing your personal data</b> on the identity server <idserver />.",
{},
messageElements,
)}
</p>
<p>
{_t(
"We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.",
)}
</p>
<p>{_t("identity_server|disconnect_personal_data_warning_1", {}, messageElements)}</p>
<p>{_t("identity_server|disconnect_personal_data_warning_2")}</p>
</div>
);
danger = true;
button = _t("Disconnect anyway");
button = _t("identity_server|disconnect_anyway");
} else {
message = unboundMessage;
}
@ -382,37 +360,31 @@ export default class SetIdServer extends React.Component<IProps, IState> {
let sectionTitle;
let bodyText;
if (idServerUrl) {
sectionTitle = _t("Identity server (%(server)s)", { server: abbreviateUrl(idServerUrl) });
sectionTitle = _t("identity_server|url", { server: abbreviateUrl(idServerUrl) });
bodyText = _t(
"You are currently using <server></server> to discover and be discoverable by existing contacts you know. You can change your identity server below.",
"identity_server|description_connected",
{},
{ server: (sub) => <b>{abbreviateUrl(idServerUrl)}</b> },
);
if (this.props.missingTerms) {
bodyText = _t(
"If you don't want to use <server /> to discover and be discoverable by existing contacts you know, enter another identity server below.",
"identity_server|change_server_prompt",
{},
{ server: (sub) => <b>{abbreviateUrl(idServerUrl)}</b> },
);
}
} else {
sectionTitle = _t("common|identity_server");
bodyText = _t(
"You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.",
);
bodyText = _t("identity_server|description_disconnected");
}
let discoSection;
if (idServerUrl) {
let discoButtonContent: React.ReactNode = _t("action|disconnect");
let discoBodyText = _t(
"Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.",
);
let discoBodyText = _t("identity_server|disconnect_warning");
if (this.props.missingTerms) {
discoBodyText = _t(
"Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.",
);
discoButtonContent = _t("Do not use an identity server");
discoBodyText = _t("identity_server|description_optional");
discoButtonContent = _t("identity_server|do_not_use");
}
if (this.state.disconnectBusy) {
discoButtonContent = <InlineSpinner />;
@ -431,7 +403,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
<SettingsFieldset legend={sectionTitle} description={bodyText}>
<form className="mx_SetIdServer" onSubmit={this.checkIdServer}>
<Field
label={_t("Enter a new identity server")}
label={_t("identity_server|url_field_label")}
type="text"
autoComplete="off"
placeholder={this.state.defaultIdServer}

View file

@ -63,12 +63,12 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
if (currentManager) {
managerName = `(${currentManager.name})`;
bodyText = _t(
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.",
"integration_manager|use_im_default",
{ serverName: currentManager.name },
{ b: (sub) => <b>{sub}</b> },
);
} else {
bodyText = _t("Use an integration manager to manage bots, widgets, and sticker packs.");
bodyText = _t("integration_manager|use_im");
}
return (
@ -79,7 +79,7 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
>
<div className="mx_SettingsFlag">
<div className="mx_SetIntegrationManager_heading_manager">
<Heading size="2">{_t("Manage integrations")}</Heading>
<Heading size="2">{_t("integration_manager|manage_title")}</Heading>
<Heading size="3">{managerName}</Heading>
</div>
<ToggleSwitch
@ -90,11 +90,7 @@ export default class SetIntegrationManager extends React.Component<IProps, IStat
/>
</div>
<SettingsSubsectionText>{bodyText}</SettingsSubsectionText>
<SettingsSubsectionText>
{_t(
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.",
)}
</SettingsSubsectionText>
<SettingsSubsectionText>{_t("integration_manager|explainer")}</SettingsSubsectionText>
</label>
);
}

View file

@ -88,7 +88,7 @@ export class ExistingEmailAddress extends React.Component<IExistingEmailAddressP
.catch((err) => {
logger.error("Unable to remove contact information: " + err);
Modal.createDialog(ErrorDialog, {
title: _t("Unable to remove contact information"),
title: _t("settings|general|error_remove_3pid"),
description: err && err.message ? err.message : _t("invite|failed_generic"),
});
});
@ -99,7 +99,7 @@ export class ExistingEmailAddress extends React.Component<IExistingEmailAddressP
return (
<div className="mx_GeneralUserSettingsTab_section--discovery_existing">
<span className="mx_GeneralUserSettingsTab_section--discovery_existing_promptText">
{_t("Remove %(email)s?", { email: this.props.email.address })}
{_t("settings|general|remove_email_prompt", { email: this.props.email.address })}
</span>
<AccessibleButton
onClick={this.onActuallyRemove}
@ -182,8 +182,8 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
// TODO: Inline field validation
if (!Email.looksValid(email)) {
Modal.createDialog(ErrorDialog, {
title: _t("Invalid Email Address"),
description: _t("This doesn't appear to be a valid email address"),
title: _t("settings|general|error_invalid_email"),
description: _t("settings|general|error_invalid_email_detail"),
});
return;
}
@ -199,7 +199,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
logger.error("Unable to add email address " + email + " " + err);
this.setState({ verifying: false, continueDisabled: false, addTask: null });
Modal.createDialog(ErrorDialog, {
title: _t("Unable to add email address"),
title: _t("settings|general|error_add_email"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
});
@ -239,14 +239,12 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
if (underlyingError instanceof MatrixError && underlyingError.errcode === "M_THREEPID_AUTH_FAILED") {
Modal.createDialog(ErrorDialog, {
title: _t("Your email address hasn't been verified yet"),
description: _t(
"Click the link in the email you received to verify and then click continue again.",
),
title: _t("settings|general|email_not_verified"),
description: _t("settings|general|email_verification_instructions"),
});
} else {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify email address."),
title: _t("settings|general|error_email_verification"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
}
@ -273,11 +271,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
if (this.state.verifying) {
addButton = (
<div>
<div>
{_t(
"We've sent you an email to verify your address. Please follow the instructions there and then click the button below.",
)}
</div>
<div>{_t("settings|general|add_email_instructions")}</div>
<AccessibleButton
onClick={this.onContinueClick}
kind="primary"
@ -295,7 +289,7 @@ export default class EmailAddresses extends React.Component<IProps, IState> {
<form onSubmit={this.onAddClick} autoComplete="off" noValidate={true}>
<Field
type="text"
label={_t("Email Address")}
label={_t("settings|general|email_address_label")}
autoComplete="email"
disabled={this.props.disabled || this.state.verifying}
value={this.state.newEmailAddress}

View file

@ -84,7 +84,7 @@ export class ExistingPhoneNumber extends React.Component<IExistingPhoneNumberPro
.catch((err) => {
logger.error("Unable to remove contact information: " + err);
Modal.createDialog(ErrorDialog, {
title: _t("Unable to remove contact information"),
title: _t("settings|general|error_remove_3pid"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
});
@ -95,7 +95,7 @@ export class ExistingPhoneNumber extends React.Component<IExistingPhoneNumberPro
return (
<div className="mx_GeneralUserSettingsTab_section--discovery_existing">
<span className="mx_GeneralUserSettingsTab_section--discovery_existing_promptText">
{_t("Remove %(phone)s?", { phone: this.props.msisdn.address })}
{_t("settings|general|remove_msisdn_prompt", { phone: this.props.msisdn.address })}
</span>
<AccessibleButton
onClick={this.onActuallyRemove}
@ -244,11 +244,11 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
if (underlyingError.errcode !== "M_THREEPID_AUTH_FAILED") {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify phone number."),
title: _t("settings|general|error_msisdn_verification"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
} else {
this.setState({ verifyError: _t("Incorrect verification code") });
this.setState({ verifyError: _t("settings|general|incorrect_msisdn_verification") });
}
});
};
@ -279,17 +279,14 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
addVerifySection = (
<div>
<div>
{_t(
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.",
{ msisdn: msisdn },
)}
{_t("settings|general|add_msisdn_instructions", { msisdn: msisdn })}
<br />
{this.state.verifyError}
</div>
<form onSubmit={this.onContinueClick} autoComplete="off" noValidate={true}>
<Field
type="text"
label={_t("Verification code")}
label={_t("settings|general|msisdn_verification_field_label")}
autoComplete="off"
disabled={this.props.disabled || this.state.continueDisabled}
value={this.state.newPhoneNumberCode}
@ -329,7 +326,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
<div className="mx_PhoneNumbers_input">
<Field
type="text"
label={_t("Phone Number")}
label={_t("settings|general|msisdn_label")}
autoComplete="tel-national"
disabled={this.props.disabled || this.state.verifying}
prefixComponent={phoneCountry}

View file

@ -49,7 +49,7 @@ const DeviceNameEditor: React.FC<Props & { stopEditing: () => void }> = ({ devic
await saveDeviceName(deviceName);
stopEditing();
} catch (error) {
setError(_t("Failed to set display name"));
setError(_t("settings|sessions|error_set_name"));
setIsLoading(false);
}
};

View file

@ -71,7 +71,7 @@ export const deleteDevicesWithInteractiveAuth = async (
},
};
Modal.createDialog(InteractiveAuthDialog, {
title: _t("Authentication"),
title: _t("common|authentication"),
matrixClient: matrixClient,
authData: error.data as IAuthData,
onFinished,

View file

@ -194,8 +194,8 @@ export const useOwnDevices = (): DevicesState => {
await matrixClient.setDeviceDetails(deviceId, { display_name: deviceName });
await refreshDevices();
} catch (error) {
logger.error("Error setting session display name", error);
throw new Error(_t("Failed to set display name"));
logger.error("Error setting device name", error);
throw new Error(_t("settings|sessions|error_set_name"));
}
},
[matrixClient, devices, refreshDevices],
@ -217,7 +217,7 @@ export const useOwnDevices = (): DevicesState => {
}
} catch (error) {
logger.error("Error setting pusher state", error);
throw new Error(_t("Failed to set pusher state"));
throw new Error(_t("settings|sessions|error_pusher_state"));
} finally {
await refreshDevices();
}

View file

@ -116,7 +116,7 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
this.changeBinding({
bind: false,
label: "revoke",
errorTitle: _t("Unable to revoke sharing for email address"),
errorTitle: _t("settings|general|error_revoke_email_discovery"),
});
};
@ -126,7 +126,7 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
this.changeBinding({
bind: true,
label: "share",
errorTitle: _t("Unable to share email address"),
errorTitle: _t("settings|general|error_share_email_discovery"),
});
};
@ -152,15 +152,13 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
if (underlyingError instanceof MatrixError && underlyingError.errcode === "M_THREEPID_AUTH_FAILED") {
Modal.createDialog(ErrorDialog, {
title: _t("Your email address hasn't been verified yet"),
description: _t(
"Click the link in the email you received to verify and then click continue again.",
),
title: _t("settings|general|email_not_verified"),
description: _t("settings|general|email_verification_instructions"),
});
} else {
logger.error("Unable to verify email address: " + err);
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify email address."),
title: _t("settings|general|error_email_verification"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
}
@ -178,7 +176,7 @@ export class EmailAddress extends React.Component<IEmailAddressProps, IEmailAddr
if (verifying) {
status = (
<span>
{_t("Verify the link in your inbox")}
{_t("settings|general|discovery_email_verification_instructions")}
<AccessibleButton
className="mx_GeneralUserSettingsTab_section--discovery_existing_button"
kind="primary_sm"
@ -242,10 +240,8 @@ export default class EmailAddresses extends React.Component<IProps> {
return (
<SettingsSubsection
heading={_t("Email addresses")}
description={
(!hasEmails && _t("Discovery options will appear once you have added an email above.")) || undefined
}
heading={_t("settings|general|emails_heading")}
description={(!hasEmails && _t("settings|general|discovery_email_empty")) || undefined}
stretchContent
>
{content}

View file

@ -117,7 +117,7 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
this.changeBinding({
bind: false,
label: "revoke",
errorTitle: _t("Unable to revoke sharing for phone number"),
errorTitle: _t("settings|general|error_revoke_msisdn_discovery"),
});
};
@ -127,7 +127,7 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
this.changeBinding({
bind: true,
label: "share",
errorTitle: _t("Unable to share phone number"),
errorTitle: _t("settings|general|error_share_msisdn_discovery"),
});
};
@ -163,11 +163,11 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
this.setState({ continueDisabled: false });
if (underlyingError instanceof MatrixError && underlyingError.errcode !== "M_THREEPID_AUTH_FAILED") {
Modal.createDialog(ErrorDialog, {
title: _t("Unable to verify phone number."),
title: _t("settings|general|error_msisdn_verification"),
description: extractErrorMessageFromError(err, _t("invite|failed_generic")),
});
} else {
this.setState({ verifyError: _t("Incorrect verification code") });
this.setState({ verifyError: _t("settings|general|incorrect_msisdn_verification") });
}
}
};
@ -181,14 +181,14 @@ export class PhoneNumber extends React.Component<IPhoneNumberProps, IPhoneNumber
status = (
<span className="mx_GeneralUserSettingsTab_section--discovery_existing_verification">
<span>
{_t("Please enter verification code sent via text.")}
{_t("settings|general|msisdn_verification_instructions")}
<br />
{this.state.verifyError}
</span>
<form onSubmit={this.onContinueClick} autoComplete="off" noValidate={true}>
<Field
type="text"
label={_t("Verification code")}
label={_t("settings|general|msisdn_verification_field_label")}
autoComplete="off"
disabled={this.state.continueDisabled}
value={this.state.verificationCode}
@ -247,13 +247,12 @@ export default class PhoneNumbers extends React.Component<IProps> {
});
}
const description =
(!content && _t("Discovery options will appear once you have added a phone number above.")) || undefined;
const description = (!content && _t("settings|general|discovery_msisdn_empty")) || undefined;
return (
<SettingsSubsection
data-testid="mx_DiscoveryPhoneNumbers"
heading={_t("Phone numbers")}
heading={_t("settings|general|msisdns_heading")}
description={description}
stretchContent
>

View file

@ -51,7 +51,7 @@ export function NotificationPusherSettings(): JSX.Element {
() => ({
kind: "email",
app_id: "m.email",
app_display_name: _t("Email Notifications"),
app_display_name: _t("notifications|email_pusher_app_display_name"),
lang: navigator.language,
data: {
brand: SdkConfig.get().brand,
@ -91,17 +91,16 @@ export function NotificationPusherSettings(): JSX.Element {
return (
<>
<SettingsSubsection className="mx_NotificationPusherSettings" heading={_t("Email summary")}>
<SettingsSubsection
className="mx_NotificationPusherSettings"
heading={_t("settings|notifications|email_section")}
>
<SettingsSubsectionText className="mx_NotificationPusherSettings_description">
{_t("Receive an email summary of missed notifications")}
{_t("settings|notifications|email_description")}
</SettingsSubsectionText>
<div className="mx_SettingsSubsection_description mx_NotificationPusherSettings_detail">
<SettingsSubsectionText>
{_t(
"Select which emails you want to send summaries to. Manage your emails in <button>General</button>.",
{},
{ button: generalTabButton },
)}
{_t("settings|notifications|email_select", {}, { button: generalTabButton })}
</SettingsSubsectionText>
</div>
<SettingsIndent>

View file

@ -58,21 +58,6 @@ function toDefaultLevels(levels: NotificationSettings["defaultLevels"]): Notific
}
}
const NotificationOptions = [
{
value: NotificationDefaultLevels.AllMessages,
label: _t("All messages"),
},
{
value: NotificationDefaultLevels.PeopleMentionsKeywords,
label: _t("People, Mentions and Keywords"),
},
{
value: NotificationDefaultLevels.MentionsKeywords,
label: _t("Mentions and Keywords only"),
},
];
function boldText(text: string): JSX.Element {
return <strong>{text}</strong>;
}
@ -101,6 +86,21 @@ export default function NotificationSettings2(): JSX.Element {
const [updatingUnread, setUpdatingUnread] = useState<boolean>(false);
const hasUnreadNotifications = useHasUnreadNotifications();
const NotificationOptions = [
{
value: NotificationDefaultLevels.AllMessages,
label: _t("notifications|all_messages"),
},
{
value: NotificationDefaultLevels.PeopleMentionsKeywords,
label: _t("settings|notifications|people_mentions_keywords"),
},
{
value: NotificationDefaultLevels.MentionsKeywords,
label: _t("settings|notifications|mentions_keywords_only"),
},
];
return (
<div className="mx_NotificationSettings2">
{hasPendingChanges && model !== null && (
@ -110,7 +110,7 @@ export default function NotificationSettings2(): JSX.Element {
onAction={() => reconcile(model!)}
>
{_t(
"<strong>Update:</strong>Weve simplified Notifications Settings to make options easier to find. Some custom settings youve chosen in the past are not shown here, but theyre still active. If you proceed, some of your settings may change. <a>Learn more</a>",
"settings|notifications|labs_notice_prompt",
{},
{
strong: boldText,
@ -140,7 +140,7 @@ export default function NotificationSettings2(): JSX.Element {
}
/>
<LabelledToggleSwitch
label={_t("Show message preview in desktop notification")}
label={_t("settings|notifications|desktop_notification_message_preview")}
value={desktopShowBody}
onChange={(value) =>
SettingsStore.setValue("notificationBodyEnabled", null, SettingLevel.DEVICE, value)
@ -155,8 +155,8 @@ export default function NotificationSettings2(): JSX.Element {
/>
</div>
<SettingsSubsection
heading={_t("I want to be notified for (Default Setting)")}
description={_t("This setting will be applied by default to all your rooms.")}
heading={_t("settings|notifications|default_setting_section")}
description={_t("settings|notifications|default_setting_description")}
>
<StyledRadioGroup
name="defaultNotificationLevel"
@ -182,8 +182,8 @@ export default function NotificationSettings2(): JSX.Element {
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("Play a sound for")}
description={_t("Applied by default to all rooms on all devices.")}
heading={_t("settings|notifications|play_sound_for_section")}
description={_t("settings|notifications|play_sound_for_description")}
>
<LabelledCheckbox
label="People"
@ -200,7 +200,7 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledCheckbox
label={_t("Mentions and Keywords")}
label={_t("settings|notifications|mentions_keywords")}
value={settings.sound.mentions !== undefined}
disabled={disabled}
onChange={(value) => {
@ -214,7 +214,7 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledCheckbox
label={_t("Audio and Video calls")}
label={_t("settings|notifications|voip")}
value={settings.sound.calls !== undefined}
disabled={disabled}
onChange={(value) => {
@ -228,9 +228,9 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
</SettingsSubsection>
<SettingsSubsection heading={_t("Other things we think you might be interested in:")}>
<SettingsSubsection heading={_t("settings|notifications|other_section")}>
<LabelledCheckbox
label={_t("Invited to a room")}
label={_t("settings|notifications|invites")}
value={settings.activity.invite}
disabled={disabled}
onChange={(value) => {
@ -244,7 +244,7 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledCheckbox
label={_t("New room activity, upgrades and status messages occur")}
label={_t("settings|notifications|room_activity")}
value={settings.activity.status_event}
disabled={disabled}
onChange={(value) => {
@ -258,7 +258,7 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledCheckbox
label={_t("Messages sent by bots")}
label={_t("settings|notifications|notices")}
value={settings.activity.bot_notices}
disabled={disabled}
onChange={(value) => {
@ -273,9 +273,9 @@ export default function NotificationSettings2(): JSX.Element {
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("Mentions and Keywords")}
heading={_t("settings|notifications|mentions_keywords")}
description={_t(
"Show a badge <badge/> when keywords are used in a room.",
"settings|notifications|keywords",
{},
{
badge: <StatelessNotificationBadge symbol="1" count={1} color={NotificationColor.Grey} />,
@ -283,7 +283,7 @@ export default function NotificationSettings2(): JSX.Element {
)}
>
<LabelledCheckbox
label={_t("Notify when someone mentions using @room")}
label={_t("settings|notifications|notify_at_room")}
value={settings.mentions.room}
disabled={disabled}
onChange={(value) => {
@ -297,7 +297,7 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledCheckbox
label={_t("Notify when someone mentions using @displayname or %(mxid)s", {
label={_t("settings|notifications|notify_mention", {
mxid: cli.getUserId()!,
})}
value={settings.mentions.user}
@ -313,8 +313,8 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledCheckbox
label={_t("Notify when someone uses a keyword")}
byline={_t("Enter keywords here, or use for spelling variations or nicknames")}
label={_t("settings|notifications|notify_keyword")}
byline={_t("settings|notifications|keywords_prompt")}
value={settings.mentions.keywords}
disabled={disabled}
onChange={(value) => {
@ -348,7 +348,7 @@ export default function NotificationSettings2(): JSX.Element {
/>
</SettingsSubsection>
<NotificationPusherSettings />
<SettingsSubsection heading={_t("Quick Actions")}>
<SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}>
{hasUnreadNotifications && (
<AccessibleButton
kind="primary_outline"
@ -359,7 +359,7 @@ export default function NotificationSettings2(): JSX.Element {
setUpdatingUnread(false);
}}
>
{_t("Mark all messages as read")}
{_t("settings|notifications|quick_actions_mark_all_read")}
</AccessibleButton>
)}
<AccessibleButton
@ -369,7 +369,7 @@ export default function NotificationSettings2(): JSX.Element {
reconcile(DefaultNotificationSettings);
}}
>
{_t("Reset to default settings")}
{_t("settings|notifications|quick_actions_reset")}
</AccessibleButton>
</SettingsSubsection>
</SettingsSection>

View file

@ -156,7 +156,13 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
return (
<SettingsTab>
<SettingsSection heading={_t("common|advanced")}>
<SettingsSubsection heading={room.isSpaceRoom() ? _t("Space information") : _t("Room information")}>
<SettingsSubsection
heading={
room.isSpaceRoom()
? _t("room_settings|advanced|information_section_space")
: _t("room_settings|advanced|information_section_room")
}
>
<div>
<span>{_t("room_settings|advanced|room_id")}</span>
<CopyableText getTextToCopy={() => this.props.room.roomId}>

View file

@ -63,7 +63,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
<div>
<p>
{_t(
"This room is bridging messages to the following platforms. <a>Learn more.</a>",
"room_settings|bridges|description",
{},
{
// TODO: We don't have this link yet: this will prevent the translators
@ -85,7 +85,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
content = (
<p>
{_t(
"This room isn't bridging messages to any platforms. <a>Learn more.</a>",
"room_settings|bridges|empty",
{},
{
// TODO: We don't have this link yet: this will prevent the translators
@ -103,7 +103,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
return (
<SettingsTab>
<SettingsSection heading={_t("Bridges")}>{content}</SettingsSection>
<SettingsSection heading={_t("room_settings|bridges|title")}>{content}</SettingsSection>
</SettingsTab>
);
}

View file

@ -89,7 +89,7 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
<RoomProfileSettings roomId={room.roomId} />
</SettingsSection>
<SettingsSection heading={_t("Room Addresses")}>
<SettingsSection heading={_t("room_settings|general|aliases_section")}>
<AliasSettings
roomId={room.roomId}
canSetCanonicalAlias={canSetCanonical}
@ -98,7 +98,7 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
/>
</SettingsSection>
<SettingsSection heading={_t("Other")}>
<SettingsSection heading={_t("room_settings|general|other_section")}>
{urlPreviewSettings}
{leaveSection}
</SettingsSection>

View file

@ -163,7 +163,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
currentUploadedFile = (
<div>
<span>
{_t("Uploaded sound")}: <code>{this.state.uploadedFile.name}</code>
{_t("room_settings|notifications|uploaded_sound")}: <code>{this.state.uploadedFile.name}</code>
</span>
</div>
);
@ -181,10 +181,10 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
className: "mx_NotificationSettingsTab_defaultEntry",
label: (
<>
{_t("Default")}
{_t("notifications|default")}
<div className="mx_NotificationSettingsTab_microCopy">
{_t(
"Get notifications as set up in your <a>settings</a>",
"room_settings|notifications|settings_link",
{},
{
a: (sub) => (
@ -206,9 +206,9 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
className: "mx_NotificationSettingsTab_allMessagesEntry",
label: (
<>
{_t("All messages")}
{_t("notifications|all_messages")}
<div className="mx_NotificationSettingsTab_microCopy">
{_t("Get notified for every message")}
{_t("notifications|all_messages_description")}
</div>
</>
),
@ -218,10 +218,10 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
className: "mx_NotificationSettingsTab_mentionsKeywordsEntry",
label: (
<>
{_t("@mentions & keywords")}
{_t("notifications|mentions_and_keywords")}
<div className="mx_NotificationSettingsTab_microCopy">
{_t(
"Get notified only with mentions and keywords as set up in your <a>settings</a>",
"notifications|mentions_and_keywords_description",
{},
{
a: (sub) => (
@ -245,7 +245,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
<>
{_t("common|off")}
<div className="mx_NotificationSettingsTab_microCopy">
{_t("You won't get any notifications")}
{_t("notifications|mute_description")}
</div>
</>
),
@ -256,11 +256,12 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
/>
</div>
<SettingsSubsection heading={_t("Sounds")}>
<SettingsSubsection heading={_t("room_settings|notifications|sounds_section")}>
<div>
<div className="mx_SettingsTab_subsectionText">
<span>
{_t("Notification sound")}: <code>{this.state.currentSound}</code>
{_t("room_settings|notifications|notification_sound")}:{" "}
<code>{this.state.currentSound}</code>
</span>
</div>
<AccessibleButton
@ -273,7 +274,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
</AccessibleButton>
</div>
<div>
<h4 className="mx_Heading_h4">{_t("Set a new custom sound")}</h4>
<h4 className="mx_Heading_h4">{_t("room_settings|notifications|custom_sound_prompt")}</h4>
<div className="mx_SettingsFlag">
<form autoComplete="off" noValidate={true}>
<input
@ -283,7 +284,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
onClick={chromeFileInputFix}
onChange={this.onSoundUploadChanged}
accept="audio/*"
aria-label={_t("Upload custom sound")}
aria-label={_t("room_settings|notifications|upload_sound_label")}
/>
</form>
@ -295,7 +296,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
onClick={this.triggerUploader}
kind="primary"
>
{_t("Browse")}
{_t("room_settings|notifications|browse_button")}
</AccessibleButton>
<AccessibleButton

View file

@ -52,7 +52,7 @@ const SeeMoreOrLess: VFC<{ roomMember: RoomMember }> = ({ roomMember }) => {
</p>
{shouldTruncate && (
<AccessibleButton kind="link" onClick={() => setSeeMore(!seeMore)}>
{seeMore ? _t("See less") : _t("See more")}
{seeMore ? _t("room_settings|people|see_less") : _t("room_settings|people|see_more")}
</AccessibleButton>
)}
</>
@ -151,7 +151,7 @@ export const PeopleRoomSettingsTab: VFC<{ room: Room }> = ({ room }) => {
return (
<SettingsTab>
<SettingsSection heading={_t("common|people")}>
<SettingsFieldset legend={_t("Asking to join")}>
<SettingsFieldset legend={_t("room_settings|people|knock_section")}>
{knockMembers.length ? (
knockMembers.map((knockMember) => (
<Knock
@ -164,7 +164,7 @@ export const PeopleRoomSettingsTab: VFC<{ room: Room }> = ({ room }) => {
/>
))
) : (
<p className="mx_PeopleRoomSettingsTab_paragraph">{_t("No requests")}</p>
<p className="mx_PeopleRoomSettingsTab_paragraph">{_t("room_settings|people|knock_empty")}</p>
)}
</SettingsFieldset>
</SettingsSection>

View file

@ -95,7 +95,7 @@ export class BannedUser extends React.Component<IBannedUserProps> {
logger.error("Failed to unban: " + err);
Modal.createDialog(ErrorDialog, {
title: _t("common|error"),
description: _t("Failed to unban"),
description: _t("room_settings|permissions|error_unbanning"),
});
});
};
@ -119,9 +119,11 @@ export class BannedUser extends React.Component<IBannedUserProps> {
return (
<li>
{unbanButton}
<span title={_t("Banned by %(displayName)s", { displayName: this.props.by })}>
<span title={_t("room_settings|permissions|banned_by", { displayName: this.props.by })}>
<strong>{this.props.member.name}</strong> {userId}
{this.props.reason ? " " + _t("Reason") + ": " + this.props.reason : ""}
{this.props.reason
? " " + _t("room_settings|permissions|ban_reason") + ": " + this.props.reason
: ""}
</span>
</li>
);
@ -205,10 +207,8 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
logger.error(e);
Modal.createDialog(ErrorDialog, {
title: _t("Error changing power level requirement"),
description: _t(
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.",
),
title: _t("room_settings|permissions|error_changing_pl_reqs_title"),
description: _t("room_settings|permissions|error_changing_pl_reqs_description"),
});
});
};
@ -230,10 +230,8 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
logger.error(e);
Modal.createDialog(ErrorDialog, {
title: _t("Error changing power level"),
description: _t(
"An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.",
),
title: _t("room_settings|permissions|error_changing_pl_title"),
description: _t("room_settings|permissions|error_changing_pl_description"),
});
});
};

View file

@ -301,8 +301,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
private onJoinRuleChangeError = (error: Error): void => {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to update the join rules"),
description: error.message ?? _t("Unknown failure"),
title: _t("room_settings|security|error_join_rule_change_title"),
description: error.message ?? _t("room_settings|security|error_join_rule_change_unknown"),
});
};

View file

@ -81,14 +81,14 @@ const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
return (
<LabelledToggleSwitch
data-testid="element-call-switch"
label={_t("Enable %(brand)s as an additional calling option in this room", { brand })}
caption={_t("%(brand)s is end-to-end encrypted, but is currently limited to smaller numbers of users.", {
label={_t("room_settings|voip|enable_element_call_label", { brand })}
caption={_t("room_settings|voip|enable_element_call_caption", {
brand,
})}
value={elementCallEnabled}
onChange={onChange}
disabled={!maySend}
tooltip={_t("You do not have sufficient permissions to change this.")}
tooltip={_t("room_settings|voip|enable_element_call_no_permissions_tooltip")}
/>
);
};
@ -100,8 +100,8 @@ interface Props {
export const VoipRoomSettingsTab: React.FC<Props> = ({ room }) => {
return (
<SettingsTab>
<SettingsSection heading={_t("Voice & Video")}>
<SettingsSubsection heading={_t("Call type")}>
<SettingsSection heading={_t("settings|voip|title")}>
<SettingsSubsection heading={_t("room_settings|voip|call_type_section")}>
<ElementCallSwitch room={room} />
</SettingsSubsection>
</SettingsSection>

View file

@ -282,16 +282,16 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
const errorMessage = extractErrorMessageFromError(
err,
_t("Unknown password change error (%(stringifiedError)s)", {
_t("settings|general|error_password_change_unknown", {
stringifiedError: String(err),
}),
);
let errorMessageToDisplay = errorMessage;
if (underlyingError instanceof HTTPError && underlyingError.httpStatus === 403) {
errorMessageToDisplay = _t("Failed to change password. Is your password correct?");
errorMessageToDisplay = _t("settings|general|error_password_change_403");
} else if (underlyingError instanceof HTTPError) {
errorMessageToDisplay = _t("%(errorMessage)s (HTTP status %(httpStatus)s)", {
errorMessageToDisplay = _t("settings|general|error_password_change_http", {
errorMessage,
httpStatus: underlyingError.httpStatus,
});
@ -299,13 +299,13 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
// TODO: Figure out a design that doesn't involve replacing the current dialog
Modal.createDialog(ErrorDialog, {
title: _t("Error changing password"),
title: _t("settings|general|error_password_change_title"),
description: errorMessageToDisplay,
});
};
private onPasswordChanged = (): void => {
const description = _t("Your password was successfully changed.");
const description = _t("settings|general|password_change_success");
// TODO: Figure out a design that doesn't involve replacing the current dialog
Modal.createDialog(ErrorDialog, {
title: _t("common|success"),
@ -346,7 +346,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
threepidSection = (
<>
<SettingsSubsection
heading={_t("Email addresses")}
heading={_t("settings|general|emails_heading")}
stretchContent
data-testid="mx_AccountEmailAddresses"
>
@ -354,7 +354,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
</SettingsSubsection>
<SettingsSubsection
heading={_t("Phone numbers")}
heading={_t("settings|general|msisdns_heading")}
stretchContent
data-testid="mx_AccountPhoneNumbers"
>
@ -368,7 +368,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
if (this.state.canChangePassword) {
passwordChangeSection = (
<>
<SettingsSubsectionText>{_t("Set a new account password…")}</SettingsSubsectionText>
<SettingsSubsectionText>{_t("settings|general|password_change_section")}</SettingsSubsectionText>
<ChangePassword
className="mx_GeneralUserSettingsTab_section--account_changePassword"
rowClassName=""
@ -388,7 +388,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
<>
<SettingsSubsectionText data-testid="external-account-management-outer">
{_t(
"Your account details are managed separately at <code>%(hostname)s</code>.",
"settings|general|external_account_management",
{ hostname },
{ code: (sub) => <code>{sub}</code> },
)}
@ -457,10 +457,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
if (this.state.requiredPolicyInfo.hasTerms) {
const intro = (
<SettingsSubsectionText>
{_t(
"Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.",
{ serverName: this.state.idServerName },
)}
{_t("settings|general|discovery_needs_terms", { serverName: this.state.idServerName })}
</SettingsSubsectionText>
);
return (
@ -504,14 +501,14 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
private renderManagementSection(): JSX.Element {
// TODO: Improve warning text for account deactivation
return (
<SettingsSection heading={_t("Deactivate account")}>
<SettingsSection heading={_t("settings|general|deactivate_section")}>
<SettingsSubsection
heading={_t("Account management")}
heading={_t("settings|general|account_management_section")}
data-testid="account-management-section"
description={_t("Deactivating your account is a permanent action — be careful!")}
description={_t("settings|general|deactivate_warning")}
>
<AccessibleButton onClick={this.onDeactivateClicked} kind="danger">
{_t("Deactivate Account")}
{_t("settings|general|deactivate_section")}
</AccessibleButton>
</SettingsSubsection>
</SettingsSection>
@ -549,7 +546,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
const heading = (
<Heading size="2">
{discoWarning}
{_t("Discovery")}
{_t("settings|general|discovery_section")}
</Heading>
);
discoverySection = (

View file

@ -143,7 +143,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
const name = room ? room.name : list.roomId;
const renderRules = (rules: ListRule[]): JSX.Element => {
if (rules.length === 0) return <i>{_t("None")}</i>;
if (rules.length === 0) return <i>{_t("labs_mjolnir|rules_empty")}</i>;
const tiles: JSX.Element[] = [];
for (const rule of rules) {

View file

@ -63,7 +63,7 @@ export class IgnoredUser extends React.Component<IIgnoredUserProps> {
aria-describedby={id}
disabled={this.props.inProgress}
>
{_t("Unignore")}
{_t("action|unignore")}
</AccessibleButton>
<span id={id}>{this.props.userId}</span>
</div>
@ -225,7 +225,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
const { waitingUnignored, ignoredUserIds } = this.state;
const userIds = !ignoredUserIds?.length
? _t("You have no ignored users.")
? _t("settings|security|ignore_users_empty")
: ignoredUserIds.map((u) => {
return (
<IgnoredUser
@ -238,7 +238,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
});
return (
<SettingsSubsection heading={_t("Ignored users")}>
<SettingsSubsection heading={_t("settings|security|ignore_users_section")}>
<SettingsSubsectionText>{userIds}</SettingsSubsectionText>
</SettingsSubsection>
);
@ -301,9 +301,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
if (!privateShouldBeEncrypted(MatrixClientPeg.safeGet())) {
warning = (
<div className="mx_SecurityUserSettingsTab_warning">
{_t(
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
)}
{_t("settings|security|e2ee_default_disabled_warning")}
</div>
);
}
@ -320,9 +318,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
<SettingsSection heading={_t("common|privacy")}>
<SettingsSubsection
heading={_t("common|analytics")}
description={_t(
"Share anonymous data to help us identify issues. Nothing personal. No third parties.",
)}
description={_t("settings|security|analytics_description")}
>
<AccessibleButton kind="link" onClick={onClickAnalyticsLearnMore}>
{_t("action|learn_more")}

View file

@ -302,9 +302,7 @@ const SessionManagerTab: React.FC = () => {
disabled={!!signingOutDeviceIds.length}
/>
}
description={_t(
"For best security, verify your sessions and sign out from any session that you don't recognize or use anymore.",
)}
description={_t("settings|sessions|best_security_note")}
data-testid="other-sessions-section"
stretchContent
>

View file

@ -67,9 +67,7 @@ const SidebarUserSettingsTab: React.FC = () => {
<SettingsSection heading={_t("settings|sidebar|title")}>
<SettingsSubsection
heading={_t("settings|sidebar|metaspaces_subsection")}
description={_t(
"Spaces are ways to group rooms and people. Alongside the spaces you're in, you can use some pre-built ones too.",
)}
description={_t("settings|sidebar|spaces_explainer")}
>
<StyledCheckbox
checked={!!homeEnabled}

View file

@ -159,29 +159,30 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
if (!this.state.mediaDevices) {
requestButton = (
<div>
<p>{_t("Missing media permissions, click the button below to request.")}</p>
<p>{_t("settings|voip|missing_permissions_prompt")}</p>
<AccessibleButton onClick={this.requestMediaPermissions} kind="primary">
{_t("Request media permissions")}
{_t("settings|voip|request_permissions")}
</AccessibleButton>
</div>
);
} else if (this.state.mediaDevices) {
speakerDropdown = this.renderDropdown(MediaDeviceKindEnum.AudioOutput, _t("Audio Output")) || (
<p>{_t("No Audio Outputs detected")}</p>
);
speakerDropdown = this.renderDropdown(
MediaDeviceKindEnum.AudioOutput,
_t("settings|voip|audio_output"),
) || <p>{_t("settings|voip|audio_output_empty")}</p>;
microphoneDropdown = this.renderDropdown(MediaDeviceKindEnum.AudioInput, _t("common|microphone")) || (
<p>{_t("No Microphones detected")}</p>
<p>{_t("settings|voip|audio_input_empty")}</p>
);
webcamDropdown = this.renderDropdown(MediaDeviceKindEnum.VideoInput, _t("common|camera")) || (
<p>{_t("No Webcams detected")}</p>
<p>{_t("settings|voip|video_input_empty")}</p>
);
}
return (
<SettingsTab>
<SettingsSection heading={_t("Voice & Video")}>
<SettingsSection heading={_t("settings|voip|title")}>
{requestButton}
<SettingsSubsection heading={_t("Voice settings")} stretchContent>
<SettingsSubsection heading={_t("settings|voip|voice_section")} stretchContent>
{speakerDropdown}
{microphoneDropdown}
<LabelledToggleSwitch
@ -190,18 +191,18 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
await MediaDeviceHandler.setAudioAutoGainControl(v);
this.setState({ audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl() });
}}
label={_t("Automatically adjust the microphone volume")}
label={_t("settings|voip|voice_agc")}
data-testid="voice-auto-gain"
/>
</SettingsSubsection>
<SettingsSubsection heading={_t("Video settings")} stretchContent>
<SettingsSubsection heading={_t("settings|voip|video_section")} stretchContent>
{webcamDropdown}
<SettingsFlag name="VideoView.flipVideoHorizontally" level={SettingLevel.ACCOUNT} />
</SettingsSubsection>
</SettingsSection>
<SettingsSection heading={_t("common|advanced")}>
<SettingsSubsection heading={_t("Voice processing")}>
<SettingsSubsection heading={_t("settings|voip|voice_processing")}>
<LabelledToggleSwitch
value={this.state.audioNoiseSuppression}
onChange={async (v): Promise<void> => {
@ -221,7 +222,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
data-testid="voice-echo-cancellation"
/>
</SettingsSubsection>
<SettingsSubsection heading={_t("Connection")}>
<SettingsSubsection heading={_t("settings|voip|connection_section")}>
<SettingsFlag
name="webRtcAllowPeerToPeer"
level={SettingLevel.DEVICE}

View file

@ -125,7 +125,7 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
let addressesSection: JSX.Element | undefined;
if (space.getJoinRule() === JoinRule.Public) {
addressesSection = (
<SettingsSection heading={_t("Address")}>
<SettingsSection heading={_t("room_settings|visibility|alias_section")}>
<AliasSettings
roomId={space.roomId}
canSetCanonicalAlias={canSetCanonical}