Migrate more strings to translation keys (#11694)

This commit is contained in:
Michael Telatynski 2023-10-03 19:17:26 +01:00 committed by GitHub
parent 677854d318
commit e1cfde0c6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
201 changed files with 21074 additions and 18552 deletions

View file

@ -324,13 +324,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
const dialogAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("auth|uia|sso_title"),
body: _t("To continue, use Single Sign On to prove your identity."),
body: _t("auth|uia|sso_preauth_body"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {
title: _t("Confirm encryption setup"),
body: _t("Click the button below to confirm setting up encryption."),
title: _t("encryption|confirm_encryption_setup_title"),
body: _t("encryption|confirm_encryption_setup_body"),
continueText: _t("action|confirm"),
continueKind: "primary",
},

View file

@ -1228,7 +1228,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const isSpace = roomToLeave?.isSpaceRoom();
Modal.createDialog(QuestionDialog, {
title: isSpace ? _t("Leave space") : _t("action|leave_room"),
title: isSpace ? _t("space|leave_dialog_action") : _t("action|leave_room"),
description: (
<span>
{isSpace
@ -1271,7 +1271,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (room) RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
})
.catch((err) => {
const errCode = err.errcode || _td("unknown error code");
const errCode = err.errcode || _td("error|unknown_error_code");
Modal.createDialog(ErrorDialog, {
title: _t("error_dialog|forget_room_failed", { errCode }),
description: err && err.message ? err.message : _t("invite|failed_generic"),

View file

@ -246,7 +246,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
<>
<InlineSpinner w={20} h={20} />
{/* span for css */}
<span>{_t("Sending")}</span>
<span>{_t("forward|sending")}</span>
</>
);
}

View file

@ -206,9 +206,9 @@ const Tile: React.FC<ITileProps> = ({
);
}
let description = _t("%(count)s members", { count: room.num_joined_members ?? 0 });
let description = _t("common|n_members", { count: room.num_joined_members ?? 0 });
if (numChildRooms !== undefined) {
description += " · " + _t("%(count)s rooms", { count: numChildRooms });
description += " · " + _t("common|n_rooms", { count: numChildRooms });
}
let topic: ReactNode | string | null;
@ -713,7 +713,7 @@ const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, set
kind="danger_outline"
disabled={disabled}
>
{removing ? _t("Removing…") : _t("action|remove")}
{removing ? _t("redact|ongoing") : _t("action|remove")}
</Button>
<Button
{...props}
@ -857,7 +857,7 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
} else if (!hierarchy.canLoadMore) {
results = (
<div className="mx_SpaceHierarchy_noResults">
<h3>{_t("No results found")}</h3>
<h3>{_t("common|no_results_found")}</h3>
<div>{_t("space|no_search_result_hint")}</div>
</div>
);

View file

@ -407,7 +407,7 @@ const SpaceAddExistingRooms: React.FC<{
{_t("create_space|skip_action")}
</AccessibleButton>
}
filterPlaceholder={_t("Search for rooms")}
filterPlaceholder={_t("space|room_filter_placeholder")}
onFinished={onFinished}
roomsRenderer={defaultRoomsRenderer}
dmsRenderer={defaultDmsRenderer}
@ -508,7 +508,7 @@ const SpaceSetupPrivateInvite: React.FC<{
key={name}
name={name}
type="text"
label={_t("Email address")}
label={_t("common|email_address")}
placeholder={_t("auth|email_field_label")}
value={emailAddresses[i]}
onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
@ -553,7 +553,7 @@ const SpaceSetupPrivateInvite: React.FC<{
}
} catch (err) {
logger.error("Failed to invite users to space: ", err);
setError(_t("We couldn't invite those users. Please check the users you want to invite and try again."));
setError(_t("invite|error_invite"));
}
setBusy(false);
};

View file

@ -19,7 +19,7 @@ import classNames from "classnames";
import { logger } from "matrix-js-sdk/src/logger";
import { SSOFlow, SSOAction } from "matrix-js-sdk/src/matrix";
import { _t, _td, UserFriendlyError } from "../../../languageHandler";
import { _t, UserFriendlyError } from "../../../languageHandler";
import Login, { ClientLoginFlow, OidcNativeFlow } from "../../../Login";
import { messageForConnectionError, messageForLoginError } from "../../../utils/ErrorUtils";
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
@ -41,16 +41,6 @@ import { filterBoolean } from "../../../utils/arrays";
import { Features } from "../../../settings/Settings";
import { startOidcLogin } from "../../../utils/oidc/authorize";
// These are used in several places, and come from the js-sdk's autodiscovery
// stuff. We define them here so that they'll be picked up by i18n.
_td("Invalid homeserver discovery response");
_td("Failed to get autodiscovery configuration from server");
_td("Invalid base_url for m.homeserver");
_td("Homeserver URL does not appear to be a valid Matrix homeserver");
_td("Invalid identity server discovery response");
_td("Invalid base_url for m.identity_server");
_td("Identity server URL does not appear to be a valid identity server");
_td("General failure");
interface IProps {
serverConfig: ValidatedServerConfig;
// If true, the component will consider itself busy.

View file

@ -204,7 +204,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
{useRecoveryKeyButton}
</div>
<div className="mx_SetupEncryptionBody_reset">
{_t("Forgotten or lost all recovery methods? <a>Reset all</a>", undefined, {
{_t("encryption|reset_all_button", undefined, {
a: (sub) => (
<AccessibleButton
kind="link_inline"

View file

@ -315,7 +315,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
<p>{_t("auth|soft_logout_warning")}</p>
<div>
<AccessibleButton onClick={this.onClearAll} kind="danger">
{_t("Clear all data")}
{_t("auth|soft_logout|clear_data_button")}
</AccessibleButton>
</div>
</AuthBody>

View file

@ -72,7 +72,7 @@ export const EnterEmail: React.FC<EnterEmailProps> = ({
<div className="mx_AuthBody_fieldRow">
<EmailField
name="reset_email" // define a name so browser's password autofill gets less confused
label="Email address"
label={_td("common|email_address")}
labelRequired={_td("auth|forgot_password_email_required")}
labelInvalid={_td("auth|forgot_password_email_invalid")}
value={email}

View file

@ -94,7 +94,7 @@ export const VerifyEmailModal: React.FC<Props> = ({
<AccessibleButton
onClick={onCloseClick}
className="mx_Dialog_cancelButton"
aria-label={_t("Close dialog")}
aria-label={_t("dialog_close_label")}
/>
</>
);

View file

@ -407,7 +407,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
{_t("common|username")}
</option>
<option key={LoginField.Email} value={LoginField.Email}>
{_t("Email address")}
{_t("common|email_address")}
</option>
<option key={LoginField.Password} value={LoginField.Password}>
{_t("auth|msisdn_field_label")}

View file

@ -387,7 +387,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
test: ({ value }, usernameAvailable) =>
(!value || SAFE_LOCALPART_REGEX.test(value)) &&
usernameAvailable !== UsernameAvailableStatus.Invalid,
invalid: () => _t("Some characters not allowed"),
invalid: () => _t("room_settings|general|alias_field_safe_localpart_invalid"),
},
{
key: "available",
@ -453,7 +453,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
}
const emailLabel = this.authStepIsRequired("m.login.email.identity")
? _td("auth|email_field_label")
: _td("Email (optional)");
: _td("auth|registration|continue_without_email_field_label");
return (
<EmailField
fieldRef={(field) => (this[RegistrationField.Email] = field)}

View file

@ -71,7 +71,7 @@ const BeaconListItem: React.FC<Props & HTMLProps<HTMLLIElement>> = ({ beacon, ..
</div>
</BeaconStatus>
<span className="mx_BeaconListItem_lastUpdated">
{_t("Updated %(humanizedUpdateTime)s", { humanizedUpdateTime })}
{_t("location_sharing|live_update_time", { humanizedUpdateTime })}
</span>
</div>
</li>

View file

@ -35,7 +35,7 @@ interface Props {
const BeaconExpiryTime: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
const expiryTime = formatTime(new Date(getBeaconExpiryTimestamp(beacon)));
return <span className="mx_BeaconStatus_expiryTime">{_t("Live until %(expiryTime)s", { expiryTime })}</span>;
return <span className="mx_BeaconStatus_expiryTime">{_t("location_sharing|live_until", { expiryTime })}</span>;
};
const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
@ -61,13 +61,19 @@ const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
)}
<div className="mx_BeaconStatus_description">
{displayStatus === BeaconDisplayStatus.Loading && (
<span className="mx_BeaconStatus_description_status">{_t("Loading live location…")}</span>
<span className="mx_BeaconStatus_description_status">
{_t("location_sharing|loading_live_location")}
</span>
)}
{displayStatus === BeaconDisplayStatus.Stopped && (
<span className="mx_BeaconStatus_description_status">{_t("Live location ended")}</span>
<span className="mx_BeaconStatus_description_status">
{_t("location_sharing|live_location_ended")}
</span>
)}
{displayStatus === BeaconDisplayStatus.Error && (
<span className="mx_BeaconStatus_description_status">{_t("Live location error")}</span>
<span className="mx_BeaconStatus_description_status">
{_t("location_sharing|live_location_error")}
</span>
)}
{displayStatus === BeaconDisplayStatus.Active && beacon && (
<>

View file

@ -160,7 +160,9 @@ const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matr
)}
{!centerGeoUri && !mapDisplayError && (
<MapFallback data-testid="beacon-view-dialog-map-fallback" className="mx_BeaconViewDialog_map">
<span className="mx_BeaconViewDialog_mapFallbackMessage">{_t("No live locations")}</span>
<span className="mx_BeaconViewDialog_mapFallbackMessage">
{_t("location_sharing|live_locations_empty")}
</span>
<AccessibleButton
kind="primary"
onClick={onFinished}
@ -185,7 +187,7 @@ const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matr
>
<LiveLocationIcon height={12} />
&nbsp;
{_t("View list")}
{_t("action|view_list")}
</AccessibleButton>
)}
<DialogOwnBeaconStatus roomId={roomId} />

View file

@ -33,11 +33,11 @@ const DialogSidebar: React.FC<Props> = ({ beacons, onBeaconClick, requestClose }
return (
<div className="mx_DialogSidebar">
<div className="mx_DialogSidebar_header">
<Heading size="4">{_t("View List")}</Heading>
<Heading size="4">{_t("action|view_list")}</Heading>
<AccessibleButton
className="mx_DialogSidebar_closeButton"
onClick={requestClose}
title={_t("Close sidebar")}
title={_t("location_sharing|close_sidebar")}
data-testid="dialog-sidebar-close"
>
<CloseIcon className="mx_DialogSidebar_closeButtonIcon" />
@ -50,7 +50,7 @@ const DialogSidebar: React.FC<Props> = ({ beacons, onBeaconClick, requestClose }
))}
</ol>
) : (
<div className="mx_DialogSidebar_noResults">{_t("No live locations")}</div>
<div className="mx_DialogSidebar_noResults">{_t("location_sharing|live_locations_empty")}</div>
)}
</div>
);

View file

@ -52,12 +52,12 @@ const chooseBestBeacon = (
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
if (hasStoppingErrors) {
return _t("An error occurred while stopping your live location");
return _t("location_sharing|error_stopping_live_location");
}
if (hasLocationErrors) {
return _t("An error occurred whilst sharing your live location");
return _t("location_sharing|error_sharing_live_location");
}
return _t("You are sharing your live location");
return _t("location_sharing|live_location_active");
};
const useLivenessMonitor = (liveBeaconIds: BeaconIdentifier[], beacons: Map<BeaconIdentifier, Beacon>): void => {

View file

@ -51,7 +51,7 @@ const OwnBeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({ beacon,
<BeaconStatus
beacon={beacon}
displayStatus={ownDisplayStatus}
label={_t("Live location enabled")}
label={_t("location_sharing|live_location_enabled")}
displayLiveTimeRemaining
{...rest}
>

View file

@ -32,12 +32,12 @@ import { Action } from "../../../dispatcher/actions";
const getLabel = (hasLocationPublishError: boolean, hasStopSharingError: boolean): string => {
if (hasLocationPublishError) {
return _t("An error occurred whilst sharing your live location, please try again");
return _t("location_sharing|error_sharing_live_location_try_again");
}
if (hasStopSharingError) {
return _t("An error occurred while stopping your live location, please try again");
return _t("location_sharing|error_stopping_live_location_try_again");
}
return _t("You are sharing your live location");
return _t("location_sharing|live_location_active");
};
interface RoomLiveShareWarningInnerProps {

View file

@ -46,7 +46,7 @@ const ShareLatestLocation: React.FC<Props> = ({ latestLocationState }) => {
return (
<>
<TooltipTarget label={_t("Open in OpenStreetMap")}>
<TooltipTarget label={_t("timeline|context_menu|open_in_osm")}>
<a data-testid="open-location-in-osm" href={mapLink} target="_blank" rel="noreferrer noopener">
<ExternalLinkIcon className="mx_ShareLatestLocation_icon" />
</a>

View file

@ -22,9 +22,9 @@ import { IProps as IContextMenuProps } from "../../structures/ContextMenu";
import { _t, _td, TranslationKey } from "../../../languageHandler";
const SECTION_NAMES: Record<MediaDeviceKindEnum, TranslationKey> = {
[MediaDeviceKindEnum.AudioInput]: _td("Input devices"),
[MediaDeviceKindEnum.AudioOutput]: _td("Output devices"),
[MediaDeviceKindEnum.VideoInput]: _td("Cameras"),
[MediaDeviceKindEnum.AudioInput]: _td("voip|input_devices"),
[MediaDeviceKindEnum.AudioOutput]: _td("voip|output_devices"),
[MediaDeviceKindEnum.VideoInput]: _td("common|cameras"),
};
interface IDeviceContextMenuDeviceProps {

View file

@ -47,14 +47,14 @@ export default class LegacyCallContextMenu extends React.Component<IProps> {
};
public render(): React.ReactNode {
const holdUnholdCaption = this.props.call.isRemoteOnHold() ? _t("Resume") : _t("Hold");
const holdUnholdCaption = this.props.call.isRemoteOnHold() ? _t("action|resume") : _t("action|hold");
const handler = this.props.call.isRemoteOnHold() ? this.onUnholdClick : this.onHoldClick;
let transferItem;
if (this.props.call.opponentCanBeTransferred()) {
transferItem = (
<MenuItem className="mx_LegacyCallContextMenu_item" onClick={this.onTransferClick}>
{_t("Transfer")}
{_t("action|transfer")}
</MenuItem>
);
}

View file

@ -414,7 +414,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
resendReactionsButton = (
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconResend"
label={_t("Resend %(unsentCount)s reaction(s)", { unsentCount: unsentReactionsCount })}
label={_t("timeline|context_menu|resent_unsent_reactions", { unsentCount: unsentReactionsCount })}
onClick={this.onResendReactionsClick}
/>
);
@ -439,7 +439,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconOpenInMapSite"
onClick={null}
label={_t("Open in OpenStreetMap")}
label={_t("timeline|context_menu|open_in_osm")}
element="a"
{...{
href: mapSiteLink,
@ -518,7 +518,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
endPollButton = (
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconEndPoll"
label={_t("End Poll")}
label={_t("poll|end_title")}
onClick={this.onEndPollClick}
/>
);

View file

@ -108,7 +108,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
data-testid="leave-option"
iconClassName="mx_SpacePanel_iconLeave"
className="mx_IconizedContextMenu_option_red"
label={_t("Leave space")}
label={_t("space|leave_dialog_action")}
onClick={onLeaveClick}
/>
);

View file

@ -92,7 +92,7 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
{...props}
className="mx_BaseCard_header_title_button--option"
onClick={openMenu}
title={_t("Thread options")}
title={_t("right_panel|thread_list|context_menu_label")}
isExpanded={menuDisplayed}
inputRef={button}
data-testid="threadlist-dropdown-button"

View file

@ -135,9 +135,10 @@ export const WidgetContextMenu: React.FC<IProps> = ({
} catch (err) {
logger.error("Failed to start livestream", err);
// XXX: won't i18n well, but looks like widget api only support 'message'?
const message = err instanceof Error ? err.message : _t("Unable to start audio streaming.");
const message =
err instanceof Error ? err.message : _t("widget|error_unable_start_audio_stream_description");
Modal.createDialog(ErrorDialog, {
title: _t("Failed to start livestream"),
title: _t("widget|error_unable_start_audio_stream_title"),
description: message,
});
}

View file

@ -36,7 +36,7 @@ const AddExistingSubspaceDialog: React.FC<IProps> = ({ space, onCreateSubspaceCl
<BaseDialog
title={
<SubspaceSelector
title={_t("Add existing space")}
title={_t("space|add_existing_subspace|space_dropdown_title")}
space={space}
value={selectedSpace}
onChange={setSelectedSpace}
@ -53,13 +53,13 @@ const AddExistingSubspaceDialog: React.FC<IProps> = ({ space, onCreateSubspaceCl
onFinished={onFinished}
footerPrompt={
<>
<div>{_t("Want to add a new space instead?")}</div>
<div>{_t("space|add_existing_subspace|create_prompt")}</div>
<AccessibleButton onClick={onCreateSubspaceClick} kind="link">
{_t("Create a new space")}
{_t("space|add_existing_subspace|create_button")}
</AccessibleButton>
</>
}
filterPlaceholder={_t("Search for spaces")}
filterPlaceholder={_t("space|add_existing_subspace|filter_placeholder")}
spacesRenderer={defaultSpacesRenderer}
/>
</MatrixClientContext.Provider>

View file

@ -241,7 +241,9 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
/>
<span className="mx_AddExistingToSpaceDialog_error">
<div className="mx_AddExistingToSpaceDialog_errorHeading">{_t("Not all selected were added")}</div>
<div className="mx_AddExistingToSpaceDialog_errorHeading">
{_t("space|add_existing_room_space|error_heading")}
</div>
<div className="mx_AddExistingToSpaceDialog_errorCaption">{_t("action|try_again")}</div>
</span>
@ -255,7 +257,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
<span>
<ProgressBar value={progress} max={selectedToAdd.size} />
<div className="mx_AddExistingToSpaceDialog_progressText">
{_t("Adding rooms... (%(progress)s out of %(count)s)", {
{_t("space|add_existing_room_space|progress_text", {
count: selectedToAdd.size,
progress,
})}
@ -389,7 +391,7 @@ const defaultRendererFactory =
export const defaultRoomsRenderer = defaultRendererFactory(_td("common|rooms"));
export const defaultSpacesRenderer = defaultRendererFactory(_td("common|spaces"));
export const defaultDmsRenderer = defaultRendererFactory(_td("Direct Messages"));
export const defaultDmsRenderer = defaultRendererFactory(_td("space|add_existing_room_space|dm_heading"));
interface ISubspaceSelectorProps {
title: string;
@ -418,7 +420,7 @@ export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, spac
onChange(options.find((space) => space.roomId === key) || space);
}}
value={value.roomId}
label={_t("Space selection")}
label={_t("space|add_existing_room_space|space_dropdown_label")}
>
{
options.map((space) => {
@ -461,7 +463,7 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
<BaseDialog
title={
<SubspaceSelector
title={_t("Add existing rooms")}
title={_t("space|add_existing_room_space|space_dropdown_title")}
space={space}
value={selectedSpace}
onChange={setSelectedSpace}
@ -478,7 +480,7 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
onFinished={onFinished}
footerPrompt={
<>
<div>{_t("Want to add a new room instead?")}</div>
<div>{_t("space|add_existing_room_space|create")}</div>
<AccessibleButton
kind="link"
onClick={(ev: ButtonEvent) => {
@ -486,11 +488,11 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
onFinished();
}}
>
{_t("Create a new room")}
{_t("space|add_existing_room_space|create_prompt")}
</AccessibleButton>
</>
}
filterPlaceholder={_t("Search for rooms")}
filterPlaceholder={_t("space|room_filter_placeholder")}
roomsRenderer={defaultRoomsRenderer}
spacesRenderer={() => (
<div className="mx_AddExistingToSpace_section">
@ -502,7 +504,7 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
onFinished();
}}
>
{_t("Adding spaces has moved.")}
{_t("space|add_existing_room_space|subspace_moved_note")}
</AccessibleButton>
</div>
)}

View file

@ -70,15 +70,13 @@ export default function AskInviteAnywayDialog({
</li>
));
const description =
descriptionProp ??
_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?");
const description = descriptionProp ?? _t("invite|unable_find_profiles_description_default");
return (
<BaseDialog
className="mx_RetryInvitesDialog"
onFinished={onGiveUpClicked}
title={_t("The following users may not exist")}
title={_t("invite|unable_find_profiles_title")}
contentId="mx_Dialog_content"
>
<div id="mx_Dialog_content">
@ -89,10 +87,10 @@ export default function AskInviteAnywayDialog({
<div className="mx_Dialog_buttons">
<button onClick={onGiveUpClicked}>{_t("action|close")}</button>
<button onClick={onInviteNeverWarnClicked}>
{inviteNeverWarnLabel ?? _t("Invite anyway and never warn me again")}
{inviteNeverWarnLabel ?? _t("invite|unable_find_profiles_invite_never_warn_label_default")}
</button>
<button onClick={onInviteClicked} autoFocus={true}>
{inviteLabel ?? _t("Invite anyway")}
{inviteLabel ?? _t("invite|unable_find_profiles_invite_label_default")}
</button>
</div>
</BaseDialog>

View file

@ -127,7 +127,7 @@ export default class BaseDialog extends React.Component<IProps> {
<AccessibleButton
onClick={this.onCancelClick}
className="mx_Dialog_cancelButton"
aria-label={_t("Close dialog")}
aria-label={_t("dialog_close_label")}
/>
);
}

View file

@ -37,7 +37,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
return (
<GenericFeatureFeedbackDialog
title={_t("%(featureName)s Beta feedback", { featureName: info.title })}
title={_t("labs|beta_feedback_title", { featureName: info.title })}
subheading={info.feedbackSubheading ? _t(info.feedbackSubheading) : undefined}
onFinished={onFinished}
rageshakeLabel={info.feedbackLabel}
@ -57,7 +57,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
});
}}
>
{_t("To leave the beta, visit your settings.")}
{_t("labs|beta_feedback_leave_button")}
</AccessibleButton>
</GenericFeatureFeedbackDialog>
);

View file

@ -98,7 +98,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
private onSubmit = (): void => {
if ((!this.state.text || !this.state.text.trim()) && (!this.state.issueUrl || !this.state.issueUrl.trim())) {
this.setState({
err: _t("Please tell us what went wrong or, better, create a GitHub issue that describes the problem."),
err: _t("bug_reporting|error_empty"),
});
return;
}
@ -109,7 +109,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
(this.state.issueUrl.length > 0 ? this.state.issueUrl : "No issue link given");
this.setState({ busy: true, progress: null, err: null });
this.sendProgressCallback(_t("Preparing to send logs"));
this.sendProgressCallback(_t("bug_reporting|preparing_logs"));
sendBugReport(SdkConfig.get().bug_report_endpoint_url, {
userText,
@ -121,8 +121,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
if (!this.unmounted) {
this.props.onFinished(false);
Modal.createDialog(QuestionDialog, {
title: _t("Logs sent"),
description: _t("Thank you!"),
title: _t("bug_reporting|logs_sent"),
description: _t("bug_reporting|thank_you"),
hasCancelButton: false,
});
}
@ -132,7 +132,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
this.setState({
busy: false,
progress: null,
err: _t("Failed to send logs: ") + `${err.message}`,
err: _t("bug_reporting|failed_send_logs") + `${err.message}`,
});
}
},
@ -143,7 +143,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
private onDownload = async (): Promise<void> => {
this.setState({ downloadBusy: true });
this.downloadProgressCallback(_t("Preparing to download logs"));
this.downloadProgressCallback(_t("bug_reporting|preparing_download"));
try {
await downloadBugReport({
@ -160,7 +160,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
if (!this.unmounted) {
this.setState({
downloadBusy: false,
downloadProgress: _t("Failed to send logs: ") + `${err instanceof Error ? err.message : ""}`,
downloadProgress:
_t("bug_reporting|failed_send_logs") + `${err instanceof Error ? err.message : ""}`,
});
}
}
@ -208,7 +209,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
if (window.Modernizr && Object.values(window.Modernizr).some((support) => support === false)) {
warning = (
<p>
<b>{_t("Reminder: Your browser is unsupported, so your experience may be unpredictable.")}</b>
<b>{_t("bug_reporting|unsupported_browser")}</b>
</p>
);
}
@ -261,7 +262,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
<Field
className="mx_BugReportDialog_field_input"
element="textarea"
label={_t("Notes")}
label={_t("bug_reporting|textarea_label")}
rows={5}
onChange={this.onTextChange}
value={this.state.text}

View file

@ -62,10 +62,10 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
return (
<InfoDialog
onFinished={onFinished}
title={_t("No recent messages by %(user)s found", { user: member.name })}
title={_t("user_info|redact|no_recent_messages_title", { user: member.name })}
description={
<div>
<p>{_t("Try scrolling up in the timeline to see if there are any earlier ones.")}</p>
<p>{_t("user_info|redact|no_recent_messages_description")}</p>
</div>
}
/>
@ -108,32 +108,21 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
<BaseDialog
className="mx_BulkRedactDialog"
onFinished={onFinished}
title={_t("Remove recent messages by %(user)s", { user })}
title={_t("user_info|redact|confirm_title", { user })}
contentId="mx_Dialog_content"
>
<div className="mx_Dialog_content" id="mx_Dialog_content">
<p>
{_t(
"You are about to remove %(count)s messages by %(user)s. This will remove them permanently for everyone in the conversation. Do you wish to continue?",
{ count, user },
)}
</p>
<p>
{_t(
"For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.",
)}
</p>
<p>{_t("user_info|redact|confirm_description_1", { count, user })}</p>
<p>{_t("user_info|redact|confirm_description_2")}</p>
<StyledCheckbox checked={keepStateEvents} onChange={(e) => setKeepStateEvents(e.target.checked)}>
{_t("Preserve system messages")}
{_t("user_info|redact|confirm_keep_state_label")}
</StyledCheckbox>
<div className="mx_BulkRedactDialog_checkboxMicrocopy">
{_t(
"Uncheck if you also want to remove system messages on this user (e.g. membership change, profile change…)",
)}
{_t("user_info|redact|confirm_keep_state_explainer")}
</div>
</div>
<DialogButtons
primaryButton={_t("Remove %(count)s messages", { count })}
primaryButton={_t("user_info|redact|confirm_button", { count })}
primaryButtonClass="danger"
primaryDisabled={count === 0}
onPrimaryButtonClick={() => {

View file

@ -22,14 +22,8 @@ import InfoDialog from "./InfoDialog";
export const createCantStartVoiceMessageBroadcastDialog = (): void => {
Modal.createDialog(InfoDialog, {
title: _t("Can't start voice message"),
description: (
<p>
{_t(
"You can't start a voice message as you are currently recording a live broadcast. Please end your live broadcast in order to start recording a voice message.",
)}
</p>
),
title: _t("voice_message|cant_start_broadcast_title"),
description: <p>{_t("voice_message|cant_start_broadcast_description")}</p>,
hasCloseButton: true,
});
};

View file

@ -93,7 +93,7 @@ export default class ChangelogDialog extends React.Component<IProps, State> {
if (this.state[repo] == null) {
content = <Spinner key={repo} />;
} else if (typeof this.state[repo] === "string") {
content = _t("Unable to load commit detail: %(msg)s", {
content = _t("update|error_unable_load_commit", {
msg: this.state[repo],
});
} else {
@ -111,13 +111,17 @@ export default class ChangelogDialog extends React.Component<IProps, State> {
const content = (
<div className="mx_ChangelogDialog_content">
{this.props.version == null || this.props.newVersion == null ? <h2>{_t("Unavailable")}</h2> : logs}
{this.props.version == null || this.props.newVersion == null ? (
<h2>{_t("update|unavailable")}</h2>
) : (
logs
)}
</div>
);
return (
<QuestionDialog
title={_t("Changelog")}
title={_t("update|changelog")}
description={content}
button={_t("action|update")}
onFinished={this.props.onFinished}

View file

@ -88,12 +88,12 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent<IPro
<ErrorDialog
onFinished={this.props.onFinished}
title={_t("common|error")}
description={_t("You cannot delete this message. (%(code)s)", { code })}
description={_t("redact|error", { code })}
/>
);
} else {
return (
<BaseDialog onFinished={this.props.onFinished} hasCancel={false} title={_t("Removing…")}>
<BaseDialog onFinished={this.props.onFinished} hasCancel={false} title={_t("redact|ongoing")}>
<Spinner />
</BaseDialog>
);

View file

@ -36,17 +36,17 @@ interface IProps {
*/
export default class ConfirmRedactDialog extends React.Component<IProps> {
public render(): React.ReactNode {
let description = _t("Are you sure you wish to remove (delete) this event?");
let description = _t("redact|confirm_description");
if (this.props.event.isState()) {
description += " " + _t("Note that removing room changes like this could undo the change.");
description += " " + _t("redact|confirm_description_state");
}
return (
<TextInputDialog
onFinished={this.props.onFinished}
title={_t("Confirm Removal")}
title={_t("redact|confirm_button")}
description={description}
placeholder={_t("Reason (optional)")}
placeholder={_t("redact|reason_label")}
focus
button={_t("action|remove")}
/>
@ -105,7 +105,7 @@ export function createRedactEventDialog({
// display error message stating you couldn't delete this.
Modal.createDialog(ErrorDialog, {
title: _t("common|error"),
description: _t("You cannot delete this message. (%(code)s)", { code }),
description: _t("redact|error", { code }),
});
}
}

View file

@ -39,17 +39,13 @@ export default class ConfirmWipeDeviceDialog extends React.Component<IProps> {
className="mx_ConfirmWipeDeviceDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Clear all data in this session?")}
title={_t("auth|soft_logout|clear_data_title")}
>
<div className="mx_ConfirmWipeDeviceDialog_content">
<p>
{_t(
"Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.",
)}
</p>
<p>{_t("auth|soft_logout|clear_data_description")}</p>
</div>
<DialogButtons
primaryButton={_t("Clear all data")}
primaryButton={_t("auth|soft_logout|clear_data_button")}
onPrimaryButtonClick={this.onConfirm}
primaryButtonClass="danger"
cancelButton={_t("action|cancel")}

View file

@ -100,7 +100,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
joinRuleMicrocopy = (
<p>
{_t(
"Anyone in <SpaceName/> will be able to find and join.",
"create_space|subspace_join_rule_restricted_description",
{},
{
SpaceName: () => <b>{parentSpace.name}</b>,
@ -112,7 +112,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
joinRuleMicrocopy = (
<p>
{_t(
"Anyone will be able to find and join this space, not just members of <SpaceName/>.",
"create_space|subspace_join_rule_public_description",
{},
{
SpaceName: () => <b>{parentSpace.name}</b>,
@ -121,14 +121,14 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
</p>
);
} else if (joinRule === JoinRule.Invite) {
joinRuleMicrocopy = <p>{_t("Only people invited will be able to find and join this space.")}</p>;
joinRuleMicrocopy = <p>{_t("create_space|subspace_join_rule_invite_description")}</p>;
}
return (
<BaseDialog
title={
<SubspaceSelector
title={_t("Create a space")}
title={_t("create_space|subspace_dropdown_title")}
space={space}
value={parentSpace}
onChange={setParentSpace}
@ -143,7 +143,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
<div className="mx_CreateSubspaceDialog_content">
<div className="mx_CreateSubspaceDialog_betaNotice">
<BetaPill />
{_t("Add a space to a space you manage.")}
{_t("create_space|subspace_beta_notice")}
</div>
<SpaceCreateForm
@ -161,8 +161,8 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
aliasFieldRef={spaceAliasField}
>
<JoinRuleDropdown
label={_t("Space visibility")}
labelInvite={_t("Private space (invite only)")}
label={_t("create_space|subspace_join_rule_label")}
labelInvite={_t("create_space|subspace_join_rule_invite_only")}
labelPublic={_t("common|public_space")}
labelRestricted={_t("create_room|join_rule_restricted")}
width={478}
@ -175,7 +175,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
<div className="mx_CreateSubspaceDialog_footer">
<div className="mx_CreateSubspaceDialog_footer_prompt">
<div>{_t("Want to add an existing space instead?")}</div>
<div>{_t("create_space|subspace_existing_space_prompt")}</div>
<AccessibleButton
kind="link"
onClick={() => {
@ -183,7 +183,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
onFinished();
}}
>
{_t("Add existing space")}
{_t("space|add_existing_subspace|space_dropdown_title")}
</AccessibleButton>
</div>
@ -191,7 +191,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
{_t("action|cancel")}
</AccessibleButton>
<AccessibleButton kind="primary" disabled={busy} onClick={onCreateSubspaceClick}>
{busy ? _t("Adding…") : _t("action|add")}
{busy ? _t("create_space|subspace_adding") : _t("action|add")}
</AccessibleButton>
</div>
</MatrixClientContext.Provider>

View file

@ -35,10 +35,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
const _onLogoutClicked = (): void => {
Modal.createDialog(QuestionDialog, {
title: _t("action|sign_out"),
description: _t(
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this",
{ brand },
),
description: _t("encryption|incompatible_database_sign_out_description", { brand }),
button: _t("action|sign_out"),
focus: false,
onFinished: (doLogout) => {
@ -50,16 +47,13 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
});
};
const description = _t(
"You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.",
{ brand },
);
const description = _t("encryption|incompatible_database_description", { brand });
return (
<BaseDialog
className="mx_CryptoStoreTooNewDialog"
contentId="mx_Dialog_content"
title={_t("Incompatible Database")}
title={_t("encryption|incompatible_database_title")}
hasCancel={false}
onFinished={props.onFinished}
>
@ -67,7 +61,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
{description}
</div>
<DialogButtons
primaryButton={_t("Continue With Encryption Disabled")}
primaryButton={_t("encryption|incompatible_database_disable")}
hasCancel={false}
onPrimaryButtonClick={() => props.onFinished(false)}
>

View file

@ -73,13 +73,13 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
private onStagePhaseChange = (stage: AuthType, phase: number): void => {
const dialogAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
body: _t("Confirm your account deactivation by using Single Sign On to prove your identity."),
body: _t("settings|general|deactivate_confirm_body_sso"),
continueText: _t("auth|sso"),
continueKind: "danger",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {
body: _t("Are you sure you want to deactivate your account? This is irreversible."),
continueText: _t("Confirm account deactivation"),
body: _t("settings|general|deactivate_confirm_body"),
continueText: _t("settings|general|deactivate_confirm_continue"),
continueKind: "danger",
},
};
@ -90,7 +90,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
[PasswordAuthEntry.LOGIN_TYPE]: {
[DEFAULT_PHASE]: {
body: _t("To continue, please enter your account password:"),
body: _t("settings|general|deactivate_confirm_body_password"),
},
},
};
@ -122,7 +122,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
}
logger.error("Error during UI Auth:", { result });
this.setState({ errStr: _t("There was a problem communicating with the server. Please try again.") });
this.setState({ errStr: _t("settings|general|error_deactivate_communication") });
};
private onUIAuthComplete = (auth: IAuthData | null): void => {
@ -138,7 +138,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
})
.catch((e) => {
logger.error(e);
this.setState({ errStr: _t("There was a problem communicating with the server. Please try again.") });
this.setState({ errStr: _t("settings|general|error_deactivate_communication") });
});
};
@ -170,14 +170,14 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
// We'll try to log something in an vain attempt to record what happened (storage
// is also obliterated on logout).
logger.warn("User's account got deactivated without confirmation: Server had no auth");
this.setState({ errStr: _t("Server did not require any authentication") });
this.setState({ errStr: _t("settings|general|error_deactivate_no_auth") });
})
.catch((e) => {
if (e && e.httpStatus === 401 && e.data) {
// Valid UIA response
this.setState({ authData: e.data, authEnabled: true });
} else {
this.setState({ errStr: _t("Server did not return valid authentication information.") });
this.setState({ errStr: _t("settings|general|error_deactivate_invalid_auth") });
}
});
}
@ -218,32 +218,20 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
screenName="DeactivateAccount"
>
<div className="mx_Dialog_content">
<p>{_t("Confirm that you would like to deactivate your account. If you proceed:")}</p>
<p>{_t("settings|general|deactivate_confirm_content")}</p>
<ul>
<li>{_t("You will not be able to reactivate your account")}</li>
<li>{_t("You will no longer be able to log in")}</li>
<li>
{_t(
"No one will be able to reuse your username (MXID), including you: this username will remain unavailable",
)}
</li>
<li>{_t("You will leave all rooms and DMs that you are in")}</li>
<li>
{_t(
"You will be removed from the identity server: your friends will no longer be able to find you with your email or phone number",
)}
</li>
<li>{_t("settings|general|deactivate_confirm_content_1")}</li>
<li>{_t("settings|general|deactivate_confirm_content_2")}</li>
<li>{_t("settings|general|deactivate_confirm_content_3")}</li>
<li>{_t("settings|general|deactivate_confirm_content_4")}</li>
<li>{_t("settings|general|deactivate_confirm_content_5")}</li>
</ul>
<p>
{_t(
"Your old messages will still be visible to people who received them, just like emails you sent in the past. Would you like to hide your sent messages from people who join rooms in the future?",
)}
</p>
<p>{_t("settings|general|deactivate_confirm_content_6")}</p>
<div className="mx_DeactivateAccountDialog_input_section">
<p>
<StyledCheckbox checked={this.state.shouldErase} onChange={this.onEraseFieldChange}>
{_t("Hide my messages from new joiners")}
{_t("settings|general|deactivate_confirm_erase_label")}
</StyledCheckbox>
</p>
{error}

View file

@ -47,9 +47,7 @@ export default class EndPollDialog extends React.Component<IProps> {
const topAnswer = findTopAnswer(this.props.event, responses);
const message =
topAnswer === ""
? _t("The poll has ended. No votes were cast.")
: _t("The poll has ended. Top answer: %(topAnswer)s", { topAnswer });
topAnswer === "" ? _t("poll|end_message_no_votes") : _t("poll|end_message", { topAnswer });
const endEvent = PollEndEvent.from(this.props.event.getId()!, message).serialize();
@ -57,8 +55,8 @@ export default class EndPollDialog extends React.Component<IProps> {
} catch (e) {
console.error("Failed to submit poll response event:", e);
Modal.createDialog(ErrorDialog, {
title: _t("Failed to end poll"),
description: _t("Sorry, the poll did not end. Please try again."),
title: _t("poll|error_ending_title"),
description: _t("poll|error_ending_description"),
});
}
}
@ -68,11 +66,9 @@ export default class EndPollDialog extends React.Component<IProps> {
public render(): React.ReactNode {
return (
<QuestionDialog
title={_t("End Poll")}
description={_t(
"Are you sure you want to end this poll? This will show the final results of the poll and stop people from being able to vote.",
)}
button={_t("End Poll")}
title={_t("poll|end_title")}
description={_t("poll|end_description")}
button={_t("poll|end_title")}
onFinished={(endPoll: boolean) => this.onFinished(endPoll)}
/>
);

View file

@ -79,7 +79,7 @@ export default class ErrorDialog extends React.Component<IProps, IState> {
contentId="mx_Dialog_content"
>
<div className="mx_Dialog_content" id="mx_Dialog_content">
{this.props.description || _t("An error has occurred.")}
{this.props.description || _t("error|dialog_description_default")}
</div>
<div className="mx_Dialog_buttons">
<button className="mx_Dialog_primary" onClick={this.onClick} autoFocus={this.props.focus}>

View file

@ -278,7 +278,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
);
}
const sizePostFix = <span>{_t("MB")}</span>;
const sizePostFix = <span>{_t("export_chat|size_limit_postfix")}</span>;
if (exportCancelled) {
// Display successful cancellation message

View file

@ -57,7 +57,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
Modal.createDialog(InfoDialog, {
title: _t("feedback|sent"),
description: _t("Thank you!"),
description: _t("bug_reporting|thank_you"),
});
}
props.onFinished();

View file

@ -115,17 +115,17 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
className = "mx_ForwardList_canSend";
if (!room.maySendMessage()) {
disabled = true;
title = _t("You don't have permission to do this");
title = _t("forward|no_perms_title");
}
} else if (sendState === SendState.Sending) {
className = "mx_ForwardList_sending";
disabled = true;
title = _t("Sending");
title = _t("forward|sending");
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
} else if (sendState === SendState.Sent) {
className = "mx_ForwardList_sent";
disabled = true;
title = _t("Sent");
title = _t("forward|sent");
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
} else {
className = "mx_ForwardList_sendFailed";
@ -139,7 +139,7 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
<AccessibleTooltipButton
className="mx_ForwardList_roomButton"
onClick={jumpToRoom}
title={_t("Open room")}
title={_t("forward|open_room")}
alignment={Alignment.Top}
>
<DecoratedRoomAvatar room={room} size="32px" />
@ -154,7 +154,7 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
title={title}
alignment={Alignment.Top}
>
<div className="mx_ForwardList_sendLabel">{_t("Send")}</div>
<div className="mx_ForwardList_sendLabel">{_t("forward|send_label")}</div>
{icon}
</AccessibleTooltipButton>
</div>
@ -256,7 +256,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
const [truncateAt, setTruncateAt] = useState(20);
function overflowTile(overflowCount: number, totalCount: number): JSX.Element {
const text = _t("and %(count)s others...", { count: overflowCount });
const text = _t("common|and_n_others", { count: overflowCount });
return (
<EntityTile
className="mx_EntityTile_ellipsis"
@ -279,7 +279,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
onFinished={onFinished}
fixedWidth={false}
>
<h3>{_t("Message preview")}</h3>
<h3>{_t("forward|message_preview_heading")}</h3>
<div
className={classnames("mx_ForwardDialog_preview", {
mx_IRCLayout: previewLayout == Layout.IRC,
@ -297,7 +297,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
<div className="mx_ForwardList" id="mx_ForwardList">
<SearchBox
className="mx_textinput_icon mx_textinput_search"
placeholder={_t("Search for rooms or people")}
placeholder={_t("forward|filter_placeholder")}
onSearch={setQuery}
autoFocus={true}
/>

View file

@ -52,7 +52,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
Modal.createDialog(InfoDialog, {
title,
description: _t("Feedback sent! Thanks, we appreciate it!"),
description: _t("feedback|sent"),
button: _t("action|close"),
hasCloseButton: false,
fixedWidth: false,
@ -91,7 +91,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
checked={canContact}
onChange={(e) => setCanContact((e.target as HTMLInputElement).checked)}
>
{_t("You may contact me if you have any follow up questions")}
{_t("feedback|can_contact_label")}
</StyledCheckbox>
</React.Fragment>
}

View file

@ -176,31 +176,19 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
}
const userDetailText = [
<p key="p1">
{_t(
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
)}
</p>,
<p key="p1">{_t("encryption|verification|incoming_sas_user_dialog_text_1")}</p>,
<p key="p2">
{_t(
// NB. Below wording adjusted to singular 'session' until we have
// cross-signing
"Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
"encryption|verification|incoming_sas_user_dialog_text_2",
)}
</p>,
];
const selfDetailText = [
<p key="p1">
{_t(
"Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.",
)}
</p>,
<p key="p2">
{_t(
"Verifying this device will mark it as trusted, and users who have verified with you will trust this device.",
)}
</p>,
<p key="p1">{_t("encryption|verification|incoming_sas_device_dialog_text_1")}</p>,
<p key="p2">{_t("encryption|verification|incoming_sas_device_dialog_text_2")}</p>,
];
return (
@ -234,7 +222,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
return (
<div>
<Spinner />
<p>{_t("Waiting for partner to confirm…")}</p>
<p>{_t("encryption|verification|incoming_sas_dialog_waiting")}</p>
</div>
);
}
@ -268,7 +256,11 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
}
return (
<BaseDialog title={_t("Incoming Verification Request")} onFinished={this.onFinished} fixedWidth={false}>
<BaseDialog
title={_t("encryption|verification|incoming_sas_dialog_title")}
onFinished={this.onFinished}
fixedWidth={false}
>
{body}
</BaseDialog>
);

View file

@ -42,11 +42,11 @@ export default class IntegrationsDisabledDialog extends React.Component<IProps>
className="mx_IntegrationsDisabledDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Integrations are disabled")}
title={_t("integrations|disabled_dialog_title")}
>
<div className="mx_IntegrationsDisabledDialog_content">
<p>
{_t("Enable '%(manageIntegrations)s' in Settings to do this.", {
{_t("integrations|disabled_dialog_description", {
manageIntegrations: _t("integration_manager|manage_title"),
})}
</p>

View file

@ -38,15 +38,10 @@ export default class IntegrationsImpossibleDialog extends React.Component<IProps
className="mx_IntegrationsImpossibleDialog"
hasCancel={false}
onFinished={this.props.onFinished}
title={_t("Integrations not allowed")}
title={_t("integrations|impossible_dialog_title")}
>
<div className="mx_IntegrationsImpossibleDialog_content">
<p>
{_t(
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.",
{ brand },
)}
</p>
<p>{_t("integrations|impossible_dialog_description", { brand })}</p>
</div>
<DialogButtons
primaryButton={_t("action|ok")}

View file

@ -98,13 +98,13 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
const ssoAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("auth|uia|sso_title"),
body: _t("To continue, use Single Sign On to prove your identity."),
body: _t("auth|uia|sso_preauth_body"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {
title: _t("Confirm to continue"),
body: _t("Click the button below to confirm your identity."),
title: _t("auth|uia|sso_postauth_title"),
body: _t("auth|uia|sso_postauth_body"),
continueText: _t("action|confirm"),
continueKind: "primary",
},

View file

@ -271,7 +271,7 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
});
const caption = (this.props.member as ThreepidMember).isEmail
? _t("Invite by email")
? _t("invite|email_caption")
: this.highlightName(userIdentifier || this.props.member.userId);
return (
@ -566,7 +566,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
logger.error(err);
this.setState({
busy: false,
errorText: _t("We couldn't create your DM."),
errorText: _t("invite|error_dm"),
});
}
};
@ -584,11 +584,9 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
onGiveUp: () => {
this.setBusy(false);
},
description: _t(
"Unable to find profiles for the Matrix IDs listed below - would you like to start a DM anyway?",
),
inviteNeverWarnLabel: _t("Start DM anyway and never warn me again"),
inviteLabel: _t("Start DM anyway"),
description: _t("invite|ask_anyway_description"),
inviteNeverWarnLabel: _t("invite|ask_anyway_never_warn_label"),
inviteLabel: _t("invite|ask_anyway_label"),
});
}
@ -605,7 +603,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
logger.error("Failed to find the room to invite users to");
this.setState({
busy: false,
errorText: _t("Something went wrong trying to invite the users."),
errorText: _t("invite|error_find_room"),
});
return;
}
@ -620,9 +618,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
logger.error(err);
this.setState({
busy: false,
errorText: _t(
"We couldn't invite those users. Please check the users you want to invite and try again.",
),
errorText: _t("invite|error_invite"),
});
}
};
@ -635,7 +631,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
const targetIds = targets.map((t) => t.userId);
if (targetIds.length > 1) {
this.setState({
errorText: _t("A call can only be transferred to a single user."),
errorText: _t("invite|error_transfer_multiple_target"),
});
return;
}
@ -940,11 +936,8 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
if (failed.length > 0) {
Modal.createDialog(QuestionDialog, {
title: _t("Failed to find the following users"),
description: _t(
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
{ csvNames: failed.join(", ") },
),
title: _t("invite|error_find_user_title"),
description: _t("invite|error_find_user_description", { csvNames: failed.join(", ") }),
button: _t("action|ok"),
});
}
@ -991,10 +984,10 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
let showNum = kind === "recents" ? this.state.numRecentsShown : this.state.numSuggestionsShown;
const showMoreFn = kind === "recents" ? this.showMoreRecents.bind(this) : this.showMoreSuggestions.bind(this);
const lastActive = (m: Result): number | undefined => (kind === "recents" ? m.lastActive : undefined);
let sectionName = kind === "recents" ? _t("Recent Conversations") : _t("common|suggestions");
let sectionName = kind === "recents" ? _t("invite|recents_section") : _t("common|suggestions");
if (this.props.kind === InviteKind.Invite) {
sectionName = kind === "recents" ? _t("Recently Direct Messaged") : _t("common|suggestions");
sectionName = kind === "recents" ? _t("invite|suggestions_section") : _t("common|suggestions");
}
// Mix in the server results if we have any, but only if we're searching. We track the additional
@ -1134,7 +1127,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
return (
<div className="mx_InviteDialog_identityServer">
{_t(
"Use an identity server to invite by email. <default>Use the default (%(defaultIdentityServerName)s)</default> or manage in <settings>Settings</settings>.",
"invite|email_use_default_is",
{
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
},
@ -1157,7 +1150,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
return (
<div className="mx_InviteDialog_identityServer">
{_t(
"Use an identity server to invite by email. Manage in <settings>Settings</settings>.",
"invite|email_use_is",
{},
{
settings: (sub) => (
@ -1281,11 +1274,11 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
const cli = MatrixClientPeg.safeGet();
const userId = cli.getUserId()!;
if (this.props.kind === InviteKind.Dm) {
title = _t("Direct Messages");
title = _t("space|add_existing_room_space|dm_heading");
if (identityServersEnabled) {
helpText = _t(
"Start a conversation with someone using their name, email address or username (like <userId/>).",
"invite|start_conversation_name_email_mxid_prompt",
{},
{
userId: () => {
@ -1299,7 +1292,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
);
} else {
helpText = _t(
"Start a conversation with someone using their name or username (like <userId/>).",
"invite|start_conversation_name_mxid_prompt",
{},
{
userId: () => {
@ -1317,14 +1310,14 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
goButtonFn = this.checkProfileAndStartDm;
extraSection = (
<div className="mx_InviteDialog_section_hidden_suggestions_disclaimer">
<span>{_t("Some suggestions may be hidden for privacy.")}</span>
<p>{_t("If you can't see who you're looking for, send them your invite link below.")}</p>
<span>{_t("invite|suggestions_disclaimer")}</span>
<p>{_t("invite|suggestions_disclaimer_prompt")}</p>
</div>
);
const link = makeUserPermalink(MatrixClientPeg.safeGet().getSafeUserId());
footer = (
<div className="mx_InviteDialog_footer">
<h3>{_t("Or send invite link")}</h3>
<h3>{_t("invite|send_link_prompt")}</h3>
<CopyableText getTextToCopy={() => makeUserPermalink(MatrixClientPeg.safeGet().getSafeUserId())}>
<a className="mx_InviteDialog_footer_link" href={link} onClick={this.onLinkClick}>
{link}
@ -1340,30 +1333,22 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
? _t("invite|to_space", {
spaceName: room?.name || _t("common|unnamed_space"),
})
: _t("Invite to %(roomName)s", {
: _t("invite|to_room", {
roomName: room?.name || _t("common|unnamed_room"),
});
let helpTextUntranslated;
if (isSpace) {
if (identityServersEnabled) {
helpTextUntranslated = _td(
"Invite someone using their name, email address, username (like <userId/>) or <a>share this space</a>.",
);
helpTextUntranslated = _td("invite|name_email_mxid_share_space");
} else {
helpTextUntranslated = _td(
"Invite someone using their name, username (like <userId/>) or <a>share this space</a>.",
);
helpTextUntranslated = _td("invite|name_mxid_share_space");
}
} else {
if (identityServersEnabled) {
helpTextUntranslated = _td(
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.",
);
helpTextUntranslated = _td("invite|name_email_mxid_share_room");
} else {
helpTextUntranslated = _td(
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.",
);
helpTextUntranslated = _td("invite|name_mxid_share_room");
}
}
@ -1401,19 +1386,19 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
keySharingWarning = (
<p className="mx_InviteDialog_helpText">
<InfoIcon height={14} width={14} />
{" " + _t("Invited people will be able to read old messages.")}
{" " + _t("invite|key_share_warning")}
</p>
);
}
}
} else if (this.props.kind === InviteKind.CallTransfer) {
title = _t("Transfer");
title = _t("action|transfer");
consultConnectSection = (
<div className="mx_InviteDialog_transferConsultConnect">
<label>
<input type="checkbox" checked={this.state.consultFirst} onChange={this.onConsultFirstChange} />
{_t("Consult first")}
{_t("voip|transfer_consult_first_label")}
</label>
<AccessibleButton
kind="secondary"
@ -1427,7 +1412,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
onClick={this.transferCall}
disabled={!hasSelection && this.state.dialPadValue === ""}
>
{_t("Transfer")}
{_t("action|transfer")}
</AccessibleButton>
</div>
);
@ -1450,11 +1435,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
if (!this.canInviteMore() || (this.hasFilterAtLeastOneEmail() && !this.canInviteThirdParty())) {
// We are in DM case here, because of the checks in canInviteMore() / canInviteThirdParty().
onlyOneThreepidNote = (
<div className="mx_InviteDialog_oneThreepid">
{_t("Invites by email can only be sent one at a time")}
</div>
);
onlyOneThreepidNote = <div className="mx_InviteDialog_oneThreepid">{_t("invite|email_limit_one")}</div>;
} else {
results = (
<div className="mx_InviteDialog_userSections">
@ -1487,7 +1468,12 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
let dialogContent;
if (this.props.kind === InviteKind.CallTransfer) {
const tabs: NonEmptyArray<Tab<TabId>> = [
new Tab(TabId.UserDirectory, _td("User Directory"), "mx_InviteDialog_userDirectoryIcon", usersSection),
new Tab(
TabId.UserDirectory,
_td("invite|transfer_user_directory_tab"),
"mx_InviteDialog_userDirectoryIcon",
usersSection,
),
];
const backspaceButton = <DialPadBackspaceButton onBackspacePress={this.onDeletePress} />;
@ -1525,7 +1511,14 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
<Dialpad hasDial={false} onDigitPress={this.onDigitPress} onDeletePress={this.onDeletePress} />
</div>
);
tabs.push(new Tab(TabId.DialPad, _td("Dial pad"), "mx_InviteDialog_dialPadIcon", dialPadSection));
tabs.push(
new Tab(
TabId.DialPad,
_td("invite|transfer_dial_pad_tab"),
"mx_InviteDialog_dialPadIcon",
dialPadSection,
),
);
dialogContent = (
<React.Fragment>
<TabbedView

View file

@ -47,11 +47,11 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
const onCancel = useRef(onFinished);
const causes = new Map([
["_afterCrossSigningLocalKeyChange", _t("a new master key signature")],
["checkOwnCrossSigningTrust", _t("a new cross-signing key signature")],
["setDeviceVerification", _t("a device cross-signing signature")],
["_afterCrossSigningLocalKeyChange", _t("encryption|key_signature_upload_failed_master_key_signature")],
["checkOwnCrossSigningTrust", _t("encryption|key_signature_upload_failed_cross_signing_key_signature")],
["setDeviceVerification", _t("encryption|key_signature_upload_failed_device_cross_signing_key_signature")],
]);
const defaultCause = _t("a key signature");
const defaultCause = _t("encryption|key_signature_upload_failed_key_signature");
const onRetry = useCallback(async (): Promise<void> => {
try {
@ -78,7 +78,7 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
body = (
<div>
<p>{_t("%(brand)s encountered an error during upload of:", { brand })}</p>
<p>{_t("encryption|key_signature_upload_failed_body", { brand })}</p>
<p>{reason}</p>
{retrying && <Spinner />}
<pre>{JSON.stringify(failures, null, 2)}</pre>
@ -92,9 +92,11 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
</div>
);
} else {
let text = _t("Upload completed");
let text = _t("encryption|key_signature_upload_completed");
if (!success) {
text = cancelled ? _t("Cancelled signature upload") : _t("Unable to upload");
text = cancelled
? _t("encryption|key_signature_upload_cancelled")
: _t("encryption|key_signature_upload_failed");
}
body = (
@ -107,7 +109,11 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
return (
<BaseDialog
title={success ? _t("Signature upload success") : _t("Signature upload failed")}
title={
success
? _t("encryption|key_signature_upload_success_title")
: _t("encryption|key_signature_upload_failed_title")
}
fixedWidth={false}
onFinished={() => {}}
>

View file

@ -28,31 +28,25 @@ interface IProps {
const LazyLoadingDisabledDialog: React.FC<IProps> = (props) => {
const brand = SdkConfig.get().brand;
const description1 = _t(
"You've previously used %(brand)s on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, %(brand)s needs to resync your account.",
{
const description1 = _t("lazy_loading|disabled_description1", {
brand,
host: props.host,
},
);
const description2 = _t(
"If the other version of %(brand)s is still open in another tab, please close it as using %(brand)s on the same host with both lazy loading enabled and disabled simultaneously will cause issues.",
{
});
const description2 = _t("lazy_loading|disabled_description2", {
brand,
},
);
});
return (
<QuestionDialog
hasCancelButton={false}
title={_t("Incompatible local cache")}
title={_t("lazy_loading|disabled_title")}
description={
<div>
<p>{description1}</p>
<p>{description2}</p>
</div>
}
button={_t("Clear cache and resync")}
button={_t("lazy_loading|disabled_action")}
onFinished={props.onFinished}
/>
);

View file

@ -27,15 +27,12 @@ interface IProps {
const LazyLoadingResyncDialog: React.FC<IProps> = (props) => {
const brand = SdkConfig.get().brand;
const description = _t(
"%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!",
{ brand },
);
const description = _t("lazy_loading|resync_description", { brand });
return (
<QuestionDialog
hasCancelButton={false}
title={_t("Updating %(brand)s", { brand })}
title={_t("lazy_loading|resync_title", { brand })}
description={<div>{description}</div>}
button={_t("action|ok")}
onFinished={props.onFinished}

View file

@ -58,24 +58,22 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
let rejoinWarning;
if (space.getJoinRule() !== JoinRule.Public) {
rejoinWarning = _t("You won't be able to rejoin unless you are re-invited.");
rejoinWarning = _t("space|leave_dialog_public_rejoin_warning");
}
let onlyAdminWarning;
if (isOnlyAdmin(space)) {
onlyAdminWarning = _t("You're the only admin of this space. Leaving it will mean no one has control over it.");
onlyAdminWarning = _t("space|leave_dialog_only_admin_warning");
} else {
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdmin).length;
if (numChildrenOnlyAdminIn > 0) {
onlyAdminWarning = _t(
"You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.",
);
onlyAdminWarning = _t("space|leave_dialog_only_admin_room_warning");
}
}
return (
<BaseDialog
title={_t("Leave %(spaceName)s", { spaceName: space.name })}
title={_t("space|leave_dialog_title", { spaceName: space.name })}
className="mx_LeaveSpaceDialog"
contentId="mx_LeaveSpaceDialog"
onFinished={() => onFinished(false)}
@ -84,7 +82,7 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
<div className="mx_Dialog_content" id="mx_LeaveSpaceDialog">
<p>
{_t(
"You are about to leave <spaceName/>.",
"space|leave_dialog_description",
{},
{
spaceName: () => <b>{space.name}</b>,
@ -93,7 +91,7 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
&nbsp;
{rejoinWarning}
{rejoinWarning && <>&nbsp;</>}
{spaceChildren.length > 0 && _t("Would you like to leave the rooms in this space?")}
{spaceChildren.length > 0 && _t("space|leave_dialog_option_intro")}
</p>
{spaceChildren.length > 0 && (
@ -102,16 +100,16 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
spaceChildren={spaceChildren}
selected={selectedRooms}
onChange={setRoomsToLeave}
noneLabel={_t("Don't leave any rooms")}
allLabel={_t("Leave all rooms")}
specificLabel={_t("Leave some rooms")}
noneLabel={_t("space|leave_dialog_option_none")}
allLabel={_t("space|leave_dialog_option_all")}
specificLabel={_t("space|leave_dialog_option_specific")}
/>
)}
{onlyAdminWarning && <div className="mx_LeaveSpaceDialog_section_warning">{onlyAdminWarning}</div>}
</div>
<DialogButtons
primaryButton={_t("Leave space")}
primaryButton={_t("space|leave_dialog_action")}
primaryButtonClass="danger"
onPrimaryButtonClick={() => onFinished(true, roomsToLeave)}
hasCancel={true}

View file

@ -166,16 +166,8 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
private renderSetupBackupDialog(): React.ReactNode {
const description = (
<div>
<p>
{_t(
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
)}
</p>
<p>
{_t(
"When you sign out, these keys will be deleted from this device, which means you won't be able to read encrypted messages unless you have the keys for them on your other devices, or backed them up to the server.",
)}
</p>
<p>{_t("auth|logout_dialog|setup_secure_backup_description_1")}</p>
<p>{_t("auth|logout_dialog|setup_secure_backup_description_2")}</p>
<p>{_t("encryption|setup_secure_backup|explainer")}</p>
</div>
);
@ -186,7 +178,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
} else {
// if there's an error fetching the backup info, we'll just assume there's
// no backup for the purpose of the button caption
setupButtonCaption = _t("Start using Key Backup");
setupButtonCaption = _t("auth|logout_dialog|use_key_backup");
}
const dialogContent = (
@ -200,12 +192,12 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
onPrimaryButtonClick={this.onSetRecoveryMethodClick}
focus={true}
>
<button onClick={this.onLogoutConfirm}>{_t("I don't want my encrypted messages")}</button>
<button onClick={this.onLogoutConfirm}>{_t("auth|logout_dialog|skip_key_backup")}</button>
</DialogButtons>
<details>
<summary>{_t("common|advanced")}</summary>
<p>
<button onClick={this.onExportE2eKeysClicked}>{_t("Manually export keys")}</button>
<button onClick={this.onExportE2eKeysClicked}>{_t("auth|logout_dialog|megolm_export")}</button>
</p>
</details>
</div>
@ -215,7 +207,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
// confirms the action.
return (
<BaseDialog
title={_t("You'll lose access to your encrypted messages")}
title={_t("auth|logout_dialog|setup_key_backup_title")}
contentId="mx_Dialog_content"
hasCancel={true}
onFinished={this.onFinished}
@ -246,7 +238,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
<QuestionDialog
hasCancelButton={true}
title={_t("action|sign_out")}
description={_t("Are you sure you want to sign out?")}
description={_t("auth|logout_dialog|description")}
button={_t("action|sign_out")}
onFinished={this.onFinished}
/>

View file

@ -43,10 +43,10 @@ const Entry: React.FC<{
let description;
if (localRoom) {
description = _t("%(count)s members", { count: room.getJoinedMemberCount() });
description = _t("common|n_members", { count: room.getJoinedMemberCount() });
const numChildRooms = SpaceStore.instance.getChildRooms(room.roomId).length;
if (numChildRooms > 0) {
description += " · " + _t("%(count)s rooms", { count: numChildRooms });
description += " · " + _t("common|n_rooms", { count: numChildRooms });
}
}
@ -132,7 +132,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
if (newSelected.size < 1) {
inviteOnlyWarning = (
<div className="mx_ManageRestrictedJoinRuleDialog_section_info">
{_t("You're removing all spaces. Access will default to invite only")}
{_t("room_settings|security|join_rule_restricted_dialog_empty_warning")}
</div>
);
}
@ -141,14 +141,14 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
filteredSpacesContainingRoom.length + filteredOtherJoinedSpaces.length + filteredOtherEntries.length;
return (
<BaseDialog
title={_t("Select spaces")}
title={_t("room_settings|security|join_rule_restricted_dialog_title")}
className="mx_ManageRestrictedJoinRuleDialog"
onFinished={onFinished}
fixedWidth={false}
>
<p>
{_t(
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.",
"room_settings|security|join_rule_restricted_dialog_description",
{},
{
RoomName: () => <b>{room.name}</b>,
@ -158,7 +158,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
<MatrixClientContext.Provider value={cli}>
<SearchBox
className="mx_textinput_icon mx_textinput_search"
placeholder={_t("Search spaces")}
placeholder={_t("room_settings|security|join_rule_restricted_dialog_filter_placeholder")}
onSearch={setQuery}
autoFocus={true}
/>
@ -167,8 +167,8 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
<div className="mx_ManageRestrictedJoinRuleDialog_section">
<h3>
{room.isSpaceRoom()
? _t("Spaces you know that contain this space")
: _t("Spaces you know that contain this room")}
? _t("room_settings|security|join_rule_restricted_dialog_heading_space")
: _t("room_settings|security|join_rule_restricted_dialog_heading_room")}
</h3>
{filteredSpacesContainingRoom.map((space) => {
return (
@ -187,9 +187,9 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
{filteredOtherEntries.length > 0 ? (
<div className="mx_ManageRestrictedJoinRuleDialog_section">
<h3>{_t("Other spaces or rooms you might not know")}</h3>
<h3>{_t("room_settings|security|join_rule_restricted_dialog_heading_other")}</h3>
<div className="mx_ManageRestrictedJoinRuleDialog_section_info">
<div>{_t("These are likely ones other room admins are a part of.")}</div>
<div>{_t("room_settings|security|join_rule_restricted_dialog_heading_unknown")}</div>
</div>
{filteredOtherEntries.map((space) => {
return (
@ -208,7 +208,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
{filteredOtherJoinedSpaces.length > 0 ? (
<div className="mx_ManageRestrictedJoinRuleDialog_section">
<h3>{_t("Other spaces you know")}</h3>
<h3>{_t("room_settings|security|join_rule_restricted_dialog_heading_known")}</h3>
{filteredOtherJoinedSpaces.map((space) => {
return (
<Entry

View file

@ -51,9 +51,9 @@ export function ManualDeviceKeyVerificationDialog({
let text;
if (mxClient?.getUserId() === userId) {
text = _t("Confirm by comparing the following with the User Settings in your other session:");
text = _t("encryption|verification|manual_device_verification_self_text");
} else {
text = _t("Confirm this user's session by comparing the following with their User Settings:");
text = _t("encryption|verification|manual_device_verification_user_text");
}
const fingerprint = device.getFingerprint();
@ -64,16 +64,17 @@ export function ManualDeviceKeyVerificationDialog({
<div className="mx_DeviceVerifyDialog_cryptoSection">
<ul>
<li>
<label>{_t("Session name")}:</label> <span>{device.displayName}</span>
<label>{_t("encryption|verification|manual_device_verification_device_name_label")}:</label>{" "}
<span>{device.displayName}</span>
</li>
<li>
<label>{_t("Session ID")}:</label>{" "}
<label>{_t("encryption|verification|manual_device_verification_device_id_label")}:</label>{" "}
<span>
<code>{device.deviceId}</code>
</span>
</li>
<li>
<label>{_t("Session key")}:</label>{" "}
<label>{_t("encryption|verification|manual_device_verification_device_key_label")}:</label>{" "}
<span>
<code>
<b>{key}</b>
@ -82,7 +83,7 @@ export function ManualDeviceKeyVerificationDialog({
</li>
</ul>
</div>
<p>{_t("If they don't match, the security of your communication may be compromised.")}</p>
<p>{_t("encryption|verification|manual_device_verification_footer")}</p>
</div>
);

View file

@ -154,11 +154,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
if (this.state.error) {
const { error } = this.state;
if (error.errcode === "M_UNRECOGNIZED") {
content = (
<p className="mx_MessageEditHistoryDialog_error">
{_t("Your homeserver doesn't seem to support this feature.")}
</p>
);
content = <p className="mx_MessageEditHistoryDialog_error">{_t("error|edit_history_unsupported")}</p>;
} else if (error.errcode) {
// some kind of error from the homeserver
content = <p className="mx_MessageEditHistoryDialog_error">{_t("error|something_went_wrong")}</p>;
@ -190,7 +186,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
className="mx_MessageEditHistoryDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Message edits")}
title={_t("message_edit_dialog_title")}
>
{content}
</BaseDialog>

View file

@ -187,7 +187,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
return (
<BaseDialog
title={this.props.widgetDefinition.name || _t("Modal Widget")}
title={this.props.widgetDefinition.name || _t("widget|modal_title_default")}
className="mx_ModalWidgetDialog"
contentId="mx_Dialog_content"
onFinished={this.props.onFinished}
@ -199,7 +199,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
width="16"
alt=""
/>
{_t("Data on this screen is shared with %(widgetDomain)s", {
{_t("widget|modal_data_warning", {
widgetDomain: parsed.hostname,
})}
</div>

View file

@ -50,7 +50,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
return (
<BaseDialog
title={_t("Continuing without email")}
title={_t("auth|registration|continue_without_email_title")}
className="mx_RegistrationEmailPromptDialog"
contentId="mx_RegistrationEmailPromptDialog"
onFinished={() => onFinished(false)}
@ -59,7 +59,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
<div className="mx_Dialog_content" id="mx_RegistrationEmailPromptDialog">
<p>
{_t(
"Just a heads up, if you don't add an email and forget your password, you could <b>permanently lose access to your account</b>.",
"auth|registration|continue_without_email_description",
{},
{
b: (sub) => <b>{sub}</b>,
@ -70,7 +70,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
<EmailField
fieldRef={fieldRef}
autoFocus={true}
label={_td("Email (optional)")}
label={_td("auth|registration|continue_without_email_field_label")}
value={email}
onChange={(ev) => {
const target = ev.target as HTMLInputElement;

View file

@ -246,7 +246,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
// as configured in the room's state events.
const dmRoomId = await ensureDMExists(client, this.moderation.moderationBotUserId);
if (!dmRoomId) {
throw new UserFriendlyError("Unable to create room with moderation bot");
throw new UserFriendlyError("report_content|error_create_room_moderation_bot");
}
await client.sendEvent(dmRoomId, ABUSE_EVENT_TYPE, {
@ -320,37 +320,25 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
subtitle = _t("report_content|nature_disagreement");
break;
case Nature.Toxic:
subtitle = _t(
"This user is displaying toxic behaviour, for instance by insulting other users or sharing adult-only content in a family-friendly room or otherwise violating the rules of this room.\nThis will be reported to the room moderators.",
);
subtitle = _t("report_content|nature_toxic");
break;
case Nature.Illegal:
subtitle = _t(
"This user is displaying illegal behaviour, for instance by doxing people or threatening violence.\nThis will be reported to the room moderators who may escalate this to legal authorities.",
);
subtitle = _t("report_content|nature_illegal");
break;
case Nature.Spam:
subtitle = _t(
"This user is spamming the room with ads, links to ads or to propaganda.\nThis will be reported to the room moderators.",
);
subtitle = _t("report_content|nature_spam");
break;
case NonStandardValue.Admin:
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId()!)) {
subtitle = _t(
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\nThis will be reported to the administrators of %(homeserver)s. The administrators will NOT be able to read the encrypted content of this room.",
{ homeserver: homeServerName },
);
subtitle = _t("report_content|nature_nonstandard_admin_encrypted", {
homeserver: homeServerName,
});
} else {
subtitle = _t(
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\nThis will be reported to the administrators of %(homeserver)s.",
{ homeserver: homeServerName },
);
subtitle = _t("report_content|nature_nonstandard_admin", { homeserver: homeServerName });
}
break;
case Nature.Other:
subtitle = _t(
"Any other reason. Please describe the problem.\nThis will be reported to the room moderators.",
);
subtitle = _t("report_content|nature_other");
break;
default:
subtitle = _t("report_content|nature");
@ -411,7 +399,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
checked={this.state.nature == Nature.Other}
onChange={this.onNatureChosen}
>
{_t("Other")}
{_t("report_content|other_label")}
</StyledRadioButton>
<p>{subtitle}</p>
<Field
@ -447,11 +435,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
contentId="mx_ReportEventDialog"
>
<div className="mx_ReportEventDialog" id="mx_ReportEventDialog">
<p>
{_t(
"Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.",
)}
</p>
<p>{_t("report_content|description")}</p>
{adminMessage}
<Field
className="mx_ReportEventDialog_reason"

View file

@ -241,7 +241,7 @@ class RoomSettingsDialog extends React.Component<IProps, IState> {
className="mx_RoomSettingsDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Room Settings - %(roomName)s", { roomName })}
title={_t("room_settings|title", { roomName })}
>
<div className="mx_SettingsDialog_content">
<TabbedView

View file

@ -59,8 +59,9 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
})
.catch((err) => {
Modal.createDialog(ErrorDialog, {
title: _t("Failed to upgrade room"),
description: err && err.message ? err.message : _t("The room upgrade could not be completed"),
title: _t("room_settings|advanced|error_upgrade_title"),
description:
err && err.message ? err.message : _t("room_settings|advanced|error_upgrade_description"),
});
})
.finally(() => {
@ -75,7 +76,7 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
} else {
buttons = (
<DialogButtons
primaryButton={_t("Upgrade this room to version %(version)s", { version: this.targetVersion })}
primaryButton={_t("room_settings|advanced|upgrade_button", { version: this.targetVersion })}
primaryButtonClass="danger"
hasCancel={true}
onPrimaryButtonClick={this.onUpgradeClick}
@ -88,28 +89,16 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
<BaseDialog
className="mx_RoomUpgradeDialog"
onFinished={this.props.onFinished}
title={_t("Upgrade Room Version")}
title={_t("room_settings|advanced|upgrade_dialog_title")}
contentId="mx_Dialog_content"
hasCancel={true}
>
<p>
{_t(
"Upgrading this room requires closing down the current instance of the room and creating a new room in its place. To give room members the best possible experience, we will:",
)}
</p>
<p>{_t("room_settings|advanced|upgrade_dialog_description")}</p>
<ol>
<li>{_t("Create a new room with the same name, description and avatar")}</li>
<li>{_t("Update any local room aliases to point to the new room")}</li>
<li>
{_t(
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room",
)}
</li>
<li>
{_t(
"Put a link back to the old room at the start of the new room so people can see old messages",
)}
</li>
<li>{_t("room_settings|advanced|upgrade_dialog_description_1")}</li>
<li>{_t("room_settings|advanced|upgrade_dialog_description_2")}</li>
<li>{_t("room_settings|advanced|upgrade_dialog_description_3")}</li>
<li>{_t("room_settings|advanced|upgrade_dialog_description_4")}</li>
</ol>
{buttons}
</BaseDialog>

View file

@ -115,7 +115,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
<LabelledToggleSwitch
value={this.state.inviteUsersToNewRoom}
onChange={this.onInviteUsersToggle}
label={_t("Automatically invite members from this room to the new one")}
label={_t("room_settings|advanced|upgrade_warning_dialog_invite_label")}
/>
);
}
@ -123,28 +123,21 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
let title: string;
switch (this.joinRule) {
case JoinRule.Invite:
title = _t("Upgrade private room");
title = _t("room_settings|advanced|upgrade_warning_dialog_title_private");
break;
case JoinRule.Public:
title = _t("Upgrade public room");
title = _t("room_settings|advanced|upgrade_dwarning_ialog_title_public");
break;
default:
title = _t("Upgrade room");
title = _t("room_settings|advanced|upgrade_warning_dialog_title");
}
let bugReports = (
<p>
{_t(
"This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.",
{ brand },
)}
</p>
);
let bugReports = <p>{_t("room_settings|advanced|upgrade_warning_dialog_report_bug_prompt", { brand })}</p>;
if (SdkConfig.get().bug_report_endpoint_url) {
bugReports = (
<p>
{_t(
"This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please <a>report a bug</a>.",
"room_settings|advanced|upgrade_warning_dialog_report_bug_prompt_link",
{
brand,
},
@ -190,15 +183,10 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
title={title}
>
<div>
<p>
{this.props.description ||
_t(
"Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.",
)}
</p>
<p>{this.props.description || _t("room_settings|advanced|upgrade_warning_dialog_description")}</p>
<p>
{_t(
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.",
"room_settings|advanced|upgrade_warning_dialog_explainer",
{},
{
b: (sub) => <b>{sub}</b>,
@ -208,7 +196,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
{bugReports}
<p>
{_t(
"You'll upgrade this room from <oldVersion /> to <newVersion />.",
"room_settings|advanced|upgrade_warning_dialog_footer",
{},
{
oldVersion: () => <code>{this.currentVersion}</code>,

View file

@ -97,7 +97,7 @@ export default abstract class ScrollableBaseModal<
<AccessibleButton
onClick={this.onCancel}
className="mx_CompoundDialog_cancelButton"
aria-label={_t("Close dialog")}
aria-label={_t("dialog_close_label")}
/>
</div>
<form onSubmit={this.onSubmit} className="mx_CompoundDialog_form">

View file

@ -92,36 +92,32 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
public render(): React.ReactNode {
let timeline = this.renderTimeline().filter((c) => !!c); // remove nulls for next check
if (timeline.length === 0) {
timeline = [<div key={1}>{_t("You're all caught up.")}</div>];
timeline = [<div key={1}>{_t("server_offline|empty_timeline")}</div>];
}
const serverName = MatrixClientPeg.getHomeserverName();
return (
<BaseDialog
title={_t("Server isn't responding")}
title={_t("server_offline|title")}
className="mx_ServerOfflineDialog"
contentId="mx_Dialog_content"
onFinished={this.props.onFinished}
hasCancel={true}
>
<div className="mx_ServerOfflineDialog_content">
<p>
{_t(
"Your server isn't responding to some of your requests. Below are some of the most likely reasons.",
)}
</p>
<p>{_t("server_offline|description")}</p>
<ul>
<li>{_t("The server (%(serverName)s) took too long to respond.", { serverName })}</li>
<li>{_t("Your firewall or anti-virus is blocking the request.")}</li>
<li>{_t("A browser extension is preventing the request.")}</li>
<li>{_t("The server is offline.")}</li>
<li>{_t("The server has denied your request.")}</li>
<li>{_t("Your area is experiencing difficulties connecting to the internet.")}</li>
<li>{_t("A connection error occurred while trying to contact the server.")}</li>
<li>{_t("The server is not configured to indicate what the problem is (CORS).")}</li>
<li>{_t("server_offline|description_1", { serverName })}</li>
<li>{_t("server_offline|description_2")}</li>
<li>{_t("server_offline|description_3")}</li>
<li>{_t("server_offline|description_4")}</li>
<li>{_t("server_offline|description_5")}</li>
<li>{_t("server_offline|description_6")}</li>
<li>{_t("server_offline|description_7")}</li>
<li>{_t("server_offline|description_8")}</li>
</ul>
<hr />
<h2>{_t("Recent changes that have not yet been received")}</h2>
<h2>{_t("server_offline|recent_changes_heading")}</h2>
{timeline}
</div>
</BaseDialog>

View file

@ -30,19 +30,17 @@ export default class SeshatResetDialog extends React.PureComponent<Props> {
<BaseDialog
hasCancel={true}
onFinished={this.props.onFinished.bind(null, false)}
title={_t("Reset event store?")}
title={_t("seshat|reset_title")}
>
<div>
<p>
{_t("You most likely do not want to reset your event index store")}
{_t("seshat|reset_description")}
<br />
{_t(
"If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated",
)}
{_t("seshat|reset_explainer")}
</p>
</div>
<DialogButtons
primaryButton={_t("Reset event store")}
primaryButton={_t("seshat|reset_button")}
onPrimaryButtonClick={this.props.onFinished.bind(null, true)}
primaryButtonClass="danger"
cancelButton={_t("action|cancel")}

View file

@ -41,7 +41,7 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
private onClearStorageClick = (): void => {
Modal.createDialog(QuestionDialog, {
title: _t("action|sign_out"),
description: <div>{_t("Sign out and remove encryption keys?")}</div>,
description: <div>{_t("error|session_restore|clear_storage_description")}</div>,
button: _t("action|sign_out"),
danger: true,
onFinished: this.props.onFinished,
@ -59,7 +59,7 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
const clearStorageButton = (
<button onClick={this.onClearStorageClick} className="danger">
{_t("Clear Storage and Sign Out")}
{_t("error|session_restore|clear_storage_button")}
</button>
);
@ -92,25 +92,16 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
<BaseDialog
className="mx_ErrorDialog"
onFinished={this.props.onFinished}
title={_t("Unable to restore session")}
title={_t("error|session_restore|title")}
contentId="mx_Dialog_content"
hasCancel={false}
>
<div className="mx_Dialog_content" id="mx_Dialog_content">
<p>{_t("We encountered an error trying to restore your previous session.")}</p>
<p>{_t("error|session_restore|description_1")}</p>
<p>
{_t(
"If you have previously used a more recent version of %(brand)s, your session may be incompatible with this version. Close this window and return to the more recent version.",
{ brand },
)}
</p>
<p>{_t("error|session_restore|description_2", { brand })}</p>
<p>
{_t(
"Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.",
)}
</p>
<p>{_t("error|session_restore|description_3")}</p>
</div>
{dialogButtons}
</BaseDialog>

View file

@ -76,10 +76,8 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
this.addThreepid.addEmailAddress(emailAddress).then(
() => {
Modal.createDialog(QuestionDialog, {
title: _t("Verification Pending"),
description: _t(
"Please check your email and click on the link it contains. Once this is done, click continue.",
),
title: _t("auth|set_email|verification_pending_title"),
description: _t("auth|set_email|verification_pending_description"),
button: _t("action|continue"),
onFinished: this.onEmailDialogFinished,
});
@ -125,11 +123,9 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
const message =
_t("settings|general|error_email_verification") +
" " +
_t(
"Please check your email and click on the link it contains. Once this is done, click continue.",
);
_t("auth|set_email|verification_pending_description");
Modal.createDialog(QuestionDialog, {
title: _t("Verification Pending"),
title: _t("auth|set_email|verification_pending_title"),
description: message,
button: _t("action|continue"),
onFinished: this.onEmailDialogFinished,
@ -152,7 +148,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
<EditableText
initialValue={this.state.emailAddress}
className="mx_SetEmailDialog_email_input"
placeholder={_t("Email address")}
placeholder={_t("common|email_address")}
placeholderClassName="mx_SetEmailDialog_email_input_placeholder"
blurToCancel={false}
onValueChanged={this.onEmailAddressChanged}
@ -167,9 +163,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
contentId="mx_Dialog_content"
>
<div className="mx_Dialog_content">
<p id="mx_Dialog_content">
{_t("This will allow you to reset your password and receive notifications.")}
</p>
<p id="mx_Dialog_content">{_t("auth|set_email|description")}</p>
{emailInput}
</div>
<div className="mx_Dialog_buttons">

View file

@ -130,7 +130,7 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
let checkbox: JSX.Element | undefined;
if (this.props.target instanceof Room) {
title = _t("Share Room");
title = _t("share|title_room");
const events = this.props.target.getLiveTimeline().getEvents();
if (events.length > 0) {
@ -140,22 +140,22 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
checked={this.state.linkSpecificEvent}
onChange={this.onLinkSpecificEventCheckboxClick}
>
{_t("Link to most recent message")}
{_t("share|permalink_most_recent")}
</StyledCheckbox>
</div>
);
}
} else if (this.props.target instanceof User || this.props.target instanceof RoomMember) {
title = _t("Share User");
title = _t("share|title_user");
} else if (this.props.target instanceof MatrixEvent) {
title = _t("Share Room Message");
title = _t("share|title_message");
checkbox = (
<div>
<StyledCheckbox
checked={this.state.linkSpecificEvent}
onChange={this.onLinkSpecificEventCheckboxClick}
>
{_t("Link to selected message")}
{_t("share|permalink_message")}
</StyledCheckbox>
</div>
);
@ -208,7 +208,7 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
>
<div className="mx_ShareDialog_content">
<CopyableText getTextToCopy={() => matrixToUrl}>
<a title={_t("Link to room")} href={matrixToUrl} onClick={ShareDialog.onLinkClick}>
<a title={_t("share|link_title")} href={matrixToUrl} onClick={ShareDialog.onLinkClick}>
{matrixToUrl}
</a>
</CopyableText>

View file

@ -64,7 +64,7 @@ const SlashCommandHelpDialog: React.FC<IProps> = ({ onFinished }) => {
return (
<InfoDialog
className="mx_SlashCommandHelpDialog"
title={_t("Command Help")}
title={_t("slash_command|help_dialog_title")}
description={
<table>
<tbody>{body}</tbody>

View file

@ -77,7 +77,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
let nativeSupport: string;
if (hasNativeSupport === null) {
nativeSupport = _t("Checking…");
nativeSupport = _t("labs|sliding_sync_checking");
} else {
nativeSupport = hasNativeSupport
? _t("labs|sliding_sync_server_support")
@ -103,7 +103,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
key: "working",
final: true,
test: async (_, { error }) => !error,
valid: () => _t("Looks good"),
valid: () => _t("spotlight|public_rooms|network_dropdown_available_valid"),
invalid: ({ error }) => (error instanceof Error ? error.message : null),
},
],

View file

@ -42,7 +42,7 @@ const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space
return (
<SettingsTab>
<SettingsSection heading={_t("Sections to show")}>
<SettingsSection heading={_t("space|preferences|sections_section")}>
<SettingsSubsection>
<StyledCheckbox
checked={!!showPeople}
@ -58,12 +58,9 @@ const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space
{_t("common|people")}
</StyledCheckbox>
<SettingsSubsectionText>
{_t(
"This groups your chats with members of this space. Turning this off will hide those chats from your view of %(spaceName)s.",
{
{_t("space|preferences|show_people_in_space", {
spaceName: space.name,
},
)}
})}
</SettingsSubsectionText>
</SettingsSubsection>
</SettingsSection>

View file

@ -42,7 +42,7 @@ export default class StorageEvictedDialog extends React.Component<IProps> {
let logRequest;
if (SdkConfig.get().bug_report_endpoint_url) {
logRequest = _t(
"To help us prevent this in future, please <a>send us logs</a>.",
"bug_reporting|log_request",
{},
{
a: (text) => (
@ -58,18 +58,14 @@ export default class StorageEvictedDialog extends React.Component<IProps> {
<BaseDialog
className="mx_ErrorDialog"
onFinished={this.props.onFinished}
title={_t("Missing session data")}
title={_t("error|storage_evicted_title")}
contentId="mx_Dialog_content"
hasCancel={false}
>
<div className="mx_Dialog_content" id="mx_Dialog_content">
<p>{_t("error|storage_evicted_description_1")}</p>
<p>
{_t(
"Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.",
)}
</p>
<p>
{_t("Your browser likely removed this data when running low on disk space.")} {logRequest}
{_t("error|storage_evicted_description_2")} {logRequest}
</p>
</div>
<DialogButtons

View file

@ -111,9 +111,9 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
case SERVICE_TYPES.IS:
return (
<div>
{_t("Find others by phone or email")}
{_t("terms|summary_identity_server_1")}
<br />
{_t("Be found by phone or email")}
{_t("terms|summary_identity_server_2")}
</div>
);
case SERVICE_TYPES.IM:

View file

@ -35,14 +35,14 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
let newSessionText: string;
if (MatrixClientPeg.safeGet().getUserId() === user.userId) {
newSessionText = _t("You signed in to a new session without verifying it:");
askToVerifyText = _t("Verify your other session using one of the options below.");
newSessionText = _t("encryption|udd|own_new_session_text");
askToVerifyText = _t("encryption|udd|own_ask_verify_text");
} else {
newSessionText = _t("%(name)s (%(userId)s) signed in to a new session without verifying it:", {
newSessionText = _t("encryption|udd|other_new_session_text", {
name: user.displayName,
userId: user.userId,
});
askToVerifyText = _t("Ask this user to verify their session, or manually verify it below.");
askToVerifyText = _t("encryption|udd|other_ask_verify_text");
}
return (
@ -52,7 +52,7 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
title={
<>
<E2EIcon status={E2EState.Warning} isUser size={24} hideTooltip={true} />
{_t("Not Trusted")}
{_t("encryption|udd|title")}
</>
}
>
@ -65,10 +65,10 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
</div>
<div className="mx_Dialog_buttons">
<AccessibleButton kind="primary_outline" onClick={() => onFinished("legacy")}>
{_t("Manually verify by text")}
{_t("encryption|udd|manual_verification_button")}
</AccessibleButton>
<AccessibleButton kind="primary_outline" onClick={() => onFinished("sas")}>
{_t("Interactively verify by emoji")}
{_t("encryption|udd|interactive_verification_button")}
</AccessibleButton>
<AccessibleButton kind="primary" onClick={() => onFinished(false)}>
{_t("action|done")}

View file

@ -69,12 +69,12 @@ export default class UploadConfirmDialog extends React.Component<IProps> {
public render(): React.ReactNode {
let title: string;
if (this.props.totalFiles > 1 && this.props.currentIndex !== undefined) {
title = _t("Upload files (%(current)s of %(total)s)", {
title = _t("upload_file|title_progress", {
current: this.props.currentIndex + 1,
total: this.props.totalFiles,
});
} else {
title = _t("Upload files");
title = _t("upload_file|title");
}
const fileId = `mx-uploadconfirmdialog-${this.props.file.name}`;
@ -99,7 +99,7 @@ export default class UploadConfirmDialog extends React.Component<IProps> {
let uploadAllButton: JSX.Element | undefined;
if (this.props.currentIndex + 1 < this.props.totalFiles) {
uploadAllButton = <button onClick={this.onUploadAllClick}>{_t("Upload all")}</button>;
uploadAllButton = <button onClick={this.onUploadAllClick}>{_t("upload_file|upload_all_button")}</button>;
}
return (

View file

@ -49,7 +49,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
let buttons;
if (this.props.totalFiles === 1 && this.props.badFiles.length === 1) {
message = _t(
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.",
"upload_file|error_file_too_large",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
sizeOfThisFile: fileSize(this.props.badFiles[0].size),
@ -68,7 +68,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
);
} else if (this.props.totalFiles === this.props.badFiles.length) {
message = _t(
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.",
"upload_file|error_files_too_large",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
},
@ -86,7 +86,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
);
} else {
message = _t(
"Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.",
"upload_file|error_some_files_too_large",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
},
@ -97,10 +97,10 @@ export default class UploadFailureDialog extends React.Component<IProps> {
const howManyOthers = this.props.totalFiles - this.props.badFiles.length;
buttons = (
<DialogButtons
primaryButton={_t("Upload %(count)s other files", { count: howManyOthers })}
primaryButton={_t("upload_file|upload_n_others_button", { count: howManyOthers })}
onPrimaryButtonClick={this.onUploadClick}
hasCancel={true}
cancelButton={_t("Cancel All")}
cancelButton={_t("upload_file|cancel_all_button")}
onCancel={this.onCancelClick}
focus={true}
/>
@ -111,7 +111,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
<BaseDialog
className="mx_UploadFailureDialog"
onFinished={this.onCancelClick}
title={_t("Upload Error")}
title={_t("upload_file|error_title")}
contentId="mx_Dialog_content"
>
<div id="mx_Dialog_content">

View file

@ -49,7 +49,9 @@ export default class VerificationRequestDialog extends React.Component<IProps, I
const request = this.state.verificationRequest;
const otherUserId = request?.otherUserId;
const member = this.props.member || (otherUserId ? MatrixClientPeg.safeGet().getUser(otherUserId) : null);
const title = request?.isSelfVerification ? _t("Verify other device") : _t("Verification Request");
const title = request?.isSelfVerification
? _t("encryption|verification|verification_dialog_title_device")
: _t("encryption|verification|verification_dialog_title_user");
if (!member) return null;

View file

@ -120,15 +120,15 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
<BaseDialog
className="mx_WidgetCapabilitiesPromptDialog"
onFinished={this.props.onFinished}
title={_t("Approve widget permissions")}
title={_t("widget|capabilities_dialog|title")}
>
<form onSubmit={this.onSubmit}>
<div className="mx_Dialog_content">
<div className="text-muted">{_t("This widget would like to:")}</div>
<div className="text-muted">{_t("widget|capabilities_dialog|content_starting_text")}</div>
{checkboxRows}
<DialogButtons
primaryButton={_t("action|approve")}
cancelButton={_t("Decline All")}
cancelButton={_t("widget|capabilities_dialog|decline_all_permission")}
onPrimaryButtonClick={this.onSubmit}
onCancel={this.onReject}
additive={
@ -136,7 +136,7 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
value={this.state.rememberSelection}
toggleInFront={true}
onChange={this.onRememberSelectionChange}
label={_t("Remember my selection for this widget")}
label={_t("widget|capabilities_dialog|remember_Selection")}
/>
}
/>

View file

@ -79,10 +79,10 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
className="mx_WidgetOpenIDPermissionsDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Allow this widget to verify your identity")}
title={_t("widget|open_id_permissions_dialog|title")}
>
<div className="mx_WidgetOpenIDPermissionsDialog_content">
<p>{_t("The widget will verify your user ID, but won't be able to perform actions for you:")}</p>
<p>{_t("widget|open_id_permissions_dialog|starting_text")}</p>
<p className="text-muted">
{/* cheap trim to just get the path */}
{this.props.widget.templateUrl.split("?")[0].split("#")[0]}
@ -97,7 +97,7 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
value={this.state.rememberSelection}
toggleInFront={true}
onChange={this.onRememberSelectionChange}
label={_t("Remember this")}
label={_t("widget|open_id_permissions_dialog|remember_selection")}
/>
}
/>

View file

@ -117,7 +117,7 @@ export const EventEditor: React.FC<IEventEditorProps> = ({ fieldDefs, defaultCon
};
return (
<BaseTool actionLabel={_t("Send")} onAction={onAction} onBack={onBack}>
<BaseTool actionLabel={_t("forward|send_label")} onAction={onAction} onBack={onBack}>
<div className="mx_DevTools_eventTypeStateKeyGroup">{fields}</div>
<Field

View file

@ -59,7 +59,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
return (
<button className="mx_DevTools_button" onClick={showMore}>
{_t("and %(count)s others...", { count: overflowCount })}
{_t("common|and_n_others", { count: overflowCount })}
</button>
);
};
@ -67,7 +67,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
return (
<>
<Field
label={_t("Filter results")}
label={_t("common|filter_results")}
autoFocus={true}
size={64}
type="text"
@ -80,7 +80,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
/>
{filteredChildren.length < 1 ? (
_t("No results found")
_t("common|no_results_found")
) : (
<TruncatedList
getChildren={getChildren}

View file

@ -277,7 +277,7 @@ const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit })
return (
<BaseTool onBack={onBack} className="mx_DevTools_SettingsExplorer">
<Field
label={_t("Filter results")}
label={_t("common|filter_results")}
autoFocus={true}
size={64}
type="text"

View file

@ -27,7 +27,7 @@ import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
import { Tool } from "../DevtoolsDialog";
const PHASE_MAP: Record<Phase, TranslationKey> = {
[Phase.Unsent]: _td("Unsent"),
[Phase.Unsent]: _td("common|unsent"),
[Phase.Requested]: _td("devtools|phase_requested"),
[Phase.Ready]: _td("devtools|phase_ready"),
[Phase.Done]: _td("action|done"),

View file

@ -45,7 +45,7 @@ export const OidcLogoutDialog: React.FC<OidcLogoutDialogProps> = ({
return (
<BaseDialog onFinished={onFinished} title={_t("action|sign_out")} contentId="mx_Dialog_content">
<div className="mx_Dialog_content" id="mx_Dialog_content">
{_t("You will be redirected to your server's authentication provider to complete sign out.")}
{_t("auth|oidc|logout_redirect_warning")}
</div>
<div className="mx_Dialog_buttons">
{hasOpenedLogoutLink ? (

View file

@ -263,15 +263,15 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
private getKeyValidationText(): string {
if (this.state.recoveryKeyFileError) {
return _t("Wrong file type");
return _t("encryption|access_secret_storage_dialog|key_validation_text|wrong_file_type");
} else if (this.state.recoveryKeyCorrect) {
return _t("Looks good!");
return _t("encryption|access_secret_storage_dialog|key_validation_text|recovery_key_is_correct");
} else if (this.state.recoveryKeyValid) {
return _t("Wrong Security Key");
return _t("encryption|access_secret_storage_dialog|key_validation_text|wrong_security_key");
} else if (this.state.recoveryKeyValid === null) {
return "";
} else {
return _t("Invalid Security Key");
return _t("encryption|access_secret_storage_dialog|key_validation_text|invalid_security_key");
}
}
@ -280,7 +280,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
const resetButton = (
<div className="mx_AccessSecretStorageDialog_reset">
{_t("Forgotten or lost all recovery methods? <a>Reset all</a>", undefined, {
{_t("encryption|reset_all_button", undefined, {
a: (sub) => (
<AccessibleButton
kind="link_inline"
@ -298,16 +298,12 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
let title;
let titleClass;
if (this.state.resetting) {
title = _t("Reset everything");
title = _t("encryption|access_secret_storage_dialog|reset_title");
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_resetBadge"];
content = (
<div>
<p>{_t("Only do this if you have no other device to complete verification with.")}</p>
<p>
{_t(
"If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.",
)}
</p>
<p>{_t("encryption|access_secret_storage_dialog|reset_warning_1")}</p>
<p>{_t("encryption|access_secret_storage_dialog|reset_warning_2")}</p>
<DialogButtons
primaryButton={_t("action|reset")}
onPrimaryButtonClick={this.onConfirmResetAllClick}
@ -319,7 +315,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
</div>
);
} else if (hasPassphrase && !this.state.forceRecoveryKey) {
title = _t("Security Phrase");
title = _t("encryption|access_secret_storage_dialog|security_phrase_title");
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_securePhraseTitle"];
let keyStatus;
@ -327,9 +323,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
keyStatus = (
<div className="mx_AccessSecretStorageDialog_keyStatus">
{"\uD83D\uDC4E "}
{_t(
"Unable to access secret storage. Please verify that you entered the correct Security Phrase.",
)}
{_t("encryption|access_secret_storage_dialog|security_phrase_incorrect_error")}
</div>
);
} else {
@ -340,7 +334,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
<div>
<p>
{_t(
"Enter your Security Phrase or <button>use your Security Key</button> to continue.",
"encryption|access_secret_storage_dialog|enter_phrase_or_key_prompt",
{},
{
button: (s) => (
@ -358,7 +352,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
id="mx_passPhraseInput"
className="mx_AccessSecretStorageDialog_passPhraseInput"
type="password"
label={_t("Security Phrase")}
label={_t("encryption|access_secret_storage_dialog|security_phrase_title")}
value={this.state.passPhrase}
onChange={this.onPassPhraseChange}
autoFocus={true}
@ -378,7 +372,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
</div>
);
} else {
title = _t("Security Key");
title = _t("encryption|access_secret_storage_dialog|security_key_title");
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_secureBackupTitle"];
const feedbackClasses = classNames({
@ -390,7 +384,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
content = (
<div>
<p>{_t("Use your Security Key to continue.")}</p>
<p>{_t("encryption|access_secret_storage_dialog|use_security_key_prompt")}</p>
<form
className="mx_AccessSecretStorageDialog_primaryContainer"
@ -403,7 +397,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
<Field
type="password"
id="mx_securityKey"
label={_t("Security Key")}
label={_t("encryption|access_secret_storage_dialog|security_key_title")}
value={this.state.recoveryKey}
onChange={this.onRecoveryKeyChange}
autoFocus={true}
@ -412,7 +406,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
/>
</div>
<span className="mx_AccessSecretStorageDialog_recoveryKeyEntry_entryControlSeparatorText">
{_t("%(securityKey)s or %(recoveryFile)s", {
{_t("encryption|access_secret_storage_dialog|separator", {
recoveryFile: "",
securityKey: "",
})}

View file

@ -39,17 +39,13 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component<IP
className="mx_ConfirmDestroyCrossSigningDialog"
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Destroy cross-signing keys?")}
title={_t("encryption|destroy_cross_signing_dialog|title")}
>
<div className="mx_ConfirmDestroyCrossSigningDialog_content">
<p>
{_t(
"Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.",
)}
</p>
<p>{_t("encryption|destroy_cross_signing_dialog|warning")}</p>
</div>
<DialogButtons
primaryButton={_t("Clear cross-signing keys")}
primaryButton={_t("encryption|destroy_cross_signing_dialog|primary_button_text")}
onPrimaryButtonClick={this.onConfirm}
primaryButtonClass="danger"
cancelButton={_t("action|cancel")}

View file

@ -113,13 +113,13 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
const dialogAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("auth|uia|sso_title"),
body: _t("To continue, use Single Sign On to prove your identity."),
body: _t("auth|uia|sso_preauth_body"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {
title: _t("Confirm encryption setup"),
body: _t("Click the button below to confirm setting up encryption."),
title: _t("encryption|confirm_encryption_setup_title"),
body: _t("encryption|confirm_encryption_setup_body"),
continueText: _t("action|confirm"),
continueKind: "primary",
},
@ -173,7 +173,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
if (this.state.error) {
content = (
<div>
<p>{_t("Unable to set up keys")}</p>
<p>{_t("encryption|unable_to_setup_keys_error")}</p>
<div className="mx_Dialog_buttons">
<DialogButtons
primaryButton={_t("action|retry")}

View file

@ -318,18 +318,18 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
let content;
let title;
if (this.state.loading) {
title = _t("Restoring keys from backup");
title = _t("encryption|access_secret_storage_dialog|restoring");
let details;
if (this.state.progress.stage === ProgressState.Fetch) {
details = _t("Fetching keys from server…");
details = _t("restore_key_backup_dialog|key_fetch_in_progress");
} else if (this.state.progress.stage === ProgressState.LoadKeys) {
const { total, successes, failures } = this.state.progress;
details = _t("%(completed)s of %(total)s keys restored", {
details = _t("restore_key_backup_dialog|load_keys_progress", {
total,
completed: (successes ?? 0) + (failures ?? 0),
});
} else if (this.state.progress.stage === ProgressState.PreFetch) {
details = _t("Fetching keys from server…");
details = _t("restore_key_backup_dialog|key_fetch_in_progress");
}
content = (
<div>
@ -339,49 +339,41 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
);
} else if (this.state.loadError) {
title = _t("common|error");
content = _t("Unable to load backup status");
content = _t("restore_key_backup_dialog|load_error_content");
} else if (this.state.restoreError) {
if (
this.state.restoreError instanceof MatrixError &&
this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY
) {
if (this.state.restoreType === RestoreType.RecoveryKey) {
title = _t("Security Key mismatch");
title = _t("restore_key_backup_dialog|recovery_key_mismatch_title");
content = (
<div>
<p>
{_t(
"Backup could not be decrypted with this Security Key: please verify that you entered the correct Security Key.",
)}
</p>
<p>{_t("restore_key_backup_dialog|recovery_key_mismatch_description")}</p>
</div>
);
} else {
title = _t("Incorrect Security Phrase");
title = _t("restore_key_backup_dialog|incorrect_security_phrase_title");
content = (
<div>
<p>
{_t(
"Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.",
)}
</p>
<p>{_t("restore_key_backup_dialog|incorrect_security_phrase_dialog")}</p>
</div>
);
}
} else {
title = _t("common|error");
content = _t("Unable to restore backup");
content = _t("restore_key_backup_dialog|restore_failed_error");
}
} else if (this.state.backupInfo === null) {
title = _t("common|error");
content = _t("No backup found!");
content = _t("restore_key_backup_dialog|no_backup_error");
} else if (this.state.recoverInfo) {
title = _t("Keys restored");
title = _t("restore_key_backup_dialog|keys_restored_title");
let failedToDecrypt;
if (this.state.recoverInfo.total > this.state.recoverInfo.imported) {
failedToDecrypt = (
<p>
{_t("Failed to decrypt %(failedCount)s sessions!", {
{_t("restore_key_backup_dialog|count_of_decryption_failures", {
failedCount: this.state.recoverInfo.total - this.state.recoverInfo.imported,
})}
</p>
@ -390,7 +382,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
content = (
<div>
<p>
{_t("Successfully restored %(sessionCount)s keys", {
{_t("restore_key_backup_dialog|count_of_successfully_restored_keys", {
sessionCount: this.state.recoverInfo.imported,
})}
</p>
@ -404,21 +396,11 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
</div>
);
} else if (backupHasPassphrase && !this.state.forceRecoveryKey) {
title = _t("Enter Security Phrase");
title = _t("restore_key_backup_dialog|enter_phrase_title");
content = (
<div>
<p>
{_t(
"<b>Warning</b>: you should only set up key backup from a trusted computer.",
{},
{ b: (sub) => <b>{sub}</b> },
)}
</p>
<p>
{_t(
"Access your secure message history and set up secure messaging by entering your Security Phrase.",
)}
</p>
<p>{_t("restore_key_backup_dialog|key_backup_warning", {}, { b: (sub) => <b>{sub}</b> })}</p>
<p>{_t("restore_key_backup_dialog|enter_phrase_description")}</p>
<form className="mx_RestoreKeyBackupDialog_primaryContainer">
<input
@ -438,7 +420,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
/>
</form>
{_t(
"If you've forgotten your Security Phrase you can <button1>use your Security Key</button1> or <button2>set up new recovery options</button2>",
"restore_key_backup_dialog|phrase_forgotten_text",
{},
{
button1: (s) => (
@ -456,7 +438,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
</div>
);
} else {
title = _t("Enter Security Key");
title = _t("restore_key_backup_dialog|enter_key_title");
let keyStatus;
if (this.state.recoveryKey.length === 0) {
@ -465,32 +447,22 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
keyStatus = (
<div className="mx_RestoreKeyBackupDialog_keyStatus">
{"\uD83D\uDC4D "}
{_t("This looks like a valid Security Key!")}
{_t("restore_key_backup_dialog|key_is_valid")}
</div>
);
} else {
keyStatus = (
<div className="mx_RestoreKeyBackupDialog_keyStatus">
{"\uD83D\uDC4E "}
{_t("Not a valid Security Key")}
{_t("restore_key_backup_dialog|key_is_invalid")}
</div>
);
}
content = (
<div>
<p>
{_t(
"<b>Warning</b>: you should only set up key backup from a trusted computer.",
{},
{ b: (sub) => <b>{sub}</b> },
)}
</p>
<p>
{_t(
"Access your secure message history and set up secure messaging by entering your Security Key.",
)}
</p>
<p>{_t("restore_key_backup_dialog|key_backup_warning", {}, { b: (sub) => <b>{sub}</b> })}</p>
<p>{_t("restore_key_backup_dialog|enter_key_description")}</p>
<div className="mx_RestoreKeyBackupDialog_primaryContainer">
<input
@ -510,7 +482,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
/>
</div>
{_t(
"If you've forgotten your Security Key you can <button>set up new recovery options</button>",
"restore_key_backup_dialog|key_forgotten_text",
{},
{
button: (s) => (

View file

@ -60,7 +60,7 @@ export function PublicRoomResultDetails({ room, labelId, descriptionId, detailsI
</div>
<div id={detailsId} className="mx_SpotlightDialog_result_publicRoomDescription">
<span className="mx_SpotlightDialog_result_publicRoomMemberCount">
{_t("%(count)s Members", {
{_t("spotlight_dialog|count_of_members", {
count: room.num_joined_members,
})}
</span>

View file

@ -123,9 +123,9 @@ function filterToLabel(filter: Filter): string {
case Filter.People:
return _t("common|people");
case Filter.PublicRooms:
return _t("Public rooms");
return _t("spotlight_dialog|public_rooms_label");
case Filter.PublicSpaces:
return _t("Public spaces");
return _t("spotlight_dialog|public_spaces_label");
}
}
@ -571,7 +571,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
aria-labelledby="mx_SpotlightDialog_section_otherSearches"
>
<h4 id="mx_SpotlightDialog_section_otherSearches">
{trimmedQuery ? _t('Use "%(query)s" to search', { query }) : _t("Search for")}
{trimmedQuery
? _t("spotlight_dialog|heading_with_query", { query })
: _t("spotlight_dialog|heading_without_query")}
</h4>
<div>
{filter !== Filter.PublicSpaces && supportsSpaceFiltering && (
@ -760,7 +762,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
role="group"
aria-labelledby="mx_SpotlightDialog_section_people"
>
<h4 id="mx_SpotlightDialog_section_people">{_t("Recent Conversations")}</h4>
<h4 id="mx_SpotlightDialog_section_people">{_t("invite|recents_section")}</h4>
<div>{results[Section.People].slice(0, SECTION_LIMIT).map(resultMapper)}</div>
</div>
);
@ -802,7 +804,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
role="group"
aria-labelledby="mx_SpotlightDialog_section_spaces"
>
<h4 id="mx_SpotlightDialog_section_spaces">{_t("Spaces you're in")}</h4>
<h4 id="mx_SpotlightDialog_section_spaces">{_t("spotlight_dialog|spaces_title")}</h4>
<div>{results[Section.Spaces].slice(0, SECTION_LIMIT).map(resultMapper)}</div>
</div>
);
@ -815,8 +817,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
content = (
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
{filter === Filter.PublicRooms
? _t("Failed to query public rooms")
: _t("Failed to query public spaces")}
? _t("spotlight_dialog|failed_querying_public_rooms")
: _t("spotlight_dialog|failed_querying_public_spaces")}
</div>
);
} else {
@ -849,7 +851,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
aria-labelledby="mx_SpotlightDialog_section_spaceRooms"
>
<h4 id="mx_SpotlightDialog_section_spaceRooms">
{_t("Other rooms in %(spaceName)s", { spaceName: activeSpace.name })}
{_t("spotlight_dialog|other_rooms_in_space", { spaceName: activeSpace.name })}
</h4>
<div>
{spaceResults.slice(0, SECTION_LIMIT).map(
@ -909,7 +911,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
onFinished();
}}
>
{_t("Join %(roomAddress)s", {
{_t("spotlight_dialog|join_button_text", {
roomAddress: trimmedQuery,
})}
</Option>
@ -922,9 +924,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
if (filter === Filter.People) {
hiddenResultsSection = (
<div className="mx_SpotlightDialog_section mx_SpotlightDialog_hiddenResults" role="group">
<h4>{_t("Some results may be hidden for privacy")}</h4>
<h4>{_t("spotlight_dialog|result_may_be_hidden_privacy_warning")}</h4>
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
{_t("If you can't see who you're looking for, send them your invite link.")}
{_t("spotlight_dialog|cant_find_person_helpful_hint")}
</div>
<TooltipOption
id="mx_SpotlightDialog_button_inviteLink"
@ -937,7 +939,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
title={inviteLinkCopied ? _t("common|copied") : _t("action|copy")}
>
<span className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">
{_t("Copy invite link")}
{_t("spotlight_dialog|copy_link_text")}
</span>
</TooltipOption>
</div>
@ -945,9 +947,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
} else if (trimmedQuery && (filter === Filter.PublicRooms || filter === Filter.PublicSpaces)) {
hiddenResultsSection = (
<div className="mx_SpotlightDialog_section mx_SpotlightDialog_hiddenResults" role="group">
<h4>{_t("Some results may be hidden")}</h4>
<h4>{_t("spotlight_dialog|result_may_be_hidden_warning")}</h4>
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
{_t("If you can't find the room you're looking for, ask for an invite or create a new room.")}
{_t("spotlight_dialog|cant_find_room_helpful_hint")}
</div>
<Option
id="mx_SpotlightDialog_button_createNewRoom"
@ -961,7 +963,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
}
>
<span className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">
{_t("Create new room")}
{_t("spotlight_dialog|create_new_room_button")}
</span>
</Option>
</div>
@ -976,13 +978,13 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
role="group"
aria-labelledby="mx_SpotlightDialog_section_groupChat"
>
<h4 id="mx_SpotlightDialog_section_groupChat">{_t("Other options")}</h4>
<h4 id="mx_SpotlightDialog_section_groupChat">{_t("spotlight_dialog|group_chat_section_title")}</h4>
<Option
id="mx_SpotlightDialog_button_startGroupChat"
className="mx_SpotlightDialog_startGroupChat"
onClick={() => showStartChatInviteDialog(trimmedQuery)}
>
{_t("Start a group chat")}
{_t("spotlight_dialog|start_group_chat_button")}
</Option>
</div>
);
@ -996,10 +998,12 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
role="group"
aria-labelledby="mx_SpotlightDialog_section_messageSearch"
>
<h4 id="mx_SpotlightDialog_section_messageSearch">{_t("Other searches")}</h4>
<h4 id="mx_SpotlightDialog_section_messageSearch">
{_t("spotlight_dialog|message_search_section_title")}
</h4>
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
{_t(
"To search messages, look for this icon at the top of a room <icon/>",
"spotlight_dialog|search_messages_hint",
{},
{ icon: () => <div className="mx_SpotlightDialog_otherSearches_messageSearchIcon" /> },
)}
@ -1036,7 +1040,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
aria-labelledby="mx_SpotlightDialog_section_recentSearches"
>
<h4>
<span id="mx_SpotlightDialog_section_recentSearches">{_t("Recent searches")}</span>
<span id="mx_SpotlightDialog_section_recentSearches">
{_t("spotlight_dialog|recent_searches_section_title")}
</span>
<AccessibleButton kind="link" onClick={clearRecentSearches}>
{_t("action|clear")}
</AccessibleButton>
@ -1086,7 +1092,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
role="group"
aria-labelledby="mx_SpotlightDialog_section_recentlyViewed"
>
<h4 id="mx_SpotlightDialog_section_recentlyViewed">{_t("Recently viewed")}</h4>
<h4 id="mx_SpotlightDialog_section_recentlyViewed">
{_t("spotlight_dialog|recently_viewed_section_title")}
</h4>
<div>
{BreadcrumbsStore.instance.rooms
.filter((r) => r.roomId !== SdkContextClass.instance.roomViewStore.getRoomId())
@ -1209,7 +1217,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
<>
<div id="mx_SpotlightDialog_keyboardPrompt">
{_t(
"Use <arrows/> to scroll",
"spotlight_dialog|keyboard_scroll_hint",
{},
{
arrows: () => (
@ -1230,7 +1238,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
hasCancel={false}
onKeyDown={onDialogKeyDown}
screenName="UnifiedSearch"
aria-label={_t("Search Dialog")}
aria-label={_t("spotlight_dialog|search_dialog")}
>
<div className="mx_SpotlightDialog_searchBox mx_textinput">
{filter !== null && (
@ -1244,7 +1252,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
<span>{filterToLabel(filter)}</span>
<AccessibleButton
tabIndex={-1}
alt={_t("Remove search filter for %(filter)s", {
alt={_t("spotlight_dialog|remove_filter", {
filter: filterToLabel(filter),
})}
className="mx_SpotlightDialog_filter--close"

View file

@ -55,17 +55,17 @@ const validServer = withValidation<undefined, { error?: unknown }>({
{
key: "required",
test: async ({ value }) => !!value,
invalid: () => _t("Enter a server name"),
invalid: () => _t("spotlight|public_rooms|network_dropdown_required_invalid"),
},
{
key: "available",
final: true,
test: async (_, { error }) => !error,
valid: () => _t("Looks good"),
valid: () => _t("spotlight|public_rooms|network_dropdown_available_valid"),
invalid: ({ error }) =>
error instanceof MatrixError && error.errcode === "M_FORBIDDEN"
? _t("You are not allowed to view this server's rooms list")
: _t("Can't find this server or its room list"),
? _t("spotlight|public_rooms|network_dropdown_available_invalid_forbidden")
: _t("spotlight|public_rooms|network_dropdown_available_invalid"),
},
],
memoize: true,
@ -151,7 +151,8 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
const options: GenericDropdownMenuItem<IPublicRoomDirectoryConfig | null>[] = allServers.map((roomServer) => ({
key: { roomServer, instanceId: undefined },
label: roomServer,
description: roomServer === homeServer ? _t("Your server") : null,
description:
roomServer === homeServer ? _t("spotlight|public_rooms|network_dropdown_your_server_description") : null,
options: [
{
key: { roomServer, instanceId: undefined },
@ -171,7 +172,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
adornment: (
<AccessibleButton
className="mx_NetworkDropdown_removeServer"
alt={_t("Remove server “%(roomServer)s”", { roomServer })}
alt={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
onClick={() => setUserDefinedServers(without(userDefinedServers, roomServer))}
/>
),
@ -191,11 +192,11 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
const { finished } = Modal.createDialog(
TextInputDialog,
{
title: _t("Add a new server"),
description: _t("Enter the name of a new server you want to explore."),
title: _t("spotlight|public_rooms|network_dropdown_add_dialog_title"),
description: _t("spotlight|public_rooms|network_dropdown_add_dialog_description"),
button: _t("action|add"),
hasCancel: false,
placeholder: _t("Server name"),
placeholder: _t("spotlight|public_rooms|network_dropdown_add_dialog_placeholder"),
validator: validServer,
fixedWidth: false,
},
@ -214,7 +215,9 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
}}
>
<div className="mx_GenericDropdownMenu_Option--label">
<span className="mx_NetworkDropdown_addServer">{_t("Add new server…")}</span>
<span className="mx_NetworkDropdown_addServer">
{_t("spotlight|public_rooms|network_dropdown_add_server_option")}
</span>
</div>
</MenuItemRadio>
</>
@ -233,11 +236,11 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
onChange={(option) => setConfig(option)}
selectedLabel={(option) =>
option?.key
? _t("Show: %(instance)s rooms (%(server)s)", {
? _t("spotlight|public_rooms|network_dropdown_selected_label_instance", {
server: option.key.roomServer,
instance: option.key.instanceId ? option.label : "Matrix",
})
: _t("Show: Matrix rooms")
: _t("spotlight|public_rooms|network_dropdown_selected_label")
}
AdditionalOptions={addNewServer}
/>

View file

@ -42,7 +42,7 @@ export default class InfoTooltip extends React.PureComponent<ITooltipProps> {
public render(): React.ReactNode {
const { tooltip, children, tooltipClassName, className, kind } = this.props;
const title = _t("Information");
const title = _t("info_tooltip_title");
const iconClassName =
kind !== InfoTooltipKind.Warning ? "mx_InfoTooltip_icon_info" : "mx_InfoTooltip_icon_warning";

View file

@ -130,7 +130,7 @@ export default class LanguageDropdown extends React.Component<IProps, IState> {
onSearchChange={this.onSearchChange}
searchEnabled={true}
value={value}
label={_t("Language Dropdown")}
label={_t("language_dropdown_label")}
disabled={this.props.disabled}
>
{options}

View file

@ -125,7 +125,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
case PillType.EventInOtherRoom:
{
avatar = <PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />;
pillText = _t("Message in %(room)s", {
pillText = _t("pill|permalink_other_room", {
room: text,
});
}
@ -134,7 +134,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
{
if (event) {
avatar = <PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />;
pillText = _t("Message from %(user)s", {
pillText = _t("pill|permalink_this_room", {
user: text,
});
} else {

View file

@ -151,7 +151,7 @@ export default class PowerSelector<K extends undefined | string> extends React.C
public render(): React.ReactNode {
let picker;
const label = typeof this.props.label === "undefined" ? _t("Power level") : this.props.label;
const label = typeof this.props.label === "undefined" ? _t("power_level|label") : this.props.label;
if (this.state.custom) {
picker = (
<Field
@ -173,7 +173,7 @@ export default class PowerSelector<K extends undefined | string> extends React.C
text: Roles.textualPowerLevel(level, this.props.usersDefault),
};
});
options.push({ value: CUSTOM_VALUE, text: _t("Custom level") });
options.push({ value: CUSTOM_VALUE, text: _t("power_level|custom_level") });
const optionsElements = options.map((op) => {
return (
<option value={op.value} key={op.value} data-testid={`power-level-option-${op.value}`}>

View file

@ -204,9 +204,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
if (this.state.err) {
header = (
<blockquote className="mx_ReplyChain mx_ReplyChain_error">
{_t(
"Unable to load event that was replied to, it either does not exist or you do not have permission to view it.",
)}
{_t("timeline|reply|error_loading")}
</blockquote>
);
} else if (this.state.loadedEv && shouldDisplayReply(this.state.events[0])) {
@ -215,7 +213,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
header = (
<blockquote className={`mx_ReplyChain ${this.getReplyChainColorClass(ev)}`}>
{_t(
"<a>In reply to</a> <pill>",
"timeline|reply|in_reply_to",
{},
{
a: (sub) => (
@ -244,7 +242,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
header = (
<p className="mx_ReplyChain_Export">
{_t(
"In reply to <a>this message</a>",
"timeline|reply|in_reply_to_for_export",
{},
{
a: (sub) => (

Some files were not shown because too many files have changed in this diff Show more