Migrate more strings to translation keys (#11694)
This commit is contained in:
parent
677854d318
commit
e1cfde0c6e
201 changed files with 21074 additions and 18552 deletions
|
@ -324,13 +324,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
const dialogAesthetics = {
|
const dialogAesthetics = {
|
||||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
title: _t("auth|uia|sso_title"),
|
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"),
|
continueText: _t("auth|sso"),
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
title: _t("Confirm encryption setup"),
|
title: _t("encryption|confirm_encryption_setup_title"),
|
||||||
body: _t("Click the button below to confirm setting up encryption."),
|
body: _t("encryption|confirm_encryption_setup_body"),
|
||||||
continueText: _t("action|confirm"),
|
continueText: _t("action|confirm"),
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1228,7 +1228,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
const isSpace = roomToLeave?.isSpaceRoom();
|
const isSpace = roomToLeave?.isSpaceRoom();
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: isSpace ? _t("Leave space") : _t("action|leave_room"),
|
title: isSpace ? _t("space|leave_dialog_action") : _t("action|leave_room"),
|
||||||
description: (
|
description: (
|
||||||
<span>
|
<span>
|
||||||
{isSpace
|
{isSpace
|
||||||
|
@ -1271,7 +1271,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
if (room) RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
if (room) RoomListStore.instance.manualRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
const errCode = err.errcode || _td("unknown error code");
|
const errCode = err.errcode || _td("error|unknown_error_code");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("error_dialog|forget_room_failed", { errCode }),
|
title: _t("error_dialog|forget_room_failed", { errCode }),
|
||||||
description: err && err.message ? err.message : _t("invite|failed_generic"),
|
description: err && err.message ? err.message : _t("invite|failed_generic"),
|
||||||
|
|
|
@ -246,7 +246,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
||||||
<>
|
<>
|
||||||
<InlineSpinner w={20} h={20} />
|
<InlineSpinner w={20} h={20} />
|
||||||
{/* span for css */}
|
{/* span for css */}
|
||||||
<span>{_t("Sending")}</span>
|
<span>{_t("forward|sending")}</span>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
if (numChildRooms !== undefined) {
|
||||||
description += " · " + _t("%(count)s rooms", { count: numChildRooms });
|
description += " · " + _t("common|n_rooms", { count: numChildRooms });
|
||||||
}
|
}
|
||||||
|
|
||||||
let topic: ReactNode | string | null;
|
let topic: ReactNode | string | null;
|
||||||
|
@ -713,7 +713,7 @@ const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, set
|
||||||
kind="danger_outline"
|
kind="danger_outline"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{removing ? _t("Removing…") : _t("action|remove")}
|
{removing ? _t("redact|ongoing") : _t("action|remove")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -857,7 +857,7 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
|
||||||
} else if (!hierarchy.canLoadMore) {
|
} else if (!hierarchy.canLoadMore) {
|
||||||
results = (
|
results = (
|
||||||
<div className="mx_SpaceHierarchy_noResults">
|
<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>{_t("space|no_search_result_hint")}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -407,7 +407,7 @@ const SpaceAddExistingRooms: React.FC<{
|
||||||
{_t("create_space|skip_action")}
|
{_t("create_space|skip_action")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
}
|
}
|
||||||
filterPlaceholder={_t("Search for rooms")}
|
filterPlaceholder={_t("space|room_filter_placeholder")}
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
roomsRenderer={defaultRoomsRenderer}
|
roomsRenderer={defaultRoomsRenderer}
|
||||||
dmsRenderer={defaultDmsRenderer}
|
dmsRenderer={defaultDmsRenderer}
|
||||||
|
@ -508,7 +508,7 @@ const SpaceSetupPrivateInvite: React.FC<{
|
||||||
key={name}
|
key={name}
|
||||||
name={name}
|
name={name}
|
||||||
type="text"
|
type="text"
|
||||||
label={_t("Email address")}
|
label={_t("common|email_address")}
|
||||||
placeholder={_t("auth|email_field_label")}
|
placeholder={_t("auth|email_field_label")}
|
||||||
value={emailAddresses[i]}
|
value={emailAddresses[i]}
|
||||||
onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
|
onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
|
||||||
|
@ -553,7 +553,7 @@ const SpaceSetupPrivateInvite: React.FC<{
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to invite users to space: ", 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);
|
setBusy(false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@ import classNames from "classnames";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { SSOFlow, SSOAction } from "matrix-js-sdk/src/matrix";
|
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 Login, { ClientLoginFlow, OidcNativeFlow } from "../../../Login";
|
||||||
import { messageForConnectionError, messageForLoginError } from "../../../utils/ErrorUtils";
|
import { messageForConnectionError, messageForLoginError } from "../../../utils/ErrorUtils";
|
||||||
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
||||||
|
@ -41,16 +41,6 @@ import { filterBoolean } from "../../../utils/arrays";
|
||||||
import { Features } from "../../../settings/Settings";
|
import { Features } from "../../../settings/Settings";
|
||||||
import { startOidcLogin } from "../../../utils/oidc/authorize";
|
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 {
|
interface IProps {
|
||||||
serverConfig: ValidatedServerConfig;
|
serverConfig: ValidatedServerConfig;
|
||||||
// If true, the component will consider itself busy.
|
// If true, the component will consider itself busy.
|
||||||
|
|
|
@ -204,7 +204,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||||
{useRecoveryKeyButton}
|
{useRecoveryKeyButton}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_SetupEncryptionBody_reset">
|
<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) => (
|
a: (sub) => (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="link_inline"
|
kind="link_inline"
|
||||||
|
|
|
@ -315,7 +315,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||||
<p>{_t("auth|soft_logout_warning")}</p>
|
<p>{_t("auth|soft_logout_warning")}</p>
|
||||||
<div>
|
<div>
|
||||||
<AccessibleButton onClick={this.onClearAll} kind="danger">
|
<AccessibleButton onClick={this.onClearAll} kind="danger">
|
||||||
{_t("Clear all data")}
|
{_t("auth|soft_logout|clear_data_button")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</AuthBody>
|
</AuthBody>
|
||||||
|
|
|
@ -72,7 +72,7 @@ export const EnterEmail: React.FC<EnterEmailProps> = ({
|
||||||
<div className="mx_AuthBody_fieldRow">
|
<div className="mx_AuthBody_fieldRow">
|
||||||
<EmailField
|
<EmailField
|
||||||
name="reset_email" // define a name so browser's password autofill gets less confused
|
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")}
|
labelRequired={_td("auth|forgot_password_email_required")}
|
||||||
labelInvalid={_td("auth|forgot_password_email_invalid")}
|
labelInvalid={_td("auth|forgot_password_email_invalid")}
|
||||||
value={email}
|
value={email}
|
||||||
|
|
|
@ -94,7 +94,7 @@ export const VerifyEmailModal: React.FC<Props> = ({
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={onCloseClick}
|
onClick={onCloseClick}
|
||||||
className="mx_Dialog_cancelButton"
|
className="mx_Dialog_cancelButton"
|
||||||
aria-label={_t("Close dialog")}
|
aria-label={_t("dialog_close_label")}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -407,7 +407,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
|
||||||
{_t("common|username")}
|
{_t("common|username")}
|
||||||
</option>
|
</option>
|
||||||
<option key={LoginField.Email} value={LoginField.Email}>
|
<option key={LoginField.Email} value={LoginField.Email}>
|
||||||
{_t("Email address")}
|
{_t("common|email_address")}
|
||||||
</option>
|
</option>
|
||||||
<option key={LoginField.Password} value={LoginField.Password}>
|
<option key={LoginField.Password} value={LoginField.Password}>
|
||||||
{_t("auth|msisdn_field_label")}
|
{_t("auth|msisdn_field_label")}
|
||||||
|
|
|
@ -387,7 +387,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
test: ({ value }, usernameAvailable) =>
|
test: ({ value }, usernameAvailable) =>
|
||||||
(!value || SAFE_LOCALPART_REGEX.test(value)) &&
|
(!value || SAFE_LOCALPART_REGEX.test(value)) &&
|
||||||
usernameAvailable !== UsernameAvailableStatus.Invalid,
|
usernameAvailable !== UsernameAvailableStatus.Invalid,
|
||||||
invalid: () => _t("Some characters not allowed"),
|
invalid: () => _t("room_settings|general|alias_field_safe_localpart_invalid"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "available",
|
key: "available",
|
||||||
|
@ -453,7 +453,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
}
|
}
|
||||||
const emailLabel = this.authStepIsRequired("m.login.email.identity")
|
const emailLabel = this.authStepIsRequired("m.login.email.identity")
|
||||||
? _td("auth|email_field_label")
|
? _td("auth|email_field_label")
|
||||||
: _td("Email (optional)");
|
: _td("auth|registration|continue_without_email_field_label");
|
||||||
return (
|
return (
|
||||||
<EmailField
|
<EmailField
|
||||||
fieldRef={(field) => (this[RegistrationField.Email] = field)}
|
fieldRef={(field) => (this[RegistrationField.Email] = field)}
|
||||||
|
|
|
@ -71,7 +71,7 @@ const BeaconListItem: React.FC<Props & HTMLProps<HTMLLIElement>> = ({ beacon, ..
|
||||||
</div>
|
</div>
|
||||||
</BeaconStatus>
|
</BeaconStatus>
|
||||||
<span className="mx_BeaconListItem_lastUpdated">
|
<span className="mx_BeaconListItem_lastUpdated">
|
||||||
{_t("Updated %(humanizedUpdateTime)s", { humanizedUpdateTime })}
|
{_t("location_sharing|live_update_time", { humanizedUpdateTime })}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -35,7 +35,7 @@ interface Props {
|
||||||
|
|
||||||
const BeaconExpiryTime: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
|
const BeaconExpiryTime: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
|
||||||
const expiryTime = formatTime(new Date(getBeaconExpiryTimestamp(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>> = ({
|
const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
|
||||||
|
@ -61,13 +61,19 @@ const BeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({
|
||||||
)}
|
)}
|
||||||
<div className="mx_BeaconStatus_description">
|
<div className="mx_BeaconStatus_description">
|
||||||
{displayStatus === BeaconDisplayStatus.Loading && (
|
{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 && (
|
{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 && (
|
{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 && (
|
{displayStatus === BeaconDisplayStatus.Active && beacon && (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -160,7 +160,9 @@ const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matr
|
||||||
)}
|
)}
|
||||||
{!centerGeoUri && !mapDisplayError && (
|
{!centerGeoUri && !mapDisplayError && (
|
||||||
<MapFallback data-testid="beacon-view-dialog-map-fallback" className="mx_BeaconViewDialog_map">
|
<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
|
<AccessibleButton
|
||||||
kind="primary"
|
kind="primary"
|
||||||
onClick={onFinished}
|
onClick={onFinished}
|
||||||
|
@ -185,7 +187,7 @@ const BeaconViewDialog: React.FC<IProps> = ({ initialFocusedBeacon, roomId, matr
|
||||||
>
|
>
|
||||||
<LiveLocationIcon height={12} />
|
<LiveLocationIcon height={12} />
|
||||||
|
|
||||||
{_t("View list")}
|
{_t("action|view_list")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
)}
|
)}
|
||||||
<DialogOwnBeaconStatus roomId={roomId} />
|
<DialogOwnBeaconStatus roomId={roomId} />
|
||||||
|
|
|
@ -33,11 +33,11 @@ const DialogSidebar: React.FC<Props> = ({ beacons, onBeaconClick, requestClose }
|
||||||
return (
|
return (
|
||||||
<div className="mx_DialogSidebar">
|
<div className="mx_DialogSidebar">
|
||||||
<div className="mx_DialogSidebar_header">
|
<div className="mx_DialogSidebar_header">
|
||||||
<Heading size="4">{_t("View List")}</Heading>
|
<Heading size="4">{_t("action|view_list")}</Heading>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className="mx_DialogSidebar_closeButton"
|
className="mx_DialogSidebar_closeButton"
|
||||||
onClick={requestClose}
|
onClick={requestClose}
|
||||||
title={_t("Close sidebar")}
|
title={_t("location_sharing|close_sidebar")}
|
||||||
data-testid="dialog-sidebar-close"
|
data-testid="dialog-sidebar-close"
|
||||||
>
|
>
|
||||||
<CloseIcon className="mx_DialogSidebar_closeButtonIcon" />
|
<CloseIcon className="mx_DialogSidebar_closeButtonIcon" />
|
||||||
|
@ -50,7 +50,7 @@ const DialogSidebar: React.FC<Props> = ({ beacons, onBeaconClick, requestClose }
|
||||||
))}
|
))}
|
||||||
</ol>
|
</ol>
|
||||||
) : (
|
) : (
|
||||||
<div className="mx_DialogSidebar_noResults">{_t("No live locations")}</div>
|
<div className="mx_DialogSidebar_noResults">{_t("location_sharing|live_locations_empty")}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -52,12 +52,12 @@ const chooseBestBeacon = (
|
||||||
|
|
||||||
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
|
const getLabel = (hasStoppingErrors: boolean, hasLocationErrors: boolean): string => {
|
||||||
if (hasStoppingErrors) {
|
if (hasStoppingErrors) {
|
||||||
return _t("An error occurred while stopping your live location");
|
return _t("location_sharing|error_stopping_live_location");
|
||||||
}
|
}
|
||||||
if (hasLocationErrors) {
|
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 => {
|
const useLivenessMonitor = (liveBeaconIds: BeaconIdentifier[], beacons: Map<BeaconIdentifier, Beacon>): void => {
|
||||||
|
|
|
@ -51,7 +51,7 @@ const OwnBeaconStatus: React.FC<Props & HTMLProps<HTMLDivElement>> = ({ beacon,
|
||||||
<BeaconStatus
|
<BeaconStatus
|
||||||
beacon={beacon}
|
beacon={beacon}
|
||||||
displayStatus={ownDisplayStatus}
|
displayStatus={ownDisplayStatus}
|
||||||
label={_t("Live location enabled")}
|
label={_t("location_sharing|live_location_enabled")}
|
||||||
displayLiveTimeRemaining
|
displayLiveTimeRemaining
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
|
|
|
@ -32,12 +32,12 @@ import { Action } from "../../../dispatcher/actions";
|
||||||
|
|
||||||
const getLabel = (hasLocationPublishError: boolean, hasStopSharingError: boolean): string => {
|
const getLabel = (hasLocationPublishError: boolean, hasStopSharingError: boolean): string => {
|
||||||
if (hasLocationPublishError) {
|
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) {
|
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 {
|
interface RoomLiveShareWarningInnerProps {
|
||||||
|
|
|
@ -46,7 +46,7 @@ const ShareLatestLocation: React.FC<Props> = ({ latestLocationState }) => {
|
||||||
|
|
||||||
return (
|
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">
|
<a data-testid="open-location-in-osm" href={mapLink} target="_blank" rel="noreferrer noopener">
|
||||||
<ExternalLinkIcon className="mx_ShareLatestLocation_icon" />
|
<ExternalLinkIcon className="mx_ShareLatestLocation_icon" />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -22,9 +22,9 @@ import { IProps as IContextMenuProps } from "../../structures/ContextMenu";
|
||||||
import { _t, _td, TranslationKey } from "../../../languageHandler";
|
import { _t, _td, TranslationKey } from "../../../languageHandler";
|
||||||
|
|
||||||
const SECTION_NAMES: Record<MediaDeviceKindEnum, TranslationKey> = {
|
const SECTION_NAMES: Record<MediaDeviceKindEnum, TranslationKey> = {
|
||||||
[MediaDeviceKindEnum.AudioInput]: _td("Input devices"),
|
[MediaDeviceKindEnum.AudioInput]: _td("voip|input_devices"),
|
||||||
[MediaDeviceKindEnum.AudioOutput]: _td("Output devices"),
|
[MediaDeviceKindEnum.AudioOutput]: _td("voip|output_devices"),
|
||||||
[MediaDeviceKindEnum.VideoInput]: _td("Cameras"),
|
[MediaDeviceKindEnum.VideoInput]: _td("common|cameras"),
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IDeviceContextMenuDeviceProps {
|
interface IDeviceContextMenuDeviceProps {
|
||||||
|
|
|
@ -47,14 +47,14 @@ export default class LegacyCallContextMenu extends React.Component<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
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;
|
const handler = this.props.call.isRemoteOnHold() ? this.onUnholdClick : this.onHoldClick;
|
||||||
|
|
||||||
let transferItem;
|
let transferItem;
|
||||||
if (this.props.call.opponentCanBeTransferred()) {
|
if (this.props.call.opponentCanBeTransferred()) {
|
||||||
transferItem = (
|
transferItem = (
|
||||||
<MenuItem className="mx_LegacyCallContextMenu_item" onClick={this.onTransferClick}>
|
<MenuItem className="mx_LegacyCallContextMenu_item" onClick={this.onTransferClick}>
|
||||||
{_t("Transfer")}
|
{_t("action|transfer")}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,7 +414,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
resendReactionsButton = (
|
resendReactionsButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconResend"
|
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}
|
onClick={this.onResendReactionsClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -439,7 +439,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconOpenInMapSite"
|
iconClassName="mx_MessageContextMenu_iconOpenInMapSite"
|
||||||
onClick={null}
|
onClick={null}
|
||||||
label={_t("Open in OpenStreetMap")}
|
label={_t("timeline|context_menu|open_in_osm")}
|
||||||
element="a"
|
element="a"
|
||||||
{...{
|
{...{
|
||||||
href: mapSiteLink,
|
href: mapSiteLink,
|
||||||
|
@ -518,7 +518,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
||||||
endPollButton = (
|
endPollButton = (
|
||||||
<IconizedContextMenuOption
|
<IconizedContextMenuOption
|
||||||
iconClassName="mx_MessageContextMenu_iconEndPoll"
|
iconClassName="mx_MessageContextMenu_iconEndPoll"
|
||||||
label={_t("End Poll")}
|
label={_t("poll|end_title")}
|
||||||
onClick={this.onEndPollClick}
|
onClick={this.onEndPollClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -108,7 +108,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
|
||||||
data-testid="leave-option"
|
data-testid="leave-option"
|
||||||
iconClassName="mx_SpacePanel_iconLeave"
|
iconClassName="mx_SpacePanel_iconLeave"
|
||||||
className="mx_IconizedContextMenu_option_red"
|
className="mx_IconizedContextMenu_option_red"
|
||||||
label={_t("Leave space")}
|
label={_t("space|leave_dialog_action")}
|
||||||
onClick={onLeaveClick}
|
onClick={onLeaveClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -92,7 +92,7 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
|
||||||
{...props}
|
{...props}
|
||||||
className="mx_BaseCard_header_title_button--option"
|
className="mx_BaseCard_header_title_button--option"
|
||||||
onClick={openMenu}
|
onClick={openMenu}
|
||||||
title={_t("Thread options")}
|
title={_t("right_panel|thread_list|context_menu_label")}
|
||||||
isExpanded={menuDisplayed}
|
isExpanded={menuDisplayed}
|
||||||
inputRef={button}
|
inputRef={button}
|
||||||
data-testid="threadlist-dropdown-button"
|
data-testid="threadlist-dropdown-button"
|
||||||
|
|
|
@ -135,9 +135,10 @@ export const WidgetContextMenu: React.FC<IProps> = ({
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to start livestream", err);
|
logger.error("Failed to start livestream", err);
|
||||||
// XXX: won't i18n well, but looks like widget api only support 'message'?
|
// 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, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to start livestream"),
|
title: _t("widget|error_unable_start_audio_stream_title"),
|
||||||
description: message,
|
description: message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ const AddExistingSubspaceDialog: React.FC<IProps> = ({ space, onCreateSubspaceCl
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={
|
title={
|
||||||
<SubspaceSelector
|
<SubspaceSelector
|
||||||
title={_t("Add existing space")}
|
title={_t("space|add_existing_subspace|space_dropdown_title")}
|
||||||
space={space}
|
space={space}
|
||||||
value={selectedSpace}
|
value={selectedSpace}
|
||||||
onChange={setSelectedSpace}
|
onChange={setSelectedSpace}
|
||||||
|
@ -53,13 +53,13 @@ const AddExistingSubspaceDialog: React.FC<IProps> = ({ space, onCreateSubspaceCl
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
footerPrompt={
|
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">
|
<AccessibleButton onClick={onCreateSubspaceClick} kind="link">
|
||||||
{_t("Create a new space")}
|
{_t("space|add_existing_subspace|create_button")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
filterPlaceholder={_t("Search for spaces")}
|
filterPlaceholder={_t("space|add_existing_subspace|filter_placeholder")}
|
||||||
spacesRenderer={defaultSpacesRenderer}
|
spacesRenderer={defaultSpacesRenderer}
|
||||||
/>
|
/>
|
||||||
</MatrixClientContext.Provider>
|
</MatrixClientContext.Provider>
|
||||||
|
|
|
@ -241,7 +241,9 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<span className="mx_AddExistingToSpaceDialog_error">
|
<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>
|
<div className="mx_AddExistingToSpaceDialog_errorCaption">{_t("action|try_again")}</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@ -255,7 +257,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
||||||
<span>
|
<span>
|
||||||
<ProgressBar value={progress} max={selectedToAdd.size} />
|
<ProgressBar value={progress} max={selectedToAdd.size} />
|
||||||
<div className="mx_AddExistingToSpaceDialog_progressText">
|
<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,
|
count: selectedToAdd.size,
|
||||||
progress,
|
progress,
|
||||||
})}
|
})}
|
||||||
|
@ -389,7 +391,7 @@ const defaultRendererFactory =
|
||||||
|
|
||||||
export const defaultRoomsRenderer = defaultRendererFactory(_td("common|rooms"));
|
export const defaultRoomsRenderer = defaultRendererFactory(_td("common|rooms"));
|
||||||
export const defaultSpacesRenderer = defaultRendererFactory(_td("common|spaces"));
|
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 {
|
interface ISubspaceSelectorProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -418,7 +420,7 @@ export const SubspaceSelector: React.FC<ISubspaceSelectorProps> = ({ title, spac
|
||||||
onChange(options.find((space) => space.roomId === key) || space);
|
onChange(options.find((space) => space.roomId === key) || space);
|
||||||
}}
|
}}
|
||||||
value={value.roomId}
|
value={value.roomId}
|
||||||
label={_t("Space selection")}
|
label={_t("space|add_existing_room_space|space_dropdown_label")}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
options.map((space) => {
|
options.map((space) => {
|
||||||
|
@ -461,7 +463,7 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={
|
title={
|
||||||
<SubspaceSelector
|
<SubspaceSelector
|
||||||
title={_t("Add existing rooms")}
|
title={_t("space|add_existing_room_space|space_dropdown_title")}
|
||||||
space={space}
|
space={space}
|
||||||
value={selectedSpace}
|
value={selectedSpace}
|
||||||
onChange={setSelectedSpace}
|
onChange={setSelectedSpace}
|
||||||
|
@ -478,7 +480,7 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
footerPrompt={
|
footerPrompt={
|
||||||
<>
|
<>
|
||||||
<div>{_t("Want to add a new room instead?")}</div>
|
<div>{_t("space|add_existing_room_space|create")}</div>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="link"
|
kind="link"
|
||||||
onClick={(ev: ButtonEvent) => {
|
onClick={(ev: ButtonEvent) => {
|
||||||
|
@ -486,11 +488,11 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{_t("Create a new room")}
|
{_t("space|add_existing_room_space|create_prompt")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
filterPlaceholder={_t("Search for rooms")}
|
filterPlaceholder={_t("space|room_filter_placeholder")}
|
||||||
roomsRenderer={defaultRoomsRenderer}
|
roomsRenderer={defaultRoomsRenderer}
|
||||||
spacesRenderer={() => (
|
spacesRenderer={() => (
|
||||||
<div className="mx_AddExistingToSpace_section">
|
<div className="mx_AddExistingToSpace_section">
|
||||||
|
@ -502,7 +504,7 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick,
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{_t("Adding spaces has moved.")}
|
{_t("space|add_existing_room_space|subspace_moved_note")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -70,15 +70,13 @@ export default function AskInviteAnywayDialog({
|
||||||
</li>
|
</li>
|
||||||
));
|
));
|
||||||
|
|
||||||
const description =
|
const description = descriptionProp ?? _t("invite|unable_find_profiles_description_default");
|
||||||
descriptionProp ??
|
|
||||||
_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_RetryInvitesDialog"
|
className="mx_RetryInvitesDialog"
|
||||||
onFinished={onGiveUpClicked}
|
onFinished={onGiveUpClicked}
|
||||||
title={_t("The following users may not exist")}
|
title={_t("invite|unable_find_profiles_title")}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
>
|
>
|
||||||
<div id="mx_Dialog_content">
|
<div id="mx_Dialog_content">
|
||||||
|
@ -89,10 +87,10 @@ export default function AskInviteAnywayDialog({
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button onClick={onGiveUpClicked}>{_t("action|close")}</button>
|
<button onClick={onGiveUpClicked}>{_t("action|close")}</button>
|
||||||
<button onClick={onInviteNeverWarnClicked}>
|
<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>
|
||||||
<button onClick={onInviteClicked} autoFocus={true}>
|
<button onClick={onInviteClicked} autoFocus={true}>
|
||||||
{inviteLabel ?? _t("Invite anyway")}
|
{inviteLabel ?? _t("invite|unable_find_profiles_invite_label_default")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -127,7 +127,7 @@ export default class BaseDialog extends React.Component<IProps> {
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.onCancelClick}
|
onClick={this.onCancelClick}
|
||||||
className="mx_Dialog_cancelButton"
|
className="mx_Dialog_cancelButton"
|
||||||
aria-label={_t("Close dialog")}
|
aria-label={_t("dialog_close_label")}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GenericFeatureFeedbackDialog
|
<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}
|
subheading={info.feedbackSubheading ? _t(info.feedbackSubheading) : undefined}
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
rageshakeLabel={info.feedbackLabel}
|
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>
|
</AccessibleButton>
|
||||||
</GenericFeatureFeedbackDialog>
|
</GenericFeatureFeedbackDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -98,7 +98,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
private onSubmit = (): void => {
|
private onSubmit = (): void => {
|
||||||
if ((!this.state.text || !this.state.text.trim()) && (!this.state.issueUrl || !this.state.issueUrl.trim())) {
|
if ((!this.state.text || !this.state.text.trim()) && (!this.state.issueUrl || !this.state.issueUrl.trim())) {
|
||||||
this.setState({
|
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;
|
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.state.issueUrl.length > 0 ? this.state.issueUrl : "No issue link given");
|
||||||
|
|
||||||
this.setState({ busy: true, progress: null, err: null });
|
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, {
|
sendBugReport(SdkConfig.get().bug_report_endpoint_url, {
|
||||||
userText,
|
userText,
|
||||||
|
@ -121,8 +121,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
if (!this.unmounted) {
|
if (!this.unmounted) {
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Logs sent"),
|
title: _t("bug_reporting|logs_sent"),
|
||||||
description: _t("Thank you!"),
|
description: _t("bug_reporting|thank_you"),
|
||||||
hasCancelButton: false,
|
hasCancelButton: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: false,
|
busy: false,
|
||||||
progress: null,
|
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> => {
|
private onDownload = async (): Promise<void> => {
|
||||||
this.setState({ downloadBusy: true });
|
this.setState({ downloadBusy: true });
|
||||||
this.downloadProgressCallback(_t("Preparing to download logs"));
|
this.downloadProgressCallback(_t("bug_reporting|preparing_download"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await downloadBugReport({
|
await downloadBugReport({
|
||||||
|
@ -160,7 +160,8 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
if (!this.unmounted) {
|
if (!this.unmounted) {
|
||||||
this.setState({
|
this.setState({
|
||||||
downloadBusy: false,
|
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)) {
|
if (window.Modernizr && Object.values(window.Modernizr).some((support) => support === false)) {
|
||||||
warning = (
|
warning = (
|
||||||
<p>
|
<p>
|
||||||
<b>{_t("Reminder: Your browser is unsupported, so your experience may be unpredictable.")}</b>
|
<b>{_t("bug_reporting|unsupported_browser")}</b>
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +262,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
|
||||||
<Field
|
<Field
|
||||||
className="mx_BugReportDialog_field_input"
|
className="mx_BugReportDialog_field_input"
|
||||||
element="textarea"
|
element="textarea"
|
||||||
label={_t("Notes")}
|
label={_t("bug_reporting|textarea_label")}
|
||||||
rows={5}
|
rows={5}
|
||||||
onChange={this.onTextChange}
|
onChange={this.onTextChange}
|
||||||
value={this.state.text}
|
value={this.state.text}
|
||||||
|
|
|
@ -62,10 +62,10 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
|
||||||
return (
|
return (
|
||||||
<InfoDialog
|
<InfoDialog
|
||||||
onFinished={onFinished}
|
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={
|
description={
|
||||||
<div>
|
<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>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -108,32 +108,21 @@ const BulkRedactDialog: React.FC<Props> = (props) => {
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_BulkRedactDialog"
|
className="mx_BulkRedactDialog"
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
title={_t("Remove recent messages by %(user)s", { user })}
|
title={_t("user_info|redact|confirm_title", { user })}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content" id="mx_Dialog_content">
|
<div className="mx_Dialog_content" id="mx_Dialog_content">
|
||||||
<p>
|
<p>{_t("user_info|redact|confirm_description_1", { count, user })}</p>
|
||||||
{_t(
|
<p>{_t("user_info|redact|confirm_description_2")}</p>
|
||||||
"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>
|
|
||||||
<StyledCheckbox checked={keepStateEvents} onChange={(e) => setKeepStateEvents(e.target.checked)}>
|
<StyledCheckbox checked={keepStateEvents} onChange={(e) => setKeepStateEvents(e.target.checked)}>
|
||||||
{_t("Preserve system messages")}
|
{_t("user_info|redact|confirm_keep_state_label")}
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
<div className="mx_BulkRedactDialog_checkboxMicrocopy">
|
<div className="mx_BulkRedactDialog_checkboxMicrocopy">
|
||||||
{_t(
|
{_t("user_info|redact|confirm_keep_state_explainer")}
|
||||||
"Uncheck if you also want to remove system messages on this user (e.g. membership change, profile change…)",
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Remove %(count)s messages", { count })}
|
primaryButton={_t("user_info|redact|confirm_button", { count })}
|
||||||
primaryButtonClass="danger"
|
primaryButtonClass="danger"
|
||||||
primaryDisabled={count === 0}
|
primaryDisabled={count === 0}
|
||||||
onPrimaryButtonClick={() => {
|
onPrimaryButtonClick={() => {
|
||||||
|
|
|
@ -22,14 +22,8 @@ import InfoDialog from "./InfoDialog";
|
||||||
|
|
||||||
export const createCantStartVoiceMessageBroadcastDialog = (): void => {
|
export const createCantStartVoiceMessageBroadcastDialog = (): void => {
|
||||||
Modal.createDialog(InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t("Can't start voice message"),
|
title: _t("voice_message|cant_start_broadcast_title"),
|
||||||
description: (
|
description: <p>{_t("voice_message|cant_start_broadcast_description")}</p>,
|
||||||
<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>
|
|
||||||
),
|
|
||||||
hasCloseButton: true,
|
hasCloseButton: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -93,7 +93,7 @@ export default class ChangelogDialog extends React.Component<IProps, State> {
|
||||||
if (this.state[repo] == null) {
|
if (this.state[repo] == null) {
|
||||||
content = <Spinner key={repo} />;
|
content = <Spinner key={repo} />;
|
||||||
} else if (typeof this.state[repo] === "string") {
|
} 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],
|
msg: this.state[repo],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,13 +111,17 @@ export default class ChangelogDialog extends React.Component<IProps, State> {
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<div className="mx_ChangelogDialog_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>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuestionDialog
|
<QuestionDialog
|
||||||
title={_t("Changelog")}
|
title={_t("update|changelog")}
|
||||||
description={content}
|
description={content}
|
||||||
button={_t("action|update")}
|
button={_t("action|update")}
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
|
|
|
@ -88,12 +88,12 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent<IPro
|
||||||
<ErrorDialog
|
<ErrorDialog
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("common|error")}
|
title={_t("common|error")}
|
||||||
description={_t("You cannot delete this message. (%(code)s)", { code })}
|
description={_t("redact|error", { code })}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<BaseDialog onFinished={this.props.onFinished} hasCancel={false} title={_t("Removing…")}>
|
<BaseDialog onFinished={this.props.onFinished} hasCancel={false} title={_t("redact|ongoing")}>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,17 +36,17 @@ interface IProps {
|
||||||
*/
|
*/
|
||||||
export default class ConfirmRedactDialog extends React.Component<IProps> {
|
export default class ConfirmRedactDialog extends React.Component<IProps> {
|
||||||
public render(): React.ReactNode {
|
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()) {
|
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 (
|
return (
|
||||||
<TextInputDialog
|
<TextInputDialog
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Confirm Removal")}
|
title={_t("redact|confirm_button")}
|
||||||
description={description}
|
description={description}
|
||||||
placeholder={_t("Reason (optional)")}
|
placeholder={_t("redact|reason_label")}
|
||||||
focus
|
focus
|
||||||
button={_t("action|remove")}
|
button={_t("action|remove")}
|
||||||
/>
|
/>
|
||||||
|
@ -105,7 +105,7 @@ export function createRedactEventDialog({
|
||||||
// display error message stating you couldn't delete this.
|
// display error message stating you couldn't delete this.
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("common|error"),
|
title: _t("common|error"),
|
||||||
description: _t("You cannot delete this message. (%(code)s)", { code }),
|
description: _t("redact|error", { code }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,17 +39,13 @@ export default class ConfirmWipeDeviceDialog extends React.Component<IProps> {
|
||||||
className="mx_ConfirmWipeDeviceDialog"
|
className="mx_ConfirmWipeDeviceDialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished}
|
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">
|
<div className="mx_ConfirmWipeDeviceDialog_content">
|
||||||
<p>
|
<p>{_t("auth|soft_logout|clear_data_description")}</p>
|
||||||
{_t(
|
|
||||||
"Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Clear all data")}
|
primaryButton={_t("auth|soft_logout|clear_data_button")}
|
||||||
onPrimaryButtonClick={this.onConfirm}
|
onPrimaryButtonClick={this.onConfirm}
|
||||||
primaryButtonClass="danger"
|
primaryButtonClass="danger"
|
||||||
cancelButton={_t("action|cancel")}
|
cancelButton={_t("action|cancel")}
|
||||||
|
|
|
@ -100,7 +100,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
joinRuleMicrocopy = (
|
joinRuleMicrocopy = (
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_t(
|
||||||
"Anyone in <SpaceName/> will be able to find and join.",
|
"create_space|subspace_join_rule_restricted_description",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
SpaceName: () => <b>{parentSpace.name}</b>,
|
SpaceName: () => <b>{parentSpace.name}</b>,
|
||||||
|
@ -112,7 +112,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
joinRuleMicrocopy = (
|
joinRuleMicrocopy = (
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_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>,
|
SpaceName: () => <b>{parentSpace.name}</b>,
|
||||||
|
@ -121,14 +121,14 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
} else if (joinRule === JoinRule.Invite) {
|
} 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 (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={
|
title={
|
||||||
<SubspaceSelector
|
<SubspaceSelector
|
||||||
title={_t("Create a space")}
|
title={_t("create_space|subspace_dropdown_title")}
|
||||||
space={space}
|
space={space}
|
||||||
value={parentSpace}
|
value={parentSpace}
|
||||||
onChange={setParentSpace}
|
onChange={setParentSpace}
|
||||||
|
@ -143,7 +143,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
<div className="mx_CreateSubspaceDialog_content">
|
<div className="mx_CreateSubspaceDialog_content">
|
||||||
<div className="mx_CreateSubspaceDialog_betaNotice">
|
<div className="mx_CreateSubspaceDialog_betaNotice">
|
||||||
<BetaPill />
|
<BetaPill />
|
||||||
{_t("Add a space to a space you manage.")}
|
{_t("create_space|subspace_beta_notice")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SpaceCreateForm
|
<SpaceCreateForm
|
||||||
|
@ -161,8 +161,8 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
aliasFieldRef={spaceAliasField}
|
aliasFieldRef={spaceAliasField}
|
||||||
>
|
>
|
||||||
<JoinRuleDropdown
|
<JoinRuleDropdown
|
||||||
label={_t("Space visibility")}
|
label={_t("create_space|subspace_join_rule_label")}
|
||||||
labelInvite={_t("Private space (invite only)")}
|
labelInvite={_t("create_space|subspace_join_rule_invite_only")}
|
||||||
labelPublic={_t("common|public_space")}
|
labelPublic={_t("common|public_space")}
|
||||||
labelRestricted={_t("create_room|join_rule_restricted")}
|
labelRestricted={_t("create_room|join_rule_restricted")}
|
||||||
width={478}
|
width={478}
|
||||||
|
@ -175,7 +175,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
|
|
||||||
<div className="mx_CreateSubspaceDialog_footer">
|
<div className="mx_CreateSubspaceDialog_footer">
|
||||||
<div className="mx_CreateSubspaceDialog_footer_prompt">
|
<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
|
<AccessibleButton
|
||||||
kind="link"
|
kind="link"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -183,7 +183,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{_t("Add existing space")}
|
{_t("space|add_existing_subspace|space_dropdown_title")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
|
||||||
{_t("action|cancel")}
|
{_t("action|cancel")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton kind="primary" disabled={busy} onClick={onCreateSubspaceClick}>
|
<AccessibleButton kind="primary" disabled={busy} onClick={onCreateSubspaceClick}>
|
||||||
{busy ? _t("Adding…") : _t("action|add")}
|
{busy ? _t("create_space|subspace_adding") : _t("action|add")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
</MatrixClientContext.Provider>
|
</MatrixClientContext.Provider>
|
||||||
|
|
|
@ -35,10 +35,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
const _onLogoutClicked = (): void => {
|
const _onLogoutClicked = (): void => {
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("action|sign_out"),
|
title: _t("action|sign_out"),
|
||||||
description: _t(
|
description: _t("encryption|incompatible_database_sign_out_description", { brand }),
|
||||||
"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 },
|
|
||||||
),
|
|
||||||
button: _t("action|sign_out"),
|
button: _t("action|sign_out"),
|
||||||
focus: false,
|
focus: false,
|
||||||
onFinished: (doLogout) => {
|
onFinished: (doLogout) => {
|
||||||
|
@ -50,16 +47,13 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const description = _t(
|
const description = _t("encryption|incompatible_database_description", { brand });
|
||||||
"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 },
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_CryptoStoreTooNewDialog"
|
className="mx_CryptoStoreTooNewDialog"
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
title={_t("Incompatible Database")}
|
title={_t("encryption|incompatible_database_title")}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
onFinished={props.onFinished}
|
onFinished={props.onFinished}
|
||||||
>
|
>
|
||||||
|
@ -67,7 +61,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
{description}
|
{description}
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Continue With Encryption Disabled")}
|
primaryButton={_t("encryption|incompatible_database_disable")}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
onPrimaryButtonClick={() => props.onFinished(false)}
|
onPrimaryButtonClick={() => props.onFinished(false)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -73,13 +73,13 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
private onStagePhaseChange = (stage: AuthType, phase: number): void => {
|
private onStagePhaseChange = (stage: AuthType, phase: number): void => {
|
||||||
const dialogAesthetics = {
|
const dialogAesthetics = {
|
||||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
[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"),
|
continueText: _t("auth|sso"),
|
||||||
continueKind: "danger",
|
continueKind: "danger",
|
||||||
},
|
},
|
||||||
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
body: _t("Are you sure you want to deactivate your account? This is irreversible."),
|
body: _t("settings|general|deactivate_confirm_body"),
|
||||||
continueText: _t("Confirm account deactivation"),
|
continueText: _t("settings|general|deactivate_confirm_continue"),
|
||||||
continueKind: "danger",
|
continueKind: "danger",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -90,7 +90,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
|
||||||
[PasswordAuthEntry.LOGIN_TYPE]: {
|
[PasswordAuthEntry.LOGIN_TYPE]: {
|
||||||
[DEFAULT_PHASE]: {
|
[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 });
|
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 => {
|
private onUIAuthComplete = (auth: IAuthData | null): void => {
|
||||||
|
@ -138,7 +138,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
logger.error(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
|
// We'll try to log something in an vain attempt to record what happened (storage
|
||||||
// is also obliterated on logout).
|
// is also obliterated on logout).
|
||||||
logger.warn("User's account got deactivated without confirmation: Server had no auth");
|
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) => {
|
.catch((e) => {
|
||||||
if (e && e.httpStatus === 401 && e.data) {
|
if (e && e.httpStatus === 401 && e.data) {
|
||||||
// Valid UIA response
|
// Valid UIA response
|
||||||
this.setState({ authData: e.data, authEnabled: true });
|
this.setState({ authData: e.data, authEnabled: true });
|
||||||
} else {
|
} 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"
|
screenName="DeactivateAccount"
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content">
|
<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>
|
<ul>
|
||||||
<li>{_t("You will not be able to reactivate your account")}</li>
|
<li>{_t("settings|general|deactivate_confirm_content_1")}</li>
|
||||||
<li>{_t("You will no longer be able to log in")}</li>
|
<li>{_t("settings|general|deactivate_confirm_content_2")}</li>
|
||||||
<li>
|
<li>{_t("settings|general|deactivate_confirm_content_3")}</li>
|
||||||
{_t(
|
<li>{_t("settings|general|deactivate_confirm_content_4")}</li>
|
||||||
"No one will be able to reuse your username (MXID), including you: this username will remain unavailable",
|
<li>{_t("settings|general|deactivate_confirm_content_5")}</li>
|
||||||
)}
|
|
||||||
</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>
|
|
||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>{_t("settings|general|deactivate_confirm_content_6")}</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>
|
|
||||||
|
|
||||||
<div className="mx_DeactivateAccountDialog_input_section">
|
<div className="mx_DeactivateAccountDialog_input_section">
|
||||||
<p>
|
<p>
|
||||||
<StyledCheckbox checked={this.state.shouldErase} onChange={this.onEraseFieldChange}>
|
<StyledCheckbox checked={this.state.shouldErase} onChange={this.onEraseFieldChange}>
|
||||||
{_t("Hide my messages from new joiners")}
|
{_t("settings|general|deactivate_confirm_erase_label")}
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
</p>
|
</p>
|
||||||
{error}
|
{error}
|
||||||
|
|
|
@ -47,9 +47,7 @@ export default class EndPollDialog extends React.Component<IProps> {
|
||||||
const topAnswer = findTopAnswer(this.props.event, responses);
|
const topAnswer = findTopAnswer(this.props.event, responses);
|
||||||
|
|
||||||
const message =
|
const message =
|
||||||
topAnswer === ""
|
topAnswer === "" ? _t("poll|end_message_no_votes") : _t("poll|end_message", { topAnswer });
|
||||||
? _t("The poll has ended. No votes were cast.")
|
|
||||||
: _t("The poll has ended. Top answer: %(topAnswer)s", { topAnswer });
|
|
||||||
|
|
||||||
const endEvent = PollEndEvent.from(this.props.event.getId()!, message).serialize();
|
const endEvent = PollEndEvent.from(this.props.event.getId()!, message).serialize();
|
||||||
|
|
||||||
|
@ -57,8 +55,8 @@ export default class EndPollDialog extends React.Component<IProps> {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to submit poll response event:", e);
|
console.error("Failed to submit poll response event:", e);
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to end poll"),
|
title: _t("poll|error_ending_title"),
|
||||||
description: _t("Sorry, the poll did not end. Please try again."),
|
description: _t("poll|error_ending_description"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,11 +66,9 @@ export default class EndPollDialog extends React.Component<IProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<QuestionDialog
|
<QuestionDialog
|
||||||
title={_t("End Poll")}
|
title={_t("poll|end_title")}
|
||||||
description={_t(
|
description={_t("poll|end_description")}
|
||||||
"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("poll|end_title")}
|
||||||
)}
|
|
||||||
button={_t("End Poll")}
|
|
||||||
onFinished={(endPoll: boolean) => this.onFinished(endPoll)}
|
onFinished={(endPoll: boolean) => this.onFinished(endPoll)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -79,7 +79,7 @@ export default class ErrorDialog extends React.Component<IProps, IState> {
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content" id="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>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<button className="mx_Dialog_primary" onClick={this.onClick} autoFocus={this.props.focus}>
|
<button className="mx_Dialog_primary" onClick={this.onClick} autoFocus={this.props.focus}>
|
||||||
|
|
|
@ -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) {
|
if (exportCancelled) {
|
||||||
// Display successful cancellation message
|
// Display successful cancellation message
|
||||||
|
|
|
@ -57,7 +57,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
|
|
||||||
Modal.createDialog(InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title: _t("feedback|sent"),
|
title: _t("feedback|sent"),
|
||||||
description: _t("Thank you!"),
|
description: _t("bug_reporting|thank_you"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
props.onFinished();
|
props.onFinished();
|
||||||
|
|
|
@ -115,17 +115,17 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
|
||||||
className = "mx_ForwardList_canSend";
|
className = "mx_ForwardList_canSend";
|
||||||
if (!room.maySendMessage()) {
|
if (!room.maySendMessage()) {
|
||||||
disabled = true;
|
disabled = true;
|
||||||
title = _t("You don't have permission to do this");
|
title = _t("forward|no_perms_title");
|
||||||
}
|
}
|
||||||
} else if (sendState === SendState.Sending) {
|
} else if (sendState === SendState.Sending) {
|
||||||
className = "mx_ForwardList_sending";
|
className = "mx_ForwardList_sending";
|
||||||
disabled = true;
|
disabled = true;
|
||||||
title = _t("Sending");
|
title = _t("forward|sending");
|
||||||
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
|
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
|
||||||
} else if (sendState === SendState.Sent) {
|
} else if (sendState === SendState.Sent) {
|
||||||
className = "mx_ForwardList_sent";
|
className = "mx_ForwardList_sent";
|
||||||
disabled = true;
|
disabled = true;
|
||||||
title = _t("Sent");
|
title = _t("forward|sent");
|
||||||
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
|
icon = <div className="mx_ForwardList_sendIcon" aria-label={title} />;
|
||||||
} else {
|
} else {
|
||||||
className = "mx_ForwardList_sendFailed";
|
className = "mx_ForwardList_sendFailed";
|
||||||
|
@ -139,7 +139,7 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
|
||||||
<AccessibleTooltipButton
|
<AccessibleTooltipButton
|
||||||
className="mx_ForwardList_roomButton"
|
className="mx_ForwardList_roomButton"
|
||||||
onClick={jumpToRoom}
|
onClick={jumpToRoom}
|
||||||
title={_t("Open room")}
|
title={_t("forward|open_room")}
|
||||||
alignment={Alignment.Top}
|
alignment={Alignment.Top}
|
||||||
>
|
>
|
||||||
<DecoratedRoomAvatar room={room} size="32px" />
|
<DecoratedRoomAvatar room={room} size="32px" />
|
||||||
|
@ -154,7 +154,7 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
|
||||||
title={title}
|
title={title}
|
||||||
alignment={Alignment.Top}
|
alignment={Alignment.Top}
|
||||||
>
|
>
|
||||||
<div className="mx_ForwardList_sendLabel">{_t("Send")}</div>
|
<div className="mx_ForwardList_sendLabel">{_t("forward|send_label")}</div>
|
||||||
{icon}
|
{icon}
|
||||||
</AccessibleTooltipButton>
|
</AccessibleTooltipButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -256,7 +256,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
|
||||||
|
|
||||||
const [truncateAt, setTruncateAt] = useState(20);
|
const [truncateAt, setTruncateAt] = useState(20);
|
||||||
function overflowTile(overflowCount: number, totalCount: number): JSX.Element {
|
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 (
|
return (
|
||||||
<EntityTile
|
<EntityTile
|
||||||
className="mx_EntityTile_ellipsis"
|
className="mx_EntityTile_ellipsis"
|
||||||
|
@ -279,7 +279,7 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
fixedWidth={false}
|
fixedWidth={false}
|
||||||
>
|
>
|
||||||
<h3>{_t("Message preview")}</h3>
|
<h3>{_t("forward|message_preview_heading")}</h3>
|
||||||
<div
|
<div
|
||||||
className={classnames("mx_ForwardDialog_preview", {
|
className={classnames("mx_ForwardDialog_preview", {
|
||||||
mx_IRCLayout: previewLayout == Layout.IRC,
|
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">
|
<div className="mx_ForwardList" id="mx_ForwardList">
|
||||||
<SearchBox
|
<SearchBox
|
||||||
className="mx_textinput_icon mx_textinput_search"
|
className="mx_textinput_icon mx_textinput_search"
|
||||||
placeholder={_t("Search for rooms or people")}
|
placeholder={_t("forward|filter_placeholder")}
|
||||||
onSearch={setQuery}
|
onSearch={setQuery}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -52,7 +52,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
|
||||||
|
|
||||||
Modal.createDialog(InfoDialog, {
|
Modal.createDialog(InfoDialog, {
|
||||||
title,
|
title,
|
||||||
description: _t("Feedback sent! Thanks, we appreciate it!"),
|
description: _t("feedback|sent"),
|
||||||
button: _t("action|close"),
|
button: _t("action|close"),
|
||||||
hasCloseButton: false,
|
hasCloseButton: false,
|
||||||
fixedWidth: false,
|
fixedWidth: false,
|
||||||
|
@ -91,7 +91,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
|
||||||
checked={canContact}
|
checked={canContact}
|
||||||
onChange={(e) => setCanContact((e.target as HTMLInputElement).checked)}
|
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>
|
</StyledCheckbox>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,31 +176,19 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const userDetailText = [
|
const userDetailText = [
|
||||||
<p key="p1">
|
<p key="p1">{_t("encryption|verification|incoming_sas_user_dialog_text_1")}</p>,
|
||||||
{_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="p2">
|
<p key="p2">
|
||||||
{_t(
|
{_t(
|
||||||
// NB. Below wording adjusted to singular 'session' until we have
|
// NB. Below wording adjusted to singular 'session' until we have
|
||||||
// cross-signing
|
// 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>,
|
</p>,
|
||||||
];
|
];
|
||||||
|
|
||||||
const selfDetailText = [
|
const selfDetailText = [
|
||||||
<p key="p1">
|
<p key="p1">{_t("encryption|verification|incoming_sas_device_dialog_text_1")}</p>,
|
||||||
{_t(
|
<p key="p2">{_t("encryption|verification|incoming_sas_device_dialog_text_2")}</p>,
|
||||||
"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>,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -234,7 +222,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
<p>{_t("Waiting for partner to confirm…")}</p>
|
<p>{_t("encryption|verification|incoming_sas_dialog_waiting")}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -268,7 +256,11 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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}
|
{body}
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,11 +42,11 @@ export default class IntegrationsDisabledDialog extends React.Component<IProps>
|
||||||
className="mx_IntegrationsDisabledDialog"
|
className="mx_IntegrationsDisabledDialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Integrations are disabled")}
|
title={_t("integrations|disabled_dialog_title")}
|
||||||
>
|
>
|
||||||
<div className="mx_IntegrationsDisabledDialog_content">
|
<div className="mx_IntegrationsDisabledDialog_content">
|
||||||
<p>
|
<p>
|
||||||
{_t("Enable '%(manageIntegrations)s' in Settings to do this.", {
|
{_t("integrations|disabled_dialog_description", {
|
||||||
manageIntegrations: _t("integration_manager|manage_title"),
|
manageIntegrations: _t("integration_manager|manage_title"),
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -38,15 +38,10 @@ export default class IntegrationsImpossibleDialog extends React.Component<IProps
|
||||||
className="mx_IntegrationsImpossibleDialog"
|
className="mx_IntegrationsImpossibleDialog"
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Integrations not allowed")}
|
title={_t("integrations|impossible_dialog_title")}
|
||||||
>
|
>
|
||||||
<div className="mx_IntegrationsImpossibleDialog_content">
|
<div className="mx_IntegrationsImpossibleDialog_content">
|
||||||
<p>
|
<p>{_t("integrations|impossible_dialog_description", { brand })}</p>
|
||||||
{_t(
|
|
||||||
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.",
|
|
||||||
{ brand },
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("action|ok")}
|
primaryButton={_t("action|ok")}
|
||||||
|
|
|
@ -98,13 +98,13 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
|
||||||
const ssoAesthetics = {
|
const ssoAesthetics = {
|
||||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
title: _t("auth|uia|sso_title"),
|
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"),
|
continueText: _t("auth|sso"),
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
title: _t("Confirm to continue"),
|
title: _t("auth|uia|sso_postauth_title"),
|
||||||
body: _t("Click the button below to confirm your identity."),
|
body: _t("auth|uia|sso_postauth_body"),
|
||||||
continueText: _t("action|confirm"),
|
continueText: _t("action|confirm"),
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
|
|
|
@ -271,7 +271,7 @@ class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
|
||||||
});
|
});
|
||||||
|
|
||||||
const caption = (this.props.member as ThreepidMember).isEmail
|
const caption = (this.props.member as ThreepidMember).isEmail
|
||||||
? _t("Invite by email")
|
? _t("invite|email_caption")
|
||||||
: this.highlightName(userIdentifier || this.props.member.userId);
|
: this.highlightName(userIdentifier || this.props.member.userId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -566,7 +566,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: false,
|
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: () => {
|
onGiveUp: () => {
|
||||||
this.setBusy(false);
|
this.setBusy(false);
|
||||||
},
|
},
|
||||||
description: _t(
|
description: _t("invite|ask_anyway_description"),
|
||||||
"Unable to find profiles for the Matrix IDs listed below - would you like to start a DM anyway?",
|
inviteNeverWarnLabel: _t("invite|ask_anyway_never_warn_label"),
|
||||||
),
|
inviteLabel: _t("invite|ask_anyway_label"),
|
||||||
inviteNeverWarnLabel: _t("Start DM anyway and never warn me again"),
|
|
||||||
inviteLabel: _t("Start DM anyway"),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,7 +603,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
logger.error("Failed to find the room to invite users to");
|
logger.error("Failed to find the room to invite users to");
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: false,
|
busy: false,
|
||||||
errorText: _t("Something went wrong trying to invite the users."),
|
errorText: _t("invite|error_find_room"),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -620,9 +618,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: false,
|
busy: false,
|
||||||
errorText: _t(
|
errorText: _t("invite|error_invite"),
|
||||||
"We couldn't invite those users. Please check the users you want to invite and try again.",
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -635,7 +631,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
const targetIds = targets.map((t) => t.userId);
|
const targetIds = targets.map((t) => t.userId);
|
||||||
if (targetIds.length > 1) {
|
if (targetIds.length > 1) {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorText: _t("A call can only be transferred to a single user."),
|
errorText: _t("invite|error_transfer_multiple_target"),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -940,11 +936,8 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
|
|
||||||
if (failed.length > 0) {
|
if (failed.length > 0) {
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Failed to find the following users"),
|
title: _t("invite|error_find_user_title"),
|
||||||
description: _t(
|
description: _t("invite|error_find_user_description", { csvNames: failed.join(", ") }),
|
||||||
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
|
|
||||||
{ csvNames: failed.join(", ") },
|
|
||||||
),
|
|
||||||
button: _t("action|ok"),
|
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;
|
let showNum = kind === "recents" ? this.state.numRecentsShown : this.state.numSuggestionsShown;
|
||||||
const showMoreFn = kind === "recents" ? this.showMoreRecents.bind(this) : this.showMoreSuggestions.bind(this);
|
const showMoreFn = kind === "recents" ? this.showMoreRecents.bind(this) : this.showMoreSuggestions.bind(this);
|
||||||
const lastActive = (m: Result): number | undefined => (kind === "recents" ? m.lastActive : undefined);
|
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) {
|
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
|
// 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 (
|
return (
|
||||||
<div className="mx_InviteDialog_identityServer">
|
<div className="mx_InviteDialog_identityServer">
|
||||||
{_t(
|
{_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),
|
defaultIdentityServerName: abbreviateUrl(defaultIdentityServerUrl),
|
||||||
},
|
},
|
||||||
|
@ -1157,7 +1150,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
return (
|
return (
|
||||||
<div className="mx_InviteDialog_identityServer">
|
<div className="mx_InviteDialog_identityServer">
|
||||||
{_t(
|
{_t(
|
||||||
"Use an identity server to invite by email. Manage in <settings>Settings</settings>.",
|
"invite|email_use_is",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
settings: (sub) => (
|
settings: (sub) => (
|
||||||
|
@ -1281,11 +1274,11 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
const cli = MatrixClientPeg.safeGet();
|
const cli = MatrixClientPeg.safeGet();
|
||||||
const userId = cli.getUserId()!;
|
const userId = cli.getUserId()!;
|
||||||
if (this.props.kind === InviteKind.Dm) {
|
if (this.props.kind === InviteKind.Dm) {
|
||||||
title = _t("Direct Messages");
|
title = _t("space|add_existing_room_space|dm_heading");
|
||||||
|
|
||||||
if (identityServersEnabled) {
|
if (identityServersEnabled) {
|
||||||
helpText = _t(
|
helpText = _t(
|
||||||
"Start a conversation with someone using their name, email address or username (like <userId/>).",
|
"invite|start_conversation_name_email_mxid_prompt",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
userId: () => {
|
userId: () => {
|
||||||
|
@ -1299,7 +1292,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
helpText = _t(
|
helpText = _t(
|
||||||
"Start a conversation with someone using their name or username (like <userId/>).",
|
"invite|start_conversation_name_mxid_prompt",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
userId: () => {
|
userId: () => {
|
||||||
|
@ -1317,14 +1310,14 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
goButtonFn = this.checkProfileAndStartDm;
|
goButtonFn = this.checkProfileAndStartDm;
|
||||||
extraSection = (
|
extraSection = (
|
||||||
<div className="mx_InviteDialog_section_hidden_suggestions_disclaimer">
|
<div className="mx_InviteDialog_section_hidden_suggestions_disclaimer">
|
||||||
<span>{_t("Some suggestions may be hidden for privacy.")}</span>
|
<span>{_t("invite|suggestions_disclaimer")}</span>
|
||||||
<p>{_t("If you can't see who you're looking for, send them your invite link below.")}</p>
|
<p>{_t("invite|suggestions_disclaimer_prompt")}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
const link = makeUserPermalink(MatrixClientPeg.safeGet().getSafeUserId());
|
const link = makeUserPermalink(MatrixClientPeg.safeGet().getSafeUserId());
|
||||||
footer = (
|
footer = (
|
||||||
<div className="mx_InviteDialog_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())}>
|
<CopyableText getTextToCopy={() => makeUserPermalink(MatrixClientPeg.safeGet().getSafeUserId())}>
|
||||||
<a className="mx_InviteDialog_footer_link" href={link} onClick={this.onLinkClick}>
|
<a className="mx_InviteDialog_footer_link" href={link} onClick={this.onLinkClick}>
|
||||||
{link}
|
{link}
|
||||||
|
@ -1340,30 +1333,22 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
? _t("invite|to_space", {
|
? _t("invite|to_space", {
|
||||||
spaceName: room?.name || _t("common|unnamed_space"),
|
spaceName: room?.name || _t("common|unnamed_space"),
|
||||||
})
|
})
|
||||||
: _t("Invite to %(roomName)s", {
|
: _t("invite|to_room", {
|
||||||
roomName: room?.name || _t("common|unnamed_room"),
|
roomName: room?.name || _t("common|unnamed_room"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let helpTextUntranslated;
|
let helpTextUntranslated;
|
||||||
if (isSpace) {
|
if (isSpace) {
|
||||||
if (identityServersEnabled) {
|
if (identityServersEnabled) {
|
||||||
helpTextUntranslated = _td(
|
helpTextUntranslated = _td("invite|name_email_mxid_share_space");
|
||||||
"Invite someone using their name, email address, username (like <userId/>) or <a>share this space</a>.",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
helpTextUntranslated = _td(
|
helpTextUntranslated = _td("invite|name_mxid_share_space");
|
||||||
"Invite someone using their name, username (like <userId/>) or <a>share this space</a>.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (identityServersEnabled) {
|
if (identityServersEnabled) {
|
||||||
helpTextUntranslated = _td(
|
helpTextUntranslated = _td("invite|name_email_mxid_share_room");
|
||||||
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
helpTextUntranslated = _td(
|
helpTextUntranslated = _td("invite|name_mxid_share_room");
|
||||||
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,19 +1386,19 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
keySharingWarning = (
|
keySharingWarning = (
|
||||||
<p className="mx_InviteDialog_helpText">
|
<p className="mx_InviteDialog_helpText">
|
||||||
<InfoIcon height={14} width={14} />
|
<InfoIcon height={14} width={14} />
|
||||||
{" " + _t("Invited people will be able to read old messages.")}
|
{" " + _t("invite|key_share_warning")}
|
||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.props.kind === InviteKind.CallTransfer) {
|
} else if (this.props.kind === InviteKind.CallTransfer) {
|
||||||
title = _t("Transfer");
|
title = _t("action|transfer");
|
||||||
|
|
||||||
consultConnectSection = (
|
consultConnectSection = (
|
||||||
<div className="mx_InviteDialog_transferConsultConnect">
|
<div className="mx_InviteDialog_transferConsultConnect">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" checked={this.state.consultFirst} onChange={this.onConsultFirstChange} />
|
<input type="checkbox" checked={this.state.consultFirst} onChange={this.onConsultFirstChange} />
|
||||||
{_t("Consult first")}
|
{_t("voip|transfer_consult_first_label")}
|
||||||
</label>
|
</label>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
|
@ -1427,7 +1412,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
onClick={this.transferCall}
|
onClick={this.transferCall}
|
||||||
disabled={!hasSelection && this.state.dialPadValue === ""}
|
disabled={!hasSelection && this.state.dialPadValue === ""}
|
||||||
>
|
>
|
||||||
{_t("Transfer")}
|
{_t("action|transfer")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1450,11 +1435,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
|
|
||||||
if (!this.canInviteMore() || (this.hasFilterAtLeastOneEmail() && !this.canInviteThirdParty())) {
|
if (!this.canInviteMore() || (this.hasFilterAtLeastOneEmail() && !this.canInviteThirdParty())) {
|
||||||
// We are in DM case here, because of the checks in canInviteMore() / canInviteThirdParty().
|
// We are in DM case here, because of the checks in canInviteMore() / canInviteThirdParty().
|
||||||
onlyOneThreepidNote = (
|
onlyOneThreepidNote = <div className="mx_InviteDialog_oneThreepid">{_t("invite|email_limit_one")}</div>;
|
||||||
<div className="mx_InviteDialog_oneThreepid">
|
|
||||||
{_t("Invites by email can only be sent one at a time")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
results = (
|
results = (
|
||||||
<div className="mx_InviteDialog_userSections">
|
<div className="mx_InviteDialog_userSections">
|
||||||
|
@ -1487,7 +1468,12 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
let dialogContent;
|
let dialogContent;
|
||||||
if (this.props.kind === InviteKind.CallTransfer) {
|
if (this.props.kind === InviteKind.CallTransfer) {
|
||||||
const tabs: NonEmptyArray<Tab<TabId>> = [
|
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} />;
|
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} />
|
<Dialpad hasDial={false} onDigitPress={this.onDigitPress} onDeletePress={this.onDeletePress} />
|
||||||
</div>
|
</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 = (
|
dialogContent = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<TabbedView
|
<TabbedView
|
||||||
|
|
|
@ -47,11 +47,11 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
|
||||||
const onCancel = useRef(onFinished);
|
const onCancel = useRef(onFinished);
|
||||||
|
|
||||||
const causes = new Map([
|
const causes = new Map([
|
||||||
["_afterCrossSigningLocalKeyChange", _t("a new master key signature")],
|
["_afterCrossSigningLocalKeyChange", _t("encryption|key_signature_upload_failed_master_key_signature")],
|
||||||
["checkOwnCrossSigningTrust", _t("a new cross-signing key signature")],
|
["checkOwnCrossSigningTrust", _t("encryption|key_signature_upload_failed_cross_signing_key_signature")],
|
||||||
["setDeviceVerification", _t("a device cross-signing 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> => {
|
const onRetry = useCallback(async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
|
@ -78,7 +78,7 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
|
||||||
|
|
||||||
body = (
|
body = (
|
||||||
<div>
|
<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>
|
<p>{reason}</p>
|
||||||
{retrying && <Spinner />}
|
{retrying && <Spinner />}
|
||||||
<pre>{JSON.stringify(failures, null, 2)}</pre>
|
<pre>{JSON.stringify(failures, null, 2)}</pre>
|
||||||
|
@ -92,9 +92,11 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let text = _t("Upload completed");
|
let text = _t("encryption|key_signature_upload_completed");
|
||||||
if (!success) {
|
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 = (
|
body = (
|
||||||
|
@ -107,7 +109,11 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<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}
|
fixedWidth={false}
|
||||||
onFinished={() => {}}
|
onFinished={() => {}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -28,31 +28,25 @@ interface IProps {
|
||||||
|
|
||||||
const LazyLoadingDisabledDialog: React.FC<IProps> = (props) => {
|
const LazyLoadingDisabledDialog: React.FC<IProps> = (props) => {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
const description1 = _t(
|
const description1 = _t("lazy_loading|disabled_description1", {
|
||||||
"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.",
|
|
||||||
{
|
|
||||||
brand,
|
brand,
|
||||||
host: props.host,
|
host: props.host,
|
||||||
},
|
});
|
||||||
);
|
const description2 = _t("lazy_loading|disabled_description2", {
|
||||||
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.",
|
|
||||||
{
|
|
||||||
brand,
|
brand,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuestionDialog
|
<QuestionDialog
|
||||||
hasCancelButton={false}
|
hasCancelButton={false}
|
||||||
title={_t("Incompatible local cache")}
|
title={_t("lazy_loading|disabled_title")}
|
||||||
description={
|
description={
|
||||||
<div>
|
<div>
|
||||||
<p>{description1}</p>
|
<p>{description1}</p>
|
||||||
<p>{description2}</p>
|
<p>{description2}</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
button={_t("Clear cache and resync")}
|
button={_t("lazy_loading|disabled_action")}
|
||||||
onFinished={props.onFinished}
|
onFinished={props.onFinished}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,15 +27,12 @@ interface IProps {
|
||||||
|
|
||||||
const LazyLoadingResyncDialog: React.FC<IProps> = (props) => {
|
const LazyLoadingResyncDialog: React.FC<IProps> = (props) => {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
const description = _t(
|
const description = _t("lazy_loading|resync_description", { brand });
|
||||||
"%(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 },
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuestionDialog
|
<QuestionDialog
|
||||||
hasCancelButton={false}
|
hasCancelButton={false}
|
||||||
title={_t("Updating %(brand)s", { brand })}
|
title={_t("lazy_loading|resync_title", { brand })}
|
||||||
description={<div>{description}</div>}
|
description={<div>{description}</div>}
|
||||||
button={_t("action|ok")}
|
button={_t("action|ok")}
|
||||||
onFinished={props.onFinished}
|
onFinished={props.onFinished}
|
||||||
|
|
|
@ -58,24 +58,22 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
|
||||||
|
|
||||||
let rejoinWarning;
|
let rejoinWarning;
|
||||||
if (space.getJoinRule() !== JoinRule.Public) {
|
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;
|
let onlyAdminWarning;
|
||||||
if (isOnlyAdmin(space)) {
|
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 {
|
} else {
|
||||||
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdmin).length;
|
const numChildrenOnlyAdminIn = roomsToLeave.filter(isOnlyAdmin).length;
|
||||||
if (numChildrenOnlyAdminIn > 0) {
|
if (numChildrenOnlyAdminIn > 0) {
|
||||||
onlyAdminWarning = _t(
|
onlyAdminWarning = _t("space|leave_dialog_only_admin_room_warning");
|
||||||
"You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={_t("Leave %(spaceName)s", { spaceName: space.name })}
|
title={_t("space|leave_dialog_title", { spaceName: space.name })}
|
||||||
className="mx_LeaveSpaceDialog"
|
className="mx_LeaveSpaceDialog"
|
||||||
contentId="mx_LeaveSpaceDialog"
|
contentId="mx_LeaveSpaceDialog"
|
||||||
onFinished={() => onFinished(false)}
|
onFinished={() => onFinished(false)}
|
||||||
|
@ -84,7 +82,7 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
|
||||||
<div className="mx_Dialog_content" id="mx_LeaveSpaceDialog">
|
<div className="mx_Dialog_content" id="mx_LeaveSpaceDialog">
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_t(
|
||||||
"You are about to leave <spaceName/>.",
|
"space|leave_dialog_description",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
spaceName: () => <b>{space.name}</b>,
|
spaceName: () => <b>{space.name}</b>,
|
||||||
|
@ -93,7 +91,7 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
|
||||||
|
|
||||||
{rejoinWarning}
|
{rejoinWarning}
|
||||||
{rejoinWarning && <> </>}
|
{rejoinWarning && <> </>}
|
||||||
{spaceChildren.length > 0 && _t("Would you like to leave the rooms in this space?")}
|
{spaceChildren.length > 0 && _t("space|leave_dialog_option_intro")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{spaceChildren.length > 0 && (
|
{spaceChildren.length > 0 && (
|
||||||
|
@ -102,16 +100,16 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
|
||||||
spaceChildren={spaceChildren}
|
spaceChildren={spaceChildren}
|
||||||
selected={selectedRooms}
|
selected={selectedRooms}
|
||||||
onChange={setRoomsToLeave}
|
onChange={setRoomsToLeave}
|
||||||
noneLabel={_t("Don't leave any rooms")}
|
noneLabel={_t("space|leave_dialog_option_none")}
|
||||||
allLabel={_t("Leave all rooms")}
|
allLabel={_t("space|leave_dialog_option_all")}
|
||||||
specificLabel={_t("Leave some rooms")}
|
specificLabel={_t("space|leave_dialog_option_specific")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{onlyAdminWarning && <div className="mx_LeaveSpaceDialog_section_warning">{onlyAdminWarning}</div>}
|
{onlyAdminWarning && <div className="mx_LeaveSpaceDialog_section_warning">{onlyAdminWarning}</div>}
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Leave space")}
|
primaryButton={_t("space|leave_dialog_action")}
|
||||||
primaryButtonClass="danger"
|
primaryButtonClass="danger"
|
||||||
onPrimaryButtonClick={() => onFinished(true, roomsToLeave)}
|
onPrimaryButtonClick={() => onFinished(true, roomsToLeave)}
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
|
|
|
@ -166,16 +166,8 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
private renderSetupBackupDialog(): React.ReactNode {
|
private renderSetupBackupDialog(): React.ReactNode {
|
||||||
const description = (
|
const description = (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>{_t("auth|logout_dialog|setup_secure_backup_description_1")}</p>
|
||||||
{_t(
|
<p>{_t("auth|logout_dialog|setup_secure_backup_description_2")}</p>
|
||||||
"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("encryption|setup_secure_backup|explainer")}</p>
|
<p>{_t("encryption|setup_secure_backup|explainer")}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -186,7 +178,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
} else {
|
} else {
|
||||||
// if there's an error fetching the backup info, we'll just assume there's
|
// if there's an error fetching the backup info, we'll just assume there's
|
||||||
// no backup for the purpose of the button caption
|
// 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 = (
|
const dialogContent = (
|
||||||
|
@ -200,12 +192,12 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
onPrimaryButtonClick={this.onSetRecoveryMethodClick}
|
onPrimaryButtonClick={this.onSetRecoveryMethodClick}
|
||||||
focus={true}
|
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>
|
</DialogButtons>
|
||||||
<details>
|
<details>
|
||||||
<summary>{_t("common|advanced")}</summary>
|
<summary>{_t("common|advanced")}</summary>
|
||||||
<p>
|
<p>
|
||||||
<button onClick={this.onExportE2eKeysClicked}>{_t("Manually export keys")}</button>
|
<button onClick={this.onExportE2eKeysClicked}>{_t("auth|logout_dialog|megolm_export")}</button>
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
@ -215,7 +207,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
// confirms the action.
|
// confirms the action.
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={_t("You'll lose access to your encrypted messages")}
|
title={_t("auth|logout_dialog|setup_key_backup_title")}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.onFinished}
|
onFinished={this.onFinished}
|
||||||
|
@ -246,7 +238,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
|
||||||
<QuestionDialog
|
<QuestionDialog
|
||||||
hasCancelButton={true}
|
hasCancelButton={true}
|
||||||
title={_t("action|sign_out")}
|
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")}
|
button={_t("action|sign_out")}
|
||||||
onFinished={this.onFinished}
|
onFinished={this.onFinished}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -43,10 +43,10 @@ const Entry: React.FC<{
|
||||||
|
|
||||||
let description;
|
let description;
|
||||||
if (localRoom) {
|
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;
|
const numChildRooms = SpaceStore.instance.getChildRooms(room.roomId).length;
|
||||||
if (numChildRooms > 0) {
|
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) {
|
if (newSelected.size < 1) {
|
||||||
inviteOnlyWarning = (
|
inviteOnlyWarning = (
|
||||||
<div className="mx_ManageRestrictedJoinRuleDialog_section_info">
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -141,14 +141,14 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||||
filteredSpacesContainingRoom.length + filteredOtherJoinedSpaces.length + filteredOtherEntries.length;
|
filteredSpacesContainingRoom.length + filteredOtherJoinedSpaces.length + filteredOtherEntries.length;
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={_t("Select spaces")}
|
title={_t("room_settings|security|join_rule_restricted_dialog_title")}
|
||||||
className="mx_ManageRestrictedJoinRuleDialog"
|
className="mx_ManageRestrictedJoinRuleDialog"
|
||||||
onFinished={onFinished}
|
onFinished={onFinished}
|
||||||
fixedWidth={false}
|
fixedWidth={false}
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_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>,
|
RoomName: () => <b>{room.name}</b>,
|
||||||
|
@ -158,7 +158,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||||
<MatrixClientContext.Provider value={cli}>
|
<MatrixClientContext.Provider value={cli}>
|
||||||
<SearchBox
|
<SearchBox
|
||||||
className="mx_textinput_icon mx_textinput_search"
|
className="mx_textinput_icon mx_textinput_search"
|
||||||
placeholder={_t("Search spaces")}
|
placeholder={_t("room_settings|security|join_rule_restricted_dialog_filter_placeholder")}
|
||||||
onSearch={setQuery}
|
onSearch={setQuery}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
|
@ -167,8 +167,8 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||||
<div className="mx_ManageRestrictedJoinRuleDialog_section">
|
<div className="mx_ManageRestrictedJoinRuleDialog_section">
|
||||||
<h3>
|
<h3>
|
||||||
{room.isSpaceRoom()
|
{room.isSpaceRoom()
|
||||||
? _t("Spaces you know that contain this space")
|
? _t("room_settings|security|join_rule_restricted_dialog_heading_space")
|
||||||
: _t("Spaces you know that contain this room")}
|
: _t("room_settings|security|join_rule_restricted_dialog_heading_room")}
|
||||||
</h3>
|
</h3>
|
||||||
{filteredSpacesContainingRoom.map((space) => {
|
{filteredSpacesContainingRoom.map((space) => {
|
||||||
return (
|
return (
|
||||||
|
@ -187,9 +187,9 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||||
|
|
||||||
{filteredOtherEntries.length > 0 ? (
|
{filteredOtherEntries.length > 0 ? (
|
||||||
<div className="mx_ManageRestrictedJoinRuleDialog_section">
|
<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 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>
|
</div>
|
||||||
{filteredOtherEntries.map((space) => {
|
{filteredOtherEntries.map((space) => {
|
||||||
return (
|
return (
|
||||||
|
@ -208,7 +208,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||||
|
|
||||||
{filteredOtherJoinedSpaces.length > 0 ? (
|
{filteredOtherJoinedSpaces.length > 0 ? (
|
||||||
<div className="mx_ManageRestrictedJoinRuleDialog_section">
|
<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) => {
|
{filteredOtherJoinedSpaces.map((space) => {
|
||||||
return (
|
return (
|
||||||
<Entry
|
<Entry
|
||||||
|
|
|
@ -51,9 +51,9 @@ export function ManualDeviceKeyVerificationDialog({
|
||||||
|
|
||||||
let text;
|
let text;
|
||||||
if (mxClient?.getUserId() === userId) {
|
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 {
|
} 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();
|
const fingerprint = device.getFingerprint();
|
||||||
|
@ -64,16 +64,17 @@ export function ManualDeviceKeyVerificationDialog({
|
||||||
<div className="mx_DeviceVerifyDialog_cryptoSection">
|
<div className="mx_DeviceVerifyDialog_cryptoSection">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<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>
|
||||||
<li>
|
<li>
|
||||||
<label>{_t("Session ID")}:</label>{" "}
|
<label>{_t("encryption|verification|manual_device_verification_device_id_label")}:</label>{" "}
|
||||||
<span>
|
<span>
|
||||||
<code>{device.deviceId}</code>
|
<code>{device.deviceId}</code>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label>{_t("Session key")}:</label>{" "}
|
<label>{_t("encryption|verification|manual_device_verification_device_key_label")}:</label>{" "}
|
||||||
<span>
|
<span>
|
||||||
<code>
|
<code>
|
||||||
<b>{key}</b>
|
<b>{key}</b>
|
||||||
|
@ -82,7 +83,7 @@ export function ManualDeviceKeyVerificationDialog({
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -154,11 +154,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent<IProps
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
const { error } = this.state;
|
const { error } = this.state;
|
||||||
if (error.errcode === "M_UNRECOGNIZED") {
|
if (error.errcode === "M_UNRECOGNIZED") {
|
||||||
content = (
|
content = <p className="mx_MessageEditHistoryDialog_error">{_t("error|edit_history_unsupported")}</p>;
|
||||||
<p className="mx_MessageEditHistoryDialog_error">
|
|
||||||
{_t("Your homeserver doesn't seem to support this feature.")}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
} else if (error.errcode) {
|
} else if (error.errcode) {
|
||||||
// some kind of error from the homeserver
|
// some kind of error from the homeserver
|
||||||
content = <p className="mx_MessageEditHistoryDialog_error">{_t("error|something_went_wrong")}</p>;
|
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"
|
className="mx_MessageEditHistoryDialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Message edits")}
|
title={_t("message_edit_dialog_title")}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -187,7 +187,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={this.props.widgetDefinition.name || _t("Modal Widget")}
|
title={this.props.widgetDefinition.name || _t("widget|modal_title_default")}
|
||||||
className="mx_ModalWidgetDialog"
|
className="mx_ModalWidgetDialog"
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
|
@ -199,7 +199,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
||||||
width="16"
|
width="16"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
{_t("Data on this screen is shared with %(widgetDomain)s", {
|
{_t("widget|modal_data_warning", {
|
||||||
widgetDomain: parsed.hostname,
|
widgetDomain: parsed.hostname,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -50,7 +50,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={_t("Continuing without email")}
|
title={_t("auth|registration|continue_without_email_title")}
|
||||||
className="mx_RegistrationEmailPromptDialog"
|
className="mx_RegistrationEmailPromptDialog"
|
||||||
contentId="mx_RegistrationEmailPromptDialog"
|
contentId="mx_RegistrationEmailPromptDialog"
|
||||||
onFinished={() => onFinished(false)}
|
onFinished={() => onFinished(false)}
|
||||||
|
@ -59,7 +59,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
|
||||||
<div className="mx_Dialog_content" id="mx_RegistrationEmailPromptDialog">
|
<div className="mx_Dialog_content" id="mx_RegistrationEmailPromptDialog">
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_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>,
|
b: (sub) => <b>{sub}</b>,
|
||||||
|
@ -70,7 +70,7 @@ const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
|
||||||
<EmailField
|
<EmailField
|
||||||
fieldRef={fieldRef}
|
fieldRef={fieldRef}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
label={_td("Email (optional)")}
|
label={_td("auth|registration|continue_without_email_field_label")}
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(ev) => {
|
onChange={(ev) => {
|
||||||
const target = ev.target as HTMLInputElement;
|
const target = ev.target as HTMLInputElement;
|
||||||
|
|
|
@ -246,7 +246,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
// as configured in the room's state events.
|
// as configured in the room's state events.
|
||||||
const dmRoomId = await ensureDMExists(client, this.moderation.moderationBotUserId);
|
const dmRoomId = await ensureDMExists(client, this.moderation.moderationBotUserId);
|
||||||
if (!dmRoomId) {
|
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, {
|
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");
|
subtitle = _t("report_content|nature_disagreement");
|
||||||
break;
|
break;
|
||||||
case Nature.Toxic:
|
case Nature.Toxic:
|
||||||
subtitle = _t(
|
subtitle = _t("report_content|nature_toxic");
|
||||||
"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.",
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case Nature.Illegal:
|
case Nature.Illegal:
|
||||||
subtitle = _t(
|
subtitle = _t("report_content|nature_illegal");
|
||||||
"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.",
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case Nature.Spam:
|
case Nature.Spam:
|
||||||
subtitle = _t(
|
subtitle = _t("report_content|nature_spam");
|
||||||
"This user is spamming the room with ads, links to ads or to propaganda.\nThis will be reported to the room moderators.",
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case NonStandardValue.Admin:
|
case NonStandardValue.Admin:
|
||||||
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId()!)) {
|
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId()!)) {
|
||||||
subtitle = _t(
|
subtitle = _t("report_content|nature_nonstandard_admin_encrypted", {
|
||||||
"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,
|
||||||
{ homeserver: homeServerName },
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
subtitle = _t(
|
subtitle = _t("report_content|nature_nonstandard_admin", { homeserver: homeServerName });
|
||||||
"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 },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Nature.Other:
|
case Nature.Other:
|
||||||
subtitle = _t(
|
subtitle = _t("report_content|nature_other");
|
||||||
"Any other reason. Please describe the problem.\nThis will be reported to the room moderators.",
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
subtitle = _t("report_content|nature");
|
subtitle = _t("report_content|nature");
|
||||||
|
@ -411,7 +399,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
checked={this.state.nature == Nature.Other}
|
checked={this.state.nature == Nature.Other}
|
||||||
onChange={this.onNatureChosen}
|
onChange={this.onNatureChosen}
|
||||||
>
|
>
|
||||||
{_t("Other")}
|
{_t("report_content|other_label")}
|
||||||
</StyledRadioButton>
|
</StyledRadioButton>
|
||||||
<p>{subtitle}</p>
|
<p>{subtitle}</p>
|
||||||
<Field
|
<Field
|
||||||
|
@ -447,11 +435,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
contentId="mx_ReportEventDialog"
|
contentId="mx_ReportEventDialog"
|
||||||
>
|
>
|
||||||
<div className="mx_ReportEventDialog" id="mx_ReportEventDialog">
|
<div className="mx_ReportEventDialog" id="mx_ReportEventDialog">
|
||||||
<p>
|
<p>{_t("report_content|description")}</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>
|
|
||||||
{adminMessage}
|
{adminMessage}
|
||||||
<Field
|
<Field
|
||||||
className="mx_ReportEventDialog_reason"
|
className="mx_ReportEventDialog_reason"
|
||||||
|
|
|
@ -241,7 +241,7 @@ class RoomSettingsDialog extends React.Component<IProps, IState> {
|
||||||
className="mx_RoomSettingsDialog"
|
className="mx_RoomSettingsDialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Room Settings - %(roomName)s", { roomName })}
|
title={_t("room_settings|title", { roomName })}
|
||||||
>
|
>
|
||||||
<div className="mx_SettingsDialog_content">
|
<div className="mx_SettingsDialog_content">
|
||||||
<TabbedView
|
<TabbedView
|
||||||
|
|
|
@ -59,8 +59,9 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("Failed to upgrade room"),
|
title: _t("room_settings|advanced|error_upgrade_title"),
|
||||||
description: err && err.message ? err.message : _t("The room upgrade could not be completed"),
|
description:
|
||||||
|
err && err.message ? err.message : _t("room_settings|advanced|error_upgrade_description"),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
@ -75,7 +76,7 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
|
||||||
} else {
|
} else {
|
||||||
buttons = (
|
buttons = (
|
||||||
<DialogButtons
|
<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"
|
primaryButtonClass="danger"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onPrimaryButtonClick={this.onUpgradeClick}
|
onPrimaryButtonClick={this.onUpgradeClick}
|
||||||
|
@ -88,28 +89,16 @@ export default class RoomUpgradeDialog extends React.Component<IProps, IState> {
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_RoomUpgradeDialog"
|
className="mx_RoomUpgradeDialog"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Upgrade Room Version")}
|
title={_t("room_settings|advanced|upgrade_dialog_title")}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
>
|
>
|
||||||
<p>
|
<p>{_t("room_settings|advanced|upgrade_dialog_description")}</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>
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>{_t("Create a new room with the same name, description and avatar")}</li>
|
<li>{_t("room_settings|advanced|upgrade_dialog_description_1")}</li>
|
||||||
<li>{_t("Update any local room aliases to point to the new room")}</li>
|
<li>{_t("room_settings|advanced|upgrade_dialog_description_2")}</li>
|
||||||
<li>
|
<li>{_t("room_settings|advanced|upgrade_dialog_description_3")}</li>
|
||||||
{_t(
|
<li>{_t("room_settings|advanced|upgrade_dialog_description_4")}</li>
|
||||||
"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>
|
|
||||||
</ol>
|
</ol>
|
||||||
{buttons}
|
{buttons}
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -115,7 +115,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
|
||||||
<LabelledToggleSwitch
|
<LabelledToggleSwitch
|
||||||
value={this.state.inviteUsersToNewRoom}
|
value={this.state.inviteUsersToNewRoom}
|
||||||
onChange={this.onInviteUsersToggle}
|
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;
|
let title: string;
|
||||||
switch (this.joinRule) {
|
switch (this.joinRule) {
|
||||||
case JoinRule.Invite:
|
case JoinRule.Invite:
|
||||||
title = _t("Upgrade private room");
|
title = _t("room_settings|advanced|upgrade_warning_dialog_title_private");
|
||||||
break;
|
break;
|
||||||
case JoinRule.Public:
|
case JoinRule.Public:
|
||||||
title = _t("Upgrade public room");
|
title = _t("room_settings|advanced|upgrade_dwarning_ialog_title_public");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
title = _t("Upgrade room");
|
title = _t("room_settings|advanced|upgrade_warning_dialog_title");
|
||||||
}
|
}
|
||||||
|
|
||||||
let bugReports = (
|
let bugReports = <p>{_t("room_settings|advanced|upgrade_warning_dialog_report_bug_prompt", { brand })}</p>;
|
||||||
<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>
|
|
||||||
);
|
|
||||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||||
bugReports = (
|
bugReports = (
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_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,
|
brand,
|
||||||
},
|
},
|
||||||
|
@ -190,15 +183,10 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
|
||||||
title={title}
|
title={title}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>{this.props.description || _t("room_settings|advanced|upgrade_warning_dialog_description")}</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>
|
<p>
|
||||||
{_t(
|
{_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>,
|
b: (sub) => <b>{sub}</b>,
|
||||||
|
@ -208,7 +196,7 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
|
||||||
{bugReports}
|
{bugReports}
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_t(
|
||||||
"You'll upgrade this room from <oldVersion /> to <newVersion />.",
|
"room_settings|advanced|upgrade_warning_dialog_footer",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
oldVersion: () => <code>{this.currentVersion}</code>,
|
oldVersion: () => <code>{this.currentVersion}</code>,
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default abstract class ScrollableBaseModal<
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this.onCancel}
|
onClick={this.onCancel}
|
||||||
className="mx_CompoundDialog_cancelButton"
|
className="mx_CompoundDialog_cancelButton"
|
||||||
aria-label={_t("Close dialog")}
|
aria-label={_t("dialog_close_label")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={this.onSubmit} className="mx_CompoundDialog_form">
|
<form onSubmit={this.onSubmit} className="mx_CompoundDialog_form">
|
||||||
|
|
|
@ -92,36 +92,32 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let timeline = this.renderTimeline().filter((c) => !!c); // remove nulls for next check
|
let timeline = this.renderTimeline().filter((c) => !!c); // remove nulls for next check
|
||||||
if (timeline.length === 0) {
|
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();
|
const serverName = MatrixClientPeg.getHomeserverName();
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
title={_t("Server isn't responding")}
|
title={_t("server_offline|title")}
|
||||||
className="mx_ServerOfflineDialog"
|
className="mx_ServerOfflineDialog"
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
>
|
>
|
||||||
<div className="mx_ServerOfflineDialog_content">
|
<div className="mx_ServerOfflineDialog_content">
|
||||||
<p>
|
<p>{_t("server_offline|description")}</p>
|
||||||
{_t(
|
|
||||||
"Your server isn't responding to some of your requests. Below are some of the most likely reasons.",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>{_t("The server (%(serverName)s) took too long to respond.", { serverName })}</li>
|
<li>{_t("server_offline|description_1", { serverName })}</li>
|
||||||
<li>{_t("Your firewall or anti-virus is blocking the request.")}</li>
|
<li>{_t("server_offline|description_2")}</li>
|
||||||
<li>{_t("A browser extension is preventing the request.")}</li>
|
<li>{_t("server_offline|description_3")}</li>
|
||||||
<li>{_t("The server is offline.")}</li>
|
<li>{_t("server_offline|description_4")}</li>
|
||||||
<li>{_t("The server has denied your request.")}</li>
|
<li>{_t("server_offline|description_5")}</li>
|
||||||
<li>{_t("Your area is experiencing difficulties connecting to the internet.")}</li>
|
<li>{_t("server_offline|description_6")}</li>
|
||||||
<li>{_t("A connection error occurred while trying to contact the server.")}</li>
|
<li>{_t("server_offline|description_7")}</li>
|
||||||
<li>{_t("The server is not configured to indicate what the problem is (CORS).")}</li>
|
<li>{_t("server_offline|description_8")}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr />
|
<hr />
|
||||||
<h2>{_t("Recent changes that have not yet been received")}</h2>
|
<h2>{_t("server_offline|recent_changes_heading")}</h2>
|
||||||
{timeline}
|
{timeline}
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -30,19 +30,17 @@ export default class SeshatResetDialog extends React.PureComponent<Props> {
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished.bind(null, false)}
|
onFinished={this.props.onFinished.bind(null, false)}
|
||||||
title={_t("Reset event store?")}
|
title={_t("seshat|reset_title")}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{_t("You most likely do not want to reset your event index store")}
|
{_t("seshat|reset_description")}
|
||||||
<br />
|
<br />
|
||||||
{_t(
|
{_t("seshat|reset_explainer")}
|
||||||
"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",
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Reset event store")}
|
primaryButton={_t("seshat|reset_button")}
|
||||||
onPrimaryButtonClick={this.props.onFinished.bind(null, true)}
|
onPrimaryButtonClick={this.props.onFinished.bind(null, true)}
|
||||||
primaryButtonClass="danger"
|
primaryButtonClass="danger"
|
||||||
cancelButton={_t("action|cancel")}
|
cancelButton={_t("action|cancel")}
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
|
||||||
private onClearStorageClick = (): void => {
|
private onClearStorageClick = (): void => {
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("action|sign_out"),
|
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"),
|
button: _t("action|sign_out"),
|
||||||
danger: true,
|
danger: true,
|
||||||
onFinished: this.props.onFinished,
|
onFinished: this.props.onFinished,
|
||||||
|
@ -59,7 +59,7 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
|
||||||
|
|
||||||
const clearStorageButton = (
|
const clearStorageButton = (
|
||||||
<button onClick={this.onClearStorageClick} className="danger">
|
<button onClick={this.onClearStorageClick} className="danger">
|
||||||
{_t("Clear Storage and Sign Out")}
|
{_t("error|session_restore|clear_storage_button")}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -92,25 +92,16 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_ErrorDialog"
|
className="mx_ErrorDialog"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Unable to restore session")}
|
title={_t("error|session_restore|title")}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content" id="mx_Dialog_content">
|
<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>
|
<p>{_t("error|session_restore|description_2", { brand })}</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>
|
<p>{_t("error|session_restore|description_3")}</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>
|
|
||||||
</div>
|
</div>
|
||||||
{dialogButtons}
|
{dialogButtons}
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
|
|
|
@ -76,10 +76,8 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
this.addThreepid.addEmailAddress(emailAddress).then(
|
this.addThreepid.addEmailAddress(emailAddress).then(
|
||||||
() => {
|
() => {
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Verification Pending"),
|
title: _t("auth|set_email|verification_pending_title"),
|
||||||
description: _t(
|
description: _t("auth|set_email|verification_pending_description"),
|
||||||
"Please check your email and click on the link it contains. Once this is done, click continue.",
|
|
||||||
),
|
|
||||||
button: _t("action|continue"),
|
button: _t("action|continue"),
|
||||||
onFinished: this.onEmailDialogFinished,
|
onFinished: this.onEmailDialogFinished,
|
||||||
});
|
});
|
||||||
|
@ -125,11 +123,9 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
const message =
|
const message =
|
||||||
_t("settings|general|error_email_verification") +
|
_t("settings|general|error_email_verification") +
|
||||||
" " +
|
" " +
|
||||||
_t(
|
_t("auth|set_email|verification_pending_description");
|
||||||
"Please check your email and click on the link it contains. Once this is done, click continue.",
|
|
||||||
);
|
|
||||||
Modal.createDialog(QuestionDialog, {
|
Modal.createDialog(QuestionDialog, {
|
||||||
title: _t("Verification Pending"),
|
title: _t("auth|set_email|verification_pending_title"),
|
||||||
description: message,
|
description: message,
|
||||||
button: _t("action|continue"),
|
button: _t("action|continue"),
|
||||||
onFinished: this.onEmailDialogFinished,
|
onFinished: this.onEmailDialogFinished,
|
||||||
|
@ -152,7 +148,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
<EditableText
|
<EditableText
|
||||||
initialValue={this.state.emailAddress}
|
initialValue={this.state.emailAddress}
|
||||||
className="mx_SetEmailDialog_email_input"
|
className="mx_SetEmailDialog_email_input"
|
||||||
placeholder={_t("Email address")}
|
placeholder={_t("common|email_address")}
|
||||||
placeholderClassName="mx_SetEmailDialog_email_input_placeholder"
|
placeholderClassName="mx_SetEmailDialog_email_input_placeholder"
|
||||||
blurToCancel={false}
|
blurToCancel={false}
|
||||||
onValueChanged={this.onEmailAddressChanged}
|
onValueChanged={this.onEmailAddressChanged}
|
||||||
|
@ -167,9 +163,7 @@ export default class SetEmailDialog extends React.Component<IProps, IState> {
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content">
|
<div className="mx_Dialog_content">
|
||||||
<p id="mx_Dialog_content">
|
<p id="mx_Dialog_content">{_t("auth|set_email|description")}</p>
|
||||||
{_t("This will allow you to reset your password and receive notifications.")}
|
|
||||||
</p>
|
|
||||||
{emailInput}
|
{emailInput}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
|
|
|
@ -130,7 +130,7 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
|
||||||
let checkbox: JSX.Element | undefined;
|
let checkbox: JSX.Element | undefined;
|
||||||
|
|
||||||
if (this.props.target instanceof Room) {
|
if (this.props.target instanceof Room) {
|
||||||
title = _t("Share Room");
|
title = _t("share|title_room");
|
||||||
|
|
||||||
const events = this.props.target.getLiveTimeline().getEvents();
|
const events = this.props.target.getLiveTimeline().getEvents();
|
||||||
if (events.length > 0) {
|
if (events.length > 0) {
|
||||||
|
@ -140,22 +140,22 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
|
||||||
checked={this.state.linkSpecificEvent}
|
checked={this.state.linkSpecificEvent}
|
||||||
onChange={this.onLinkSpecificEventCheckboxClick}
|
onChange={this.onLinkSpecificEventCheckboxClick}
|
||||||
>
|
>
|
||||||
{_t("Link to most recent message")}
|
{_t("share|permalink_most_recent")}
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (this.props.target instanceof User || this.props.target instanceof RoomMember) {
|
} 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) {
|
} else if (this.props.target instanceof MatrixEvent) {
|
||||||
title = _t("Share Room Message");
|
title = _t("share|title_message");
|
||||||
checkbox = (
|
checkbox = (
|
||||||
<div>
|
<div>
|
||||||
<StyledCheckbox
|
<StyledCheckbox
|
||||||
checked={this.state.linkSpecificEvent}
|
checked={this.state.linkSpecificEvent}
|
||||||
onChange={this.onLinkSpecificEventCheckboxClick}
|
onChange={this.onLinkSpecificEventCheckboxClick}
|
||||||
>
|
>
|
||||||
{_t("Link to selected message")}
|
{_t("share|permalink_message")}
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -208,7 +208,7 @@ export default class ShareDialog extends React.PureComponent<XOR<Props, EventPro
|
||||||
>
|
>
|
||||||
<div className="mx_ShareDialog_content">
|
<div className="mx_ShareDialog_content">
|
||||||
<CopyableText getTextToCopy={() => matrixToUrl}>
|
<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}
|
{matrixToUrl}
|
||||||
</a>
|
</a>
|
||||||
</CopyableText>
|
</CopyableText>
|
||||||
|
|
|
@ -64,7 +64,7 @@ const SlashCommandHelpDialog: React.FC<IProps> = ({ onFinished }) => {
|
||||||
return (
|
return (
|
||||||
<InfoDialog
|
<InfoDialog
|
||||||
className="mx_SlashCommandHelpDialog"
|
className="mx_SlashCommandHelpDialog"
|
||||||
title={_t("Command Help")}
|
title={_t("slash_command|help_dialog_title")}
|
||||||
description={
|
description={
|
||||||
<table>
|
<table>
|
||||||
<tbody>{body}</tbody>
|
<tbody>{body}</tbody>
|
||||||
|
|
|
@ -77,7 +77,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
|
||||||
|
|
||||||
let nativeSupport: string;
|
let nativeSupport: string;
|
||||||
if (hasNativeSupport === null) {
|
if (hasNativeSupport === null) {
|
||||||
nativeSupport = _t("Checking…");
|
nativeSupport = _t("labs|sliding_sync_checking");
|
||||||
} else {
|
} else {
|
||||||
nativeSupport = hasNativeSupport
|
nativeSupport = hasNativeSupport
|
||||||
? _t("labs|sliding_sync_server_support")
|
? _t("labs|sliding_sync_server_support")
|
||||||
|
@ -103,7 +103,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
|
||||||
key: "working",
|
key: "working",
|
||||||
final: true,
|
final: true,
|
||||||
test: async (_, { error }) => !error,
|
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),
|
invalid: ({ error }) => (error instanceof Error ? error.message : null),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -42,7 +42,7 @@ const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsTab>
|
<SettingsTab>
|
||||||
<SettingsSection heading={_t("Sections to show")}>
|
<SettingsSection heading={_t("space|preferences|sections_section")}>
|
||||||
<SettingsSubsection>
|
<SettingsSubsection>
|
||||||
<StyledCheckbox
|
<StyledCheckbox
|
||||||
checked={!!showPeople}
|
checked={!!showPeople}
|
||||||
|
@ -58,12 +58,9 @@ const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space
|
||||||
{_t("common|people")}
|
{_t("common|people")}
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
<SettingsSubsectionText>
|
<SettingsSubsectionText>
|
||||||
{_t(
|
{_t("space|preferences|show_people_in_space", {
|
||||||
"This groups your chats with members of this space. Turning this off will hide those chats from your view of %(spaceName)s.",
|
|
||||||
{
|
|
||||||
spaceName: space.name,
|
spaceName: space.name,
|
||||||
},
|
})}
|
||||||
)}
|
|
||||||
</SettingsSubsectionText>
|
</SettingsSubsectionText>
|
||||||
</SettingsSubsection>
|
</SettingsSubsection>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default class StorageEvictedDialog extends React.Component<IProps> {
|
||||||
let logRequest;
|
let logRequest;
|
||||||
if (SdkConfig.get().bug_report_endpoint_url) {
|
if (SdkConfig.get().bug_report_endpoint_url) {
|
||||||
logRequest = _t(
|
logRequest = _t(
|
||||||
"To help us prevent this in future, please <a>send us logs</a>.",
|
"bug_reporting|log_request",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
a: (text) => (
|
a: (text) => (
|
||||||
|
@ -58,18 +58,14 @@ export default class StorageEvictedDialog extends React.Component<IProps> {
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_ErrorDialog"
|
className="mx_ErrorDialog"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Missing session data")}
|
title={_t("error|storage_evicted_title")}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
>
|
>
|
||||||
<div className="mx_Dialog_content" id="mx_Dialog_content">
|
<div className="mx_Dialog_content" id="mx_Dialog_content">
|
||||||
|
<p>{_t("error|storage_evicted_description_1")}</p>
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_t("error|storage_evicted_description_2")} {logRequest}
|
||||||
"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}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
|
|
|
@ -111,9 +111,9 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
|
||||||
case SERVICE_TYPES.IS:
|
case SERVICE_TYPES.IS:
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{_t("Find others by phone or email")}
|
{_t("terms|summary_identity_server_1")}
|
||||||
<br />
|
<br />
|
||||||
{_t("Be found by phone or email")}
|
{_t("terms|summary_identity_server_2")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case SERVICE_TYPES.IM:
|
case SERVICE_TYPES.IM:
|
||||||
|
|
|
@ -35,14 +35,14 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
|
||||||
let newSessionText: string;
|
let newSessionText: string;
|
||||||
|
|
||||||
if (MatrixClientPeg.safeGet().getUserId() === user.userId) {
|
if (MatrixClientPeg.safeGet().getUserId() === user.userId) {
|
||||||
newSessionText = _t("You signed in to a new session without verifying it:");
|
newSessionText = _t("encryption|udd|own_new_session_text");
|
||||||
askToVerifyText = _t("Verify your other session using one of the options below.");
|
askToVerifyText = _t("encryption|udd|own_ask_verify_text");
|
||||||
} else {
|
} 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,
|
name: user.displayName,
|
||||||
userId: user.userId,
|
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 (
|
return (
|
||||||
|
@ -52,7 +52,7 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
<E2EIcon status={E2EState.Warning} isUser size={24} hideTooltip={true} />
|
<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>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<AccessibleButton kind="primary_outline" onClick={() => onFinished("legacy")}>
|
<AccessibleButton kind="primary_outline" onClick={() => onFinished("legacy")}>
|
||||||
{_t("Manually verify by text")}
|
{_t("encryption|udd|manual_verification_button")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton kind="primary_outline" onClick={() => onFinished("sas")}>
|
<AccessibleButton kind="primary_outline" onClick={() => onFinished("sas")}>
|
||||||
{_t("Interactively verify by emoji")}
|
{_t("encryption|udd|interactive_verification_button")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton kind="primary" onClick={() => onFinished(false)}>
|
<AccessibleButton kind="primary" onClick={() => onFinished(false)}>
|
||||||
{_t("action|done")}
|
{_t("action|done")}
|
||||||
|
|
|
@ -69,12 +69,12 @@ export default class UploadConfirmDialog extends React.Component<IProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let title: string;
|
let title: string;
|
||||||
if (this.props.totalFiles > 1 && this.props.currentIndex !== undefined) {
|
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,
|
current: this.props.currentIndex + 1,
|
||||||
total: this.props.totalFiles,
|
total: this.props.totalFiles,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
title = _t("Upload files");
|
title = _t("upload_file|title");
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileId = `mx-uploadconfirmdialog-${this.props.file.name}`;
|
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;
|
let uploadAllButton: JSX.Element | undefined;
|
||||||
if (this.props.currentIndex + 1 < this.props.totalFiles) {
|
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 (
|
return (
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
|
||||||
let buttons;
|
let buttons;
|
||||||
if (this.props.totalFiles === 1 && this.props.badFiles.length === 1) {
|
if (this.props.totalFiles === 1 && this.props.badFiles.length === 1) {
|
||||||
message = _t(
|
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()!),
|
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
|
||||||
sizeOfThisFile: fileSize(this.props.badFiles[0].size),
|
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) {
|
} else if (this.props.totalFiles === this.props.badFiles.length) {
|
||||||
message = _t(
|
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()!),
|
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
|
||||||
},
|
},
|
||||||
|
@ -86,7 +86,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
message = _t(
|
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()!),
|
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;
|
const howManyOthers = this.props.totalFiles - this.props.badFiles.length;
|
||||||
buttons = (
|
buttons = (
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Upload %(count)s other files", { count: howManyOthers })}
|
primaryButton={_t("upload_file|upload_n_others_button", { count: howManyOthers })}
|
||||||
onPrimaryButtonClick={this.onUploadClick}
|
onPrimaryButtonClick={this.onUploadClick}
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
cancelButton={_t("Cancel All")}
|
cancelButton={_t("upload_file|cancel_all_button")}
|
||||||
onCancel={this.onCancelClick}
|
onCancel={this.onCancelClick}
|
||||||
focus={true}
|
focus={true}
|
||||||
/>
|
/>
|
||||||
|
@ -111,7 +111,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_UploadFailureDialog"
|
className="mx_UploadFailureDialog"
|
||||||
onFinished={this.onCancelClick}
|
onFinished={this.onCancelClick}
|
||||||
title={_t("Upload Error")}
|
title={_t("upload_file|error_title")}
|
||||||
contentId="mx_Dialog_content"
|
contentId="mx_Dialog_content"
|
||||||
>
|
>
|
||||||
<div id="mx_Dialog_content">
|
<div id="mx_Dialog_content">
|
||||||
|
|
|
@ -49,7 +49,9 @@ export default class VerificationRequestDialog extends React.Component<IProps, I
|
||||||
const request = this.state.verificationRequest;
|
const request = this.state.verificationRequest;
|
||||||
const otherUserId = request?.otherUserId;
|
const otherUserId = request?.otherUserId;
|
||||||
const member = this.props.member || (otherUserId ? MatrixClientPeg.safeGet().getUser(otherUserId) : null);
|
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;
|
if (!member) return null;
|
||||||
|
|
||||||
|
|
|
@ -120,15 +120,15 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
className="mx_WidgetCapabilitiesPromptDialog"
|
className="mx_WidgetCapabilitiesPromptDialog"
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Approve widget permissions")}
|
title={_t("widget|capabilities_dialog|title")}
|
||||||
>
|
>
|
||||||
<form onSubmit={this.onSubmit}>
|
<form onSubmit={this.onSubmit}>
|
||||||
<div className="mx_Dialog_content">
|
<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}
|
{checkboxRows}
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("action|approve")}
|
primaryButton={_t("action|approve")}
|
||||||
cancelButton={_t("Decline All")}
|
cancelButton={_t("widget|capabilities_dialog|decline_all_permission")}
|
||||||
onPrimaryButtonClick={this.onSubmit}
|
onPrimaryButtonClick={this.onSubmit}
|
||||||
onCancel={this.onReject}
|
onCancel={this.onReject}
|
||||||
additive={
|
additive={
|
||||||
|
@ -136,7 +136,7 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
|
||||||
value={this.state.rememberSelection}
|
value={this.state.rememberSelection}
|
||||||
toggleInFront={true}
|
toggleInFront={true}
|
||||||
onChange={this.onRememberSelectionChange}
|
onChange={this.onRememberSelectionChange}
|
||||||
label={_t("Remember my selection for this widget")}
|
label={_t("widget|capabilities_dialog|remember_Selection")}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -79,10 +79,10 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
|
||||||
className="mx_WidgetOpenIDPermissionsDialog"
|
className="mx_WidgetOpenIDPermissionsDialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished}
|
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">
|
<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">
|
<p className="text-muted">
|
||||||
{/* cheap trim to just get the path */}
|
{/* cheap trim to just get the path */}
|
||||||
{this.props.widget.templateUrl.split("?")[0].split("#")[0]}
|
{this.props.widget.templateUrl.split("?")[0].split("#")[0]}
|
||||||
|
@ -97,7 +97,7 @@ export default class WidgetOpenIDPermissionsDialog extends React.PureComponent<I
|
||||||
value={this.state.rememberSelection}
|
value={this.state.rememberSelection}
|
||||||
toggleInFront={true}
|
toggleInFront={true}
|
||||||
onChange={this.onRememberSelectionChange}
|
onChange={this.onRememberSelectionChange}
|
||||||
label={_t("Remember this")}
|
label={_t("widget|open_id_permissions_dialog|remember_selection")}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -117,7 +117,7 @@ export const EventEditor: React.FC<IEventEditorProps> = ({ fieldDefs, defaultCon
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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>
|
<div className="mx_DevTools_eventTypeStateKeyGroup">{fields}</div>
|
||||||
|
|
||||||
<Field
|
<Field
|
||||||
|
|
|
@ -59,7 +59,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="mx_DevTools_button" onClick={showMore}>
|
<button className="mx_DevTools_button" onClick={showMore}>
|
||||||
{_t("and %(count)s others...", { count: overflowCount })}
|
{_t("common|and_n_others", { count: overflowCount })}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -67,7 +67,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field
|
<Field
|
||||||
label={_t("Filter results")}
|
label={_t("common|filter_results")}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
size={64}
|
size={64}
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -80,7 +80,7 @@ const FilteredList: React.FC<IProps> = ({ children, query, onChange }) => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{filteredChildren.length < 1 ? (
|
{filteredChildren.length < 1 ? (
|
||||||
_t("No results found")
|
_t("common|no_results_found")
|
||||||
) : (
|
) : (
|
||||||
<TruncatedList
|
<TruncatedList
|
||||||
getChildren={getChildren}
|
getChildren={getChildren}
|
||||||
|
|
|
@ -277,7 +277,7 @@ const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit })
|
||||||
return (
|
return (
|
||||||
<BaseTool onBack={onBack} className="mx_DevTools_SettingsExplorer">
|
<BaseTool onBack={onBack} className="mx_DevTools_SettingsExplorer">
|
||||||
<Field
|
<Field
|
||||||
label={_t("Filter results")}
|
label={_t("common|filter_results")}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
size={64}
|
size={64}
|
||||||
type="text"
|
type="text"
|
||||||
|
|
|
@ -27,7 +27,7 @@ import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
||||||
import { Tool } from "../DevtoolsDialog";
|
import { Tool } from "../DevtoolsDialog";
|
||||||
|
|
||||||
const PHASE_MAP: Record<Phase, TranslationKey> = {
|
const PHASE_MAP: Record<Phase, TranslationKey> = {
|
||||||
[Phase.Unsent]: _td("Unsent"),
|
[Phase.Unsent]: _td("common|unsent"),
|
||||||
[Phase.Requested]: _td("devtools|phase_requested"),
|
[Phase.Requested]: _td("devtools|phase_requested"),
|
||||||
[Phase.Ready]: _td("devtools|phase_ready"),
|
[Phase.Ready]: _td("devtools|phase_ready"),
|
||||||
[Phase.Done]: _td("action|done"),
|
[Phase.Done]: _td("action|done"),
|
||||||
|
|
|
@ -45,7 +45,7 @@ export const OidcLogoutDialog: React.FC<OidcLogoutDialogProps> = ({
|
||||||
return (
|
return (
|
||||||
<BaseDialog onFinished={onFinished} title={_t("action|sign_out")} contentId="mx_Dialog_content">
|
<BaseDialog onFinished={onFinished} title={_t("action|sign_out")} contentId="mx_Dialog_content">
|
||||||
<div className="mx_Dialog_content" id="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>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
{hasOpenedLogoutLink ? (
|
{hasOpenedLogoutLink ? (
|
||||||
|
|
|
@ -263,15 +263,15 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
|
|
||||||
private getKeyValidationText(): string {
|
private getKeyValidationText(): string {
|
||||||
if (this.state.recoveryKeyFileError) {
|
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) {
|
} 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) {
|
} 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) {
|
} else if (this.state.recoveryKeyValid === null) {
|
||||||
return "";
|
return "";
|
||||||
} else {
|
} 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 = (
|
const resetButton = (
|
||||||
<div className="mx_AccessSecretStorageDialog_reset">
|
<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) => (
|
a: (sub) => (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
kind="link_inline"
|
kind="link_inline"
|
||||||
|
@ -298,16 +298,12 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
let title;
|
let title;
|
||||||
let titleClass;
|
let titleClass;
|
||||||
if (this.state.resetting) {
|
if (this.state.resetting) {
|
||||||
title = _t("Reset everything");
|
title = _t("encryption|access_secret_storage_dialog|reset_title");
|
||||||
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_resetBadge"];
|
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_resetBadge"];
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t("Only do this if you have no other device to complete verification with.")}</p>
|
<p>{_t("encryption|access_secret_storage_dialog|reset_warning_1")}</p>
|
||||||
<p>
|
<p>{_t("encryption|access_secret_storage_dialog|reset_warning_2")}</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>
|
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("action|reset")}
|
primaryButton={_t("action|reset")}
|
||||||
onPrimaryButtonClick={this.onConfirmResetAllClick}
|
onPrimaryButtonClick={this.onConfirmResetAllClick}
|
||||||
|
@ -319,7 +315,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (hasPassphrase && !this.state.forceRecoveryKey) {
|
} 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"];
|
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_securePhraseTitle"];
|
||||||
|
|
||||||
let keyStatus;
|
let keyStatus;
|
||||||
|
@ -327,9 +323,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
keyStatus = (
|
keyStatus = (
|
||||||
<div className="mx_AccessSecretStorageDialog_keyStatus">
|
<div className="mx_AccessSecretStorageDialog_keyStatus">
|
||||||
{"\uD83D\uDC4E "}
|
{"\uD83D\uDC4E "}
|
||||||
{_t(
|
{_t("encryption|access_secret_storage_dialog|security_phrase_incorrect_error")}
|
||||||
"Unable to access secret storage. Please verify that you entered the correct Security Phrase.",
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -340,7 +334,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{_t(
|
{_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) => (
|
button: (s) => (
|
||||||
|
@ -358,7 +352,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
id="mx_passPhraseInput"
|
id="mx_passPhraseInput"
|
||||||
className="mx_AccessSecretStorageDialog_passPhraseInput"
|
className="mx_AccessSecretStorageDialog_passPhraseInput"
|
||||||
type="password"
|
type="password"
|
||||||
label={_t("Security Phrase")}
|
label={_t("encryption|access_secret_storage_dialog|security_phrase_title")}
|
||||||
value={this.state.passPhrase}
|
value={this.state.passPhrase}
|
||||||
onChange={this.onPassPhraseChange}
|
onChange={this.onPassPhraseChange}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
@ -378,7 +372,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
title = _t("Security Key");
|
title = _t("encryption|access_secret_storage_dialog|security_key_title");
|
||||||
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_secureBackupTitle"];
|
titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_secureBackupTitle"];
|
||||||
|
|
||||||
const feedbackClasses = classNames({
|
const feedbackClasses = classNames({
|
||||||
|
@ -390,7 +384,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
|
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t("Use your Security Key to continue.")}</p>
|
<p>{_t("encryption|access_secret_storage_dialog|use_security_key_prompt")}</p>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
className="mx_AccessSecretStorageDialog_primaryContainer"
|
className="mx_AccessSecretStorageDialog_primaryContainer"
|
||||||
|
@ -403,7 +397,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
<Field
|
<Field
|
||||||
type="password"
|
type="password"
|
||||||
id="mx_securityKey"
|
id="mx_securityKey"
|
||||||
label={_t("Security Key")}
|
label={_t("encryption|access_secret_storage_dialog|security_key_title")}
|
||||||
value={this.state.recoveryKey}
|
value={this.state.recoveryKey}
|
||||||
onChange={this.onRecoveryKeyChange}
|
onChange={this.onRecoveryKeyChange}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
@ -412,7 +406,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="mx_AccessSecretStorageDialog_recoveryKeyEntry_entryControlSeparatorText">
|
<span className="mx_AccessSecretStorageDialog_recoveryKeyEntry_entryControlSeparatorText">
|
||||||
{_t("%(securityKey)s or %(recoveryFile)s", {
|
{_t("encryption|access_secret_storage_dialog|separator", {
|
||||||
recoveryFile: "",
|
recoveryFile: "",
|
||||||
securityKey: "",
|
securityKey: "",
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -39,17 +39,13 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component<IP
|
||||||
className="mx_ConfirmDestroyCrossSigningDialog"
|
className="mx_ConfirmDestroyCrossSigningDialog"
|
||||||
hasCancel={true}
|
hasCancel={true}
|
||||||
onFinished={this.props.onFinished}
|
onFinished={this.props.onFinished}
|
||||||
title={_t("Destroy cross-signing keys?")}
|
title={_t("encryption|destroy_cross_signing_dialog|title")}
|
||||||
>
|
>
|
||||||
<div className="mx_ConfirmDestroyCrossSigningDialog_content">
|
<div className="mx_ConfirmDestroyCrossSigningDialog_content">
|
||||||
<p>
|
<p>{_t("encryption|destroy_cross_signing_dialog|warning")}</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>
|
|
||||||
</div>
|
</div>
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("Clear cross-signing keys")}
|
primaryButton={_t("encryption|destroy_cross_signing_dialog|primary_button_text")}
|
||||||
onPrimaryButtonClick={this.onConfirm}
|
onPrimaryButtonClick={this.onConfirm}
|
||||||
primaryButtonClass="danger"
|
primaryButtonClass="danger"
|
||||||
cancelButton={_t("action|cancel")}
|
cancelButton={_t("action|cancel")}
|
||||||
|
|
|
@ -113,13 +113,13 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
||||||
const dialogAesthetics = {
|
const dialogAesthetics = {
|
||||||
[SSOAuthEntry.PHASE_PREAUTH]: {
|
[SSOAuthEntry.PHASE_PREAUTH]: {
|
||||||
title: _t("auth|uia|sso_title"),
|
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"),
|
continueText: _t("auth|sso"),
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
[SSOAuthEntry.PHASE_POSTAUTH]: {
|
||||||
title: _t("Confirm encryption setup"),
|
title: _t("encryption|confirm_encryption_setup_title"),
|
||||||
body: _t("Click the button below to confirm setting up encryption."),
|
body: _t("encryption|confirm_encryption_setup_body"),
|
||||||
continueText: _t("action|confirm"),
|
continueText: _t("action|confirm"),
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
|
@ -173,7 +173,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>{_t("Unable to set up keys")}</p>
|
<p>{_t("encryption|unable_to_setup_keys_error")}</p>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className="mx_Dialog_buttons">
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
primaryButton={_t("action|retry")}
|
primaryButton={_t("action|retry")}
|
||||||
|
|
|
@ -318,18 +318,18 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
let content;
|
let content;
|
||||||
let title;
|
let title;
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
title = _t("Restoring keys from backup");
|
title = _t("encryption|access_secret_storage_dialog|restoring");
|
||||||
let details;
|
let details;
|
||||||
if (this.state.progress.stage === ProgressState.Fetch) {
|
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) {
|
} else if (this.state.progress.stage === ProgressState.LoadKeys) {
|
||||||
const { total, successes, failures } = this.state.progress;
|
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,
|
total,
|
||||||
completed: (successes ?? 0) + (failures ?? 0),
|
completed: (successes ?? 0) + (failures ?? 0),
|
||||||
});
|
});
|
||||||
} else if (this.state.progress.stage === ProgressState.PreFetch) {
|
} 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 = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
|
@ -339,49 +339,41 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
);
|
);
|
||||||
} else if (this.state.loadError) {
|
} else if (this.state.loadError) {
|
||||||
title = _t("common|error");
|
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) {
|
} else if (this.state.restoreError) {
|
||||||
if (
|
if (
|
||||||
this.state.restoreError instanceof MatrixError &&
|
this.state.restoreError instanceof MatrixError &&
|
||||||
this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY
|
this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY
|
||||||
) {
|
) {
|
||||||
if (this.state.restoreType === RestoreType.RecoveryKey) {
|
if (this.state.restoreType === RestoreType.RecoveryKey) {
|
||||||
title = _t("Security Key mismatch");
|
title = _t("restore_key_backup_dialog|recovery_key_mismatch_title");
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>{_t("restore_key_backup_dialog|recovery_key_mismatch_description")}</p>
|
||||||
{_t(
|
|
||||||
"Backup could not be decrypted with this Security Key: please verify that you entered the correct Security Key.",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
title = _t("Incorrect Security Phrase");
|
title = _t("restore_key_backup_dialog|incorrect_security_phrase_title");
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>{_t("restore_key_backup_dialog|incorrect_security_phrase_dialog")}</p>
|
||||||
{_t(
|
|
||||||
"Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
title = _t("common|error");
|
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) {
|
} else if (this.state.backupInfo === null) {
|
||||||
title = _t("common|error");
|
title = _t("common|error");
|
||||||
content = _t("No backup found!");
|
content = _t("restore_key_backup_dialog|no_backup_error");
|
||||||
} else if (this.state.recoverInfo) {
|
} else if (this.state.recoverInfo) {
|
||||||
title = _t("Keys restored");
|
title = _t("restore_key_backup_dialog|keys_restored_title");
|
||||||
let failedToDecrypt;
|
let failedToDecrypt;
|
||||||
if (this.state.recoverInfo.total > this.state.recoverInfo.imported) {
|
if (this.state.recoverInfo.total > this.state.recoverInfo.imported) {
|
||||||
failedToDecrypt = (
|
failedToDecrypt = (
|
||||||
<p>
|
<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,
|
failedCount: this.state.recoverInfo.total - this.state.recoverInfo.imported,
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
@ -390,7 +382,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{_t("Successfully restored %(sessionCount)s keys", {
|
{_t("restore_key_backup_dialog|count_of_successfully_restored_keys", {
|
||||||
sessionCount: this.state.recoverInfo.imported,
|
sessionCount: this.state.recoverInfo.imported,
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
@ -404,21 +396,11 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (backupHasPassphrase && !this.state.forceRecoveryKey) {
|
} else if (backupHasPassphrase && !this.state.forceRecoveryKey) {
|
||||||
title = _t("Enter Security Phrase");
|
title = _t("restore_key_backup_dialog|enter_phrase_title");
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>{_t("restore_key_backup_dialog|key_backup_warning", {}, { b: (sub) => <b>{sub}</b> })}</p>
|
||||||
{_t(
|
<p>{_t("restore_key_backup_dialog|enter_phrase_description")}</p>
|
||||||
"<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>
|
|
||||||
|
|
||||||
<form className="mx_RestoreKeyBackupDialog_primaryContainer">
|
<form className="mx_RestoreKeyBackupDialog_primaryContainer">
|
||||||
<input
|
<input
|
||||||
|
@ -438,7 +420,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
{_t(
|
{_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) => (
|
button1: (s) => (
|
||||||
|
@ -456,7 +438,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
title = _t("Enter Security Key");
|
title = _t("restore_key_backup_dialog|enter_key_title");
|
||||||
|
|
||||||
let keyStatus;
|
let keyStatus;
|
||||||
if (this.state.recoveryKey.length === 0) {
|
if (this.state.recoveryKey.length === 0) {
|
||||||
|
@ -465,32 +447,22 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
keyStatus = (
|
keyStatus = (
|
||||||
<div className="mx_RestoreKeyBackupDialog_keyStatus">
|
<div className="mx_RestoreKeyBackupDialog_keyStatus">
|
||||||
{"\uD83D\uDC4D "}
|
{"\uD83D\uDC4D "}
|
||||||
{_t("This looks like a valid Security Key!")}
|
{_t("restore_key_backup_dialog|key_is_valid")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
keyStatus = (
|
keyStatus = (
|
||||||
<div className="mx_RestoreKeyBackupDialog_keyStatus">
|
<div className="mx_RestoreKeyBackupDialog_keyStatus">
|
||||||
{"\uD83D\uDC4E "}
|
{"\uD83D\uDC4E "}
|
||||||
{_t("Not a valid Security Key")}
|
{_t("restore_key_backup_dialog|key_is_invalid")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>{_t("restore_key_backup_dialog|key_backup_warning", {}, { b: (sub) => <b>{sub}</b> })}</p>
|
||||||
{_t(
|
<p>{_t("restore_key_backup_dialog|enter_key_description")}</p>
|
||||||
"<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>
|
|
||||||
|
|
||||||
<div className="mx_RestoreKeyBackupDialog_primaryContainer">
|
<div className="mx_RestoreKeyBackupDialog_primaryContainer">
|
||||||
<input
|
<input
|
||||||
|
@ -510,7 +482,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps,
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{_t(
|
{_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) => (
|
button: (s) => (
|
||||||
|
|
|
@ -60,7 +60,7 @@ export function PublicRoomResultDetails({ room, labelId, descriptionId, detailsI
|
||||||
</div>
|
</div>
|
||||||
<div id={detailsId} className="mx_SpotlightDialog_result_publicRoomDescription">
|
<div id={detailsId} className="mx_SpotlightDialog_result_publicRoomDescription">
|
||||||
<span className="mx_SpotlightDialog_result_publicRoomMemberCount">
|
<span className="mx_SpotlightDialog_result_publicRoomMemberCount">
|
||||||
{_t("%(count)s Members", {
|
{_t("spotlight_dialog|count_of_members", {
|
||||||
count: room.num_joined_members,
|
count: room.num_joined_members,
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -123,9 +123,9 @@ function filterToLabel(filter: Filter): string {
|
||||||
case Filter.People:
|
case Filter.People:
|
||||||
return _t("common|people");
|
return _t("common|people");
|
||||||
case Filter.PublicRooms:
|
case Filter.PublicRooms:
|
||||||
return _t("Public rooms");
|
return _t("spotlight_dialog|public_rooms_label");
|
||||||
case Filter.PublicSpaces:
|
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"
|
aria-labelledby="mx_SpotlightDialog_section_otherSearches"
|
||||||
>
|
>
|
||||||
<h4 id="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>
|
</h4>
|
||||||
<div>
|
<div>
|
||||||
{filter !== Filter.PublicSpaces && supportsSpaceFiltering && (
|
{filter !== Filter.PublicSpaces && supportsSpaceFiltering && (
|
||||||
|
@ -760,7 +762,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
role="group"
|
role="group"
|
||||||
aria-labelledby="mx_SpotlightDialog_section_people"
|
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>{results[Section.People].slice(0, SECTION_LIMIT).map(resultMapper)}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -802,7 +804,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
role="group"
|
role="group"
|
||||||
aria-labelledby="mx_SpotlightDialog_section_spaces"
|
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>{results[Section.Spaces].slice(0, SECTION_LIMIT).map(resultMapper)}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -815,8 +817,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
content = (
|
content = (
|
||||||
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
|
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
|
||||||
{filter === Filter.PublicRooms
|
{filter === Filter.PublicRooms
|
||||||
? _t("Failed to query public rooms")
|
? _t("spotlight_dialog|failed_querying_public_rooms")
|
||||||
: _t("Failed to query public spaces")}
|
: _t("spotlight_dialog|failed_querying_public_spaces")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -849,7 +851,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
aria-labelledby="mx_SpotlightDialog_section_spaceRooms"
|
aria-labelledby="mx_SpotlightDialog_section_spaceRooms"
|
||||||
>
|
>
|
||||||
<h4 id="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>
|
</h4>
|
||||||
<div>
|
<div>
|
||||||
{spaceResults.slice(0, SECTION_LIMIT).map(
|
{spaceResults.slice(0, SECTION_LIMIT).map(
|
||||||
|
@ -909,7 +911,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{_t("Join %(roomAddress)s", {
|
{_t("spotlight_dialog|join_button_text", {
|
||||||
roomAddress: trimmedQuery,
|
roomAddress: trimmedQuery,
|
||||||
})}
|
})}
|
||||||
</Option>
|
</Option>
|
||||||
|
@ -922,9 +924,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
if (filter === Filter.People) {
|
if (filter === Filter.People) {
|
||||||
hiddenResultsSection = (
|
hiddenResultsSection = (
|
||||||
<div className="mx_SpotlightDialog_section mx_SpotlightDialog_hiddenResults" role="group">
|
<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">
|
<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>
|
</div>
|
||||||
<TooltipOption
|
<TooltipOption
|
||||||
id="mx_SpotlightDialog_button_inviteLink"
|
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")}
|
title={inviteLinkCopied ? _t("common|copied") : _t("action|copy")}
|
||||||
>
|
>
|
||||||
<span className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">
|
<span className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">
|
||||||
{_t("Copy invite link")}
|
{_t("spotlight_dialog|copy_link_text")}
|
||||||
</span>
|
</span>
|
||||||
</TooltipOption>
|
</TooltipOption>
|
||||||
</div>
|
</div>
|
||||||
|
@ -945,9 +947,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
} else if (trimmedQuery && (filter === Filter.PublicRooms || filter === Filter.PublicSpaces)) {
|
} else if (trimmedQuery && (filter === Filter.PublicRooms || filter === Filter.PublicSpaces)) {
|
||||||
hiddenResultsSection = (
|
hiddenResultsSection = (
|
||||||
<div className="mx_SpotlightDialog_section mx_SpotlightDialog_hiddenResults" role="group">
|
<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">
|
<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>
|
</div>
|
||||||
<Option
|
<Option
|
||||||
id="mx_SpotlightDialog_button_createNewRoom"
|
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">
|
<span className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">
|
||||||
{_t("Create new room")}
|
{_t("spotlight_dialog|create_new_room_button")}
|
||||||
</span>
|
</span>
|
||||||
</Option>
|
</Option>
|
||||||
</div>
|
</div>
|
||||||
|
@ -976,13 +978,13 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
role="group"
|
role="group"
|
||||||
aria-labelledby="mx_SpotlightDialog_section_groupChat"
|
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
|
<Option
|
||||||
id="mx_SpotlightDialog_button_startGroupChat"
|
id="mx_SpotlightDialog_button_startGroupChat"
|
||||||
className="mx_SpotlightDialog_startGroupChat"
|
className="mx_SpotlightDialog_startGroupChat"
|
||||||
onClick={() => showStartChatInviteDialog(trimmedQuery)}
|
onClick={() => showStartChatInviteDialog(trimmedQuery)}
|
||||||
>
|
>
|
||||||
{_t("Start a group chat")}
|
{_t("spotlight_dialog|start_group_chat_button")}
|
||||||
</Option>
|
</Option>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -996,10 +998,12 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
role="group"
|
role="group"
|
||||||
aria-labelledby="mx_SpotlightDialog_section_messageSearch"
|
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">
|
<div className="mx_SpotlightDialog_otherSearches_messageSearchText">
|
||||||
{_t(
|
{_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" /> },
|
{ 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"
|
aria-labelledby="mx_SpotlightDialog_section_recentSearches"
|
||||||
>
|
>
|
||||||
<h4>
|
<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}>
|
<AccessibleButton kind="link" onClick={clearRecentSearches}>
|
||||||
{_t("action|clear")}
|
{_t("action|clear")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
@ -1086,7 +1092,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
role="group"
|
role="group"
|
||||||
aria-labelledby="mx_SpotlightDialog_section_recentlyViewed"
|
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>
|
<div>
|
||||||
{BreadcrumbsStore.instance.rooms
|
{BreadcrumbsStore.instance.rooms
|
||||||
.filter((r) => r.roomId !== SdkContextClass.instance.roomViewStore.getRoomId())
|
.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">
|
<div id="mx_SpotlightDialog_keyboardPrompt">
|
||||||
{_t(
|
{_t(
|
||||||
"Use <arrows/> to scroll",
|
"spotlight_dialog|keyboard_scroll_hint",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
arrows: () => (
|
arrows: () => (
|
||||||
|
@ -1230,7 +1238,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
onKeyDown={onDialogKeyDown}
|
onKeyDown={onDialogKeyDown}
|
||||||
screenName="UnifiedSearch"
|
screenName="UnifiedSearch"
|
||||||
aria-label={_t("Search Dialog")}
|
aria-label={_t("spotlight_dialog|search_dialog")}
|
||||||
>
|
>
|
||||||
<div className="mx_SpotlightDialog_searchBox mx_textinput">
|
<div className="mx_SpotlightDialog_searchBox mx_textinput">
|
||||||
{filter !== null && (
|
{filter !== null && (
|
||||||
|
@ -1244,7 +1252,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
<span>{filterToLabel(filter)}</span>
|
<span>{filterToLabel(filter)}</span>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
alt={_t("Remove search filter for %(filter)s", {
|
alt={_t("spotlight_dialog|remove_filter", {
|
||||||
filter: filterToLabel(filter),
|
filter: filterToLabel(filter),
|
||||||
})}
|
})}
|
||||||
className="mx_SpotlightDialog_filter--close"
|
className="mx_SpotlightDialog_filter--close"
|
||||||
|
|
|
@ -55,17 +55,17 @@ const validServer = withValidation<undefined, { error?: unknown }>({
|
||||||
{
|
{
|
||||||
key: "required",
|
key: "required",
|
||||||
test: async ({ value }) => !!value,
|
test: async ({ value }) => !!value,
|
||||||
invalid: () => _t("Enter a server name"),
|
invalid: () => _t("spotlight|public_rooms|network_dropdown_required_invalid"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "available",
|
key: "available",
|
||||||
final: true,
|
final: true,
|
||||||
test: async (_, { error }) => !error,
|
test: async (_, { error }) => !error,
|
||||||
valid: () => _t("Looks good"),
|
valid: () => _t("spotlight|public_rooms|network_dropdown_available_valid"),
|
||||||
invalid: ({ error }) =>
|
invalid: ({ error }) =>
|
||||||
error instanceof MatrixError && error.errcode === "M_FORBIDDEN"
|
error instanceof MatrixError && error.errcode === "M_FORBIDDEN"
|
||||||
? _t("You are not allowed to view this server's rooms list")
|
? _t("spotlight|public_rooms|network_dropdown_available_invalid_forbidden")
|
||||||
: _t("Can't find this server or its room list"),
|
: _t("spotlight|public_rooms|network_dropdown_available_invalid"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
memoize: true,
|
memoize: true,
|
||||||
|
@ -151,7 +151,8 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
const options: GenericDropdownMenuItem<IPublicRoomDirectoryConfig | null>[] = allServers.map((roomServer) => ({
|
const options: GenericDropdownMenuItem<IPublicRoomDirectoryConfig | null>[] = allServers.map((roomServer) => ({
|
||||||
key: { roomServer, instanceId: undefined },
|
key: { roomServer, instanceId: undefined },
|
||||||
label: roomServer,
|
label: roomServer,
|
||||||
description: roomServer === homeServer ? _t("Your server") : null,
|
description:
|
||||||
|
roomServer === homeServer ? _t("spotlight|public_rooms|network_dropdown_your_server_description") : null,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
key: { roomServer, instanceId: undefined },
|
key: { roomServer, instanceId: undefined },
|
||||||
|
@ -171,7 +172,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
adornment: (
|
adornment: (
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className="mx_NetworkDropdown_removeServer"
|
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))}
|
onClick={() => setUserDefinedServers(without(userDefinedServers, roomServer))}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
@ -191,11 +192,11 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
const { finished } = Modal.createDialog(
|
const { finished } = Modal.createDialog(
|
||||||
TextInputDialog,
|
TextInputDialog,
|
||||||
{
|
{
|
||||||
title: _t("Add a new server"),
|
title: _t("spotlight|public_rooms|network_dropdown_add_dialog_title"),
|
||||||
description: _t("Enter the name of a new server you want to explore."),
|
description: _t("spotlight|public_rooms|network_dropdown_add_dialog_description"),
|
||||||
button: _t("action|add"),
|
button: _t("action|add"),
|
||||||
hasCancel: false,
|
hasCancel: false,
|
||||||
placeholder: _t("Server name"),
|
placeholder: _t("spotlight|public_rooms|network_dropdown_add_dialog_placeholder"),
|
||||||
validator: validServer,
|
validator: validServer,
|
||||||
fixedWidth: false,
|
fixedWidth: false,
|
||||||
},
|
},
|
||||||
|
@ -214,7 +215,9 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="mx_GenericDropdownMenu_Option--label">
|
<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>
|
</div>
|
||||||
</MenuItemRadio>
|
</MenuItemRadio>
|
||||||
</>
|
</>
|
||||||
|
@ -233,11 +236,11 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
|
||||||
onChange={(option) => setConfig(option)}
|
onChange={(option) => setConfig(option)}
|
||||||
selectedLabel={(option) =>
|
selectedLabel={(option) =>
|
||||||
option?.key
|
option?.key
|
||||||
? _t("Show: %(instance)s rooms (%(server)s)", {
|
? _t("spotlight|public_rooms|network_dropdown_selected_label_instance", {
|
||||||
server: option.key.roomServer,
|
server: option.key.roomServer,
|
||||||
instance: option.key.instanceId ? option.label : "Matrix",
|
instance: option.key.instanceId ? option.label : "Matrix",
|
||||||
})
|
})
|
||||||
: _t("Show: Matrix rooms")
|
: _t("spotlight|public_rooms|network_dropdown_selected_label")
|
||||||
}
|
}
|
||||||
AdditionalOptions={addNewServer}
|
AdditionalOptions={addNewServer}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default class InfoTooltip extends React.PureComponent<ITooltipProps> {
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const { tooltip, children, tooltipClassName, className, kind } = this.props;
|
const { tooltip, children, tooltipClassName, className, kind } = this.props;
|
||||||
const title = _t("Information");
|
const title = _t("info_tooltip_title");
|
||||||
const iconClassName =
|
const iconClassName =
|
||||||
kind !== InfoTooltipKind.Warning ? "mx_InfoTooltip_icon_info" : "mx_InfoTooltip_icon_warning";
|
kind !== InfoTooltipKind.Warning ? "mx_InfoTooltip_icon_info" : "mx_InfoTooltip_icon_warning";
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ export default class LanguageDropdown extends React.Component<IProps, IState> {
|
||||||
onSearchChange={this.onSearchChange}
|
onSearchChange={this.onSearchChange}
|
||||||
searchEnabled={true}
|
searchEnabled={true}
|
||||||
value={value}
|
value={value}
|
||||||
label={_t("Language Dropdown")}
|
label={_t("language_dropdown_label")}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
>
|
>
|
||||||
{options}
|
{options}
|
||||||
|
|
|
@ -125,7 +125,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
|
||||||
case PillType.EventInOtherRoom:
|
case PillType.EventInOtherRoom:
|
||||||
{
|
{
|
||||||
avatar = <PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />;
|
avatar = <PillRoomAvatar shouldShowPillAvatar={shouldShowPillAvatar} room={targetRoom} />;
|
||||||
pillText = _t("Message in %(room)s", {
|
pillText = _t("pill|permalink_other_room", {
|
||||||
room: text,
|
room: text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
|
||||||
{
|
{
|
||||||
if (event) {
|
if (event) {
|
||||||
avatar = <PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />;
|
avatar = <PillMemberAvatar shouldShowPillAvatar={shouldShowPillAvatar} member={member} />;
|
||||||
pillText = _t("Message from %(user)s", {
|
pillText = _t("pill|permalink_this_room", {
|
||||||
user: text,
|
user: text,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -151,7 +151,7 @@ export default class PowerSelector<K extends undefined | string> extends React.C
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let picker;
|
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) {
|
if (this.state.custom) {
|
||||||
picker = (
|
picker = (
|
||||||
<Field
|
<Field
|
||||||
|
@ -173,7 +173,7 @@ export default class PowerSelector<K extends undefined | string> extends React.C
|
||||||
text: Roles.textualPowerLevel(level, this.props.usersDefault),
|
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) => {
|
const optionsElements = options.map((op) => {
|
||||||
return (
|
return (
|
||||||
<option value={op.value} key={op.value} data-testid={`power-level-option-${op.value}`}>
|
<option value={op.value} key={op.value} data-testid={`power-level-option-${op.value}`}>
|
||||||
|
|
|
@ -204,9 +204,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
||||||
if (this.state.err) {
|
if (this.state.err) {
|
||||||
header = (
|
header = (
|
||||||
<blockquote className="mx_ReplyChain mx_ReplyChain_error">
|
<blockquote className="mx_ReplyChain mx_ReplyChain_error">
|
||||||
{_t(
|
{_t("timeline|reply|error_loading")}
|
||||||
"Unable to load event that was replied to, it either does not exist or you do not have permission to view it.",
|
|
||||||
)}
|
|
||||||
</blockquote>
|
</blockquote>
|
||||||
);
|
);
|
||||||
} else if (this.state.loadedEv && shouldDisplayReply(this.state.events[0])) {
|
} else if (this.state.loadedEv && shouldDisplayReply(this.state.events[0])) {
|
||||||
|
@ -215,7 +213,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
||||||
header = (
|
header = (
|
||||||
<blockquote className={`mx_ReplyChain ${this.getReplyChainColorClass(ev)}`}>
|
<blockquote className={`mx_ReplyChain ${this.getReplyChainColorClass(ev)}`}>
|
||||||
{_t(
|
{_t(
|
||||||
"<a>In reply to</a> <pill>",
|
"timeline|reply|in_reply_to",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
a: (sub) => (
|
a: (sub) => (
|
||||||
|
@ -244,7 +242,7 @@ export default class ReplyChain extends React.Component<IProps, IState> {
|
||||||
header = (
|
header = (
|
||||||
<p className="mx_ReplyChain_Export">
|
<p className="mx_ReplyChain_Export">
|
||||||
{_t(
|
{_t(
|
||||||
"In reply to <a>this message</a>",
|
"timeline|reply|in_reply_to_for_export",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
a: (sub) => (
|
a: (sub) => (
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue