Merge branch 'develop' into germain-gg/facepile-offset

This commit is contained in:
Germain 2023-09-22 08:46:37 +01:00 committed by GitHub
commit 224f34c211
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
163 changed files with 15302 additions and 13240 deletions

View file

@ -12,7 +12,7 @@ jobs:
- name: "Get modified files"
id: changed_files
if: github.event_name == 'pull_request' && github.event.pull_request.user.login != 'RiotTranslateBot' && github.event.pull_request.user.login != 't3chguy'
uses: tj-actions/changed-files@48566bbcc22ceb7c5809ebdd27377309f2c3de8c # v39
uses: tj-actions/changed-files@41960309398d165631f08c5df47a11147e14712b # v39
with:
files: |
src/i18n/strings/*

View file

@ -54,7 +54,7 @@ jobs:
- name: Get number of CPU cores
id: cpu-cores
uses: SimenB/github-actions-cpu-cores@410541432439795d30db6501fb1d8178eb41e502 # v1
uses: SimenB/github-actions-cpu-cores@97ba232459a8e02ff6121db9362b09661c875ab8 # v2
- name: Run tests
run: |

View file

@ -404,9 +404,9 @@ describe("Cryptography", function () {
cy.get(".mx_EventTile_last")
.should("contain", "test encrypted from unverified")
.find(".mx_EventTile_e2eIcon", { timeout: 100000 })
.find(".mx_EventTile_e2eIcon")
.should("have.class", "mx_EventTile_e2eIcon_warning")
.should("have.attr", "aria-label", "Encrypted by an unverified user.");
.should("have.attr", "aria-label", "Encrypted by a device not verified by its owner.");
/* Should show a grey padlock for a message from an unknown device */
@ -415,10 +415,12 @@ describe("Cryptography", function () {
.then(() => bobSecondDevice.logout(true))
.then(() => cy.log(`Bob logged out second device`));
// some debate over whether this should have a red or a grey shield. Legacy crypto shows a grey shield,
// Rust crypto a red one.
cy.get(".mx_EventTile_last")
.should("contain", "test encrypted from unverified")
.find(".mx_EventTile_e2eIcon")
.should("have.class", "mx_EventTile_e2eIcon_normal")
//.should("have.class", "mx_EventTile_e2eIcon_normal")
.should("have.attr", "aria-label", "Encrypted by an unknown or deleted device.");
});
@ -437,7 +439,7 @@ describe("Cryptography", function () {
// no e2e icon
.should("not.have.descendants", ".mx_EventTile_e2eIcon");
/* log out, and back i */
/* log out, and back in */
logOutOfElement();
cy.get<string>("@securityKey").then((securityKey) => {
logIntoElement(homeserver.baseUrl, aliceCredentials.username, aliceCredentials.password, securityKey);

View file

@ -102,7 +102,7 @@
"matrix-encrypt-attachment": "^1.0.3",
"matrix-events-sdk": "0.0.1",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-widget-api": "^1.5.0",
"matrix-widget-api": "^1.6.0",
"memoize-one": "^6.0.0",
"minimist": "^1.2.5",
"oidc-client-ts": "^2.2.4",
@ -161,7 +161,7 @@
"@types/fs-extra": "^11.0.0",
"@types/geojson": "^7946.0.8",
"@types/glob-to-regexp": "^0.4.1",
"@types/jest": "29.5.4",
"@types/jest": "29.5.5",
"@types/katex": "^0.16.0",
"@types/lodash": "^4.14.168",
"@types/modernizr": "^3.5.3",

View file

@ -158,9 +158,7 @@ limitations under the License.
display: flex;
.mx_BaseAvatar {
display: inline-flex;
margin: auto 16px auto 5px;
vertical-align: middle;
}
> div {

View file

@ -89,4 +89,10 @@ limitations under the License.
height: 16px;
width: 16px;
}
&.mx_SpacePill {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
padding-left: 4px;
}
}

View file

@ -25,7 +25,7 @@ import {
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
import { KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
import dis from "./dispatcher/dispatcher";
import {
@ -62,10 +62,10 @@ export default class DeviceListener {
private dismissed = new Set<string>();
// has the user dismissed any of the various nag toasts to setup encryption on this device?
private dismissedThisDeviceToast = false;
// cache of the key backup info
private keyBackupInfo: IKeyBackupInfo | null = null;
/** Cache of the info about the current key backup on the server. */
private keyBackupInfo: KeyBackupInfo | null = null;
/** When `keyBackupInfo` was last updated */
private keyBackupFetchedAt: number | null = null;
private keyBackupStatusChecked = false;
// We keep a list of our own device IDs so we can batch ones that were already
// there the last time the app launched into a single toast, but display new
// ones in their own toasts.
@ -243,9 +243,14 @@ export default class DeviceListener {
this.updateClientInformation();
};
// The server doesn't tell us when key backup is set up, so we poll
// & cache the result
private async getKeyBackupInfo(): Promise<IKeyBackupInfo | null> {
/**
* Fetch the key backup information from the server.
*
* The result is cached for `KEY_BACKUP_POLL_INTERVAL` ms to avoid repeated API calls.
*
* @returns The key backup info from the server, or `null` if there is no key backup.
*/
private async getKeyBackupInfo(): Promise<KeyBackupInfo | null> {
if (!this.client) return null;
const now = new Date().getTime();
if (
@ -402,18 +407,23 @@ export default class DeviceListener {
this.displayingToastsForDeviceIds = newUnverifiedDeviceIds;
}
/**
* Check if key backup is enabled, and if not, raise an `Action.ReportKeyBackupNotEnabled` event (which will
* trigger an auto-rageshake).
*/
private checkKeyBackupStatus = async (): Promise<void> => {
if (this.keyBackupStatusChecked || !this.client) {
return;
}
// returns null when key backup status hasn't finished being checked
const isKeyBackupEnabled = this.client.getKeyBackupEnabled();
this.keyBackupStatusChecked = isKeyBackupEnabled !== null;
const activeKeyBackupVersion = await this.client.getCrypto()?.getActiveSessionBackupVersion();
// if key backup is enabled, no need to check this ever again (XXX: why only when it is enabled?)
this.keyBackupStatusChecked = !!activeKeyBackupVersion;
if (isKeyBackupEnabled === false) {
if (!activeKeyBackupVersion) {
dis.dispatch({ action: Action.ReportKeyBackupNotEnabled });
}
};
private keyBackupStatusChecked = false;
private onRecordClientInformationSettingChange: CallbackFn = (
_originalSettingName,

View file

@ -104,7 +104,7 @@ export default class CommandProvider extends AutocompleteProvider {
}
public getName(): string {
return "*️⃣ " + _t("Commands");
return "*️⃣ " + _t("composer|autocomplete|command_description");
}
public renderCompletions(completions: React.ReactNode[]): React.ReactNode {
@ -112,7 +112,7 @@ export default class CommandProvider extends AutocompleteProvider {
<div
className="mx_Autocomplete_Completion_container_pill"
role="presentation"
aria-label={_t("Command Autocomplete")}
aria-label={_t("composer|autocomplete|command_a11y")}
>
{completions}
</div>

View file

@ -184,7 +184,7 @@ export default class EmojiProvider extends AutocompleteProvider {
<div
className="mx_Autocomplete_Completion_container_pill"
role="presentation"
aria-label={_t("Emoji Autocomplete")}
aria-label={_t("composer|autocomplete|emoji_a11y")}
>
{completions}
</div>

View file

@ -55,7 +55,7 @@ export default class NotifProvider extends AutocompleteProvider {
type: "at-room",
suffix: " ",
component: (
<PillCompletion title="@room" description={_t("Notify the whole room")}>
<PillCompletion title="@room" description={_t("composer|autocomplete|@room_description")}>
<RoomAvatar size="24px" room={this.room} />
</PillCompletion>
),
@ -67,7 +67,7 @@ export default class NotifProvider extends AutocompleteProvider {
}
public getName(): string {
return "❗️ " + _t("Room Notification");
return "❗️ " + _t("composer|autocomplete|notification_description");
}
public renderCompletions(completions: React.ReactNode[]): React.ReactNode {
@ -75,7 +75,7 @@ export default class NotifProvider extends AutocompleteProvider {
<div
className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate"
role="presentation"
aria-label={_t("Notification Autocomplete")}
aria-label={_t("composer|autocomplete|notification_a11y")}
>
{completions}
</div>

View file

@ -142,7 +142,7 @@ export default class RoomProvider extends AutocompleteProvider {
<div
className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate"
role="presentation"
aria-label={_t("Room Autocomplete")}
aria-label={_t("composer|autocomplete|room_a11y")}
>
{completions}
</div>

View file

@ -38,7 +38,7 @@ export default class SpaceProvider extends RoomProvider {
<div
className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate"
role="listbox"
aria-label={_t("Space Autocomplete")}
aria-label={_t("composer|autocomplete|space_a11y")}
>
{completions}
</div>

View file

@ -146,7 +146,7 @@ export default class UserProvider extends AutocompleteProvider {
}
public getName(): string {
return _t("Users");
return _t("composer|autocomplete|user_description");
}
private makeUsers(): void {
@ -186,7 +186,7 @@ export default class UserProvider extends AutocompleteProvider {
<div
className="mx_Autocomplete_Completion_container_pill"
role="presentation"
aria-label={_t("User Autocomplete")}
aria-label={_t("composer|autocomplete|user_a11y")}
>
{completions}
</div>

View file

@ -119,7 +119,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
className="mx_FileDropTarget_image"
alt=""
/>
{_t("Drop file here to upload")}
{_t("room|drop_file_prompt")}
</div>
);
}

View file

@ -231,7 +231,7 @@ class FilePanel extends React.Component<IProps, IState> {
<BaseCard className="mx_FilePanel mx_RoomView_messageListWrapper" onClose={this.props.onClose}>
<div className="mx_RoomView_empty">
{_t(
"You must <a>register</a> to use this functionality",
"file_panel|guest_note",
{},
{
a: (sub) => (
@ -247,7 +247,7 @@ class FilePanel extends React.Component<IProps, IState> {
} else if (this.noRoom) {
return (
<BaseCard className="mx_FilePanel mx_RoomView_messageListWrapper" onClose={this.props.onClose}>
<div className="mx_RoomView_empty">{_t("You must join the room to see its files")}</div>
<div className="mx_RoomView_empty">{_t("file_panel|peek_note")}</div>
</BaseCard>
);
}
@ -256,8 +256,8 @@ class FilePanel extends React.Component<IProps, IState> {
const emptyState = (
<div className="mx_RightPanel_empty mx_FilePanel_empty">
<h2>{_t("No files visible in this room")}</h2>
<p>{_t("Attach files from chat or just drag and drop them anywhere in a room.")}</p>
<h2>{_t("file_panel|empty_heading")}</h2>
<p>{_t("file_panel|empty_description")}</p>
</div>
);

View file

@ -515,12 +515,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const normalFontSize = "15px";
const waitText = _t("Wait!");
const scamText = _t(
"If someone told you to copy/paste something here, there is a high likelihood you're being scammed!",
);
const devText = _t(
"If you know what you're doing, Element is open-source, be sure to check out our GitHub (https://github.com/vector-im/element-web/) and contribute!",
);
const scamText = _t("console_scam_warning");
const devText = _t("console_dev_note");
global.mx_rage_logger.bypassRageshake(
"log",
@ -1611,8 +1607,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
Modal.createDialog(ErrorDialog, {
title: _t("Signed Out"),
description: _t("For security, this session has been signed out. Please sign in again."),
title: _t("auth|session_logged_out_title"),
description: _t("auth|session_logged_out_description"),
});
dis.dispatch({
@ -1623,19 +1619,13 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
Modal.createDialog(
QuestionDialog,
{
title: _t("Terms and Conditions"),
title: _t("terms|tac_title"),
description: (
<div>
<p>
{" "}
{_t(
"To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.",
{ homeserverDomain: cli.getDomain() },
)}
</p>
<p> {_t("terms|tac_description", { homeserverDomain: cli.getDomain() })}</p>
</div>
),
button: _t("Review terms and conditions"),
button: _t("terms|tac_button"),
cancelButton: _t("action|dismiss"),
onFinished: (confirmed) => {
if (confirmed) {
@ -1676,11 +1666,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
switch (type) {
case "CRYPTO_WARNING_OLD_VERSION_DETECTED":
Modal.createDialog(ErrorDialog, {
title: _t("Old cryptography data detected"),
description: _t(
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.",
{ brand: SdkConfig.get().brand },
),
title: _t("encryption|old_version_detected_title"),
description: _t("encryption|old_version_detected_description", {
brand: SdkConfig.get().brand,
}),
});
break;
}
@ -1736,7 +1725,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} else if (request.pending) {
ToastStore.sharedInstance().addOrReplaceToast({
key: "verifreq_" + request.transactionId,
title: _t("Verification requested"),
title: _t("encryption|verification_requested_toast_title"),
icon: "verification",
props: { request },
component: VerificationRequestToast,

View file

@ -1232,9 +1232,9 @@ class CreationGrouper extends BaseGrouper {
const roomId = ev.getRoomId();
const creator = ev.sender?.name ?? ev.getSender();
if (roomId && DMRoomMap.shared().getUserIdForRoomId(roomId)) {
summaryText = _t("%(creator)s created this DM.", { creator });
summaryText = _t("timeline|creation_summary_dm", { creator });
} else {
summaryText = _t("%(creator)s created and configured the room.", { creator });
summaryText = _t("timeline|creation_summary_room", { creator });
}
ret.push(<NewRoomIntro key="newroomintro" />);

View file

@ -58,8 +58,8 @@ export default class NotificationPanel extends React.PureComponent<IProps, IStat
public render(): React.ReactNode {
const emptyState = (
<div className="mx_RightPanel_empty mx_NotificationPanel_empty">
<h2>{_t("You're all caught up")}</h2>
<p>{_t("You have no visible notifications.")}</p>
<h2>{_t("notif_panel|empty_heading")}</h2>
<p>{_t("notif_panel|empty_description")}</p>
</div>
);

View file

@ -2335,7 +2335,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
className="mx_RoomView_auxPanel_hiddenHighlights"
onClick={this.onHiddenHighlightsClick}
>
{_t("You have %(count)s unread notifications in a prior version of this room.", {
{_t("room|unread_notifications_predecessor", {
count: hiddenHighlightCount,
})}
</AccessibleButton>

View file

@ -245,9 +245,7 @@ const Tile: React.FC<ITileProps> = ({
let suggestedSection: ReactElement | undefined;
if (suggested && (!joinedRoom || hasPermissions)) {
suggestedSection = (
<InfoTooltip tooltip={_t("This room is suggested as a good one to join")}>{_t("Suggested")}</InfoTooltip>
);
suggestedSection = <InfoTooltip tooltip={_t("space|suggested_tooltip")}>{_t("space|suggested")}</InfoTooltip>;
}
const content = (
@ -670,14 +668,14 @@ const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, set
if (!selectedRelations.length) {
Button = AccessibleTooltipButton;
props = {
tooltip: _t("Select a room below first"),
tooltip: _t("space|select_room_below"),
alignment: Alignment.Top,
};
}
let buttonText = _t("Saving…");
if (!saving) {
buttonText = selectionAllSuggested ? _t("Mark as not suggested") : _t("Mark as suggested");
buttonText = selectionAllSuggested ? _t("space|unmark_suggested") : _t("space|mark_suggested");
}
return (
@ -707,7 +705,7 @@ const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, set
hierarchy.removeRelation(parentId, childId);
}
} catch (e) {
setError(_t("Failed to remove some rooms. Try again later"));
setError(_t("space|failed_remove_rooms"));
}
setRemoving(false);
setSelected(new Map());
@ -788,13 +786,13 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
const [error, setError] = useState("");
let errorText = error;
if (!error && hierarchyError) {
errorText = _t("Failed to load list of rooms.");
errorText = _t("space|failed_load_rooms");
}
const loaderRef = useIntersectionObserver(loadMore);
if (!loading && hierarchy!.noSupport) {
return <p>{_t("Your server does not support showing space hierarchies.")}</p>;
return <p>{_t("space|incompatible_server_hierarchy")}</p>;
}
const onKeyDown = (ev: KeyboardEvent, state: IState): void => {

View file

@ -487,7 +487,7 @@ const validateEmailRules = withValidation({
{
key: "email",
test: ({ value }) => !value || Email.looksValid(value),
invalid: () => _t("Doesn't look like a valid email address"),
invalid: () => _t("auth|email_field_label_invalid"),
},
],
});
@ -509,7 +509,7 @@ const SpaceSetupPrivateInvite: React.FC<{
name={name}
type="text"
label={_t("Email address")}
placeholder={_t("Email")}
placeholder={_t("auth|email_field_label")}
value={emailAddresses[i]}
onChange={(ev: React.ChangeEvent<HTMLInputElement>) => setEmailAddress(i, ev.target.value)}
ref={fieldRefs[i]}

View file

@ -354,7 +354,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
/>
<IconizedContextMenuOption
iconClassName="mx_UserMenu_iconLock"
label={_t("Security & Privacy")}
label={_t("room_settings|security|title")}
onClick={(e) => this.onSettingsOpen(e, UserTab.Security)}
/>
<IconizedContextMenuOption
@ -410,11 +410,16 @@ export default class UserMenu extends React.Component<IProps, IState> {
<RovingAccessibleTooltipButton
className="mx_UserMenu_contextMenu_themeButton"
onClick={this.onSwitchThemeClick}
title={this.state.isDarkTheme ? _t("Switch to light mode") : _t("Switch to dark mode")}
title={
this.state.isDarkTheme
? _t("user_menu|switch_theme_light")
: _t("user_menu|switch_theme_dark")
}
>
<img
src={require("../../../res/img/element-icons/roomlist/dark-light-mode.svg").default}
alt={_t("Switch theme")}
role="presentation"
alt=""
width={16}
/>
</RovingAccessibleTooltipButton>

View file

@ -79,19 +79,21 @@ export default class ViewSource extends React.Component<IProps, IState> {
<>
<details open className="mx_ViewSource_details">
<summary>
<span className="mx_ViewSource_heading">{_t("Decrypted event source")}</span>
<span className="mx_ViewSource_heading">
{_t("devtools|view_source_decrypted_event_source")}
</span>
</summary>
{decryptedEventSource ? (
<CopyableText getTextToCopy={copyDecryptedFunc}>
<SyntaxHighlight language="json">{stringify(decryptedEventSource)}</SyntaxHighlight>
</CopyableText>
) : (
<div>{_t("Decrypted source unavailable")}</div>
<div>{_t("devtools|view_source_decrypted_event_source_unavailable")}</div>
)}
</details>
<details className="mx_ViewSource_details">
<summary>
<span className="mx_ViewSource_heading">{_t("Original event source")}</span>
<span className="mx_ViewSource_heading">{_t("devtools|original_event_source")}</span>
</summary>
<CopyableText getTextToCopy={copyOriginalFunc}>
<SyntaxHighlight language="json">{stringify(originalEventSource)}</SyntaxHighlight>
@ -102,7 +104,7 @@ export default class ViewSource extends React.Component<IProps, IState> {
} else {
return (
<>
<div className="mx_ViewSource_heading">{_t("Original event source")}</div>
<div className="mx_ViewSource_heading">{_t("devtools|original_event_source")}</div>
<CopyableText getTextToCopy={copyOriginalFunc}>
<SyntaxHighlight language="json">{stringify(originalEventSource)}</SyntaxHighlight>
</CopyableText>

View file

@ -396,7 +396,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
<PassphraseField
name="reset_password"
type="password"
label={_td("New Password")}
label={_td("auth|change_password_new_label")}
value={this.state.password}
minScore={PASSWORD_MIN_SCORE}
fieldRef={(field) => (this.fieldPassword = field)}

View file

@ -591,7 +591,7 @@ export default class Registration extends React.Component<IProps, IState> {
const signIn = (
<span className="mx_AuthBody_changeFlow">
{_t(
"auth|sign_in_instead",
"auth|sign_in_instead_prompt",
{},
{
a: (sub) => (
@ -682,7 +682,7 @@ export default class Registration extends React.Component<IProps, IState> {
title={_t("Create account")}
serverPicker={
<ServerPicker
title={_t("auth|server_picker_title")}
title={_t("auth|server_picker_title_registration")}
dialogTitle={_t("auth|server_picker_dialog_title")}
serverConfig={this.props.serverConfig}
onServerConfigChange={

View file

@ -53,7 +53,7 @@ export const CheckEmail: React.FC<CheckEmailProps> = ({
return (
<>
<EMailPromptIcon className="mx_AuthBody_emailPromptIcon--shifted" />
<h1>{_t("Check your email to continue")}</h1>
<h1>{_t("auth|uia|email_auth_header")}</h1>
<div className="mx_AuthBody_text">
<p>{_t("auth|check_email_explainer", { email: email }, { b: (t) => <b>{t}</b> })}</p>
<div className="mx_AuthBody_did-not-receive">

View file

@ -40,9 +40,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
class EmailField extends PureComponent<IProps> {
public static defaultProps = {
label: _td("Email"),
labelRequired: _td("Enter email address"),
labelInvalid: _td("Doesn't look like a valid email address"),
label: _td("auth|email_field_label"),
labelRequired: _td("auth|email_field_label_required"),
labelInvalid: _td("auth|email_field_label_invalid"),
};
public readonly validate = withValidation({

View file

@ -169,7 +169,7 @@ export class PasswordAuthEntry extends React.Component<IAuthEntryProps, IPasswor
return (
<div>
<p>{_t("Confirm your identity by entering your account password below.")}</p>
<p>{_t("auth|uia|password_prompt")}</p>
<form onSubmit={this.onSubmit} className="mx_InteractiveAuthEntryComponents_passwordSection">
<Field
className={passwordBoxClass}
@ -219,9 +219,7 @@ export class RecaptchaAuthEntry extends React.Component<IRecaptchaAuthEntryProps
let sitePublicKey: string | undefined;
if (!this.props.stageParams || !this.props.stageParams.public_key) {
errorText = _t(
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.",
);
errorText = _t("auth|uia|recaptcha_missing_params");
} else {
sitePublicKey = this.props.stageParams.public_key;
}
@ -352,7 +350,7 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
if (allChecked) {
this.props.submitAuthDict({ type: AuthType.Terms });
} else {
this.setState({ errorText: _t("Please review and accept all of the homeserver's policies") });
this.setState({ errorText: _t("auth|uia|terms_invalid") });
}
};
@ -403,7 +401,7 @@ export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITerms
return (
<div className="mx_InteractiveAuthEntryComponents">
<p>{_t("Please review and accept the policies of this homeserver:")}</p>
<p>{_t("auth|uia|terms")}</p>
{checkboxes}
{errorSection}
{submitButton}
@ -474,19 +472,19 @@ export class EmailIdentityAuthEntry extends React.Component<
return (
<div className="mx_InteractiveAuthEntryComponents_emailWrapper">
<AuthHeaderModifier
title={_t("Check your email to continue")}
icon={<img src={EmailPromptIcon} alt={_t("Unread email icon")} width={16} />}
title={_t("auth|uia|email_auth_header")}
icon={<img src={EmailPromptIcon} role="presentation" alt="" width={16} />}
hideServerPicker={true}
/>
<p>
{_t("To create your account, open the link in the email we just sent to %(emailAddress)s.", {
{_t("auth|uia|email", {
emailAddress: <b>{this.props.inputs.emailAddress}</b>,
})}
</p>
{this.state.requesting ? (
<p className="secondary">
{_t(
"Did not receive it? <a>Resend it</a>",
"auth|uia|email_resend_prompt",
{},
{
a: (text: string) => (
@ -502,13 +500,15 @@ export class EmailIdentityAuthEntry extends React.Component<
) : (
<p className="secondary">
{_t(
"Did not receive it? <a>Resend it</a>",
"auth|uia|email_resend_prompt",
{},
{
a: (text: string) => (
<AccessibleTooltipButton
kind="link_inline"
title={this.state.requested ? _t("Resent!") : _t("action|resend")}
title={
this.state.requested ? _t("auth|uia|email_resent") : _t("action|resend")
}
alignment={Alignment.Right}
onHideTooltip={
this.state.requested
@ -642,7 +642,7 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
});
} else {
this.setState({
errorText: _t("Token incorrect"),
errorText: _t("auth|uia|msisdn_token_incorrect"),
});
}
} catch (e) {
@ -670,8 +670,8 @@ export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps, IMsi
}
return (
<div>
<p>{_t("A text message has been sent to %(msisdn)s", { msisdn: <i>{this.msisdn}</i> })}</p>
<p>{_t("Please enter the code it contains:")}</p>
<p>{_t("auth|uia|msisdn", { msisdn: <i>{this.msisdn}</i> })}</p>
<p>{_t("auth|uia|msisdn_token_prompt")}</p>
<div className="mx_InteractiveAuthEntryComponents_msisdnWrapper">
<form onSubmit={this.onFormSubmit}>
<input
@ -761,13 +761,13 @@ export class RegistrationTokenAuthEntry extends React.Component<IAuthEntryProps,
return (
<div>
<p>{_t("Enter a registration token provided by the homeserver administrator.")}</p>
<p>{_t("auth|uia|registration_token_prompt")}</p>
<form onSubmit={this.onSubmit} className="mx_InteractiveAuthEntryComponents_registrationTokenSection">
<Field
className={registrationTokenBoxClass}
type="text"
name="registrationTokenField"
label={_t("Registration token")}
label={_t("auth|uia|registration_token_label")}
autoFocus={true}
value={this.state.registrationToken}
onChange={this.onRegistrationTokenFieldChange}
@ -895,7 +895,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
} else if (this.state.attemptFailed) {
errorSection = (
<div className="error" role="alert">
{_t("Something went wrong in confirming your identity. Cancel and try again.")}
{_t("auth|uia|sso_failed")}
</div>
);
}
@ -972,7 +972,7 @@ export class FallbackAuthEntry extends React.Component<IAuthEntryProps> {
return (
<div>
<AccessibleButton kind="link" inputRef={this.fallbackButton} onClick={this.onShowFallbackClick}>
{_t("Start authentication")}
{_t("auth|uia|fallback_button")}
</AccessibleButton>
{errorSection}
</div>

View file

@ -169,7 +169,7 @@ export default class LoginWithQRFlow extends React.Component<IProps> {
);
break;
case Phase.ShowingQR:
title = _t("Sign in with QR code");
title = _t("settings|sessions|sign_in_with_qr");
if (this.props.code) {
const code = (
<div className="mx_LoginWithQR_qrWrapper">

View file

@ -37,9 +37,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> {
class PassphraseConfirmField extends PureComponent<IProps> {
public static defaultProps = {
label: _td("Confirm password"),
labelRequired: _td("Confirm password"),
labelInvalid: _td("Passwords don't match"),
label: _td("auth|change_password_confirm_label"),
labelRequired: _td("auth|change_password_confirm_label"),
labelInvalid: _td("auth|change_password_confirm_invalid"),
};
private validate = withValidation({

View file

@ -46,9 +46,9 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
class PassphraseField extends PureComponent<IProps> {
public static defaultProps = {
label: _td("common|password"),
labelEnterPassword: _td("Enter password"),
labelStrongPassword: _td("Nice, strong password!"),
labelAllowedButUnsafe: _td("Password is allowed, but unsafe"),
labelEnterPassword: _td("auth|password_field_label"),
labelStrongPassword: _td("auth|password_field_strong_label"),
labelAllowedButUnsafe: _td("auth|password_field_weak_label"),
};
public readonly validate = withValidation<this, ZxcvbnResult | null>({
@ -91,7 +91,7 @@ class PassphraseField extends PureComponent<IProps> {
return null;
}
const { feedback } = complexity;
return feedback.warning || feedback.suggestions[0] || _t("Keep going…");
return feedback.warning || feedback.suggestions[0] || _t("auth|password_field_keep_going_prompt");
},
},
],

View file

@ -214,7 +214,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
test({ value, allowEmpty }) {
return allowEmpty || !!value;
},
invalid: () => _t("Enter username"),
invalid: () => _t("auth|username_field_required_invalid"),
},
],
});
@ -236,12 +236,12 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
test({ value, allowEmpty }): boolean {
return allowEmpty || !!value;
},
invalid: (): string => _t("Enter phone number"),
invalid: (): string => _t("auth|msisdn_field_required_invalid"),
},
{
key: "number",
test: ({ value }): boolean => !value || PHONE_NUMBER_REGEX.test(value),
invalid: (): string => _t("That phone number doesn't look quite right, please check and try again"),
invalid: (): string => _t("auth|msisdn_field_number_invalid"),
},
],
});
@ -259,7 +259,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
test({ value, allowEmpty }): boolean {
return allowEmpty || !!value;
},
invalid: (): string => _t("Enter password"),
invalid: (): string => _t("auth|password_field_label"),
},
],
});
@ -341,7 +341,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
autoComplete="tel-national"
key="phone_input"
type="text"
label={_t("Phone")}
label={_t("auth|msisdn_field_label")}
value={this.props.phoneNumber}
prefixComponent={phoneCountry}
onChange={this.onPhoneNumberChanged}
@ -378,7 +378,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
kind="link"
onClick={this.onForgotPasswordClick}
>
{_t("Forgot password?")}
{_t("auth|reset_password_button")}
</AccessibleButton>
);
}
@ -396,7 +396,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
if (!SdkConfig.get().disable_3pid_login) {
loginType = (
<div className="mx_Login_type_container">
<label className="mx_Login_type_label">{_t("Sign in with")}</label>
<label className="mx_Login_type_label">{_t("auth|identifier_label")}</label>
<Field
element="select"
value={this.state.loginType}
@ -410,7 +410,7 @@ export default class PasswordLogin extends React.PureComponent<IProps, IState> {
{_t("Email address")}
</option>
<option key={LoginField.Password} value={LoginField.Password}>
{_t("Phone")}
{_t("auth|msisdn_field_label")}
</option>
</Field>
</div>

View file

@ -267,7 +267,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
};
private validateEmailRules = withValidation({
description: () => _t("Use an email address to recover your account"),
description: () => _t("auth|reset_password_email_field_description"),
hideDescriptionIfValid: true,
rules: [
{
@ -275,12 +275,12 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
test(this: RegistrationForm, { value, allowEmpty }) {
return allowEmpty || !this.authStepIsRequired("m.login.email.identity") || !!value;
},
invalid: () => _t("Enter email address (required on this homeserver)"),
invalid: () => _t("auth|reset_password_email_field_required_invalid"),
},
{
key: "email",
test: ({ value }) => !value || Email.looksValid(value),
invalid: () => _t("Doesn't look like a valid email address"),
invalid: () => _t("auth|email_field_label_invalid"),
},
],
});
@ -324,7 +324,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
};
private validatePhoneNumberRules = withValidation({
description: () => _t("Other users can invite you to rooms using your contact details"),
description: () => _t("auth|msisdn_field_description"),
hideDescriptionIfValid: true,
rules: [
{
@ -332,12 +332,12 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
test(this: RegistrationForm, { value, allowEmpty }) {
return allowEmpty || !this.authStepIsRequired("m.login.msisdn") || !!value;
},
invalid: () => _t("Enter phone number (required on this homeserver)"),
invalid: () => _t("auth|registration_msisdn_field_required_invalid"),
},
{
key: "email",
test: ({ value }) => !value || phoneNumberLooksValid(value),
invalid: () => _t("That phone number doesn't look quite right, please check and try again"),
invalid: () => _t("auth|msisdn_field_number_invalid"),
},
],
});
@ -358,7 +358,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
description: (_, results) => {
// omit the description if the only failing result is the `available` one as it makes no sense for it.
if (results.every(({ key, valid }) => key === "available" || valid)) return null;
return _t("Use lowercase letters, numbers, dashes and underscores only");
return _t("auth|registration_username_validation");
},
hideDescriptionIfValid: true,
async deriveData(this: RegistrationForm, { value }) {
@ -380,7 +380,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
{
key: "required",
test: ({ value, allowEmpty }) => allowEmpty || !!value,
invalid: () => _t("Enter username"),
invalid: () => _t("auth|username_field_required_invalid"),
},
{
key: "safeLocalpart",
@ -401,8 +401,8 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
},
invalid: (usernameAvailable) =>
usernameAvailable === UsernameAvailableStatus.Error
? _t("Unable to check if username has been taken. Try again later.")
: _t("Someone already has that username. Try another or if it is you, sign in below."),
? _t("auth|registration_username_unable_check")
: _t("auth|registration_username_in_use"),
},
],
});
@ -451,7 +451,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
if (!this.showEmail()) {
return null;
}
const emailLabel = this.authStepIsRequired("m.login.email.identity") ? _td("Email") : _td("Email (optional)");
const emailLabel = this.authStepIsRequired("m.login.email.identity")
? _td("auth|email_field_label")
: _td("Email (optional)");
return (
<EmailField
fieldRef={(field) => (this[RegistrationField.Email] = field)}
@ -496,7 +498,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
if (!this.showPhoneNumber()) {
return null;
}
const phoneLabel = this.authStepIsRequired("m.login.msisdn") ? _t("Phone") : _t("Phone (optional)");
const phoneLabel = this.authStepIsRequired("m.login.msisdn")
? _t("auth|phone_label")
: _t("auth|phone_optional_label");
const phoneCountry = (
<CountryDropdown
value={this.state.phoneCountry}
@ -549,15 +553,13 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
if (this.showPhoneNumber()) {
emailHelperText = (
<div>
{_t("Add an email to be able to reset your password.")}{" "}
{_t("Use email or phone to optionally be discoverable by existing contacts.")}
{_t("auth|email_help_text")} {_t("auth|email_phone_discovery_text")}
</div>
);
} else {
emailHelperText = (
<div>
{_t("Add an email to be able to reset your password.")}{" "}
{_t("Use email to optionally be discoverable by existing contacts.")}
{_t("auth|email_help_text")} {_t("auth|email_discovery_text")}
</div>
);
}

View file

@ -132,7 +132,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
devtoolsOption = (
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconSettings"
label={_t("See room timeline (devtools)")}
label={_t("space|context_menu|devtools_open_timeline")}
onClick={onViewTimelineClick}
/>
);
@ -243,13 +243,13 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
<IconizedContextMenuOptionList first>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconHome"
label={_t("Space home")}
label={_t("space|context_menu|home")}
onClick={onHomeClick}
/>
{inviteOption}
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconExplore"
label={canAddRooms ? _t("Manage & explore rooms") : _t("Explore rooms")}
label={canAddRooms ? _t("space|context_menu|manage_and_explore") : _t("space|context_menu|explore")}
onClick={onExploreRoomsClick}
/>
<IconizedContextMenuOption

View file

@ -16,7 +16,6 @@ limitations under the License.
*/
import React from "react";
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
import { logger } from "matrix-js-sdk/src/logger";
import type CreateKeyBackupDialog from "../../../async-components/views/dialogs/security/CreateKeyBackupDialog";
@ -35,10 +34,28 @@ interface IProps {
onFinished: (success: boolean) => void;
}
enum BackupStatus {
/** we're trying to figure out if there is an active backup */
LOADING,
/** crypto is disabled in this client (so no need to back up) */
NO_CRYPTO,
/** Key backup is active and working */
BACKUP_ACTIVE,
/** there is a backup on the server but we are not backing up to it */
SERVER_BACKUP_BUT_DISABLED,
/** backup is not set up locally and there is no backup on the server */
NO_BACKUP,
/** there was an error fetching the state */
ERROR,
}
interface IState {
shouldLoadBackupStatus: boolean;
loading: boolean;
backupInfo: IKeyBackupInfo | null;
backupStatus: BackupStatus;
}
export default class LogoutDialog extends React.Component<IProps, IState> {
@ -49,33 +66,40 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
public constructor(props: IProps) {
super(props);
const cli = MatrixClientPeg.safeGet();
const shouldLoadBackupStatus = cli.isCryptoEnabled() && !cli.getKeyBackupEnabled();
this.state = {
shouldLoadBackupStatus: shouldLoadBackupStatus,
loading: shouldLoadBackupStatus,
backupInfo: null,
backupStatus: BackupStatus.LOADING,
};
if (shouldLoadBackupStatus) {
this.loadBackupStatus();
}
// we can't call setState() immediately, so wait a beat
window.setTimeout(() => this.startLoadBackupStatus(), 0);
}
/** kick off the asynchronous calls to populate `state.backupStatus` in the background */
private startLoadBackupStatus(): void {
this.loadBackupStatus().catch((e) => {
logger.log("Unable to fetch key backup status", e);
this.setState({
backupStatus: BackupStatus.ERROR,
});
});
}
private async loadBackupStatus(): Promise<void> {
try {
const backupInfo = await MatrixClientPeg.safeGet().getKeyBackupVersion();
this.setState({
loading: false,
backupInfo,
});
} catch (e) {
logger.log("Unable to fetch key backup status", e);
this.setState({
loading: false,
});
const client = MatrixClientPeg.safeGet();
const crypto = client.getCrypto();
if (!crypto) {
this.setState({ backupStatus: BackupStatus.NO_CRYPTO });
return;
}
if ((await crypto.getActiveSessionBackupVersion()) !== null) {
this.setState({ backupStatus: BackupStatus.BACKUP_ACTIVE });
return;
}
// backup is not active. see if there is a backup version on the server we ought to back up to.
const backupInfo = await client.getKeyBackupVersion();
this.setState({ backupStatus: backupInfo ? BackupStatus.SERVER_BACKUP_BUT_DISABLED : BackupStatus.NO_BACKUP });
}
private onExportE2eKeysClicked = (): void => {
@ -98,7 +122,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
};
private onSetRecoveryMethodClick = (): void => {
if (this.state.backupInfo) {
if (this.state.backupStatus === BackupStatus.SERVER_BACKUP_BUT_DISABLED) {
// A key backup exists for this account, but the creating device is not
// verified, so restore the backup which will give us the keys from it and
// allow us to trust it (ie. upload keys to it)
@ -132,82 +156,106 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
this.props.onFinished(true);
};
public render(): React.ReactNode {
if (this.state.shouldLoadBackupStatus) {
const description = (
<div>
<p>
{_t(
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
)}
</p>
<p>
{_t(
"When you sign out, these keys will be deleted from this device, which means you won't be able to read encrypted messages unless you have the keys for them on your other devices, or backed them up to the server.",
)}
</p>
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p>
</div>
);
/**
* Show a dialog prompting the user to set up key backup.
*
* Either there is no backup at all ({@link BackupStatus.NO_BACKUP}), there is a backup on the server but
* we are not connected to it ({@link BackupStatus.SERVER_BACKUP_BUT_DISABLED}), or we were unable to pull the
* backup data ({@link BackupStatus.ERROR}). In all three cases, we should prompt the user to set up key backup.
*/
private renderSetupBackupDialog(): React.ReactNode {
const description = (
<div>
<p>
{_t(
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
)}
</p>
<p>
{_t(
"When you sign out, these keys will be deleted from this device, which means you won't be able to read encrypted messages unless you have the keys for them on your other devices, or backed them up to the server.",
)}
</p>
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p>
</div>
);
let dialogContent;
if (this.state.loading) {
dialogContent = <Spinner />;
} else {
let setupButtonCaption;
if (this.state.backupInfo) {
setupButtonCaption = _t("Connect this session to Key Backup");
} else {
// if there's an error fetching the backup info, we'll just assume there's
// no backup for the purpose of the button caption
setupButtonCaption = _t("Start using Key Backup");
}
dialogContent = (
<div>
<div className="mx_Dialog_content" id="mx_Dialog_content">
{description}
</div>
<DialogButtons
primaryButton={setupButtonCaption}
hasCancel={false}
onPrimaryButtonClick={this.onSetRecoveryMethodClick}
focus={true}
>
<button onClick={this.onLogoutConfirm}>{_t("I don't want my encrypted messages")}</button>
</DialogButtons>
<details>
<summary>{_t("Advanced")}</summary>
<p>
<button onClick={this.onExportE2eKeysClicked}>{_t("Manually export keys")}</button>
</p>
</details>
</div>
);
}
// Not quite a standard question dialog as the primary button cancels
// the action and does something else instead, whilst non-default button
// confirms the action.
return (
<BaseDialog
title={_t("You'll lose access to your encrypted messages")}
contentId="mx_Dialog_content"
hasCancel={true}
onFinished={this.onFinished}
>
{dialogContent}
</BaseDialog>
);
let setupButtonCaption;
if (this.state.backupStatus === BackupStatus.SERVER_BACKUP_BUT_DISABLED) {
setupButtonCaption = _t("Connect this session to Key Backup");
} else {
return (
<QuestionDialog
hasCancelButton={true}
title={_t("action|sign_out")}
description={_t("Are you sure you want to sign out?")}
button={_t("action|sign_out")}
onFinished={this.onFinished}
/>
);
// if there's an error fetching the backup info, we'll just assume there's
// no backup for the purpose of the button caption
setupButtonCaption = _t("Start using Key Backup");
}
const dialogContent = (
<div>
<div className="mx_Dialog_content" id="mx_Dialog_content">
{description}
</div>
<DialogButtons
primaryButton={setupButtonCaption}
hasCancel={false}
onPrimaryButtonClick={this.onSetRecoveryMethodClick}
focus={true}
>
<button onClick={this.onLogoutConfirm}>{_t("I don't want my encrypted messages")}</button>
</DialogButtons>
<details>
<summary>{_t("Advanced")}</summary>
<p>
<button onClick={this.onExportE2eKeysClicked}>{_t("Manually export keys")}</button>
</p>
</details>
</div>
);
// Not quite a standard question dialog as the primary button cancels
// the action and does something else instead, whilst non-default button
// confirms the action.
return (
<BaseDialog
title={_t("You'll lose access to your encrypted messages")}
contentId="mx_Dialog_content"
hasCancel={true}
onFinished={this.onFinished}
>
{dialogContent}
</BaseDialog>
);
}
public render(): React.ReactNode {
switch (this.state.backupStatus) {
case BackupStatus.LOADING:
// while we're deciding if we have backups, show a spinner
return (
<BaseDialog
title={_t("action|sign_out")}
contentId="mx_Dialog_content"
hasCancel={true}
onFinished={this.onFinished}
>
<Spinner />;
</BaseDialog>
);
case BackupStatus.NO_CRYPTO:
case BackupStatus.BACKUP_ACTIVE:
return (
<QuestionDialog
hasCancelButton={true}
title={_t("action|sign_out")}
description={_t("Are you sure you want to sign out?")}
button={_t("action|sign_out")}
onFinished={this.onFinished}
/>
);
case BackupStatus.NO_BACKUP:
case BackupStatus.SERVER_BACKUP_BUT_DISABLED:
case BackupStatus.ERROR:
return this.renderSetupBackupDialog();
}
}
}

View file

@ -88,9 +88,9 @@ export function ManualDeviceKeyVerificationDialog({
return (
<QuestionDialog
title={_t("Verify session")}
title={_t("settings|sessions|verify_session")}
description={body}
button={_t("Verify session")}
button={_t("settings|sessions|verify_session")}
onFinished={onLegacyFinished}
/>
);

View file

@ -136,6 +136,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
clientId: ELEMENT_CLIENT_ID,
clientTheme: SettingsStore.getValue("theme"),
clientLanguage: getUserLanguage(),
baseUrl: MatrixClientPeg.safeGet().baseUrl,
});
const parsed = new URL(templated);

View file

@ -163,7 +163,7 @@ class RoomSettingsDialog extends React.Component<IProps, IState> {
tabs.push(
new Tab(
RoomSettingsTab.Security,
_td("Security & Privacy"),
_td("room_settings|security|title"),
"mx_RoomSettingsDialog_securityIcon",
<SecurityRoomSettingsTab room={this.state.room} closeSettingsFn={() => this.props.onFinished(true)} />,
"RoomSettingsSecurityPrivacy",
@ -172,7 +172,7 @@ class RoomSettingsDialog extends React.Component<IProps, IState> {
tabs.push(
new Tab(
RoomSettingsTab.Roles,
_td("Roles & Permissions"),
_td("room_settings|permissions|title"),
"mx_RoomSettingsDialog_rolesIcon",
<RolesRoomSettingsTab room={this.state.room} />,
"RoomSettingsRolesPermissions",

View file

@ -80,8 +80,8 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
nativeSupport = _t("Checking…");
} else {
nativeSupport = hasNativeSupport
? _t("Your server has native support")
: _t("Your server lacks native support");
? _t("labs|sliding_sync_server_support")
: _t("labs|sliding_sync_server_no_support");
}
const validProxy = withValidation<undefined, { error?: unknown }>({
@ -97,7 +97,7 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
{
key: "required",
test: async ({ value }) => !!value || !!hasNativeSupport,
invalid: () => _t("Your server lacks native support, you must specify a proxy"),
invalid: () => _t("labs|sliding_sync_server_specify_proxy"),
},
{
key: "working",
@ -111,16 +111,20 @@ export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean):
return (
<TextInputDialog
title={_t("Sliding Sync configuration")}
title={_t("labs|sliding_sync_configuration")}
description={
<div>
<div>
<b>{_t("To disable you will need to log out and back in, use with caution!")}</b>
<b>{_t("labs|sliding_sync_disable_warning")}</b>
</div>
{nativeSupport}
</div>
}
placeholder={hasNativeSupport ? _t("Proxy URL (optional)") : _t("Proxy URL")}
placeholder={
hasNativeSupport
? _t("labs|sliding_sync_proxy_url_optional_label")
: _t("labs|sliding_sync_proxy_url_label")
}
value={currentProxy}
button={_t("action|enable")}
validator={validProxy}

View file

@ -67,7 +67,7 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
),
new Tab(
SpaceSettingsTab.Roles,
_td("Roles & Permissions"),
_td("room_settings|permissions|title"),
"mx_RoomSettingsDialog_rolesIcon",
<RolesRoomSettingsTab room={space} />,
),
@ -84,7 +84,7 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
return (
<BaseDialog
title={_t("Settings - %(spaceName)s", { spaceName: space.name || _t("common|unnamed_space") })}
title={_t("space_settings|title", { spaceName: space.name || _t("common|unnamed_space") })}
className="mx_SpaceSettingsDialog"
contentId="mx_SpaceSettingsDialog"
onFinished={onFinished}

View file

@ -117,7 +117,7 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
</div>
);
case SERVICE_TYPES.IM:
return <div>{_t("Use bots, bridges, widgets and sticker packs")}</div>;
return <div>{_t("terms|integration_manager")}</div>;
}
}
@ -192,19 +192,19 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
<BaseDialog
fixedWidth={false}
onFinished={this.onCancelClick}
title={_t("Terms of Service")}
title={_t("terms|tos")}
contentId="mx_Dialog_content"
hasCancel={false}
>
<div id="mx_Dialog_content">
<p>{_t("To continue you need to accept the terms of this service.")}</p>
<p>{_t("terms|intro")}</p>
<table className="mx_TermsDialog_termsTable">
<tbody>
<tr className="mx_TermsDialog_termsTableHeader">
<th>{_t("Service")}</th>
<th>{_t("Summary")}</th>
<th>{_t("Document")}</th>
<th>{_t("terms|column_service")}</th>
<th>{_t("terms|column_summary")}</th>
<th>{_t("terms|column_document")}</th>
<th>{_t("action|accept")}</th>
</tr>
{rows}

View file

@ -144,7 +144,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
tabs.push(
new Tab(
UserTab.Security,
_td("Security & Privacy"),
_td("room_settings|security|title"),
"mx_UserSettingsDialog_securityIcon",
<SecurityUserSettingsTab closeSettingsFn={this.props.onFinished} />,
"UserSettingsSecurityPrivacy",
@ -179,7 +179,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
tabs.push(
new Tab(
UserTab.Mjolnir,
_td("Ignored users"),
_td("labs_mjolnir|title"),
"mx_UserSettingsDialog_mjolnirIcon",
<MjolnirUserSettingsTab />,
"UserSettingMjolnir",

View file

@ -479,6 +479,7 @@ export default class ImageView extends React.Component<IProps, IState> {
fallbackUserId={mxEvent.getSender()}
size="32px"
viewUserOnClick={true}
className="mx_Dialog_nonDialogButton"
/>
);

View file

@ -103,7 +103,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
const classes = classNames("mx_Pill", {
mx_AtRoomPill: type === PillType.AtRoomMention,
mx_RoomPill: type === PillType.RoomMention,
mx_SpacePill: type === "space",
mx_SpacePill: type === "space" || targetRoom?.isSpaceRoom(),
mx_UserPill: type === PillType.UserMention,
mx_UserPill_me: resourceId === MatrixClientPeg.safeGet().getUserId(),
mx_EventPill: type === PillType.EventInOtherRoom || type === PillType.EventInSameRoom,

View file

@ -63,8 +63,8 @@ const MAX_OPTION_LENGTH = 340;
function creatingInitialState(): IState {
return {
title: _t("Create poll"),
actionLabel: _t("Create Poll"),
title: _t("poll|create_poll_title"),
actionLabel: _t("poll|create_poll_action"),
canSubmit: false, // need to add a question and at least one option first
question: "",
options: arraySeed("", DEFAULT_NUM_OPTIONS),
@ -79,7 +79,7 @@ function editingInitialState(editingMxEvent: MatrixEvent): IState {
if (!poll?.isEquivalentTo(M_POLL_START)) return creatingInitialState();
return {
title: _t("Edit poll"),
title: _t("poll|edit_poll_title"),
actionLabel: _t("action|done"),
canSubmit: true,
question: poll.question.text,
@ -175,8 +175,8 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
.catch((e) => {
console.error("Failed to post poll:", e);
Modal.createDialog(QuestionDialog, {
title: _t("Failed to post poll"),
description: _t("Sorry, the poll you tried to create was not posted."),
title: _t("poll|failed_send_poll_title"),
description: _t("poll|failed_send_poll_description"),
button: _t("action|try_again"),
cancelButton: _t("action|cancel"),
onFinished: (tryAgain: boolean) => {
@ -197,37 +197,37 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
protected renderContent(): React.ReactNode {
return (
<div className="mx_PollCreateDialog">
<h2>{_t("Poll type")}</h2>
<h2>{_t("poll|type_heading")}</h2>
<Field element="select" value={this.state.kind.name} onChange={this.onPollTypeChange}>
<option key={M_POLL_KIND_DISCLOSED.name} value={M_POLL_KIND_DISCLOSED.name}>
{_t("Open poll")}
{_t("poll|type_open")}
</option>
<option key={M_POLL_KIND_UNDISCLOSED.name} value={M_POLL_KIND_UNDISCLOSED.name}>
{_t("Closed poll")}
{_t("poll|type_closed")}
</option>
</Field>
<p>{pollTypeNotes(this.state.kind)}</p>
<h2>{_t("What is your poll question or topic?")}</h2>
<h2>{_t("poll|topic_heading")}</h2>
<Field
id="poll-topic-input"
value={this.state.question}
maxLength={MAX_QUESTION_LENGTH}
label={_t("Question or topic")}
placeholder={_t("Write something…")}
label={_t("poll|topic_label")}
placeholder={_t("poll|topic_placeholder")}
onChange={this.onQuestionChange}
usePlaceholderAsHint={true}
disabled={this.state.busy}
autoFocus={this.state.autoFocusTarget === FocusTarget.Topic}
/>
<h2>{_t("Create options")}</h2>
<h2>{_t("poll|options_heading")}</h2>
{this.state.options.map((op, i) => (
<div key={`option_${i}`} className="mx_PollCreateDialog_option">
<Field
id={`pollcreate_option_${i}`}
value={op}
maxLength={MAX_OPTION_LENGTH}
label={_t("Option %(number)s", { number: i + 1 })}
placeholder={_t("Write an option")}
label={_t("poll|options_label", { number: i + 1 })}
placeholder={_t("poll|options_placeholder")}
onChange={(e: ChangeEvent<HTMLInputElement>) => this.onOptionChange(i, e)}
usePlaceholderAsHint={true}
disabled={this.state.busy}
@ -250,7 +250,7 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
className="mx_PollCreateDialog_addOption"
inputRef={this.addOptionRef}
>
{_t("Add option")}
{_t("poll|options_add_button")}
</AccessibleButton>
{this.state.busy && (
<div className="mx_PollCreateDialog_busy">
@ -270,8 +270,8 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
function pollTypeNotes(kind: KnownPollKind): string {
if (M_POLL_KIND_DISCLOSED.matches(kind.name)) {
return _t("Voters see results as soon as they have voted");
return _t("poll|disclosed_notes");
} else {
return _t("Results are only revealed when you end the poll");
return _t("poll|notes");
}
}

View file

@ -99,7 +99,7 @@ export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
dis.dispatch({ action: "open_room_settings" });
}}
>
{_t("Edit topic")}
{_t("room|edit_topic")}
</AccessibleButton>
)}
</div>
@ -119,7 +119,7 @@ export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
onClick={onClick}
dir="auto"
tooltipTargetClassName={className}
label={_t("Click to read topic")}
label={_t("room|read_topic")}
alignment={Alignment.Bottom}
ignoreHover={ignoreHover}
>

View file

@ -106,7 +106,7 @@ const EncryptionInfo: React.FC<IProps> = ({
return (
<React.Fragment>
<div data-testid="encryption-info-description" className="mx_UserInfo_container">
<h3>{_t("Encryption")}</h3>
<h3>{_t("settings|security|encryption_section")}</h3>
{description}
</div>
<div className="mx_UserInfo_container">

View file

@ -78,7 +78,7 @@ export default class RoomPublishSetting extends React.PureComponent<IProps, ISta
value={this.state.isRoomPublished}
onChange={this.onRoomPublishChange}
disabled={!enabled}
label={_t("Publish this room to the public in %(domain)s's room directory?", {
label={_t("room_settings|general|publish_toggle", {
domain: client.getDomain(),
})}
/>

View file

@ -53,7 +53,7 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
const accountEnabled = SettingsStore.getValueAt(SettingLevel.ACCOUNT, "urlPreviewsEnabled");
if (accountEnabled) {
previewsForAccount = _t(
"You have <a>enabled</a> URL previews by default.",
"room_settings|general|user_url_previews_default_on",
{},
{
a: (sub) => (
@ -65,7 +65,7 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
);
} else {
previewsForAccount = _t(
"You have <a>disabled</a> URL previews by default.",
"room_settings|general|user_url_previews_default_off",
{},
{
a: (sub) => (
@ -87,16 +87,14 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
/>
);
} else {
let str = _td("URL previews are enabled by default for participants in this room.");
let str = _td("room_settings|general|default_url_previews_on");
if (!SettingsStore.getValueAt(SettingLevel.ROOM, "urlPreviewsEnabled", roomId, /*explicit=*/ true)) {
str = _td("URL previews are disabled by default for participants in this room.");
str = _td("room_settings|general|default_url_previews_off");
}
previewsForRoom = <div>{_t(str)}</div>;
}
} else {
previewsForAccount = _t(
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.",
);
previewsForAccount = _t("room_settings|general|url_preview_encryption_warning");
}
const previewsForRoomAccount = // in an e2ee room we use a special key to enforce per-room opt-in
@ -110,17 +108,13 @@ export default class UrlPreviewSettings extends React.Component<IProps> {
const description = (
<>
<p>
{_t(
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.",
)}
</p>
<p>{_t("room_settings|general|url_preview_explainer")}</p>
<p>{previewsForAccount}</p>
</>
);
return (
<SettingsFieldset legend={_t("URL Previews")} description={description}>
<SettingsFieldset legend={_t("room_settings|general|url_previews_section")} description={description}>
{previewsForRoom}
{previewsForRoomAccount}
</SettingsFieldset>

View file

@ -813,7 +813,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
initialTabId: UserTab.Labs,
});
const betaPill = isVideoRoom ? (
<BetaPill onClick={viewLabs} tooltipTitle={_t("Video rooms are a beta feature")} />
<BetaPill onClick={viewLabs} tooltipTitle={_t("labs|video_rooms_beta")} />
) : null;
return (

View file

@ -46,14 +46,14 @@ function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room):
const determineIntroMessage = (room: Room, encryptedSingle3rdPartyInvite: boolean): TranslationKey => {
if (room instanceof LocalRoom) {
return _td("Send your first message to invite <displayName/> to chat");
return _td("room|intro|send_message_start_dm");
}
if (encryptedSingle3rdPartyInvite) {
return _td("Once everyone has joined, youll be able to chat");
return _td("room|intro|encrypted_3pid_dm_pending_join");
}
return _td("This is the beginning of your direct message history with <displayName/>.");
return _td("room|intro|start_of_dm_history");
};
const NewRoomIntro: React.FC = () => {
@ -78,7 +78,7 @@ const NewRoomIntro: React.FC = () => {
!encryptedSingle3rdPartyInvite &&
room.getJoinedMemberCount() + room.getInvitedMemberCount() === 2
) {
caption = _t("Only the two of you are in this conversation, unless either of you invites anyone to join.");
caption = _t("room|intro|dm_caption");
}
const member = room?.getMember(dmPartner);
@ -133,7 +133,7 @@ const NewRoomIntro: React.FC = () => {
let topicText;
if (canAddTopic && topic) {
topicText = _t(
"Topic: %(topic)s (<a>edit</a>)",
"room|intro|topic_edit",
{ topic },
{
a: (sub) => (
@ -144,10 +144,10 @@ const NewRoomIntro: React.FC = () => {
},
);
} else if (topic) {
topicText = _t("Topic: %(topic)s ", { topic });
topicText = _t("room|intro|topic", { topic });
} else if (canAddTopic) {
topicText = _t(
"<a>Add a topic</a> to help people know what it is about.",
"room|intro|no_topic",
{},
{
a: (sub) => (
@ -164,9 +164,9 @@ const NewRoomIntro: React.FC = () => {
let createdText: string;
if (creator === cli.getUserId()) {
createdText = _t("You created this room.");
createdText = _t("room|intro|you_created");
} else {
createdText = _t("%(displayName)s created this room.", {
createdText = _t("room|intro|user_created", {
displayName: creatorName,
});
}
@ -200,7 +200,7 @@ const NewRoomIntro: React.FC = () => {
defaultDispatcher.dispatch({ action: "view_invite", roomId });
}}
>
{_t("Invite to just this room")}
{_t("room|intro|room_invite")}
</AccessibleButton>
)}
</div>
@ -228,7 +228,7 @@ const NewRoomIntro: React.FC = () => {
avatar = (
<MiniAvatarUploader
hasAvatar={false}
noAvatarLabel={_t("Add a photo, so people can easily spot your room.")}
noAvatarLabel={_t("room|intro|no_avatar_label")}
setAvatarUrl={(url) => cli.sendStateEvent(roomId, EventType.RoomAvatar, { url }, "")}
>
{avatar}
@ -245,7 +245,7 @@ const NewRoomIntro: React.FC = () => {
<p>
{createdText}{" "}
{_t(
"This is the start of <roomName/>.",
"room|intro|start_of_room",
{},
{
roomName: () => <b>{room.name}</b>,
@ -266,9 +266,7 @@ const NewRoomIntro: React.FC = () => {
});
}
const subText = _t(
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.",
);
const subText = _t("room|intro|private_unencrypted_warning");
let subButton: JSX.Element | undefined;
if (
@ -277,7 +275,7 @@ const NewRoomIntro: React.FC = () => {
) {
subButton = (
<AccessibleButton kind="link_inline" onClick={openRoomSettings}>
{_t("Enable encryption in settings.")}
{_t("room|intro|enable_encryption_prompt")}
</AccessibleButton>
);
}
@ -294,7 +292,7 @@ const NewRoomIntro: React.FC = () => {
{!hasExpectedEncryptionSettings(cli, room) && (
<EventTileBubble
className="mx_cryptoEvent mx_cryptoEvent_icon_warning"
title={_t("End-to-end encryption isn't enabled")}
title={_t("room|intro|unencrypted_warning")}
subtitle={subtitle}
/>
)}

View file

@ -47,6 +47,7 @@ import { useRoomState } from "../../../hooks/useRoomState";
import RoomAvatar from "../avatars/RoomAvatar";
import { formatCount } from "../../../utils/FormattingUtils";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { Linkify, topicToHtml } from "../../../HtmlUtils";
/**
* A helper to transform a notification color to the what the Compound Icon Button
@ -100,6 +101,11 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
const notificationsEnabled = useFeatureEnabled("feature_notifications");
const roomTopicBody = useMemo(
() => topicToHtml(roomTopic?.text, roomTopic?.html),
[roomTopic?.html, roomTopic?.text],
);
return (
<Flex
as="header"
@ -159,7 +165,7 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element {
</BodyText>
{roomTopic && (
<BodyText as="div" size="sm" className="mx_RoomHeader_topic">
{roomTopic.text}
<Linkify>{roomTopicBody}</Linkify>
</BodyText>
)}
</Box>

View file

@ -162,7 +162,7 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
<>
<RoomAvatar room={room} size="50px" viewAvatarOnClick />
<div className="mx_RoomPreviewCard_video" />
<BetaPill onClick={viewLabs} tooltipTitle={_t("Video rooms are a beta feature")} />
<BetaPill onClick={viewLabs} tooltipTitle={_t("labs|video_rooms_beta")} />
</>
);
} else if (room.isSpaceRoom()) {

View file

@ -78,7 +78,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
</p>
<p>
{_t(
"<b>Warning</b>: upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.",
"room_settings|advanced|room_upgrade_warning",
{},
{
b: (sub) => <b>{sub}</b>,
@ -89,7 +89,7 @@ export default class RoomUpgradeWarningBar extends React.PureComponent<IProps, I
</div>
<p className="mx_RoomUpgradeWarningBar_upgradelink">
<AccessibleButton onClick={this.onUpgradeClick}>
{_t("Upgrade this room to the recommended room version")}
{_t("room_settings|advanced|room_upgrade_button")}
</AccessibleButton>
</p>
</div>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -67,7 +67,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
}
public componentDidMount(): void {
this.checkKeyBackupStatus();
this.loadBackupStatus();
MatrixClientPeg.safeGet().on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
MatrixClientPeg.safeGet().on(CryptoEvent.KeyBackupSessionsRemaining, this.onKeyBackupSessionsRemaining);
@ -97,28 +97,6 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
this.loadBackupStatus();
};
private async checkKeyBackupStatus(): Promise<void> {
this.getUpdatedDiagnostics();
try {
const keyBackupResult = await MatrixClientPeg.safeGet().checkKeyBackup();
this.setState({
loading: false,
error: false,
backupInfo: keyBackupResult?.backupInfo ?? null,
backupSigStatus: keyBackupResult?.trustInfo ?? null,
});
} catch (e) {
logger.log("Unable to fetch check backup status", e);
if (this.unmounted) return;
this.setState({
loading: false,
error: true,
backupInfo: null,
backupSigStatus: null,
});
}
}
private async loadBackupStatus(): Promise<void> {
this.setState({ loading: true });
this.getUpdatedDiagnostics();
@ -388,18 +366,28 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
<table className="mx_SecureBackupPanel_statusList">
<tr>
<th scope="row">{_t("Backup key stored:")}</th>
<td>{backupKeyStored === true ? _t("in secret storage") : _t("not stored")}</td>
<td>
{backupKeyStored === true
? _t("settings|security|cross_signing_in_4s")
: _t("not stored")}
</td>
</tr>
<tr>
<th scope="row">{_t("Backup key cached:")}</th>
<td>
{backupKeyCached ? _t("cached locally") : _t("not found locally")}
{backupKeyCached
? _t("settings|security|cross_signing_cached")
: _t("settings|security|cross_signing_not_cached")}
{backupKeyWellFormedText}
</td>
</tr>
<tr>
<th scope="row">{_t("Secret storage public key:")}</th>
<td>{secretStorageKeyInAccount ? _t("in account data") : _t("not found")}</td>
<td>
{secretStorageKeyInAccount
? _t("in account data")
: _t("settings|security|cross_signing_not_found")}
</td>
</tr>
<tr>
<th scope="row">{_t("Secret storage:")}</th>

View file

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

View file

@ -68,7 +68,7 @@ const CurrentDeviceSectionHeading: React.FC<CurrentDeviceSectionHeadingProps> =
? [
<IconizedContextMenuOption
key="sign-out-all-others"
label={_t("Sign out of all other sessions (%(otherSessionsCount)s)", { otherSessionsCount })}
label={_t("settings|sessions|sign_out_all_other_sessions", { otherSessionsCount })}
onClick={signOutAllOtherSessions}
isDestructive
/>,
@ -76,7 +76,7 @@ const CurrentDeviceSectionHeading: React.FC<CurrentDeviceSectionHeadingProps> =
: []),
];
return (
<SettingsSubsectionHeading heading={_t("Current session")}>
<SettingsSubsectionHeading heading={_t("settings|sessions|current_session")}>
<KebabContextMenu
disabled={disabled}
title={_t("common|options")}

View file

@ -60,7 +60,7 @@ const DeviceNameEditor: React.FC<Props & { stopEditing: () => void }> = ({ devic
return (
<form aria-disabled={isLoading} className="mx_DeviceDetailHeading_renameForm" onSubmit={onSubmit} method="post">
<p id={headingId} className="mx_DeviceDetailHeading_renameFormHeading">
{_t("Rename session")}
{_t("settings|sessions|rename_form_heading")}
</p>
<div>
<Field
@ -77,21 +77,13 @@ const DeviceNameEditor: React.FC<Props & { stopEditing: () => void }> = ({ devic
maxLength={100}
/>
<Caption id={descriptionId}>
{_t("Please be aware that session names are also visible to people you communicate with.")}
{_t("settings|sessions|rename_form_caption")}
<LearnMore
title={_t("Renaming sessions")}
title={_t("settings|sessions|rename_form_learn_more")}
description={
<>
<p>
{_t(
"Other users in direct messages and rooms that you join are able to view a full list of your sessions.",
)}
</p>
<p>
{_t(
"This provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.",
)}
</p>
<p>{_t("settings|sessions|rename_form_learn_more_description_1")}</p>
<p>{_t("settings|sessions|rename_form_learn_more_description_2")}</p>
</>
}
/>

View file

@ -64,9 +64,9 @@ const DeviceDetails: React.FC<Props> = ({
{
id: "session",
values: [
{ label: _t("Session ID"), value: device.device_id },
{ label: _t("settings|sessions|session_id"), value: device.device_id },
{
label: _t("Last activity"),
label: _t("settings|sessions|last_activity"),
value: device.last_seen_ts && formatDate(new Date(device.last_seen_ts)),
},
],
@ -77,7 +77,7 @@ const DeviceDetails: React.FC<Props> = ({
values: [
{ label: _t("common|name"), value: device.appName },
{ label: _t("common|version"), value: device.appVersion },
{ label: _t("URL"), value: device.url },
{ label: _t("settings|sessions|url"), value: device.url },
],
},
{
@ -85,9 +85,9 @@ const DeviceDetails: React.FC<Props> = ({
heading: _t("common|device"),
values: [
{ label: _t("common|model"), value: device.deviceModel },
{ label: _t("Operating system"), value: device.deviceOperatingSystem },
{ label: _t("Browser"), value: device.client },
{ label: _t("IP address"), value: device.last_seen_ip },
{ label: _t("settings|sessions|os"), value: device.deviceOperatingSystem },
{ label: _t("settings|sessions|browser"), value: device.client },
{ label: _t("settings|sessions|ip"), value: device.last_seen_ip },
],
},
]
@ -122,7 +122,7 @@ const DeviceDetails: React.FC<Props> = ({
<DeviceVerificationStatusCard device={device} onVerifyDevice={onVerifyDevice} isCurrentDevice />
</section>
<section className="mx_DeviceDetails_section">
<p className="mx_DeviceDetails_sectionHeading">{_t("Session details")}</p>
<p className="mx_DeviceDetails_sectionHeading">{_t("settings|sessions|details_heading")}</p>
{metadata.map(({ heading, values, id }, index) => (
<table
className="mx_DeviceDetails_metadataTable"
@ -158,13 +158,13 @@ const DeviceDetails: React.FC<Props> = ({
checked={isPushNotificationsEnabled(pusher, localNotificationSettings)}
disabled={isCheckboxDisabled(pusher, localNotificationSettings)}
onChange={(checked) => setPushNotifications?.(device.device_id, checked)}
title={_t("Toggle push notifications on this session.")}
title={_t("settings|sessions|push_toggle")}
data-testid="device-detail-push-notification-checkbox"
/>
<p className="mx_DeviceDetails_sectionHeading">
{_t("Push notifications")}
{_t("settings|sessions|push_heading")}
<small className="mx_DeviceDetails_sectionSubheading">
{_t("Receive push notifications on this session.")}
{_t("settings|sessions|push_subheading")}
</small>
</p>
</section>
@ -177,7 +177,7 @@ const DeviceDetails: React.FC<Props> = ({
data-testid="device-detail-sign-out-cta"
>
<span className="mx_DeviceDetails_signOutButtonContent">
{_t("Sign out of this session")}
{_t("settings|sessions|sign_out")}
{isSigningOut && <Spinner w={16} h={16} />}
</span>
</AccessibleButton>

View file

@ -27,7 +27,7 @@ interface Props extends React.ComponentProps<typeof AccessibleTooltipButton> {
}
export const DeviceExpandDetailsButton: React.FC<Props> = ({ isExpanded, onClick, ...rest }) => {
const label = isExpanded ? _t("Hide details") : _t("Show details");
const label = isExpanded ? _t("settings|sessions|hide_details") : _t("settings|sessions|show_details");
return (
<AccessibleTooltipButton
{...rest}

View file

@ -50,7 +50,7 @@ const getInactiveMetadata = (device: ExtendedDevice): { id: string; value: React
value: (
<>
<InactiveIcon className="mx_DeviceTile_inactiveIcon" />
{_t("Inactive for %(inactiveAgeDays)s+ days", { inactiveAgeDays: INACTIVE_DEVICE_AGE_DAYS }) +
{_t("settings|sessions|inactive_days", { inactiveAgeDays: INACTIVE_DEVICE_AGE_DAYS }) +
` (${formatLastActivity(device.last_seen_ts)})`}
</>
),
@ -62,7 +62,8 @@ const DeviceMetaDatum: React.FC<{ value: string | React.ReactNode; id: string }>
export const DeviceMetaData: React.FC<Props> = ({ device }) => {
const inactive = getInactiveMetadata(device);
const lastActivity = device.last_seen_ts && `${_t("Last activity")} ${formatLastActivity(device.last_seen_ts)}`;
const lastActivity =
device.last_seen_ts && `${_t("settings|sessions|last_activity")} ${formatLastActivity(device.last_seen_ts)}`;
const verificationStatus = device.isVerified ? _t("common|verified") : _t("common|unverified");
// if device is inactive, don't display last activity or verificationStatus
const metadata = inactive

View file

@ -32,73 +32,41 @@ const securityCardContent: Record<
}
> = {
[DeviceSecurityVariation.Verified]: {
title: _t("Verified sessions"),
title: _t("settings|sessions|verified_sessions"),
description: (
<>
<p>
{_t(
"Verified sessions are anywhere you are using this account after entering your passphrase or confirming your identity with another verified session.",
)}
</p>
<p>
{_t(
"This means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.",
)}
</p>
<p>{_t("settings|sessions|verified_sessions_explainer_1")}</p>
<p>{_t("settings|sessions|verified_sessions_explainer_2")}</p>
</>
),
},
[DeviceSecurityVariation.Unverified]: {
title: _t("Unverified sessions"),
title: _t("settings|sessions|unverified_sessions"),
description: (
<>
<p>
{_t(
"Unverified sessions are sessions that have logged in with your credentials but have not been cross-verified.",
)}
</p>
<p>
{_t(
"You should make especially certain that you recognise these sessions as they could represent an unauthorised use of your account.",
)}
</p>
<p>{_t("settings|sessions|unverified_sessions_explainer_1")}</p>
<p>{_t("settings|sessions|unverified_sessions_explainer_2")}</p>
</>
),
},
// unverifiable uses single-session case
// because it is only ever displayed on a single session detail
[DeviceSecurityVariation.Unverifiable]: {
title: _t("Unverified session"),
title: _t("settings|sessions|unverified_session"),
description: (
<>
<p>{_t(`This session doesn't support encryption and thus can't be verified.`)}</p>
<p>
{_t(
`You won't be able to participate in rooms where encryption is enabled when using this session.`,
)}
</p>
<p>
{_t(
`For best security and privacy, it is recommended to use Matrix clients that support encryption.`,
)}
</p>
<p>{_t("settings|sessions|unverified_session_explainer_1")}</p>
<p>{_t("settings|sessions|unverified_session_explainer_2")}</p>
<p>{_t("settings|sessions|unverified_session_explainer_3")}</p>
</>
),
},
[DeviceSecurityVariation.Inactive]: {
title: _t("Inactive sessions"),
title: _t("settings|sessions|inactive_sessions"),
description: (
<>
<p>
{_t(
"Inactive sessions are sessions you have not used in some time, but they continue to receive encryption keys.",
)}
</p>
<p>
{_t(
"Removing inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious.",
)}
</p>
<p>{_t("settings|sessions|inactive_sessions_explainer_1")}</p>
<p>{_t("settings|sessions|inactive_sessions_explainer_2")}</p>
</>
),
},

View file

@ -23,7 +23,7 @@ import { Icon as WebIcon } from "../../../../../res/img/element-icons/settings/w
import { Icon as MobileIcon } from "../../../../../res/img/element-icons/settings/mobile.svg";
import { Icon as VerifiedIcon } from "../../../../../res/img/e2e/verified.svg";
import { Icon as UnverifiedIcon } from "../../../../../res/img/e2e/warning.svg";
import { _t } from "../../../../languageHandler";
import { _t, _td, TranslationKey } from "../../../../languageHandler";
import { ExtendedDevice } from "./types";
import { DeviceType } from "../../../../utils/device/parseUserAgent";
@ -39,16 +39,16 @@ const deviceTypeIcon: Record<DeviceType, React.FC<React.SVGProps<SVGSVGElement>>
[DeviceType.Web]: WebIcon,
[DeviceType.Unknown]: UnknownDeviceIcon,
};
const deviceTypeLabel: Record<DeviceType, string> = {
[DeviceType.Desktop]: _t("Desktop session"),
[DeviceType.Mobile]: _t("Mobile session"),
[DeviceType.Web]: _t("Web session"),
[DeviceType.Unknown]: _t("Unknown session type"),
const deviceTypeLabel: Record<DeviceType, TranslationKey> = {
[DeviceType.Desktop]: _td("settings|sessions|desktop_session"),
[DeviceType.Mobile]: _td("settings|sessions|mobile_session"),
[DeviceType.Web]: _td("settings|sessions|web_session"),
[DeviceType.Unknown]: _td("settings|sessions|unknown_session"),
};
export const DeviceTypeIcon: React.FC<Props> = ({ isVerified, isSelected, deviceType }) => {
const Icon = deviceTypeIcon[deviceType!] || deviceTypeIcon[DeviceType.Unknown];
const label = deviceTypeLabel[deviceType!] || deviceTypeLabel[DeviceType.Unknown];
const label = _t(deviceTypeLabel[deviceType!] || deviceTypeLabel[DeviceType.Unknown]);
return (
<div
className={classNames("mx_DeviceTypeIcon", {

View file

@ -38,11 +38,11 @@ const getCardProps = (
} => {
if (device.isVerified) {
const descriptionText = isCurrentDevice
? _t("Your current session is ready for secure messaging.")
: _t("This session is ready for secure messaging.");
? _t("settings|sessions|device_verified_description_current")
: _t("settings|sessions|device_verified_description");
return {
variation: DeviceSecurityVariation.Verified,
heading: _t("Verified session"),
heading: _t("settings|sessions|verified_session"),
description: (
<>
{descriptionText}
@ -54,10 +54,10 @@ const getCardProps = (
if (device.isVerified === null) {
return {
variation: DeviceSecurityVariation.Unverified,
heading: _t("Unverified session"),
heading: _t("settings|sessions|unverified_session"),
description: (
<>
{_t(`This session doesn't support encryption and thus can't be verified.`)}
{_t("settings|sessions|unverified_session_explainer_1")}
<DeviceSecurityLearnMore variation={DeviceSecurityVariation.Unverifiable} />
</>
),
@ -65,11 +65,11 @@ const getCardProps = (
}
const descriptionText = isCurrentDevice
? _t("Verify your current session for enhanced secure messaging.")
: _t("Verify or sign out from this session for best security and reliability.");
? _t("settings|sessions|device_unverified_description_current")
: _t("settings|sessions|device_unverified_description");
return {
variation: DeviceSecurityVariation.Unverified,
heading: _t("Unverified session"),
heading: _t("settings|sessions|unverified_session"),
description: (
<>
{descriptionText}
@ -95,7 +95,7 @@ export const DeviceVerificationStatusCard: React.FC<DeviceVerificationStatusCard
onClick={onVerifyDevice}
data-testid={`verification-status-button-${device.device_id}`}
>
{_t("Verify session")}
{_t("settings|sessions|verify_session")}
</AccessibleButton>
)}
</DeviceSecurityCard>

View file

@ -73,36 +73,6 @@ const getFilteredSortedDevices = (devices: DevicesDictionary, filter?: FilterVar
const ALL_FILTER_ID = "ALL";
type DeviceFilterKey = FilterVariation | typeof ALL_FILTER_ID;
const securityCardContent: Record<
DeviceSecurityVariation,
{
title: string;
description: string;
}
> = {
[DeviceSecurityVariation.Verified]: {
title: _t("Verified sessions"),
description: _t("For best security, sign out from any session that you don't recognize or use anymore."),
},
[DeviceSecurityVariation.Unverified]: {
title: _t("Unverified sessions"),
description: _t(
"Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.",
),
},
[DeviceSecurityVariation.Unverifiable]: {
title: _t("Unverified session"),
description: _t(`This session doesn't support encryption and thus can't be verified.`),
},
[DeviceSecurityVariation.Inactive]: {
title: _t("Inactive sessions"),
description: _t(
"Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore.",
{ inactiveAgeDays: INACTIVE_DEVICE_AGE_DAYS },
),
},
};
const isSecurityVariation = (filter?: DeviceFilterKey): filter is FilterVariation =>
!!filter &&
(
@ -115,6 +85,33 @@ const isSecurityVariation = (filter?: DeviceFilterKey): filter is FilterVariatio
const FilterSecurityCard: React.FC<{ filter?: DeviceFilterKey }> = ({ filter }) => {
if (isSecurityVariation(filter)) {
const securityCardContent: Record<
DeviceSecurityVariation,
{
title: string;
description: string;
}
> = {
[DeviceSecurityVariation.Verified]: {
title: _t("settings|sessions|verified_sessions"),
description: _t("settings|sessions|verified_sessions_list_description"),
},
[DeviceSecurityVariation.Unverified]: {
title: _t("settings|sessions|unverified_sessions"),
description: _t("settings|sessions|unverified_sessions_list_description"),
},
[DeviceSecurityVariation.Unverifiable]: {
title: _t("settings|sessions|unverified_session"),
description: _t("settings|sessions|unverified_session_explainer_1"),
},
[DeviceSecurityVariation.Inactive]: {
title: _t("settings|sessions|inactive_sessions"),
description: _t("settings|sessions|inactive_sessions_list_description", {
inactiveAgeDays: INACTIVE_DEVICE_AGE_DAYS,
}),
},
};
const { title, description } = securityCardContent[filter];
return (
<div className="mx_FilteredDeviceList_securityCard">
@ -138,13 +135,13 @@ const FilterSecurityCard: React.FC<{ filter?: DeviceFilterKey }> = ({ filter })
const getNoResultsMessage = (filter?: FilterVariation): string => {
switch (filter) {
case DeviceSecurityVariation.Verified:
return _t("No verified sessions found.");
return _t("settings|sessions|no_verified_sessions");
case DeviceSecurityVariation.Unverified:
return _t("No unverified sessions found.");
return _t("settings|sessions|no_unverified_sessions");
case DeviceSecurityVariation.Inactive:
return _t("No inactive sessions found.");
return _t("settings|sessions|no_inactive_sessions");
default:
return _t("No sessions found.");
return _t("settings|sessions|no_sessions");
}
};
interface NoResultsProps {
@ -281,21 +278,21 @@ export const FilteredDeviceList = forwardRef(
};
const options: FilterDropdownOption<DeviceFilterKey>[] = [
{ id: ALL_FILTER_ID, label: _t("All") },
{ id: ALL_FILTER_ID, label: _t("settings|sessions|filter_all") },
{
id: DeviceSecurityVariation.Verified,
label: _t("common|verified"),
description: _t("Ready for secure messaging"),
description: _t("settings|sessions|filter_verified_description"),
},
{
id: DeviceSecurityVariation.Unverified,
label: _t("common|unverified"),
description: _t("Not ready for secure messaging"),
description: _t("settings|sessions|filter_unverified_description"),
},
{
id: DeviceSecurityVariation.Inactive,
label: _t("Inactive"),
description: _t("Inactive for %(inactiveAgeDays)s days or longer", {
label: _t("settings|sessions|filter_inactive"),
description: _t("settings|sessions|filter_inactive_description", {
inactiveAgeDays: INACTIVE_DEVICE_AGE_DAYS,
}),
},
@ -349,7 +346,7 @@ export const FilteredDeviceList = forwardRef(
) : (
<FilterDropdown<DeviceFilterKey>
id="device-list-filter"
label={_t("Filter devices")}
label={_t("settings|sessions|filter_label")}
value={filter || ALL_FILTER_ID}
onOptionChange={onFilterOptionChange}
options={options}

View file

@ -37,7 +37,7 @@ const FilteredDeviceListHeader: React.FC<Props> = ({
children,
...rest
}) => {
const checkboxLabel = isAllSelected ? _t("Deselect all") : _t("Select all");
const checkboxLabel = isAllSelected ? _t("common|deselect_all") : _t("common|select_all");
return (
<div className="mx_FilteredDeviceListHeader" {...rest}>
{!isSelectDisabled && (
@ -54,7 +54,7 @@ const FilteredDeviceListHeader: React.FC<Props> = ({
)}
<span className="mx_FilteredDeviceListHeader_label">
{selectedDeviceCount > 0
? _t("%(count)s sessions selected", { count: selectedDeviceCount })
? _t("settings|sessions|n_sessions_selected", { count: selectedDeviceCount })
: _t("Sessions")}
</span>
{children}

View file

@ -52,15 +52,13 @@ export default class LoginWithQRSection extends React.Component<IProps> {
}
return (
<SettingsSubsection heading={_t("Sign in with QR code")}>
<SettingsSubsection heading={_t("settings|sessions|sign_in_with_qr")}>
<div className="mx_LoginWithQRSection">
<p className="mx_SettingsTab_subsectionText">
{_t(
"You can use this device to sign in a new device with a QR code. You will need to scan the QR code shown on this device with your device that's signed out.",
)}
{_t("settings|sessions|sign_in_with_qr_description")}
</p>
<AccessibleButton onClick={this.props.onShowQr} kind="primary">
{_t("Show QR code")}
{_t("settings|sessions|sign_in_with_qr_button")}
</AccessibleButton>
</div>
</SettingsSubsection>

View file

@ -41,14 +41,14 @@ export const OtherSessionsSectionHeading: React.FC<Props> = ({
signOutAllOtherSessions ? (
<IconizedContextMenuOption
key="sign-out-all-others"
label={_t("Sign out of %(count)s sessions", { count: otherSessionsCount })}
label={_t("settings|sessions|sign_out_n_sessions", { count: otherSessionsCount })}
onClick={signOutAllOtherSessions}
isDestructive
/>
) : null,
]);
return (
<SettingsSubsectionHeading heading={_t("Other sessions")}>
<SettingsSubsectionHeading heading={_t("settings|sessions|other_sessions_heading")}>
{!!menuOptions.length && (
<KebabContextMenu
disabled={disabled}

View file

@ -52,19 +52,17 @@ const SecurityRecommendations: React.FC<Props> = ({ devices, currentDeviceId, go
return (
<SettingsSubsection
heading={_t("Security recommendations")}
description={_t("Improve your account security by following these recommendations.")}
heading={_t("settings|sessions|security_recommendations")}
description={_t("settings|sessions|security_recommendations_description")}
data-testid="security-recommendations-section"
>
{!!unverifiedDevicesCount && (
<DeviceSecurityCard
variation={DeviceSecurityVariation.Unverified}
heading={_t("Unverified sessions")}
heading={_t("settings|sessions|unverified_sessions")}
description={
<>
{_t(
"Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.",
)}
{_t("settings|sessions|unverified_sessions_list_description")}
<DeviceSecurityLearnMore variation={DeviceSecurityVariation.Unverified} />
</>
}
@ -83,13 +81,10 @@ const SecurityRecommendations: React.FC<Props> = ({ devices, currentDeviceId, go
{!!unverifiedDevicesCount && <div className="mx_SecurityRecommendations_spacing" />}
<DeviceSecurityCard
variation={DeviceSecurityVariation.Inactive}
heading={_t("Inactive sessions")}
heading={_t("settings|sessions|inactive_sessions")}
description={
<>
{_t(
"Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore.",
{ inactiveAgeDays },
)}
{_t("settings|sessions|inactive_sessions_list_description", { inactiveAgeDays })}
<DeviceSecurityLearnMore variation={DeviceSecurityVariation.Inactive} />
</>
}

View file

@ -53,20 +53,20 @@ export const deleteDevicesWithInteractiveAuth = async (
const dialogAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("Use Single Sign On to continue"),
body: _t("Confirm logging out these devices by using Single Sign On to prove your identity.", {
body: _t("settings|sessions|confirm_sign_out_sso", {
count: numDevices,
}),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {
title: _t("Confirm signing out these devices", {
title: _t("settings|sessions|confirm_sign_out", {
count: numDevices,
}),
body: _t("Click the button below to confirm signing out these devices.", {
body: _t("settings|sessions|confirm_sign_out_body", {
count: numDevices,
}),
continueText: _t("Sign out devices", { count: numDevices }),
continueText: _t("settings|sessions|confirm_sign_out_continue", { count: numDevices }),
continueKind: "danger",
},
};

View file

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

View file

@ -341,7 +341,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
parseIntWithDefault(plContent.events_default, powerLevelDescriptors.events_default.defaultValue),
);
let privilegedUsersSection = <div>{_t("No users have specific privileges in this room")}</div>;
let privilegedUsersSection = <div>{_t("room_settings|permissions|no_privileged_users")}</div>;
let mutedUsersSection;
if (Object.keys(userLevels).length) {
const privilegedUsers: JSX.Element[] = [];
@ -391,11 +391,17 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
if (privilegedUsers.length) {
privilegedUsersSection = (
<SettingsFieldset legend={_t("Privileged Users")}>{privilegedUsers}</SettingsFieldset>
<SettingsFieldset legend={_t("room_settings|permissions|privileged_users_section")}>
{privilegedUsers}
</SettingsFieldset>
);
}
if (mutedUsers.length) {
mutedUsersSection = <SettingsFieldset legend={_t("Muted Users")}>{mutedUsers}</SettingsFieldset>;
mutedUsersSection = (
<SettingsFieldset legend={_t("room_settings|permissions|muted_users_section")}>
{mutedUsers}
</SettingsFieldset>
);
}
}
@ -404,7 +410,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
if (banned?.length) {
const canBanUsers = currentUserLevel >= banLevel;
bannedUsersSection = (
<SettingsFieldset legend={_t("Banned users")}>
<SettingsFieldset legend={_t("room_settings|permissions|banned_users_section")}>
<ul className="mx_RolesRoomSettingsTab_bannedList">
{banned.map((member) => {
const banEvent = member.events.member?.getContent();
@ -468,7 +474,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;
label = _t(translationKeyForEvent, { brand });
} else {
label = _t("Send %(eventType)s events", { eventType });
label = _t("room_settings|permissions|send_event_type", { eventType });
}
return (
<div key={eventType}>
@ -487,17 +493,17 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
return (
<SettingsTab>
<SettingsSection heading={_t("Roles & Permissions")}>
<SettingsSection heading={_t("room_settings|permissions|title")}>
{privilegedUsersSection}
{canChangeLevels && <AddPrivilegedUsers room={room} defaultUserLevel={defaultUserLevel} />}
{mutedUsersSection}
{bannedUsersSection}
<SettingsFieldset
legend={_t("Permissions")}
legend={_t("room_settings|permissions|permissions_section")}
description={
isSpaceRoom
? _t("Select the roles required to change various parts of the space")
: _t("Select the roles required to change various parts of the room")
? _t("room_settings|permissions|permissions_section_description_space")
: _t("room_settings|permissions|permissions_section_description_room")
}
>
{powerSelectors}

View file

@ -116,13 +116,13 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
private onEncryptionChange = async (): Promise<void> => {
if (this.props.room.getJoinRule() === JoinRule.Public) {
const dialog = Modal.createDialog(QuestionDialog, {
title: _t("Are you sure you want to add encryption to this public room?"),
title: _t("room_settings|security|enable_encryption_public_room_confirm_title"),
description: (
<div>
<p>
{" "}
{_t(
"<b>It's not recommended to add encryption to public rooms.</b> Anyone can find and join public rooms, so anyone can read messages in them. You'll get none of the benefits of encryption, and you won't be able to turn it off later. Encrypting messages in a public room will make receiving and sending messages slower.",
"room_settings|security|enable_encryption_public_room_confirm_description_1",
undefined,
{ b: (sub) => <b>{sub}</b> },
)}{" "}
@ -130,7 +130,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
<p>
{" "}
{_t(
"To avoid these issues, create a <a>new encrypted room</a> for the conversation you plan to have.",
"room_settings|security|enable_encryption_public_room_confirm_description_2",
undefined,
{
a: (sub) => (
@ -158,9 +158,9 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
}
Modal.createDialog(QuestionDialog, {
title: _t("Enable encryption?"),
title: _t("room_settings|security|enable_encryption_confirm_title"),
description: _t(
"Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>",
"room_settings|security|enable_encryption_confirm_description",
{},
{
a: (sub) => <ExternalLink href={SdkConfig.get("help_encryption_url")}>{sub}</ExternalLink>,
@ -259,11 +259,11 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
aliasWarning = (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("To link to this room, please add an address.")}</span>
<span>{_t("room_settings|security|public_without_alias_warning")}</span>
</div>
);
}
const description = _t("Decide who can join %(roomName)s.", {
const description = _t("room_settings|security|join_rule_description", {
roomName: room.name,
});
@ -309,37 +309,31 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
private onBeforeJoinRuleChange = async (joinRule: JoinRule): Promise<boolean> => {
if (this.state.encrypted && joinRule === JoinRule.Public) {
const dialog = Modal.createDialog(QuestionDialog, {
title: _t("Are you sure you want to make this encrypted room public?"),
title: _t("room_settings|security|encrypted_room_public_confirm_title"),
description: (
<div>
<p>
{" "}
{_t(
"<b>It's not recommended to make encrypted rooms public.</b> It will mean anyone can find and join the room, so anyone can read messages. You'll get none of the benefits of encryption. Encrypting messages in a public room will make receiving and sending messages slower.",
undefined,
{ b: (sub) => <b>{sub}</b> },
)}{" "}
{_t("room_settings|security|encrypted_room_public_confirm_description_1", undefined, {
b: (sub) => <b>{sub}</b>,
})}{" "}
</p>
<p>
{" "}
{_t(
"To avoid these issues, create a <a>new public room</a> for the conversation you plan to have.",
undefined,
{
a: (sub) => (
<AccessibleButton
kind="link_inline"
onClick={(): void => {
dialog.close();
this.createNewRoom(true, false);
}}
>
{" "}
{sub}{" "}
</AccessibleButton>
),
},
)}{" "}
{_t("room_settings|security|encrypted_room_public_confirm_description_2", undefined, {
a: (sub) => (
<AccessibleButton
kind="link_inline"
onClick={(): void => {
dialog.close();
this.createNewRoom(true, false);
}}
>
{" "}
{sub}{" "}
</AccessibleButton>
),
})}{" "}
</p>
</div>
),
@ -366,15 +360,15 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
const options = [
{
value: HistoryVisibility.Shared,
label: _t("Members only (since the point in time of selecting this option)"),
label: _t("room_settings|security|history_visibility_shared"),
},
{
value: HistoryVisibility.Invited,
label: _t("Members only (since they were invited)"),
label: _t("room_settings|security|history_visibility_invited"),
},
{
value: HistoryVisibility.Joined,
label: _t("Members only (since they joined)"),
label: _t("room_settings|security|history_visibility_joined"),
},
];
@ -382,16 +376,14 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
if (!this.state.encrypted || history === HistoryVisibility.WorldReadable) {
options.unshift({
value: HistoryVisibility.WorldReadable,
label: _t("Anyone"),
label: _t("room_settings|security|history_visibility_world_readable"),
});
}
const description = _t(
"Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.",
);
const description = _t("room_settings|security|history_visibility_warning");
return (
<SettingsFieldset legend={_t("Who can read history?")} description={description}>
<SettingsFieldset legend={_t("room_settings|security|history_visibility_legend")} description={description}>
<StyledRadioGroup
name="historyVis"
value={history}
@ -421,11 +413,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
disabled={!canSetGuestAccess}
label={_t("Enable guest access")}
/>
<p>
{_t(
"People with supported clients will be able to join the room without having a registered account.",
)}
</p>
<p>{_t("room_settings|security|guest_access_warning")}</p>
</div>
);
}
@ -454,13 +442,13 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
return (
<SettingsTab>
<SettingsSection heading={_t("Security & Privacy")}>
<SettingsSection heading={_t("room_settings|security|title")}>
<SettingsFieldset
legend={_t("Encryption")}
legend={_t("settings|security|encryption_section")}
description={
isEncryptionForceDisabled && !isEncrypted
? undefined
: _t("Once enabled, encryption cannot be disabled.")
: _t("room_settings|security|encryption_permanent")
}
>
<LabelledToggleSwitch
@ -470,7 +458,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
disabled={!canEnableEncryption}
/>
{isEncryptionForceDisabled && !isEncrypted && (
<Caption>{_t("Your server requires encryption to be disabled.")}</Caption>
<Caption>{_t("room_settings|security|encryption_forced")}</Caption>
)}
{encryptionSettings}
</SettingsFieldset>

View file

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

View file

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

View file

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

View file

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

View file

@ -104,6 +104,7 @@ export const HomeButtonContextMenu: React.FC<ComponentProps<typeof SpaceContextM
label={_t("Show all rooms")}
active={allRoomsInHome}
onClick={() => {
onFinished();
SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.ACCOUNT, !allRoomsInHome);
}}
/>

View file

@ -29,14 +29,10 @@ export default class VerificationComplete extends React.Component<IProps> {
<div>
<h2>{_t("encryption|verification|complete_title")}</h2>
<p>{_t("encryption|verification|complete_description")}</p>
<p>
{_t(
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.",
)}
</p>
<p>{_t("encryption|verification|explainer")}</p>
<DialogButtons
onPrimaryButtonClick={this.props.onDone}
primaryButton={_t("Got It")}
primaryButton={_t("encryption|verification|complete_action")}
hasCancel={false}
/>
</div>

View file

@ -133,18 +133,18 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
</div>
);
sasCaption = this.props.isSelf
? _t("Confirm the emoji below are displayed on both devices, in the same order:")
: _t("Verify this user by confirming the following emoji appear on their screen.");
? _t("encryption|verification|sas_emoji_caption_self")
: _t("encryption|verification|sas_emoji_caption_user");
} else if (this.props.sas.decimal) {
const numberBlocks = this.props.sas.decimal.map((num, i) => <span key={i}>{num}</span>);
sasDisplay = <div className="mx_VerificationShowSas_decimalSas">{numberBlocks}</div>;
sasCaption = this.props.isSelf
? _t("Verify this device by confirming the following number appears on its screen.")
: _t("Verify this user by confirming the following number appears on their screen.");
? _t("encryption|verification|sas_caption_self")
: _t("encryption|verification|sas_caption_user");
} else {
return (
<div>
{_t("Unable to find a supported verification method.")}
{_t("encryption|verification|unsupported_method")}
<AccessibleButton kind="primary" onClick={this.props.onCancel}>
{_t("action|cancel")}
</AccessibleButton>
@ -159,21 +159,21 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
// logged out during verification
const otherDevice = this.props.otherDeviceDetails;
if (otherDevice) {
text = _t("Waiting for you to verify on your other device, %(deviceName)s (%(deviceId)s)…", {
text = _t("encryption|verification|waiting_other_device_details", {
deviceName: otherDevice.displayName,
deviceId: otherDevice.deviceId,
});
} else {
text = _t("Waiting for you to verify on your other device…");
text = _t("encryption|verification|waiting_other_device");
}
confirm = <p>{text}</p>;
} else if (this.state.pending || this.state.cancelling) {
let text;
if (this.state.pending) {
const { displayName } = this.props;
text = _t("Waiting for %(displayName)s to verify…", { displayName });
text = _t("encryption|verification|waiting_other_user", { displayName });
} else {
text = _t("Cancelling…");
text = _t("encryption|verification|cancelling");
}
confirm = <PendingActionSpinner text={text} />;
} else {

View file

@ -32,6 +32,11 @@ export const getTopic = (room?: Room): Optional<ContentHelpers.TopicState> => {
return !!content ? ContentHelpers.parseTopicContent(content) : null;
};
/**
* Helper to retrieve the room topic for given room
* @param room
* @returns the raw text and an html parsion version of the room topic
*/
export function useTopic(room?: Room): Optional<ContentHelpers.TopicState> {
const [topic, setTopic] = useState(getTopic(room));
useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => {

View file

@ -9,7 +9,6 @@
"Unavailable": "غير متوفر",
"All Rooms": "كل الغُرف",
"All messages": "كل الرسائل",
"No update available.": "لا يوجد هناك أي تحديث.",
"Changelog": "سِجل التغييرات",
"Thank you!": "شكرًا !",
"Use Single Sign On to continue": "استعمل الولوج الموحّد للمواصلة",
@ -279,15 +278,6 @@
"%(duration)sh": "%(duration)sس",
"%(duration)sm": "%(duration)sد",
"%(duration)ss": "%(duration)sث",
"This is the start of <roomName/>.": "هذه بداية <roomName/>.",
"Add a photo, so people can easily spot your room.": "أضف صورة ، حتى يسهل على الناس تمييز غرفتك.",
"You created this room.": "أنت أنشأت هذه الغرفة.",
"%(displayName)s created this room.": "%(displayName)s أنشأ هذه الغرفة.",
"<a>Add a topic</a> to help people know what it is about.": "<a>أضف موضوعاً</a> ليُعرف ما يدور حوله الحديث.",
"Topic: %(topic)s ": "الموضوع: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "الموضوع: %(topic)s (<a>عدل</a>)",
"This is the beginning of your direct message history with <displayName/>.": "هذه هي بداية محفوظات رسائلك المباشرة باسم <displayName/>.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "أنتما فقط في هذه المحادثة ، إلا إذا دعا أي منكما أي شخص للانضمام.",
"Italics": "مائل",
"You do not have permission to post to this room": "ليس لديك إذن للنشر في هذه الغرفة",
"This room has been replaced and is no longer active.": "تم استبدال هذه الغرفة ولم تعد نشطة.",
@ -306,27 +296,8 @@
"Encrypted by a deleted session": "مشفرة باتصال محذوف",
"Unencrypted": "غير مشفر",
"Encrypted by an unverified session": "مشفرة باتصال لم يتم التحقق منه",
"Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "يتم تجاهل الأشخاص من خلال قوائم الحظر التي تحتوي على قواعد لمن يتم حظره. الاشتراك في قائمة حظر يعني أن المستخدمين / الخوادم المحظورة بواسطة تلك القائمة سيتم إخفاؤهم عنك.",
"Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, <code>@bot:*</code> would ignore all users that have the name 'bot' on any server.": "أضف المستخدمين والخوادم التي تريد تجاهلها هنا. استخدم علامة النجمة لجعل %(brand)s s تطابق أي أحرف. على سبيل المثال ، قد يتجاهل <code>bot: * </code> جميع المستخدمين الذين اسمهم \"bot\" على أي خادم.",
"⚠ These settings are meant for advanced users.": "⚠ هذه الإعدادات مخصصة للمستخدمين المتقدمين.",
"Ignored users": "المستخدمون المتجاهَلون",
"You are currently subscribed to:": "أنت مشترك حاليا ب:",
"View rules": "عرض القواعد",
"You are not subscribed to any lists": "أنت غير مشترك في أي قوائم",
"You are currently ignoring:": "حاليًّا أنت متجاهل:",
"You have not ignored anyone.": "أنت لم تتجاهل أحداً.",
"User rules": "قواعد المستخدم",
"Server rules": "قواعد الخادم",
"Ban list rules - %(roomName)s": "قواعد قائمة الحظر - %(roomName)s",
"None": "لا شيء",
"Please try again or view your console for hints.": "يرجى المحاولة مرة أخرى أو عرض وحدة التحكم (console) للتلميحات.",
"Error unsubscribing from list": "تعذر إلغاء الاشتراك من القائمة",
"Error removing ignored user/server": "تعذر حذف مستخدم/خادم مُتجاهَل",
"Please verify the room ID or address and try again.": "يرجى التحقق من معرف الغرفة أو العنوان والمحاولة مرة أخرى.",
"Error subscribing to list": "تعذر الاشتراك في القائمة",
"Something went wrong. Please try again or view your console for hints.": "هناك خطأ ما. يرجى المحاولة مرة أخرى أو عرض وحدة التحكم (console) للتلميحات.",
"Error adding ignored user/server": "تعذر إضافة مستخدم/خادم مُتجاهَل",
"Ignored/Blocked": "المُتجاهل/المحظور",
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "للإبلاغ عن مشكلة أمنية متعلقة بMatrix ، يرجى قراءة <a>سياسة الإفصاح الأمني</a> في Matrix.org.",
"General": "عام",
"Discovery": "الاكتشاف",
@ -334,13 +305,8 @@
"Deactivate Account": "تعطيل الحساب",
"Account management": "إدارة الحساب",
"Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "وافق على شروط خدمة خادم الهوية %(serverName)s لتكون قابلاً للاكتشاف عن طريق عنوان البريد الإلكتروني أو رقم الهاتف.",
"Language and region": "اللغة والمنطقة",
"Account": "الحساب",
"Phone numbers": "أرقام الهواتف",
"Email addresses": "عنوان البريد الإلكتروني",
"New version available. <a>Update now.</a>": "ثمة إصدارٌ جديد. <a>حدّث الآن.</a>",
"Check for update": "ابحث عن تحديث",
"Error encountered (%(errorDetail)s).": "صودِفَ خطأ: (%(errorDetail)s).",
"Manage integrations": "إدارة التكاملات",
"Enter a new identity server": "أدخل خادم هوية جديدًا",
"Do not use an identity server": "لا تستخدم خادم هوية",
@ -456,13 +422,6 @@
"Start Verification": "ابدأ التحقق",
"Accepting…": "جارٍ القبول …",
"Waiting for %(displayName)s to accept…": "بانتظار %(displayName)s ليقبل …",
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "عندما يضع شخص ما عنوان URL في رسالته ، يمكن عرض معاينة عنوان URL لإعطاء مزيد من المعلومات حول هذا الرابط مثل العنوان والوصف وصورة من موقع الويب.",
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.": "في الغرف المشفرة ، مثل هذه الغرفة ، يتم تعطيل معاينات URL أصلاً للتأكد من أن خادمك الوسيط (حيث يتم إنشاء المعاينات) لا يمكنه جمع معلومات حول الروابط التي تراها في هذه الغرفة.",
"URL previews are disabled by default for participants in this room.": "معاينات URL معطلة بشكل أصلي للمشاركين في هذه الغرفة.",
"URL previews are enabled by default for participants in this room.": "يتم تمكين معاينات URL أصلًا للمشاركين في هذه الغرفة.",
"You have <a>disabled</a> URL previews by default.": "لقد <a> عطلت </a> معاينات عناوين URL بشكل أصلي.",
"You have <a>enabled</a> URL previews by default.": "لقد قمت <a> بتمكين </a> معاينات URL بشكل أصلي.",
"Publish this room to the public in %(domain)s's room directory?": "هل تريد نشر هذه الغرفة للملأ في دليل غرف %(domain)s؟",
"Room avatar": "صورة الغرفة",
"Room Topic": "موضوع الغرفة",
"Room Name": "اسم الغرفة",
@ -472,48 +431,19 @@
"%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.": "%(brand)s يفقد بعض المكونات المطلوبة لحفظ آمن محليًّا للرسائل المشفرة. إذا أدرت تجربة هذه الخاصية، فأنشئ %(brand)s على سطح المكتب مع <nativeLink>إضافة مكونات البحث</nativeLink>.",
"Securely cache encrypted messages locally for them to appear in search results.": "تخزين الرسائل المشفرة بشكل آمن (في cache) محليًا حتى تظهر في نتائج البحث.",
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "تحقق بشكل فردي من كل اتصال يستخدمه المستخدم لتمييزه أنه موثوق ، دون الوثوق بالأجهزة الموقعة بالتبادل.",
"Encryption": "تشفير",
"Failed to set display name": "تعذر تعيين الاسم الظاهر",
"Authentication": "المصادقة",
"exists": "يوجد",
"User signing private key:": "المفتاح الخاص لتوقيع المستخدم:",
"Self signing private key:": "المفتاح الخاص للتوقيع الذاتي:",
"not found locally": "لم يعثر عليه محليًّا",
"cached locally": "حُفظ (في cache) محليًّا",
"Master private key:": "المفتاح الخاص الرئيسي:",
"not found in storage": "لم يعثر عليها في المخزن",
"in secret storage": "في المخزن السري",
"Cross-signing private keys:": "المفاتيح الخاصة للتوقيع المتبادل:",
"not found": "لم يعثر عليه",
"in memory": "في الذاكرة",
"Cross-signing public keys:": "المفاتيح العامة للتوقيع المتبادل:",
"Set up": "تأسيس",
"Cross-signing is not set up.": "لم يتم إعداد التوقيع المتبادل.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "يحتوي حسابك على هوية توقيع متبادل في وحدة تخزين سرية ، لكن هذا الاتصال لم يثق به بعد.",
"Cross-signing is ready for use.": "التوقيع المتبادل جاهز للاستخدام.",
"Your homeserver does not support cross-signing.": "خادوم المنزل الذي تستعمل لا يدعم التوقيع المتبادل (cross-signing).",
"Change Password": "تغيير كلمة المرور",
"Confirm password": "تأكيد كلمة المرور",
"New Password": "كلمة مرور جديدة",
"Current password": "كلمة المرور الحالية",
"Do you want to set an email address?": "هل تريد تعيين عنوان بريد إلكتروني؟",
"Export E2E room keys": "تصدير مفاتيح E2E للغرفة",
"Warning!": "إنذار!",
"Passwords can't be empty": "كلمات المرور لا يمكن أن تكون فارغة",
"New passwords don't match": "كلمات المرور الجديدة لا تتطابق",
"No display name": "لا اسم ظاهر",
"Show more": "أظهر أكثر",
"This bridge is managed by <user />.": "هذا الجسر يديره <user />.",
"Accept <policyLink /> to continue:": "قبول <policyLink /> للمتابعة:",
"Your server isn't responding to some <a>requests</a>.": "خادمك لا يتجاوب مع بعض <a>الطلبات</a>.",
"Dog": "كلب",
"Cancelling…": "جارٍ الإلغاء…",
"Waiting for %(displayName)s to verify…": "بانتظار %(displayName)s للتحقق…",
"Unable to find a supported verification method.": "تعذر العثور على أحد طرق التحقق الممكنة.",
"Verify this user by confirming the following number appears on their screen.": "تحقق من هذا المستخدم من خلال التأكد من ظهور الرقم التالي على شاشته.",
"Verify this user by confirming the following emoji appear on their screen.": "تحقق من هذا المستخدم من خلال التأكيد من ظهور الرموز التعبيرية التالية على شاشته.",
"Got It": "فهمت",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "الرسائل الآمنة مع هذا المستخدم مشفرة من طرفك إلى طرفه ولا يمكن قراءتها من قبل جهات خارجية.",
"IRC display name width": "عرض الاسم الظاهر لIRC",
"Change notification settings": "تغيير إعدادات الإشعار",
"Please contact your homeserver administrator.": "يُرجى تواصلك مع مدير خادمك.",
@ -527,7 +457,6 @@
"You have verified this user. This user has verified all of their sessions.": "لقد تحققت من هذا المستخدم. لقد تحقق هذا المستخدم من جميع اتصالاته.",
"You have not verified this user.": "أنت لم تتحقق من هذا المستخدم.",
"This user has not verified all of their sessions.": "هذا المستخدم لم يتحقق من جميع اتصالاته.",
"Drop file here to upload": "قم بإسقاط الملف هنا ليُرفَع",
"Phone Number": "رقم الهاتف",
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "تم إرسال رسالة نصية إلى +%(msisdn)s. الرجاء إدخال رمز التحقق الذي فيها.",
"Remove %(phone)s?": "حذف %(phone)s؟",
@ -552,25 +481,6 @@
"Your email address hasn't been verified yet": "لم يتم التحقق من عنوان بريدك الإلكتروني حتى الآن",
"Unable to share email address": "تعذرت مشاركة البريد الإلتكروني",
"Unable to revoke sharing for email address": "تعذر إبطال مشاركة عنوان البريد الإلكتروني",
"Once enabled, encryption cannot be disabled.": "لا يمكن تعطيل التشفير بعد تمكينه.",
"Security & Privacy": "الأمان والخصوصية",
"Who can read history?": "من يستطيع قراءة التاريخ؟",
"Members only (since they joined)": "الأعضاء فقط (منذ انضمامهم)",
"Members only (since they were invited)": "الأعضاء فقط (منذ أن تمت دعوتهم)",
"Members only (since the point in time of selecting this option)": "الأعضاء فقط (منذ اللحظة التي حدد فيها هذا الخيار)",
"Anyone": "أي أحد",
"Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "ستنطبق التغييرات على من يمكنه قراءة السجل على الرسائل المستقبلية في هذه الغرفة فقط. رؤية التاريخ الحالي لن تتغير.",
"To link to this room, please add an address.": "للربط لهذه الغرفة ، يرجى إضافة عنوان.",
"Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>": "لا يمكن العدول عن التشفير بعد تمكينه للغرفة. التشفير يحجب حتى الخادم من رؤية رسائل الغرفة، فقط أعضاؤها هم من يرونها. قد يمنع تمكين التشفير العديد من الروبوتات والجسور من العمل بشكل صحيح. <a> اعرف المزيد حول التشفير. </a>",
"Enable encryption?": "تمكين التشفير؟",
"Select the roles required to change various parts of the room": "حدد الأدوار المطلوبة لتغيير أجزاء مختلفة من الغرفة",
"Permissions": "الصلاحيات",
"Roles & Permissions": "الأدوار والصلاحيات",
"Send %(eventType)s events": "إرسال أحداث من نوع %(eventType)s",
"Banned users": "المستخدمون المحظورون",
"Muted Users": "المستخدمون المكتومون",
"Privileged Users": "المستخدمون المميزون",
"No users have specific privileges in this room": "لا يوجد مستخدمين لديهم امتيازات خاصة في هذه الغرفة",
"An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "تعذر تغيير مستوى قوة المستخدم. تأكد من أن لديك صلاحيات كافية وحاول مرة أخرى.",
"Error changing power level": "تعذر تغيير مستوى القوة",
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "تعذر تغيير مستوى قوة الغرفة. تأكد من أن لديك صلاحيات كافية وحاول مرة أخرى.",
@ -584,15 +494,9 @@
"Sounds": "الأصوات",
"Uploaded sound": "صوت تمام الرفع",
"Room Addresses": "عناوين الغرف",
"URL Previews": "معاينة الروابط",
"Bridges": "الجسور",
"This room is bridging messages to the following platforms. <a>Learn more.</a>": "تعمل هذه الغرفة على توصيل الرسائل بالمنصات التالية. <a> اعرف المزيد. </a>",
"Room version:": "إصدار الغرفة:",
"Room version": "إصدار الغرفة",
"Room information": "معلومات الغرفة",
"View older messages in %(roomName)s.": "عرض رسائل أقدم في %(roomName)s.",
"Upgrade this room to the recommended room version": "قم بترقية هذه الغرفة إلى إصدار الغرفة الموصى به",
"This room is not accessible by remote Matrix servers": "لا يمكن الوصول إلى هذه الغرفة بواسطة خوادم Matrix البعيدة",
"Voice & Video": "الصوت والفيديو",
"Audio Output": "مخرج الصوت",
"No Webcams detected": "لم يتم الكشف عن كاميرات الويب",
@ -607,18 +511,7 @@
"Reject all %(invitedRooms)s invites": "رفض كل الدعوات (%(invitedRooms)s)",
"Accept all %(invitedRooms)s invites": "قبول كل الدعوات (%(invitedRooms)s)",
"Bulk options": "خيارات مجمعة",
"Session key:": "مفتاح الاتصال:",
"Session ID:": "معرّف الاتصال:",
"Cryptography": "التشفير",
"Import E2E room keys": "تعبئة مفاتيح E2E للغرف",
"<not supported>": "<غير معتمد>",
"Room ID or address of ban list": "معرف الغرفة أو عنوان قائمة الحظر",
"If this isn't what you want, please use a different tool to ignore users.": "إذا لم يكن هذا ما تريده ، فيرجى استخدام أداة مختلفة لتجاهل المستخدمين.",
"Subscribing to a ban list will cause you to join it!": "سيؤدي الاشتراك في قائمة الحظر إلى انضمامك إليها!",
"Subscribed lists": "قوائم متشرك بها",
"eg: @bot:* or example.org": "مثلاً: @bot:* أو example.org",
"Server or user ID to ignore": "الخادم أو معرف المستخدم المطلوب تجاهله",
"Personal ban list": "قائمة الحظر الشخصية",
"Safeguard against losing access to encrypted messages & data": "حماية ضد فقدان الوصول إلى الرسائل والبيانات المشفرة",
"Verify this session": "تحقق من هذا الاتصال",
"Encryption upgrade available": "ترقية التشفير متاحة",
@ -933,7 +826,8 @@
"group_widgets": "عناصر الواجهة",
"group_rooms": "الغرف",
"group_voip": "الصوت والفيديو",
"group_encryption": "تشفير"
"group_encryption": "تشفير",
"bridge_state_manager": "هذا الجسر يديره <user />."
},
"keyboard": {
"number": "[رقم]",
@ -1039,13 +933,35 @@
"strict_encryption": "لا ترسل أبدًا رسائل مشفرة إلى اتصالات لم يتم التحقق منها من هذا الاتصال",
"enable_message_search": "تمكين البحث عن الرسائل في الغرف المشفرة",
"message_search_sleep_time": "ما مدى سرعة تنزيل الرسائل.",
"manually_verify_all_sessions": "تحقق يدويًا من جميع الاتصالات البعيدة"
"manually_verify_all_sessions": "تحقق يدويًا من جميع الاتصالات البعيدة",
"cross_signing_public_keys": "المفاتيح العامة للتوقيع المتبادل:",
"cross_signing_in_memory": "في الذاكرة",
"cross_signing_not_found": "لم يعثر عليه",
"cross_signing_private_keys": "المفاتيح الخاصة للتوقيع المتبادل:",
"cross_signing_in_4s": "في المخزن السري",
"cross_signing_not_in_4s": "لم يعثر عليها في المخزن",
"cross_signing_master_private_Key": "المفتاح الخاص الرئيسي:",
"cross_signing_cached": "حُفظ (في cache) محليًّا",
"cross_signing_not_cached": "لم يعثر عليه محليًّا",
"cross_signing_self_signing_private_key": "المفتاح الخاص للتوقيع الذاتي:",
"cross_signing_user_signing_private_key": "المفتاح الخاص لتوقيع المستخدم:",
"cross_signing_homeserver_support_exists": "يوجد",
"export_megolm_keys": "تصدير مفاتيح E2E للغرفة",
"import_megolm_keys": "تعبئة مفاتيح E2E للغرف",
"cryptography_section": "التشفير",
"session_id": "معرّف الاتصال:",
"session_key": "مفتاح الاتصال:",
"encryption_section": "تشفير"
},
"preferences": {
"room_list_heading": "قائمة الغرفة",
"composer_heading": "الكاتب",
"autocomplete_delay": "تأخير الإكمال التلقائي (مللي ثانية)",
"always_show_menu_bar": "أظهر شريط قائمة النافذة دائمًا"
},
"general": {
"account_section": "الحساب",
"language_section": "اللغة والمنطقة"
}
},
"devtools": {
@ -1305,10 +1221,47 @@
"state_default": "تغيير الإعدادات",
"ban": "حظر المستخدمين",
"redact": "حذف رسائل الآخرين",
"notifications.room": "إشعار الجميع"
"notifications.room": "إشعار الجميع",
"no_privileged_users": "لا يوجد مستخدمين لديهم امتيازات خاصة في هذه الغرفة",
"privileged_users_section": "المستخدمون المميزون",
"muted_users_section": "المستخدمون المكتومون",
"banned_users_section": "المستخدمون المحظورون",
"send_event_type": "إرسال أحداث من نوع %(eventType)s",
"title": "الأدوار والصلاحيات",
"permissions_section": "الصلاحيات",
"permissions_section_description_room": "حدد الأدوار المطلوبة لتغيير أجزاء مختلفة من الغرفة"
},
"security": {
"strict_encryption": "لا ترسل أبدًا رسائل مشفرة إلى اتصالات التي لم يتم التحقق منها في هذه الغرفة من هذا الاتصال"
"strict_encryption": "لا ترسل أبدًا رسائل مشفرة إلى اتصالات التي لم يتم التحقق منها في هذه الغرفة من هذا الاتصال",
"enable_encryption_confirm_title": "تمكين التشفير؟",
"enable_encryption_confirm_description": "لا يمكن العدول عن التشفير بعد تمكينه للغرفة. التشفير يحجب حتى الخادم من رؤية رسائل الغرفة، فقط أعضاؤها هم من يرونها. قد يمنع تمكين التشفير العديد من الروبوتات والجسور من العمل بشكل صحيح. <a> اعرف المزيد حول التشفير. </a>",
"public_without_alias_warning": "للربط لهذه الغرفة ، يرجى إضافة عنوان.",
"history_visibility": {},
"history_visibility_warning": "ستنطبق التغييرات على من يمكنه قراءة السجل على الرسائل المستقبلية في هذه الغرفة فقط. رؤية التاريخ الحالي لن تتغير.",
"history_visibility_legend": "من يستطيع قراءة التاريخ؟",
"title": "الأمان والخصوصية",
"encryption_permanent": "لا يمكن تعطيل التشفير بعد تمكينه.",
"history_visibility_shared": "الأعضاء فقط (منذ اللحظة التي حدد فيها هذا الخيار)",
"history_visibility_invited": "الأعضاء فقط (منذ أن تمت دعوتهم)",
"history_visibility_joined": "الأعضاء فقط (منذ انضمامهم)",
"history_visibility_world_readable": "أي أحد"
},
"general": {
"publish_toggle": "هل تريد نشر هذه الغرفة للملأ في دليل غرف %(domain)s؟",
"user_url_previews_default_on": "لقد قمت <a> بتمكين </a> معاينات URL بشكل أصلي.",
"user_url_previews_default_off": "لقد <a> عطلت </a> معاينات عناوين URL بشكل أصلي.",
"default_url_previews_on": "يتم تمكين معاينات URL أصلًا للمشاركين في هذه الغرفة.",
"default_url_previews_off": "معاينات URL معطلة بشكل أصلي للمشاركين في هذه الغرفة.",
"url_preview_encryption_warning": "في الغرف المشفرة ، مثل هذه الغرفة ، يتم تعطيل معاينات URL أصلاً للتأكد من أن خادمك الوسيط (حيث يتم إنشاء المعاينات) لا يمكنه جمع معلومات حول الروابط التي تراها في هذه الغرفة.",
"url_preview_explainer": "عندما يضع شخص ما عنوان URL في رسالته ، يمكن عرض معاينة عنوان URL لإعطاء مزيد من المعلومات حول هذا الرابط مثل العنوان والوصف وصورة من موقع الويب.",
"url_previews_section": "معاينة الروابط"
},
"advanced": {
"unfederated": "لا يمكن الوصول إلى هذه الغرفة بواسطة خوادم Matrix البعيدة",
"room_upgrade_button": "قم بترقية هذه الغرفة إلى إصدار الغرفة الموصى به",
"room_predecessor": "عرض رسائل أقدم في %(roomName)s.",
"room_version_section": "إصدار الغرفة",
"room_version": "إصدار الغرفة:"
}
},
"encryption": {
@ -1321,7 +1274,14 @@
"complete_description": "لقد نجحت في التحقق من هذا المستخدم.",
"qr_prompt": "امسح هذا الرمز الفريد",
"sas_prompt": "قارن رمزاً تعبيريًّا فريداً",
"sas_description": "قارن مجموعة فريدة من الرموز التعبيرية إذا لم يكن لديك كاميرا على أي من الجهازين"
"sas_description": "قارن مجموعة فريدة من الرموز التعبيرية إذا لم يكن لديك كاميرا على أي من الجهازين",
"explainer": "الرسائل الآمنة مع هذا المستخدم مشفرة من طرفك إلى طرفه ولا يمكن قراءتها من قبل جهات خارجية.",
"complete_action": "فهمت",
"sas_emoji_caption_user": "تحقق من هذا المستخدم من خلال التأكيد من ظهور الرموز التعبيرية التالية على شاشته.",
"sas_caption_user": "تحقق من هذا المستخدم من خلال التأكد من ظهور الرقم التالي على شاشته.",
"unsupported_method": "تعذر العثور على أحد طرق التحقق الممكنة.",
"waiting_other_user": "بانتظار %(displayName)s للتحقق…",
"cancelling": "جارٍ الإلغاء…"
}
},
"emoji": {
@ -1342,7 +1302,14 @@
"footer_powered_by_matrix": "مشغل بواسطة Matrix",
"sign_in_or_register": "لِج أو أنشِئ حسابًا",
"sign_in_or_register_description": "استعمل حسابك أو أنشِئ واحدًا جديدًا للمواصلة.",
"register_action": "أنشِئ حسابًا"
"register_action": "أنشِئ حسابًا",
"change_password_mismatch": "كلمات المرور الجديدة لا تتطابق",
"change_password_empty": "كلمات المرور لا يمكن أن تكون فارغة",
"set_email_prompt": "هل تريد تعيين عنوان بريد إلكتروني؟",
"change_password_confirm_label": "تأكيد كلمة المرور",
"change_password_current_label": "كلمة المرور الحالية",
"change_password_new_label": "كلمة مرور جديدة",
"change_password_action": "تغيير كلمة المرور"
},
"export_chat": {
"messages": "الرسائل"
@ -1471,10 +1438,60 @@
"see_changes_button": "ما الجديد ؟",
"release_notes_toast_title": "آخِر المُستجدّات",
"toast_title": "حدّث: %(brand)s",
"toast_description": "يتوفر إصدار جديد من %(brand)s"
"toast_description": "يتوفر إصدار جديد من %(brand)s",
"error_encountered": "صودِفَ خطأ: (%(errorDetail)s).",
"no_update": "لا يوجد هناك أي تحديث.",
"new_version_available": "ثمة إصدارٌ جديد. <a>حدّث الآن.</a>",
"check_action": "ابحث عن تحديث"
},
"labs_mjolnir": {
"room_name": "قائمة الحظر",
"room_topic": "هذه قائمتك للمستخدمين / الخوادم التي حظرت - لا تغادر الغرفة!"
"room_topic": "هذه قائمتك للمستخدمين / الخوادم التي حظرت - لا تغادر الغرفة!",
"ban_reason": "المُتجاهل/المحظور",
"error_adding_ignore": "تعذر إضافة مستخدم/خادم مُتجاهَل",
"something_went_wrong": "هناك خطأ ما. يرجى المحاولة مرة أخرى أو عرض وحدة التحكم (console) للتلميحات.",
"error_adding_list_title": "تعذر الاشتراك في القائمة",
"error_adding_list_description": "يرجى التحقق من معرف الغرفة أو العنوان والمحاولة مرة أخرى.",
"error_removing_ignore": "تعذر حذف مستخدم/خادم مُتجاهَل",
"error_removing_list_title": "تعذر إلغاء الاشتراك من القائمة",
"error_removing_list_description": "يرجى المحاولة مرة أخرى أو عرض وحدة التحكم (console) للتلميحات.",
"rules_title": "قواعد قائمة الحظر - %(roomName)s",
"rules_server": "قواعد الخادم",
"rules_user": "قواعد المستخدم",
"personal_empty": "أنت لم تتجاهل أحداً.",
"personal_section": "حاليًّا أنت متجاهل:",
"no_lists": "أنت غير مشترك في أي قوائم",
"view_rules": "عرض القواعد",
"lists": "أنت مشترك حاليا ب:",
"title": "المستخدمون المتجاهَلون",
"advanced_warning": "⚠ هذه الإعدادات مخصصة للمستخدمين المتقدمين.",
"explainer_1": "أضف المستخدمين والخوادم التي تريد تجاهلها هنا. استخدم علامة النجمة لجعل %(brand)s s تطابق أي أحرف. على سبيل المثال ، قد يتجاهل <code>bot: * </code> جميع المستخدمين الذين اسمهم \"bot\" على أي خادم.",
"explainer_2": "يتم تجاهل الأشخاص من خلال قوائم الحظر التي تحتوي على قواعد لمن يتم حظره. الاشتراك في قائمة حظر يعني أن المستخدمين / الخوادم المحظورة بواسطة تلك القائمة سيتم إخفاؤهم عنك.",
"personal_heading": "قائمة الحظر الشخصية",
"personal_new_label": "الخادم أو معرف المستخدم المطلوب تجاهله",
"personal_new_placeholder": "مثلاً: @bot:* أو example.org",
"lists_heading": "قوائم متشرك بها",
"lists_description_1": "سيؤدي الاشتراك في قائمة الحظر إلى انضمامك إليها!",
"lists_description_2": "إذا لم يكن هذا ما تريده ، فيرجى استخدام أداة مختلفة لتجاهل المستخدمين.",
"lists_new_label": "معرف الغرفة أو عنوان قائمة الحظر"
},
"room": {
"drop_file_prompt": "قم بإسقاط الملف هنا ليُرفَع",
"intro": {
"start_of_dm_history": "هذه هي بداية محفوظات رسائلك المباشرة باسم <displayName/>.",
"dm_caption": "أنتما فقط في هذه المحادثة ، إلا إذا دعا أي منكما أي شخص للانضمام.",
"topic_edit": "الموضوع: %(topic)s (<a>عدل</a>)",
"topic": "الموضوع: %(topic)s ",
"no_topic": "<a>أضف موضوعاً</a> ليُعرف ما يدور حوله الحديث.",
"you_created": "أنت أنشأت هذه الغرفة.",
"user_created": "%(displayName)s أنشأ هذه الغرفة.",
"no_avatar_label": "أضف صورة ، حتى يسهل على الناس تمييز غرفتك.",
"start_of_room": "هذه بداية <roomName/>."
}
},
"space": {
"context_menu": {
"explore": "استكشِف الغرف"
}
}
}
}

View file

@ -42,14 +42,6 @@
"You are no longer ignoring %(userId)s": "Siz %(userId)s blokdan çıxardınız",
"Reason": "Səbəb",
"Incorrect verification code": "Təsdiq etmənin səhv kodu",
"Phone": "Telefon",
"New passwords don't match": "Yeni şifrlər uyğun gəlmir",
"Passwords can't be empty": "Şifrələr boş ola bilməz",
"Export E2E room keys": "Şifrləmənin açarlarının ixracı",
"Current password": "Cari şifrə",
"New Password": "Yeni şifrə",
"Confirm password": "Yeni şifrə təsdiq edin",
"Change Password": "Şifrəni dəyişdirin",
"Authentication": "Müəyyənləşdirilmə",
"Failed to set display name": "Görünüş adını təyin etmək bacarmadı",
"Notification targets": "Xəbərdarlıqlar üçün qurğular",
@ -72,17 +64,12 @@
"Banned by %(displayName)s": "%(displayName)s bloklanıb",
"unknown error code": "naməlum səhv kodu",
"Failed to forget room %(errCode)s": "Otağı unutmağı bacarmadı: %(errCode)s",
"No users have specific privileges in this room": "Heç bir istifadəçi bu otaqda xüsusi hüquqlara malik deyil",
"Banned users": "Bloklanmış istifadəçilər",
"Favourite": "Seçilmiş",
"Who can read history?": "Kim tarixi oxuya bilər?",
"Permissions": "Girişin hüquqları",
"Sunday": "Bazar",
"Friday": "Cümə",
"Today": "Bu gün",
"Decrypt %(text)s": "Şifrini açmaq %(text)s",
"Download %(text)s": "Yükləmək %(text)s",
"Sign in with": "Seçmək",
"Create new room": "Otağı yaratmaq",
"Home": "Başlanğıc",
"%(items)s and %(lastItem)s": "%(items)s və %(lastItem)s",
@ -97,7 +84,6 @@
"Reject invitation": "Dəvəti rədd etmək",
"Are you sure you want to reject the invitation?": "Siz əminsiniz ki, siz dəvəti rədd etmək istəyirsiniz?",
"Failed to reject invitation": "Dəvəti rədd etməyi bacarmadı",
"For security, this session has been signed out. Please sign in again.": "Təhlükəsizliyin təmin olunması üçün sizin sessiyanız başa çatmışdır idi. Zəhmət olmasa, yenidən girin.",
"Notifications": "Xəbərdarlıqlar",
"Connectivity to the server has been lost.": "Serverlə əlaqə itirilmişdir.",
"Sent messages will be stored until your connection has returned.": "Hələ ki serverlə əlaqə bərpa olmayacaq, göndərilmiş mesajlar saxlanacaq.",
@ -106,16 +92,10 @@
"Failed to load timeline position": "Xronologiyadan nişanı yükləməyi bacarmadı",
"Unable to remove contact information": "Əlaqə məlumatlarının silməyi bacarmadı",
"<not supported>": "<dəstəklənmir>",
"Import E2E room keys": "Şifrləmənin açarlarının idxalı",
"Cryptography": "Kriptoqrafiya",
"Email": "E-poçt",
"Profile": "Profil",
"Account": "Hesab",
"A new password must be entered.": "Yeni parolu daxil edin.",
"New passwords must match each other.": "Yeni şifrələr uyğun olmalıdır.",
"Return to login screen": "Girişin ekranına qayıtmaq",
"Commands": "Komandalar",
"Users": "İstifadəçilər",
"Confirm passphrase": "Şifrəni təsdiqləyin",
"This email address is already in use": "Bu e-mail ünvanı istifadə olunur",
"This phone number is already in use": "Bu telefon nömrəsi artıq istifadə olunur",
@ -211,6 +191,14 @@
"appearance": {
"timeline_image_size_default": "Varsayılan olaraq",
"image_size_default": "Varsayılan olaraq"
},
"security": {
"export_megolm_keys": "Şifrləmənin açarlarının ixracı",
"import_megolm_keys": "Şifrləmənin açarlarının idxalı",
"cryptography_section": "Kriptoqrafiya"
},
"general": {
"account_section": "Hesab"
}
},
"timeline": {
@ -302,9 +290,41 @@
"auth": {
"footer_powered_by_matrix": "Matrix tərəfindən təchiz edilmişdir",
"unsupported_auth_msisdn": "Bu server telefon nömrəsinin köməyi ilə müəyyənləşdirilməni dəstəkləmir.",
"register_action": "Hesab Aç"
"register_action": "Hesab Aç",
"phone_label": "Telefon",
"session_logged_out_description": "Təhlükəsizliyin təmin olunması üçün sizin sessiyanız başa çatmışdır idi. Zəhmət olmasa, yenidən girin.",
"change_password_mismatch": "Yeni şifrlər uyğun gəlmir",
"change_password_empty": "Şifrələr boş ola bilməz",
"change_password_confirm_label": "Yeni şifrə təsdiq edin",
"change_password_current_label": "Cari şifrə",
"change_password_new_label": "Yeni şifrə",
"change_password_action": "Şifrəni dəyişdirin",
"email_field_label": "E-poçt",
"msisdn_field_label": "Telefon",
"identifier_label": "Seçmək"
},
"update": {
"release_notes_toast_title": "Nə dəyişdi"
},
"composer": {
"autocomplete": {
"command_description": "Komandalar",
"user_description": "İstifadəçilər"
}
},
"space": {
"context_menu": {
"explore": "Otaqları kəşf edin"
}
},
"room_settings": {
"permissions": {
"no_privileged_users": "Heç bir istifadəçi bu otaqda xüsusi hüquqlara malik deyil",
"banned_users_section": "Bloklanmış istifadəçilər",
"permissions_section": "Girişin hüquqları"
},
"security": {
"history_visibility_legend": "Kim tarixi oxuya bilər?"
}
}
}

View file

@ -70,19 +70,9 @@
"Not a valid %(brand)s keyfile": "Невалиден файл с ключ за %(brand)s",
"Authentication check failed: incorrect password?": "Неуспешна автентикация: неправилна парола?",
"Incorrect verification code": "Неправилен код за потвърждение",
"Phone": "Телефон",
"No display name": "Няма име",
"New passwords don't match": "Новите пароли не съвпадат",
"Passwords can't be empty": "Полето с парола не може да е празно",
"Export E2E room keys": "Експортирай E2E ключове",
"Do you want to set an email address?": "Искате ли да зададете имейл адрес?",
"Current password": "Текуща парола",
"New Password": "Нова парола",
"Confirm password": "Потвърждаване на парола",
"Change Password": "Смяна на парола",
"Authentication": "Автентикация",
"Failed to set display name": "Неуспешно задаване на име",
"Drop file here to upload": "Пуснете файла тук, за да се качи",
"Unban": "Отблокирай",
"Failed to ban user": "Неуспешно блокиране на потребителя",
"Failed to mute user": "Неуспешно заглушаване на потребителя",
@ -118,25 +108,9 @@
"%(roomName)s is not accessible at this time.": "%(roomName)s не е достъпна към този момент.",
"Failed to unban": "Неуспешно отблокиране",
"Banned by %(displayName)s": "Блокиран от %(displayName)s",
"Privileged Users": "Потребители с привилегии",
"No users have specific privileges in this room": "Никой няма специфични привилегии в тази стая",
"Banned users": "Блокирани потребители",
"This room is not accessible by remote Matrix servers": "Тази стая не е достъпна за отдалечени Matrix сървъри",
"Publish this room to the public in %(domain)s's room directory?": "Публично публикуване на тази стая в директорията на %(domain)s?",
"Who can read history?": "Кой може да чете историята?",
"Anyone": "Всеки",
"Members only (since the point in time of selecting this option)": "Само членове (от момента на избиране на тази опция)",
"Members only (since they were invited)": "Само членове (от момента, в който те са поканени)",
"Members only (since they joined)": "Само членове (от момента, в който са се присъединили)",
"Permissions": "Разрешения",
"Jump to first unread message.": "Отиди до първото непрочетено съобщение.",
"not specified": "неопределен",
"This room has no local addresses": "Тази стая няма локални адреси",
"You have <a>enabled</a> URL previews by default.": "Вие сте <a>включили</a> URL прегледи по подразбиране.",
"You have <a>disabled</a> URL previews by default.": "Вие сте <a>изключили</a> URL прегледи по подразбиране.",
"URL previews are enabled by default for participants in this room.": "URL прегледи са включени по подразбиране за участниците в тази стая.",
"URL previews are disabled by default for participants in this room.": "URL прегледи са изключени по подразбиране за участниците в тази стая.",
"URL Previews": "URL прегледи",
"Error decrypting attachment": "Грешка при разшифроване на прикачен файл",
"Decrypt %(text)s": "Разшифровай %(text)s",
"Download %(text)s": "Изтегли %(text)s",
@ -147,11 +121,6 @@
"Copied!": "Копирано!",
"Failed to copy": "Неуспешно копиране",
"Add an Integration": "Добавяне на интеграция",
"Token incorrect": "Неправителен тоукън",
"A text message has been sent to %(msisdn)s": "Текстово съобщение беше изпратено на %(msisdn)s",
"Please enter the code it contains:": "Моля, въведете кода, който то съдържа:",
"Start authentication": "Започни автентикация",
"Sign in with": "Влизане с",
"Email address": "Имейл адрес",
"Something went wrong!": "Нещо се обърка!",
"Delete Widget": "Изтриване на приспособление",
@ -185,16 +154,11 @@
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Беше направен опит да се зареди конкретна точка в хронологията на тази стая, но не я намери.",
"Unable to remove contact information": "Неуспешно премахване на информацията за контакти",
"This will allow you to reset your password and receive notifications.": "Това ще Ви позволи да възстановите Вашата парола и да получавате известия.",
"You must <a>register</a> to use this functionality": "Трябва да се <a>регистрирате</a>, за да използвате тази функционалност",
"You must join the room to see its files": "Трябва да се присъедините към стаята, за да видите файловете, които съдържа",
"Reject invitation": "Отхвърли поканата",
"Are you sure you want to reject the invitation?": "Сигурни ли сте, че искате да отхвърлите поканата?",
"Failed to reject invitation": "Неуспешно отхвърляне на поканата",
"This room is not public. You will not be able to rejoin without an invite.": "Тази стая не е публична. Няма да можете да се присъедините отново без покана.",
"Are you sure you want to leave the room '%(roomName)s'?": "Сигурни ли сте, че искате да напуснете стаята '%(roomName)s'?",
"Old cryptography data detected": "Бяха открити стари криптографски данни",
"Signed Out": "Излязохте",
"For security, this session has been signed out. Please sign in again.": "Поради мерки за сигурност, тази сесия е прекратена. Моля, влезте отново.",
"Connectivity to the server has been lost.": "Връзката със сървъра е изгубена.",
"Sent messages will be stored until your connection has returned.": "Изпратените съобщения ще бъдат запаметени докато връзката Ви се възвърне.",
"You seem to be uploading files, are you sure you want to quit?": "Изглежда, че качвате файлове. Сигурни ли сте, че искате да затворите програмата?",
@ -212,26 +176,17 @@
},
"Uploading %(filename)s": "Качване на %(filename)s",
"<not supported>": "<не се поддържа>",
"Import E2E room keys": "Импортирай E2E ключове",
"Cryptography": "Криптография",
"Check for update": "Провери за нова версия",
"No media permissions": "Няма разрешения за медийните устройства",
"You may need to manually permit %(brand)s to access your microphone/webcam": "Може да се наложи ръчно да разрешите на %(brand)s да получи достъп до Вашия микрофон/уеб камера",
"No Microphones detected": "Няма открити микрофони",
"No Webcams detected": "Няма открити уеб камери",
"Default Device": "Устройство по подразбиране",
"Email": "Имейл",
"Profile": "Профил",
"Account": "Акаунт",
"A new password must be entered.": "Трябва да бъде въведена нова парола.",
"New passwords must match each other.": "Новите пароли трябва да съвпадат една с друга.",
"Return to login screen": "Връщане към страницата за влизане в профила",
"Please note you are logging into the %(hs)s server, not matrix.org.": "Моля, обърнете внимание, че влизате в %(hs)s сървър, а не в matrix.org.",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Не е възможно свързване към Home сървъра чрез HTTP, когато има HTTPS адрес в лентата на браузъра Ви. Или използвайте HTTPS или <a>включете функция небезопасни скриптове</a>.",
"Commands": "Команди",
"Notify the whole room": "Извести всички в стаята",
"Room Notification": "Известие за стая",
"Users": "Потребители",
"Session ID": "Идентификатор на сесията",
"Passphrases must match": "Паролите трябва да съвпадат",
"Passphrase must not be empty": "Паролата не трябва да е празна",
@ -242,7 +197,6 @@
"File to import": "Файл за импортиране",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "На път сте да бъдете отведени до друг сайт, където можете да удостоверите профила си за използване с %(integrationsUrl)s. Искате ли да продължите?",
"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)s, Вашата сесия може да не бъде съвместима с текущата версия. Затворете този прозорец и се върнете в по-новата версия.",
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Засечени са данни от по-стара версия на %(brand)s. Това ще доведе до неправилна работа на криптографията от край до край в по-старата версия. Шифрованите от край до край съобщения, които са били обменени наскоро (при използването на по-стара версия), може да не успеят да бъдат разшифровани в тази версия. Това също може да доведе до неуспех в обмяната на съобщения в тази версия. Ако имате проблеми, излезте и влезте отново в профила си. За да запазите историята на съобщенията, експортирайте и импортирайте отново Вашите ключове.",
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Няма връзка с Home сървъра. Моля, проверете Вашата връзка. Уверете се, че <a>SSL сертификатът на Home сървъра</a> е надежден и че някое разширение на браузъра не блокира заявките.",
"This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "Този процес Ви позволява да експортирате във файл ключовете за съобщения в шифровани стаи. Така ще можете да импортирате файла в друг Matrix клиент, така че той също да може да разшифрова такива съобщения.",
"This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "Този процес позволява да импортирате ключове за шифроване, които преди сте експортирали от друг Matrix клиент. Тогава ще можете да разшифровате всяко съобщение, което другият клиент може да разшифрова.",
@ -258,7 +212,6 @@
"Unavailable": "Не е наличен",
"Source URL": "URL на източника",
"Filter results": "Филтриране на резултати",
"No update available.": "Няма нова версия.",
"Search…": "Търсене…",
"Tuesday": "Вторник",
"Preparing to send logs": "Подготовка за изпращане на логове",
@ -272,7 +225,6 @@
"Thursday": "Четвъртък",
"Logs sent": "Логовете са изпратени",
"Yesterday": "Вчера",
"Error encountered (%(errorDetail)s).": "Възникна грешка (%(errorDetail)s).",
"Low Priority": "Нисък приоритет",
"Thank you!": "Благодарим!",
"Missing roomId.": "Липсва идентификатор на стая.",
@ -282,12 +234,8 @@
"Send Logs": "Изпрати логове",
"We encountered an error trying to restore your previous session.": "Възникна грешка при възстановяване на предишната Ви сесия.",
"Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Изчистване на запазените данни в браузъра може да поправи проблема, но ще Ви изкара от профила и ще направи шифрованите съобщения нечетими.",
"Muted Users": "Заглушени потребители",
"Can't leave Server Notices room": "Не може да напуснете стая \"Server Notices\"",
"This room is used for important messages from the Homeserver, so you cannot leave it.": "Тази стая се използва за важни съобщения от сървъра, така че не можете да я напуснете.",
"Terms and Conditions": "Правила и условия",
"To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "За да продължите да ползвате %(homeserverDomain)s е необходимо да прегледате и да се съгласите с правилата и условията за ползване.",
"Review terms and conditions": "Прегледай правилата и условията",
"Share Link to User": "Сподели връзка с потребител",
"Share room": "Сподели стаята",
"Share Room": "Споделяне на стая",
@ -297,8 +245,6 @@
"Link to selected message": "Създай връзка към избраното съобщение",
"No Audio Outputs detected": "Не са открити аудио изходи",
"Audio Output": "Аудио изходи",
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.": "В шифровани стаи като тази, по подразбиране URL прегледите са изключени, за да се подсигури че сървърът (където става генерирането на прегледите) не може да събира информация за връзките споделени в стаята.",
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "Когато се сподели URL връзка в съобщение, може да бъде показан URL преглед даващ повече информация за връзката (заглавие, описание и картинка от уебсайта).",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Не можете да изпращате съобщения докато не прегледате и се съгласите с <consentLink>нашите правила и условия</consentLink>.",
"Demote yourself?": "Понижете себе си?",
"Demote": "Понижение",
@ -329,7 +275,6 @@
"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)s все още е отворена в друг таб, моля затворете я. Използването на %(brand)s на един адрес във версии с постепенно и без постепенно зареждане ще причини проблеми.",
"Incompatible local cache": "Несъвместим локален кеш",
"Clear cache and resync": "Изчисти кеша и ресинхронизирай",
"Please review and accept the policies of this homeserver:": "Моля, прегледайте и приемете политиките на този сървър:",
"Add some now": "Добави сега",
"Unable to load! Check your network connectivity and try again.": "Неуспешно зареждане! Проверете мрежовите настройки и опитайте пак.",
"You do not have permission to invite people to this room.": "Нямате привилегии да каните хора в тази стая.",
@ -337,7 +282,6 @@
"Delete Backup": "Изтрий резервното копие",
"Unable to load key backup status": "Неуспешно зареждане на състоянието на резервното копие на ключа",
"Set up": "Настрой",
"Please review and accept all of the homeserver's policies": "Моля прегледайте и приемете всички политики на сървъра",
"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)s за да направите това",
"Incompatible Database": "Несъвместима база данни",
"Continue With Encryption Disabled": "Продължи с изключено шифроване",
@ -362,9 +306,6 @@
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Не бяга открити профили за изброените по-долу Matrix идентификатори. Желаете ли да ги поканите въпреки това?",
"Invite anyway and never warn me again": "Покани въпреки това и не питай отново",
"Invite anyway": "Покани въпреки това",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Защитените съобщения с този потребител са шифровани от край-до-край и не могат да бъдат прочетени от други.",
"Got It": "Разбрах",
"Verify this user by confirming the following number appears on their screen.": "Потвърдете този потребител като се уверите, че следното число се вижда на екрана му.",
"We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Изпратихме Ви имейл за да потвърдим адреса Ви. Последвайте инструкциите в имейла и след това кликнете на бутона по-долу.",
"Email Address": "Имейл адрес",
"All keys backed up": "Всички ключове са в резервното копие",
@ -374,19 +315,11 @@
"Profile picture": "Профилна снимка",
"Display Name": "Име",
"Room information": "Информация за стаята",
"Room version": "Версия на стаята",
"Room version:": "Версия на стаята:",
"General": "Общи",
"Room Addresses": "Адреси на стаята",
"Email addresses": "Имейл адреси",
"Phone numbers": "Телефонни номера",
"Language and region": "Език и регион",
"Account management": "Управление на акаунта",
"Roles & Permissions": "Роли и привилегии",
"Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Промени в настройките за четене на историята касаят само за нови съобщения. Видимостта на съществуващата история не се променя.",
"Security & Privacy": "Сигурност и поверителност",
"Encryption": "Шифроване",
"Once enabled, encryption cannot be disabled.": "Веднъж включено, шифроването не може да бъде изключено.",
"Ignored users": "Игнорирани потребители",
"Bulk options": "Масови действия",
"Missing media permissions, click the button below to request.": "Липсва достъп до медийните устройства. Кликнете бутона по-долу за да поискате такъв.",
@ -399,14 +332,11 @@
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Потвърди потребителя и го маркирай като доверен. Доверяването на потребители Ви дава допълнително спокойствие при използване на съобщения шифровани от край-до-край.",
"Incoming Verification Request": "Входяща заявка за потвърждение",
"Email (optional)": "Имейл (незадължително)",
"Phone (optional)": "Телефон (незадължително)",
"Join millions for free on the largest public server": "Присъединете се безплатно към милиони други на най-големия публичен сървър",
"Create account": "Създай акаунт",
"Recovery Method Removed": "Методът за възстановяване беше премахнат",
"If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ако не сте премахнали метода за възстановяване, е възможно нападател да се опитва да получи достъп до акаунта Ви. Променете паролата на акаунта и настройте нов метод за възстановяване веднага от Настройки.",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Файлът '%(fileName)s' надхвърля ограничението за размер на файлове за този сървър",
"Verify this user by confirming the following emoji appear on their screen.": "Потвърдете този потребител, като установите че следното емоджи се вижда на екрана им.",
"Unable to find a supported verification method.": "Не може да бъде намерен поддържан метод за потвърждение.",
"Dog": "Куче",
"Cat": "Котка",
"Lion": "Лъв",
@ -490,13 +420,8 @@
"Could not load user profile": "Неуспешно зареждане на потребителския профил",
"The user must be unbanned before they can be invited.": "Трябва да се махне блокирането на потребителя преди да може да бъде поканен пак.",
"Accept all %(invitedRooms)s invites": "Приеми всички %(invitedRooms)s покани",
"Send %(eventType)s events": "Изпрати %(eventType)s събития",
"Select the roles required to change various parts of the room": "Изберете ролите необходими за промяна на различни части от стаята",
"Enable encryption?": "Включване на шифроване?",
"Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>": "Веднъж включено, шифроването за стаята не може да бъде изключено. Съобщенията изпратени в шифрована стая не могат да бъдат прочетени от сървърът, а само от участниците в стаята. Включването на шифроване може да попречи на много ботове или мостове към други мрежи да работят правилно. <a>Научете повече за шифроването.</a>",
"Power level": "Ниво на достъп",
"The file '%(fileName)s' failed to upload.": "Файлът '%(fileName)s' не можа да бъде качен.",
"Upgrade this room to the recommended room version": "Обнови тази стая до препоръчаната версия на стаята",
"This room is running room version <roomVersion />, which this homeserver has marked as <i>unstable</i>.": "Тази стая използва версия на стая <roomVersion />, която сървърът счита за <i>нестабилна</i>.",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Обновяването на тази стая ще изключи текущата стая и ще създаде обновена стая със същото име.",
"Failed to revoke invite": "Неуспешно оттегляне на поканата",
@ -521,15 +446,10 @@
"Cancel All": "Откажи всички",
"Upload Error": "Грешка при качване",
"Remember my selection for this widget": "Запомни избора ми за това приспособление",
"You have %(count)s unread notifications in a prior version of this room.": {
"other": "Имате %(count)s непрочетени известия в предишна версия на тази стая.",
"one": "Имате %(count)s непрочетено известие в предишна версия на тази стая."
},
"The server does not support the room version specified.": "Сървърът не поддържа указаната версия на стая.",
"No homeserver URL provided": "Не е указан адрес на сървър",
"Unexpected error resolving homeserver configuration": "Неочаквана грешка в намирането на сървърната конфигурация",
"The user's homeserver does not support the version of the room.": "Сървърът на потребителя не поддържа версията на стаята.",
"View older messages in %(roomName)s.": "Виж по-стари съобщения в %(roomName)s.",
"Join the conversation with an account": "Присъедини се към разговор с акаунт",
"Sign Up": "Регистриране",
"Reason: %(reason)s": "Причина: %(reason)s",
@ -555,16 +475,6 @@
"Rotate Left": "Завърти наляво",
"Rotate Right": "Завърти надясно",
"Edit message": "Редактирай съобщението",
"Use an email address to recover your account": "Използвайте имейл адрес за да възстановите акаунта си",
"Enter email address (required on this homeserver)": "Въведете имейл адрес (задължително за този сървър)",
"Doesn't look like a valid email address": "Не изглежда като валиден имейл адрес",
"Enter password": "Въведете парола",
"Password is allowed, but unsafe": "Паролата се приема, но не е безопасна",
"Nice, strong password!": "Хубава, силна парола!",
"Passwords don't match": "Паролите не съвпадат",
"Other users can invite you to rooms using your contact details": "Други потребители могат да Ви канят в стаи посредством данните за контакт",
"Enter phone number (required on this homeserver)": "Въведете телефонен номер (задължително за този сървър)",
"Enter username": "Въведете потребителско име",
"Some characters not allowed": "Някои символи не са позволени",
"Add room": "Добави стая",
"Failed to get autodiscovery configuration from server": "Неуспешно автоматично откриване на конфигурацията за сървъра",
@ -581,7 +491,6 @@
"You can reset your password, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "Може да възстановите паролата си, но някои функции няма да са достъпни докато сървъра за самоличност е офлайн. Ако продължавате да виждате това предупреждение, проверете конфигурацията или се свържете с администратора на сървъра.",
"You can log in, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "Може да влезете в профила си, но някои функции няма да са достъпни докато сървъра за самоличност е офлайн. Ако продължавате да виждате това предупреждение, проверете конфигурацията или се свържете с администратора на сървъра.",
"Unexpected error resolving identity server configuration": "Неочаквана грешка при откриване на конфигурацията на сървъра за самоличност",
"Use lowercase letters, numbers, dashes and underscores only": "Използвайте само малки букви, цифри, тирета и подчерта",
"Upload all": "Качи всички",
"Edited at %(date)s. Click to view edits.": "Редактирано на %(date)s. Кликнете за да видите редакциите.",
"Message edits": "Редакции на съобщение",
@ -595,10 +504,6 @@
"Clear personal data": "Изчисти личните данни",
"Find others by phone or email": "Открийте други по телефон или имейл",
"Be found by phone or email": "Бъдете открит по телефон или имейл",
"Use bots, bridges, widgets and sticker packs": "Използвайте ботове, връзки с други мрежи, приспособления и стикери",
"Terms of Service": "Условия за ползване",
"Service": "Услуга",
"Summary": "Обобщение",
"Call failed due to misconfigured server": "Неуспешен разговор поради неправилно конфигуриран сървър",
"Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.": "Попитайте администратора на сървъра ви (<code>%(homeserverDomain)s</code>) да конфигурира TURN сървър, за да може разговорите да работят надеждно.",
"Checking server": "Проверка на сървъра",
@ -685,17 +590,8 @@
"Message Actions": "Действия със съобщението",
"Show image": "Покажи снимката",
"Cancel search": "Отмени търсенето",
"To continue you need to accept the terms of this service.": "За да продължите, трябва да приемете условията за ползване.",
"Document": "Документ",
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Липсва публичния ключ за catcha в конфигурацията на сървъра. Съобщете това на администратора на сървъра.",
"%(creator)s created and configured the room.": "%(creator)s създаде и настрой стаята.",
"Jump to first unread room.": "Отиди до първата непрочетена стая.",
"Jump to first invite.": "Отиди до първата покана.",
"Command Autocomplete": "Подсказка за команди",
"Emoji Autocomplete": "Подсказка за емоджита",
"Notification Autocomplete": "Подсказка за уведомления",
"Room Autocomplete": "Подсказка за стаи",
"User Autocomplete": "Подсказка за потребители",
"%(name)s (%(userId)s)": "%(name)s (%(userId)s)",
"You verified %(name)s": "Потвърдихте %(name)s",
"You cancelled verifying %(name)s": "Отказахте потвърждаването за %(name)s",
@ -710,39 +606,11 @@
"The integration manager is offline or it cannot reach your homeserver.": "Мениджъра на интеграции е офлайн или не може да се свърже със сървъра ви.",
"Error upgrading room": "Грешка при обновяване на стаята",
"Double check that your server supports the room version chosen and try again.": "Проверете дали сървъра поддържа тази версия на стаята и опитайте пак.",
"Cross-signing public keys:": "Публични ключове за кръстосано-подписване:",
"not found": "не са намерени",
"Cross-signing private keys:": "Private ключове за кръстосано подписване:",
"in secret storage": "в секретно складиране",
"Secret storage public key:": "Публичен ключ за секретно складиране:",
"in account data": "в данни за акаунта",
"not stored": "не е складиран",
"Manage integrations": "Управление на интеграциите",
"Ignored/Blocked": "Игнорирани/блокирани",
"Error adding ignored user/server": "Грешка при добавяне на игнориран потребител/сървър",
"Something went wrong. Please try again or view your console for hints.": "Нещо се обърка. Опитайте пак или вижте конзолата за информация какво не е наред.",
"Error subscribing to list": "Грешка при абониране за списък",
"Error removing ignored user/server": "Грешка при премахване на игнориран потребител/сървър",
"Error unsubscribing from list": "Грешка при отписването от списък",
"Please try again or view your console for hints.": "Опитайте пак или вижте конзолата за информация какво не е наред.",
"None": "Няма нищо",
"Ban list rules - %(roomName)s": "Списък с правила за блокиране - %(roomName)s",
"Server rules": "Сървърни правила",
"User rules": "Потребителски правила",
"You have not ignored anyone.": "Не сте игнорирали никой.",
"You are currently ignoring:": "В момента игнорирате:",
"You are not subscribed to any lists": "Не сте абонирани към списъци",
"View rules": "Виж правилата",
"You are currently subscribed to:": "В момента сте абонирани към:",
"⚠ These settings are meant for advanced users.": "⚠ Тези настройки са за напреднали потребители.",
"Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, <code>@bot:*</code> would ignore all users that have the name 'bot' on any server.": "Добавете тук потребители или сървъри, които искате да игнорирате. Използвайте звездички за да кажете на %(brand)s да търси съвпадения с всеки символ. Например: <code>@bot:*</code> ще игнорира всички потребители с име 'bot' на кой да е сървър.",
"Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "Игнорирането на хора става чрез списъци за блокиране, които съдържат правила кой да бъде блокиран. Абонирането към списък за блокиране означава, че сървърите/потребителите блокирани от този списък ще бъдат скрити от вас.",
"Personal ban list": "Персонален списък за блокиране",
"Server or user ID to ignore": "Сървър или потребителски идентификатор за игнориране",
"eg: @bot:* or example.org": "напр.: @bot:* или example.org",
"Subscribed lists": "Абонирани списъци",
"Subscribing to a ban list will cause you to join it!": "Абонирането към списък ще направи така, че да се присъедините към него!",
"If this isn't what you want, please use a different tool to ignore users.": "Ако това не е каквото искате, използвайте друг инструмент за игнориране на потребители.",
"Unencrypted": "Нешифровано",
"Close preview": "Затвори прегледа",
"<userName/> wants to chat": "<userName/> иска да чати",
@ -779,7 +647,6 @@
"Country Dropdown": "Падащо меню за избор на държава",
"Verification Request": "Заявка за потвърждение",
"Unable to set up secret storage": "Неуспешна настройка на секретно складиране",
"This bridge is managed by <user />.": "Тази връзка с друга мрежа се управлява от <user />.",
"Recent Conversations": "Скорошни разговори",
"Show more": "Покажи повече",
"Direct Messages": "Директни съобщения",
@ -805,23 +672,13 @@
"Ask this user to verify their session, or manually verify it below.": "Поискайте от този потребител да потвърди сесията си, или я потвърдете ръчно по-долу.",
"New login. Was this you?": "Нов вход. Вие ли бяхте това?",
"%(name)s is requesting verification": "%(name)s изпрати запитване за верификация",
"Waiting for %(displayName)s to verify…": "Изчакване на %(displayName)s да потвърди…",
"Cancelling…": "Отказване…",
"Lock": "Заключи",
"Later": "По-късно",
"Other users may not trust it": "Други потребители може да не се доверят",
"This bridge was provisioned by <user />.": "Мостът е настроен от <user />.",
"Your homeserver does not support cross-signing.": "Сървърът ви не поддържа кръстосано-подписване.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Профилът ви има самоличност за кръстосано подписване в секретно складиране, но все още не е доверено от тази сесия.",
"well formed": "коректен",
"unexpected type": "непознат тип",
"in memory": "в паметта",
"Self signing private key:": "Частен ключ за самоподписване:",
"cached locally": "кеширан локално",
"not found locally": "ненамерен локално",
"User signing private key:": "Частен ключ за подписване на потребители:",
"Homeserver feature support:": "Поддържани функции от сървъра:",
"exists": "съществува",
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Потвърждавай индивидуално всяка сесия на потребителите, маркирайки я като доверена и недоверявайки се на кръстосано-подписваните устройства.",
"Securely cache encrypted messages locally for them to appear in search results.": "Кеширай шифровани съобщения локално по сигурен начин за да се появяват в резултати от търсения.",
"%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.": "Липсват задължителни компоненти в %(brand)s, за да могат да бъдат складирани локално и по сигурен начин шифровани съобщения. Ако искате да експериментирате с тази функция, \"компилирайте\" версия на %(brand)s Desktop с <nativeLink>добавени компоненти за търсене</nativeLink>.",
@ -831,8 +688,6 @@
"This backup is trusted because it has been restored on this session": "Това резервно копие е доверено, защото е било възстановено в текущата сесия",
"Your keys are <b>not being backed up from this session</b>.": "На ключовете ви <b>не се прави резервно копие от тази сесия</b>.",
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "За да съобщените за проблем със сигурността свързан с Matrix, прочетете <a>Политиката за споделяне на проблеми със сигурността</a> на Matrix.org.",
"Session ID:": "Сесиен идентификатор:",
"Session key:": "Сесиен ключ:",
"Message search": "Търсене на съобщения",
"This room is bridging messages to the following platforms. <a>Learn more.</a>": "Тази стая препредава съобщения със следните платформи. <a>Научи повече.</a>",
"Bridges": "Мостове",
@ -911,7 +766,6 @@
"Are you sure you want to deactivate your account? This is irreversible.": "Сигурни ли сте, че искате да деактивирате профила си? Това е необратимо.",
"Confirm account deactivation": "Потвърдете деактивирането на профила",
"There was a problem communicating with the server. Please try again.": "Имаше проблем при комуникацията със сървъра. Опитайте пак.",
"Verify session": "Потвърди сесията",
"Session name": "Име на сесията",
"Session key": "Ключ за сесията",
"Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "Верифицирането на този потребител ще маркира сесията им като доверена при вас, както и вашата като доверена при тях.",
@ -942,10 +796,6 @@
"Your homeserver has exceeded one of its resource limits.": "Беше надвишен някой от лимитите на сървъра.",
"Contact your <a>server admin</a>.": "Свържете се със <a>сървърния администратор</a>.",
"Ok": "Добре",
"New version available. <a>Update now.</a>": "Налична е нова версия. <a>Обновете сега.</a>",
"Please verify the room ID or address and try again.": "Проверете идентификатора или адреса на стаята и опитайте пак.",
"Room ID or address of ban list": "Идентификатор или адрес на стая списък за блокиране",
"To link to this room, please add an address.": "За да споделите тази стая, добавете адрес.",
"Error creating address": "Неуспешно създаване на адрес",
"There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "Възникна грешка при създаването на този адрес. Или не е позволен от сървъра или е временен проблем.",
"You don't have permission to delete the address.": "Нямате права да изтриете адреса.",
@ -959,11 +809,8 @@
"%(completed)s of %(total)s keys restored": "%(completed)s от %(total)s ключа са възстановени",
"Keys restored": "Ключовете бяха възстановени",
"Successfully restored %(sessionCount)s keys": "Успешно бяха възстановени %(sessionCount)s ключа",
"Confirm your identity by entering your account password below.": "Потвърдете самоличността си чрез въвеждане на паролата за профила по-долу.",
"Sign in with SSO": "Влезте със SSO",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Администраторът на сървъра е изключил шифроване от край-до-край по подразбиране за лични стаи и за директни съобщения.",
"Switch to light mode": "Смени на светъл режим",
"Switch to dark mode": "Смени на тъмен режим",
"Switch theme": "Смени темата",
"All settings": "Всички настройки",
"Confirm encryption setup": "Потвърждение на настройки за шифроване",
@ -1059,8 +906,6 @@
"The operation could not be completed": "Операцията не можа да бъде завършена",
"Failed to save your profile": "Неуспешно запазване на профила ви",
"%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.": "%(brand)s не може да кешира шифровани съобщения локално по сигурен начин когато работи в уеб браузър. Използвайте <desktopLink>%(brand)s Desktop </desktopLink> за да можете да търсите шифровани съобщения.",
"Master private key:": "Главен частен ключ:",
"not found in storage": "не е намерено в складирането",
"Cross-signing is not set up.": "Кръстосаното-подписване не е настроено.",
"Cross-signing is ready for use.": "Кръстосаното-подписване е готово за използване.",
"Your server isn't responding to some <a>requests</a>.": "Сървърът ви не отговаря на някои <a>заявки</a>.",
@ -1075,10 +920,6 @@
"Enter a Security Phrase": "Въведете фраза за сигурност",
"Generate a Security Key": "Генерирай ключ за сигурност",
"Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Предпазете се от загуба на достъп до шифрованите съобщения и данни като направите резервно копие на ключовете за шифроване върху сървъра.",
"Attach files from chat or just drag and drop them anywhere in a room.": "Прикачете файлове от чата или ги издърпайте и пуснете в стаята.",
"No files visible in this room": "Няма видими файлове в тази стая",
"%(creator)s created this DM.": "%(creator)s създаде този директен чат.",
"You have no visible notifications.": "Нямате видими уведомления.",
"There was a problem communicating with the homeserver, please try again later.": "Възникна проблем при комуникацията със Home сървъра, моля опитайте отново по-късно.",
"This session has detected that your Security Phrase and key for Secure Messages have been removed.": "Тази сесия откри, че вашата фраза за сигурност и ключ за защитени съобщения бяха премахнати.",
"A new Security Phrase and key for Secure Messages have been detected.": "Новa фраза за сигурност и ключ за защитени съобщения бяха открити.",
@ -1335,10 +1176,7 @@
"Afghanistan": "Афганистан",
"United States": "Съединените щати",
"United Kingdom": "Обединеното кралство",
"Manage & explore rooms": "Управление и откриване на стаи",
"Space options": "Опции на пространството",
"Workspace: <networkLink/>": "Работна област: <networkLink/>",
"Channel: <channelLink/>": "Канал: <channelLink/>",
"Add existing room": "Добави съществуваща стая",
"Leave space": "Напусни пространство",
"Invite with email or username": "Покани чрез имейл или потребителско име",
@ -1557,7 +1395,11 @@
"group_widgets": "Приспособления",
"group_rooms": "Стаи",
"group_voip": "Глас и видео",
"group_encryption": "Шифроване"
"group_encryption": "Шифроване",
"bridge_state_creator": "Мостът е настроен от <user />.",
"bridge_state_manager": "Тази връзка с друга мрежа се управлява от <user />.",
"bridge_state_workspace": "Работна област: <networkLink/>",
"bridge_state_channel": "Канал: <channelLink/>"
},
"keyboard": {
"home": "Начална страница",
@ -1603,7 +1445,18 @@
"placeholder_reply_encrypted": "Изпрати шифрован отговор…",
"placeholder_reply": "Изпрати отговор…",
"placeholder_encrypted": "Изпрати шифровано съобщение…",
"placeholder": "Изпрати съобщение…"
"placeholder": "Изпрати съобщение…",
"autocomplete": {
"command_description": "Команди",
"command_a11y": "Подсказка за команди",
"emoji_a11y": "Подсказка за емоджита",
"@room_description": "Извести всички в стаята",
"notification_description": "Известие за стая",
"notification_a11y": "Подсказка за уведомления",
"room_a11y": "Подсказка за стаи",
"user_description": "Потребители",
"user_a11y": "Подсказка за потребители"
}
},
"Bold": "Удебелено",
"Code": "Код",
@ -1727,7 +1580,26 @@
"send_analytics": "Изпращане на статистически данни",
"strict_encryption": "Никога не изпращай шифровани съобщения към непотвърдени сесии от тази сесия",
"enable_message_search": "Включи търсенето на съобщения в шифровани стаи",
"manually_verify_all_sessions": "Ръчно потвърждаване на всички отдалечени сесии"
"manually_verify_all_sessions": "Ръчно потвърждаване на всички отдалечени сесии",
"cross_signing_public_keys": "Публични ключове за кръстосано-подписване:",
"cross_signing_in_memory": "в паметта",
"cross_signing_not_found": "не са намерени",
"cross_signing_private_keys": "Private ключове за кръстосано подписване:",
"cross_signing_in_4s": "в секретно складиране",
"cross_signing_not_in_4s": "не е намерено в складирането",
"cross_signing_master_private_Key": "Главен частен ключ:",
"cross_signing_cached": "кеширан локално",
"cross_signing_not_cached": "ненамерен локално",
"cross_signing_self_signing_private_key": "Частен ключ за самоподписване:",
"cross_signing_user_signing_private_key": "Частен ключ за подписване на потребители:",
"cross_signing_homeserver_support": "Поддържани функции от сървъра:",
"cross_signing_homeserver_support_exists": "съществува",
"export_megolm_keys": "Експортирай E2E ключове",
"import_megolm_keys": "Импортирай E2E ключове",
"cryptography_section": "Криптография",
"session_id": "Сесиен идентификатор:",
"session_key": "Сесиен ключ:",
"encryption_section": "Шифроване"
},
"preferences": {
"room_list_heading": "Списък със стаи",
@ -1736,6 +1608,14 @@
"rm_lifetime": "Живот на маркера за прочитане (мсек)",
"rm_lifetime_offscreen": "Живот на маркера за прочитане извън екрана (мсек)",
"always_show_menu_bar": "Винаги показвай менютата на прозореца"
},
"sessions": {
"session_id": "Идентификатор на сесията",
"verify_session": "Потвърди сесията"
},
"general": {
"account_section": "Акаунт",
"language_section": "Език и регион"
}
},
"devtools": {
@ -1966,7 +1846,9 @@
"lightbox_title": "%(senderDisplayName)s промени аватара на %(roomName)s",
"removed": "%(senderDisplayName)s премахна аватара на стаята.",
"changed_img": "%(senderDisplayName)s промени аватара на стаята на <img/>"
}
},
"creation_summary_dm": "%(creator)s създаде този директен чат.",
"creation_summary_room": "%(creator)s създаде и настрой стаята."
},
"slash_command": {
"spoiler": "Изпраща даденото съобщение като спойлер",
@ -2096,10 +1978,47 @@
"state_default": "Промяна на настройките",
"ban": "Блокиране на потребители",
"redact": "Премахвай съобщения изпратени от други",
"notifications.room": "Уведомяване на всички"
"notifications.room": "Уведомяване на всички",
"no_privileged_users": "Никой няма специфични привилегии в тази стая",
"privileged_users_section": "Потребители с привилегии",
"muted_users_section": "Заглушени потребители",
"banned_users_section": "Блокирани потребители",
"send_event_type": "Изпрати %(eventType)s събития",
"title": "Роли и привилегии",
"permissions_section": "Разрешения",
"permissions_section_description_room": "Изберете ролите необходими за промяна на различни части от стаята"
},
"security": {
"strict_encryption": "Никога не изпращай шифровани съобщения към непотвърдени сесии в тази стая от тази сесия"
"strict_encryption": "Никога не изпращай шифровани съобщения към непотвърдени сесии в тази стая от тази сесия",
"enable_encryption_confirm_title": "Включване на шифроване?",
"enable_encryption_confirm_description": "Веднъж включено, шифроването за стаята не може да бъде изключено. Съобщенията изпратени в шифрована стая не могат да бъдат прочетени от сървърът, а само от участниците в стаята. Включването на шифроване може да попречи на много ботове или мостове към други мрежи да работят правилно. <a>Научете повече за шифроването.</a>",
"public_without_alias_warning": "За да споделите тази стая, добавете адрес.",
"history_visibility": {},
"history_visibility_warning": "Промени в настройките за четене на историята касаят само за нови съобщения. Видимостта на съществуващата история не се променя.",
"history_visibility_legend": "Кой може да чете историята?",
"title": "Сигурност и поверителност",
"encryption_permanent": "Веднъж включено, шифроването не може да бъде изключено.",
"history_visibility_shared": "Само членове (от момента на избиране на тази опция)",
"history_visibility_invited": "Само членове (от момента, в който те са поканени)",
"history_visibility_joined": "Само членове (от момента, в който са се присъединили)",
"history_visibility_world_readable": "Всеки"
},
"general": {
"publish_toggle": "Публично публикуване на тази стая в директорията на %(domain)s?",
"user_url_previews_default_on": "Вие сте <a>включили</a> URL прегледи по подразбиране.",
"user_url_previews_default_off": "Вие сте <a>изключили</a> URL прегледи по подразбиране.",
"default_url_previews_on": "URL прегледи са включени по подразбиране за участниците в тази стая.",
"default_url_previews_off": "URL прегледи са изключени по подразбиране за участниците в тази стая.",
"url_preview_encryption_warning": "В шифровани стаи като тази, по подразбиране URL прегледите са изключени, за да се подсигури че сървърът (където става генерирането на прегледите) не може да събира информация за връзките споделени в стаята.",
"url_preview_explainer": "Когато се сподели URL връзка в съобщение, може да бъде показан URL преглед даващ повече информация за връзката (заглавие, описание и картинка от уебсайта).",
"url_previews_section": "URL прегледи"
},
"advanced": {
"unfederated": "Тази стая не е достъпна за отдалечени Matrix сървъри",
"room_upgrade_button": "Обнови тази стая до препоръчаната версия на стаята",
"room_predecessor": "Виж по-стари съобщения в %(roomName)s.",
"room_version_section": "Версия на стаята",
"room_version": "Версия на стаята:"
}
},
"encryption": {
@ -2112,8 +2031,17 @@
"complete_description": "Успешно потвърдихте този потребител.",
"qr_prompt": "Сканирайте този уникален код",
"sas_prompt": "Сравнете уникални емоджи",
"sas_description": "Сравнете уникални емоджи, ако нямате камера на някое от устройствата"
}
"sas_description": "Сравнете уникални емоджи, ако нямате камера на някое от устройствата",
"explainer": "Защитените съобщения с този потребител са шифровани от край-до-край и не могат да бъдат прочетени от други.",
"complete_action": "Разбрах",
"sas_emoji_caption_user": "Потвърдете този потребител, като установите че следното емоджи се вижда на екрана им.",
"sas_caption_user": "Потвърдете този потребител като се уверите, че следното число се вижда на екрана му.",
"unsupported_method": "Не може да бъде намерен поддържан метод за потвърждение.",
"waiting_other_user": "Изчакване на %(displayName)s да потвърди…",
"cancelling": "Отказване…"
},
"old_version_detected_title": "Бяха открити стари криптографски данни",
"old_version_detected_description": "Засечени са данни от по-стара версия на %(brand)s. Това ще доведе до неправилна работа на криптографията от край до край в по-старата версия. Шифрованите от край до край съобщения, които са били обменени наскоро (при използването на по-стара версия), може да не успеят да бъдат разшифровани в тази версия. Това също може да доведе до неуспех в обмяната на съобщения в тази версия. Ако имате проблеми, излезте и влезте отново в профила си. За да запазите историята на съобщенията, експортирайте и импортирайте отново Вашите ключове."
},
"emoji": {
"category_frequently_used": "Често използвани",
@ -2141,7 +2069,7 @@
"sso": "Single Sign On",
"continue_with_sso": "Продължаване с %(ssoButtons)s",
"sso_or_username_password": "%(ssoButtons)s Или %(usernamePassword)s",
"sign_in_instead": "Вече имате профил? <a>Влезте от тук</a>",
"sign_in_instead_prompt": "Вече имате профил? <a>Влезте от тук</a>",
"account_clash": "Новият ви профил (%(newAccountId)s) е регистриран, но вече сте влезли с друг профил (%(loggedInUserId)s).",
"account_clash_previous_account": "Продължи с предишния профил",
"log_in_new_account": "<a>Влезте</a> в новия си профил.",
@ -2167,7 +2095,42 @@
"sign_in_or_register_description": "Използвайте профила си или създайте нов за да продължите.",
"register_action": "Създай профил",
"incorrect_credentials": "Неправилно потребителско име и/или парола.",
"account_deactivated": "Този акаунт е деактивиран."
"account_deactivated": "Този акаунт е деактивиран.",
"registration_username_validation": "Използвайте само малки букви, цифри, тирета и подчерта",
"phone_label": "Телефон",
"phone_optional_label": "Телефон (незадължително)",
"session_logged_out_title": "Излязохте",
"session_logged_out_description": "Поради мерки за сигурност, тази сесия е прекратена. Моля, влезте отново.",
"change_password_mismatch": "Новите пароли не съвпадат",
"change_password_empty": "Полето с парола не може да е празно",
"set_email_prompt": "Искате ли да зададете имейл адрес?",
"change_password_confirm_label": "Потвърждаване на парола",
"change_password_confirm_invalid": "Паролите не съвпадат",
"change_password_current_label": "Текуща парола",
"change_password_new_label": "Нова парола",
"change_password_action": "Смяна на парола",
"email_field_label": "Имейл",
"email_field_label_invalid": "Не изглежда като валиден имейл адрес",
"uia": {
"password_prompt": "Потвърдете самоличността си чрез въвеждане на паролата за профила по-долу.",
"recaptcha_missing_params": "Липсва публичния ключ за catcha в конфигурацията на сървъра. Съобщете това на администратора на сървъра.",
"terms_invalid": "Моля прегледайте и приемете всички политики на сървъра",
"terms": "Моля, прегледайте и приемете политиките на този сървър:",
"msisdn_token_incorrect": "Неправителен тоукън",
"msisdn": "Текстово съобщение беше изпратено на %(msisdn)s",
"msisdn_token_prompt": "Моля, въведете кода, който то съдържа:",
"fallback_button": "Започни автентикация"
},
"password_field_label": "Въведете парола",
"password_field_strong_label": "Хубава, силна парола!",
"password_field_weak_label": "Паролата се приема, но не е безопасна",
"username_field_required_invalid": "Въведете потребителско име",
"msisdn_field_label": "Телефон",
"identifier_label": "Влизане с",
"reset_password_email_field_description": "Използвайте имейл адрес за да възстановите акаунта си",
"reset_password_email_field_required_invalid": "Въведете имейл адрес (задължително за този сървър)",
"msisdn_field_description": "Други потребители могат да Ви канят в стаи посредством данните за контакт",
"registration_msisdn_field_required_invalid": "Въведете телефонен номер (задължително за този сървър)"
},
"export_chat": {
"messages": "Съобщения"
@ -2258,11 +2221,42 @@
"see_changes_button": "Какво ново?",
"release_notes_toast_title": "Какво ново",
"toast_title": "Обнови %(brand)s",
"toast_description": "Налична е нова версия на %(brand)s"
"toast_description": "Налична е нова версия на %(brand)s",
"error_encountered": "Възникна грешка (%(errorDetail)s).",
"no_update": "Няма нова версия.",
"new_version_available": "Налична е нова версия. <a>Обновете сега.</a>",
"check_action": "Провери за нова версия"
},
"labs_mjolnir": {
"room_name": "Моя списък с блокирания",
"room_topic": "Това е списък с хора/сървъри, които сте блокирали - не напускайте стаята!"
"room_topic": "Това е списък с хора/сървъри, които сте блокирали - не напускайте стаята!",
"ban_reason": "Игнорирани/блокирани",
"error_adding_ignore": "Грешка при добавяне на игнориран потребител/сървър",
"something_went_wrong": "Нещо се обърка. Опитайте пак или вижте конзолата за информация какво не е наред.",
"error_adding_list_title": "Грешка при абониране за списък",
"error_adding_list_description": "Проверете идентификатора или адреса на стаята и опитайте пак.",
"error_removing_ignore": "Грешка при премахване на игнориран потребител/сървър",
"error_removing_list_title": "Грешка при отписването от списък",
"error_removing_list_description": "Опитайте пак или вижте конзолата за информация какво не е наред.",
"rules_title": "Списък с правила за блокиране - %(roomName)s",
"rules_server": "Сървърни правила",
"rules_user": "Потребителски правила",
"personal_empty": "Не сте игнорирали никой.",
"personal_section": "В момента игнорирате:",
"no_lists": "Не сте абонирани към списъци",
"view_rules": "Виж правилата",
"lists": "В момента сте абонирани към:",
"title": "Игнорирани потребители",
"advanced_warning": "⚠ Тези настройки са за напреднали потребители.",
"explainer_1": "Добавете тук потребители или сървъри, които искате да игнорирате. Използвайте звездички за да кажете на %(brand)s да търси съвпадения с всеки символ. Например: <code>@bot:*</code> ще игнорира всички потребители с име 'bot' на кой да е сървър.",
"explainer_2": "Игнорирането на хора става чрез списъци за блокиране, които съдържат правила кой да бъде блокиран. Абонирането към списък за блокиране означава, че сървърите/потребителите блокирани от този списък ще бъдат скрити от вас.",
"personal_heading": "Персонален списък за блокиране",
"personal_new_label": "Сървър или потребителски идентификатор за игнориране",
"personal_new_placeholder": "напр.: @bot:* или example.org",
"lists_heading": "Абонирани списъци",
"lists_description_1": "Абонирането към списък ще направи така, че да се присъедините към него!",
"lists_description_2": "Ако това не е каквото искате, използвайте друг инструмент за игнориране на потребители.",
"lists_new_label": "Идентификатор или адрес на стая списък за блокиране"
},
"create_space": {
"name_required": "Моля, въведете име на пространството",
@ -2271,5 +2265,42 @@
"public_heading": "Вашето публично пространство",
"private_heading": "Вашето лично пространство",
"add_details_prompt": "Добавете някои подробности, за да помогнете на хората да го разпознаят."
},
"user_menu": {
"switch_theme_light": "Смени на светъл режим",
"switch_theme_dark": "Смени на тъмен режим"
},
"notif_panel": {
"empty_description": "Нямате видими уведомления."
},
"room": {
"drop_file_prompt": "Пуснете файла тук, за да се качи",
"unread_notifications_predecessor": {
"other": "Имате %(count)s непрочетени известия в предишна версия на тази стая.",
"one": "Имате %(count)s непрочетено известие в предишна версия на тази стая."
}
},
"file_panel": {
"guest_note": "Трябва да се <a>регистрирате</a>, за да използвате тази функционалност",
"peek_note": "Трябва да се присъедините към стаята, за да видите файловете, които съдържа",
"empty_heading": "Няма видими файлове в тази стая",
"empty_description": "Прикачете файлове от чата или ги издърпайте и пуснете в стаята."
},
"space": {
"context_menu": {
"explore": "Открий стаи",
"manage_and_explore": "Управление и откриване на стаи"
}
},
"terms": {
"integration_manager": "Използвайте ботове, връзки с други мрежи, приспособления и стикери",
"tos": "Условия за ползване",
"intro": "За да продължите, трябва да приемете условията за ползване.",
"column_service": "Услуга",
"column_summary": "Обобщение",
"column_document": "Документ",
"tac_title": "Правила и условия",
"tac_description": "За да продължите да ползвате %(homeserverDomain)s е необходимо да прегледате и да се съгласите с правилата и условията за ползване.",
"tac_button": "Прегледай правилата и условията"
}
}
}

View file

@ -9,5 +9,10 @@
},
"auth": {
"register_action": "Otvori račun"
},
"space": {
"context_menu": {
"explore": "Istražite sobe"
}
}
}

View file

@ -1,5 +1,4 @@
{
"Account": "Compte",
"No Microphones detected": "No s'ha detectat cap micròfon",
"No Webcams detected": "No s'ha detectat cap càmera web",
"Create new room": "Crea una sala nova",
@ -73,19 +72,9 @@
"Not a valid %(brand)s keyfile": "El fitxer no és un fitxer de claus de %(brand)s vàlid",
"Authentication check failed: incorrect password?": "Ha fallat l'autenticació: heu introduït correctament la contrasenya?",
"Incorrect verification code": "El codi de verificació és incorrecte",
"Phone": "Telèfon",
"No display name": "Sense nom visible",
"New passwords don't match": "Les noves contrasenyes no coincideixen",
"Passwords can't be empty": "Les contrasenyes no poden estar buides",
"Export E2E room keys": "Exporta les claus E2E de la sala",
"Do you want to set an email address?": "Voleu establir una adreça de correu electrònic?",
"Current password": "Contrasenya actual",
"New Password": "Nova contrasenya",
"Confirm password": "Confirma la contrasenya",
"Change Password": "Canvia la contrasenya",
"Authentication": "Autenticació",
"Failed to set display name": "No s'ha pogut establir el nom visible",
"Drop file here to upload": "Deixa anar el fitxer aquí per pujar-lo",
"Unban": "Retira l'expulsió",
"This room is not public. You will not be able to rejoin without an invite.": "Aquesta sala no és pública. No podreu tronar a entrar sense invitació.",
"Failed to ban user": "No s'ha pogut expulsar l'usuari",
@ -124,25 +113,9 @@
"%(roomName)s is not accessible at this time.": "La sala %(roomName)s no és accessible en aquest moment.",
"Failed to unban": "No s'ha pogut expulsar",
"Banned by %(displayName)s": "Expulsat per %(displayName)s",
"Privileged Users": "Usuaris amb privilegis",
"No users have specific privileges in this room": "Cap usuari té privilegis específics en aquesta sala",
"Banned users": "Usuaris expulsats",
"This room is not accessible by remote Matrix servers": "Aquesta sala no és accessible per a servidors de Matrix remots",
"Publish this room to the public in %(domain)s's room directory?": "Vols publicar aquesta sala al directori de sales públiques de %(domain)s?",
"Who can read history?": "Qui pot llegir l'historial?",
"Anyone": "Qualsevol",
"Members only (since the point in time of selecting this option)": "Només els membres (a partir del punt en què seleccioneu aquesta opció)",
"Members only (since they were invited)": "Només els membres (a partir del punt en què hi són convidats)",
"Members only (since they joined)": "Només els membres (a partir del punt en què entrin a la sala)",
"Permissions": "Permisos",
"Jump to first unread message.": "Salta al primer missatge no llegit.",
"not specified": "sense especificar",
"This room has no local addresses": "Aquesta sala no té adreces locals",
"You have <a>enabled</a> URL previews by default.": "Heu <a>habilitat</a> les previsualitzacions per defecte dels URL.",
"You have <a>disabled</a> URL previews by default.": "Heu <a>inhabilitat</a> les previsualitzacions per defecte dels URL.",
"URL previews are enabled by default for participants in this room.": "Les previsualitzacions dels URL estan habilitades per defecte per als membres d'aquesta sala.",
"URL previews are disabled by default for participants in this room.": "Les previsualitzacions dels URL estan inhabilitades per defecte per als membres d'aquesta sala.",
"URL Previews": "Previsualitzacions dels URL",
"Error decrypting attachment": "Error desxifrant fitxer adjunt",
"Decrypt %(text)s": "Desxifra %(text)s",
"Download %(text)s": "Baixa %(text)s",
@ -152,11 +125,6 @@
"Copied!": "Copiat!",
"Failed to copy": "No s'ha pogut copiar",
"Add an Integration": "Afegeix una integració",
"Token incorrect": "Token incorrecte",
"A text message has been sent to %(msisdn)s": "S'ha enviat un missatge de text a %(msisdn)s",
"Please enter the code it contains:": "Introdueix el codi que conté:",
"Start authentication": "Inicia l'autenticació",
"Sign in with": "Inicieu sessió amb",
"Email address": "Correu electrònic",
"<a>In reply to</a> <pill>": "<a>En resposta a</a> <pill>",
"Something went wrong!": "Alguna cosa ha anat malament!",
@ -188,16 +156,11 @@
"Unable to verify email address.": "No s'ha pogut verificar el correu electrònic.",
"This will allow you to reset your password and receive notifications.": "Això us permetrà restablir la vostra contrasenya i rebre notificacions.",
"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.": "Si anteriorment heu utilitzat un versió de %(brand)s més recent, la vostra sessió podría ser incompatible amb aquesta versió. Tanqueu aquesta finestra i torneu a la versió més recent.",
"You must <a>register</a> to use this functionality": "Per poder utilitzar aquesta funcionalitat has de <a>registrar-te</a>",
"You must join the room to see its files": "Per poder veure els fitxers de la sala t'hi has d'unir",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Estàs a punt de ser redirigit a una web de tercers per autenticar el teu compte i poder ser utilitzat amb %(integrationsUrl)s. Vols continuar?",
"Reject invitation": "Rebutja la invitació",
"Are you sure you want to reject the invitation?": "Esteu segur que voleu rebutjar la invitació?",
"Failed to reject invitation": "No s'ha pogut rebutjar la invitació",
"Are you sure you want to leave the room '%(roomName)s'?": "Esteu segur que voleu sortir de la sala '%(roomName)s'?",
"For security, this session has been signed out. Please sign in again.": "Per seguretat, aquesta sessió s'ha tancat. Torna a iniciar la sessió.",
"Old cryptography data detected": "S'han detectat dades de criptografia antigues",
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "S'han detectat dades d'una versió antiga del %(brand)s. Això haurà provocat que el xifratge d'extrem a extrem no funcioni correctament a la versió anterior. Els missatges xifrats d'extrem a extrem que s'han intercanviat recentment mentre s'utilitzava la versió anterior no es poden desxifrar en aquesta versió. També pot provocar que els missatges intercanviats amb aquesta versió fallin. Si teniu problemes, sortiu de la sessió i torneu a entrar-hi. Per poder llegir l'historial dels missatges xifrats, exporteu i torneu a importar les vostres claus.",
"Connectivity to the server has been lost.": "S'ha perdut la connectivitat amb el servidor.",
"Sent messages will be stored until your connection has returned.": "Els missatges enviats s'emmagatzemaran fins que la vostra connexió hagi tornat.",
"You seem to be uploading files, are you sure you want to quit?": "Sembla que s'està pujant fitxers, esteu segur que voleu sortir?",
@ -209,18 +172,14 @@
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "S'ha intentat carregar un punt específic dins la línia de temps d'aquesta sala, però no teniu permís per veure el missatge en qüestió.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "S'ha intentat carregar un punt específic de la línia de temps d'aquesta sala, però no s'ha pogut trobar.",
"Failed to load timeline position": "No s'ha pogut carregar aquesta posició de la línia de temps",
"Signed Out": "Sessió tancada",
"Uploading %(filename)s and %(count)s others": {
"other": "Pujant %(filename)s i %(count)s més"
},
"Uploading %(filename)s": "Pujant %(filename)s",
"Import E2E room keys": "Importar claus E2E de sala",
"Cryptography": "Criptografia",
"Session ID": "ID de la sessió",
"Export room keys": "Exporta les claus de la sala",
"Confirm passphrase": "Introduïu una contrasenya",
"Import room keys": "Importa les claus de la sala",
"Email": "Correu electrònic",
"Sunday": "Diumenge",
"Notification targets": "Objectius de les notificacions",
"Today": "Avui",
@ -231,7 +190,6 @@
"Unavailable": "No disponible",
"Source URL": "URL origen",
"Filter results": "Resultats del filtre",
"No update available.": "No hi ha cap actualització disponible.",
"Search…": "Cerca…",
"Tuesday": "Dimarts",
"Preparing to send logs": "Preparant l'enviament de logs",
@ -245,7 +203,6 @@
"Thursday": "Dijous",
"Logs sent": "Logs enviats",
"Yesterday": "Ahir",
"Error encountered (%(errorDetail)s).": "S'ha trobat un error (%(errorDetail)s).",
"Low Priority": "Baixa prioritat",
"Thank you!": "Gràcies!",
"Permission Required": "Es necessita permís",
@ -264,7 +221,6 @@
"Please contact your homeserver administrator.": "Si us plau contacteu amb l'administrador del vostre homeserver.",
"Email addresses": "Adreces de correu electrònic",
"Phone numbers": "Números de telèfon",
"Language and region": "Idioma i regió",
"Phone Number": "Número de telèfon",
"We encountered an error trying to restore your previous session.": "Hem trobat un error en intentar recuperar la teva sessió prèvia.",
"Upload Error": "Error de pujada",
@ -272,7 +228,6 @@
"%(brand)s encountered an error during upload of:": "%(brand)s ha trobat un error durant la pujada de:",
"There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "S'ha produït un error en actualitzar l'adreça principal de la sala. Pot ser que el servidor no ho permeti o que s'hagi produït un error temporal.",
"Error upgrading room": "Error actualitzant sala",
"Error unsubscribing from list": "Error en cancel·lar subscripció de la llista",
"Error changing power level requirement": "Error en canviar requisit del nivell d'autoritat",
"Error changing power level": "Error en canviar nivell d'autoritat",
"Error updating main address": "Error actualitzant adreça principal",
@ -281,9 +236,6 @@
"There was an error removing that address. It may no longer exist or a temporary error occurred.": "S'ha produït un error en eliminar l'adreça. Pot ser que ja no existeixi o que s'hagi produït un error temporal.",
"There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "S'ha produït un error en crear l'adreça. Pot ser que el servidor no ho permeti o que s'hagi produït un error temporal.",
"There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "S'ha produït un error en actualitzar l'adreça alternativa de la sala. Pot ser que el servidor no ho permeti o que s'hagi produït un error temporal.",
"Error removing ignored user/server": "Error eliminant usuari/servidor ignorat",
"Error subscribing to list": "Error subscrivint-se a la llista",
"Error adding ignored user/server": "Error afegint usuari/servidor ignorat",
"Unexpected server error trying to leave the room": "Error de servidor inesperat intentant sortir de la sala",
"Error leaving room": "Error sortint de la sala",
"Unexpected error resolving identity server configuration": "Error inesperat resolent la configuració del servidor d'identitat",
@ -321,7 +273,6 @@
"Confirm by comparing the following with the User Settings in your other session:": "Confirma comparant el següent amb la configuració d'usuari de la teva altra sessió:",
"Room settings": "Configuració de sala",
"Change notification settings": "Canvia la configuració de notificacions",
"⚠ These settings are meant for advanced users.": "⚠ Aquesta configuració està pensada per usuaris avançats.",
"Link this email with your account in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, enllaça aquest correu electrònic amb el teu compte a Configuració.",
"Use an identity server in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, utilitza un servidor d'identitat a Configuració.",
"Share this email in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, comparteix aquest correu electrònic a Configuració.",
@ -470,7 +421,17 @@
"mirror_local_feed": "Remet el flux de vídeo local"
},
"security": {
"send_analytics": "Envia dades d'anàlisi"
"send_analytics": "Envia dades d'anàlisi",
"export_megolm_keys": "Exporta les claus E2E de la sala",
"import_megolm_keys": "Importar claus E2E de sala",
"cryptography_section": "Criptografia"
},
"sessions": {
"session_id": "ID de la sessió"
},
"general": {
"account_section": "Compte",
"language_section": "Idioma i regió"
}
},
"devtools": {
@ -688,7 +649,30 @@
},
"room_settings": {
"permissions": {
"state_default": "Canvia la configuració"
"state_default": "Canvia la configuració",
"no_privileged_users": "Cap usuari té privilegis específics en aquesta sala",
"privileged_users_section": "Usuaris amb privilegis",
"banned_users_section": "Usuaris expulsats",
"permissions_section": "Permisos"
},
"security": {
"history_visibility": {},
"history_visibility_legend": "Qui pot llegir l'historial?",
"history_visibility_shared": "Només els membres (a partir del punt en què seleccioneu aquesta opció)",
"history_visibility_invited": "Només els membres (a partir del punt en què hi són convidats)",
"history_visibility_joined": "Només els membres (a partir del punt en què entrin a la sala)",
"history_visibility_world_readable": "Qualsevol"
},
"general": {
"publish_toggle": "Vols publicar aquesta sala al directori de sales públiques de %(domain)s?",
"user_url_previews_default_on": "Heu <a>habilitat</a> les previsualitzacions per defecte dels URL.",
"user_url_previews_default_off": "Heu <a>inhabilitat</a> les previsualitzacions per defecte dels URL.",
"default_url_previews_on": "Les previsualitzacions dels URL estan habilitades per defecte per als membres d'aquesta sala.",
"default_url_previews_off": "Les previsualitzacions dels URL estan inhabilitades per defecte per als membres d'aquesta sala.",
"url_previews_section": "Previsualitzacions dels URL"
},
"advanced": {
"unfederated": "Aquesta sala no és accessible per a servidors de Matrix remots"
}
},
"auth": {
@ -699,7 +683,26 @@
"sign_in_or_register": "Inicia sessió o Crea un compte",
"sign_in_or_register_description": "Utilitza el teu compte o crea'n un de nou per continuar.",
"register_action": "Crea un compte",
"incorrect_credentials": "Usuari i/o contrasenya incorrectes."
"incorrect_credentials": "Usuari i/o contrasenya incorrectes.",
"phone_label": "Telèfon",
"session_logged_out_title": "Sessió tancada",
"session_logged_out_description": "Per seguretat, aquesta sessió s'ha tancat. Torna a iniciar la sessió.",
"change_password_mismatch": "Les noves contrasenyes no coincideixen",
"change_password_empty": "Les contrasenyes no poden estar buides",
"set_email_prompt": "Voleu establir una adreça de correu electrònic?",
"change_password_confirm_label": "Confirma la contrasenya",
"change_password_current_label": "Contrasenya actual",
"change_password_new_label": "Nova contrasenya",
"change_password_action": "Canvia la contrasenya",
"email_field_label": "Correu electrònic",
"uia": {
"msisdn_token_incorrect": "Token incorrecte",
"msisdn": "S'ha enviat un missatge de text a %(msisdn)s",
"msisdn_token_prompt": "Introdueix el codi que conté:",
"fallback_button": "Inicia l'autenticació"
},
"msisdn_field_label": "Telèfon",
"identifier_label": "Inicieu sessió amb"
},
"export_chat": {
"messages": "Missatges"
@ -743,10 +746,35 @@
},
"update": {
"see_changes_button": "Què hi ha de nou?",
"release_notes_toast_title": "Novetats"
"release_notes_toast_title": "Novetats",
"error_encountered": "S'ha trobat un error (%(errorDetail)s).",
"no_update": "No hi ha cap actualització disponible."
},
"room_list": {
"failed_remove_tag": "No s'ha pogut esborrar l'etiqueta %(tagName)s de la sala",
"failed_add_tag": "No s'ha pogut afegir l'etiqueta %(tagName)s a la sala"
},
"room": {
"drop_file_prompt": "Deixa anar el fitxer aquí per pujar-lo"
},
"file_panel": {
"guest_note": "Per poder utilitzar aquesta funcionalitat has de <a>registrar-te</a>",
"peek_note": "Per poder veure els fitxers de la sala t'hi has d'unir"
},
"space": {
"context_menu": {
"explore": "Explora sales"
}
},
"encryption": {
"old_version_detected_title": "S'han detectat dades de criptografia antigues",
"old_version_detected_description": "S'han detectat dades d'una versió antiga del %(brand)s. Això haurà provocat que el xifratge d'extrem a extrem no funcioni correctament a la versió anterior. Els missatges xifrats d'extrem a extrem que s'han intercanviat recentment mentre s'utilitzava la versió anterior no es poden desxifrar en aquesta versió. També pot provocar que els missatges intercanviats amb aquesta versió fallin. Si teniu problemes, sortiu de la sessió i torneu a entrar-hi. Per poder llegir l'historial dels missatges xifrats, exporteu i torneu a importar les vostres claus."
},
"labs_mjolnir": {
"error_adding_ignore": "Error afegint usuari/servidor ignorat",
"error_adding_list_title": "Error subscrivint-se a la llista",
"error_removing_ignore": "Error eliminant usuari/servidor ignorat",
"error_removing_list_title": "Error en cancel·lar subscripció de la llista",
"advanced_warning": "⚠ Aquesta configuració està pensada per usuaris avançats."
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -14,5 +14,10 @@
},
"auth": {
"register_action": "Creu Cyfrif"
},
"space": {
"context_menu": {
"explore": "Archwilio Ystafelloedd"
}
}
}

View file

@ -6,15 +6,10 @@
"New passwords must match each other.": "Nye adgangskoder skal matche hinanden.",
"A new password must be entered.": "Der skal indtastes en ny adgangskode.",
"Session ID": "Sessions ID",
"Commands": "Kommandoer",
"Warning!": "Advarsel!",
"Account": "Konto",
"Are you sure you want to reject the invitation?": "Er du sikker på du vil afvise invitationen?",
"Banned users": "Bortviste brugere",
"Cryptography": "Kryptografi",
"Deactivate Account": "Deaktiver brugerkonto",
"Default": "Standard",
"Export E2E room keys": "Eksporter E2E rum nøgler",
"Failed to change password. Is your password correct?": "Kunne ikke ændre adgangskoden. Er din adgangskode rigtig?",
"Failed to reject invitation": "Kunne ikke afvise invitationen",
"Failed to unban": "Var ikke i stand til at ophæve forbuddet",
@ -86,7 +81,6 @@
"Unavailable": "Utilgængelig",
"Source URL": "Kilde URL",
"Filter results": "Filtrér resultater",
"No update available.": "Ingen opdatering tilgængelig.",
"Search…": "Søg…",
"Tuesday": "Tirsdag",
"Saturday": "Lørdag",
@ -98,7 +92,6 @@
"You cannot delete this message. (%(code)s)": "Du kan ikke slette denne besked. (%(code)s)",
"Thursday": "Torsdag",
"Yesterday": "I går",
"Error encountered (%(errorDetail)s).": "En fejl er opstået (%(errorDetail)s).",
"Low Priority": "Lav prioritet",
"Wednesday": "Onsdag",
"Thank you!": "Tak!",
@ -173,22 +166,12 @@
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Underskriftsnøglen du supplerede matcher den underskriftsnøgle du modtog fra %(userId)s's session %(deviceId)s. Sessionen er markeret som verificeret.",
"Explore rooms": "Udforsk rum",
"Verification code": "Verifikationskode",
"Once enabled, encryption cannot be disabled.": "Efter aktivering er det ikke muligt at slå kryptering fra.",
"Security & Privacy": "Sikkerhed & Privatliv",
"Who can read history?": "Hvem kan læse historikken?",
"Enable encryption?": "Aktiver kryptering?",
"Permissions": "Tilladelser",
"Headphones": "Hovedtelefoner",
"Show more": "Vis mere",
"Passwords don't match": "Adgangskoderne matcher ikke",
"Confirm password": "Bekræft adgangskode",
"Enter password": "Indtast adgangskode",
"Add a new server": "Tilføj en ny server",
"Change notification settings": "Skift notifikations indstillinger",
"Profile picture": "Profil billede",
"Checking server": "Tjekker server",
"Change Password": "Skift adgangskode",
"Current password": "Nuværende adgangskode",
"Profile": "Profil",
"Local address": "Lokal adresse",
"This room has no local addresses": "Dette rum har ingen lokal adresse",
@ -468,7 +451,6 @@
"Unable to look up phone number": "Kan ikke slå telefonnummer op",
"Your password has been reset.": "Din adgangskode er blevet nulstillet.",
"Your password was successfully changed.": "Din adgangskode blev ændret.",
"New Password": "Ny adgangskode",
"Set a new custom sound": "Sæt en ny brugerdefineret lyd",
"Empty room": "Tomt rum",
"common": {
@ -565,6 +547,16 @@
"custom_theme_success": "Tema tilføjet!",
"timeline_image_size_default": "Standard",
"image_size_default": "Standard"
},
"sessions": {
"session_id": "Sessions ID"
},
"security": {
"export_megolm_keys": "Eksporter E2E rum nøgler",
"cryptography_section": "Kryptografi"
},
"general": {
"account_section": "Konto"
}
},
"devtools": {
@ -724,7 +716,10 @@
"composer": {
"placeholder_reply": "Besvar…",
"placeholder_encrypted": "Send en krypteret besked…",
"placeholder": "Send en besked…"
"placeholder": "Send en besked…",
"autocomplete": {
"command_description": "Kommandoer"
}
},
"voip": {
"call_failed": "Opkald mislykkedes",
@ -757,7 +752,13 @@
"sign_in_or_register": "Log ind eller Opret bruger",
"sign_in_or_register_description": "Brug din konto eller opret en ny for at fortsætte.",
"register_action": "Opret brugerkonto",
"incorrect_credentials": "Forkert brugernavn og/eller adgangskode."
"incorrect_credentials": "Forkert brugernavn og/eller adgangskode.",
"change_password_confirm_label": "Bekræft adgangskode",
"change_password_confirm_invalid": "Adgangskoderne matcher ikke",
"change_password_current_label": "Nuværende adgangskode",
"change_password_new_label": "Ny adgangskode",
"change_password_action": "Skift adgangskode",
"password_field_label": "Indtast adgangskode"
},
"export_chat": {
"messages": "Beskeder"
@ -813,6 +814,25 @@
},
"update": {
"see_changes_button": "Hvad er nyt?",
"release_notes_toast_title": "Hvad er nyt"
"release_notes_toast_title": "Hvad er nyt",
"error_encountered": "En fejl er opstået (%(errorDetail)s).",
"no_update": "Ingen opdatering tilgængelig."
},
"space": {
"context_menu": {
"explore": "Udforsk rum"
}
},
"room_settings": {
"permissions": {
"banned_users_section": "Bortviste brugere",
"permissions_section": "Tilladelser"
},
"security": {
"enable_encryption_confirm_title": "Aktiver kryptering?",
"history_visibility_legend": "Hvem kan læse historikken?",
"title": "Sikkerhed & Privatliv",
"encryption_permanent": "Efter aktivering er det ikke muligt at slå kryptering fra."
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,6 @@
{
"AM": "AM",
"PM": "PM",
"Account": "Account",
"No Microphones detected": "No Microphones detected",
"No Webcams detected": "No Webcams detected",
"No media permissions": "No media permissions",
@ -15,27 +14,18 @@
},
"A new password must be entered.": "A new password must be entered.",
"An error has occurred.": "An error has occurred.",
"Anyone": "Anyone",
"Are you sure?": "Are you sure?",
"Are you sure you want to leave the room '%(roomName)s'?": "Are you sure you want to leave the room '%(roomName)s'?",
"Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?",
"Banned users": "Banned users",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.",
"Change Password": "Change Password",
"Commands": "Commands",
"Confirm password": "Confirm password",
"Cryptography": "Cryptography",
"Current password": "Current password",
"Custom level": "Custom level",
"Deactivate Account": "Deactivate Account",
"Decrypt %(text)s": "Decrypt %(text)s",
"Default": "Default",
"Delete widget": "Delete widget",
"Download %(text)s": "Download %(text)s",
"Email": "Email",
"Email address": "Email address",
"Error decrypting attachment": "Error decrypting attachment",
"Export E2E room keys": "Export E2E room keys",
"Failed to ban user": "Failed to ban user",
"Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?",
"Failed to change power level": "Failed to change power level",
@ -52,14 +42,11 @@
"Favourite": "Favorite",
"Filter room members": "Filter room members",
"Forget room": "Forget room",
"For security, this session has been signed out. Please sign in again.": "For security, this session has been signed out. Please sign in again.",
"Historical": "Historical",
"Import E2E room keys": "Import E2E room keys",
"Incorrect verification code": "Incorrect verification code",
"Invalid Email Address": "Invalid Email Address",
"Invalid file%(extra)s": "Invalid file%(extra)s",
"Invited": "Invited",
"Sign in with": "Sign in with",
"Join Room": "Join Room",
"Jump to first unread message.": "Jump to first unread message.",
"Unignore": "Unignore",
@ -67,25 +54,18 @@
"You are no longer ignoring %(userId)s": "You are no longer ignoring %(userId)s",
"Unignored user": "Unignored user",
"Ignored user": "Ignored user",
"Publish this room to the public in %(domain)s's room directory?": "Publish this room to the public in %(domain)s's room directory?",
"Low priority": "Low priority",
"Missing room_id in request": "Missing room_id in request",
"Missing user_id in request": "Missing user_id in request",
"Moderator": "Moderator",
"New passwords don't match": "New passwords don't match",
"New passwords must match each other.": "New passwords must match each other.",
"not specified": "not specified",
"Notifications": "Notifications",
"<not supported>": "<not supported>",
"No more results": "No more results",
"No users have specific privileges in this room": "No users have specific privileges in this room",
"Operation failed": "Operation failed",
"Passwords can't be empty": "Passwords can't be empty",
"Permissions": "Permissions",
"Phone": "Phone",
"Please check your email and click on the link it contains. Once this is done, click continue.": "Please check your email and click on the link it contains. Once this is done, click continue.",
"Power level must be positive integer.": "Power level must be positive integer.",
"Privileged Users": "Privileged Users",
"Profile": "Profile",
"Reason": "Reason",
"Reject invitation": "Reject invitation",
@ -98,14 +78,12 @@
"Server may be unavailable, overloaded, or search timed out :(": "Server may be unavailable, overloaded, or search timed out :(",
"Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
"Session ID": "Session ID",
"Signed Out": "Signed Out",
"This email address is already in use": "This email address is already in use",
"This email address was not found": "This email address was not found",
"This room has no local addresses": "This room has no local addresses",
"This room is not recognised.": "This room is not recognized.",
"This doesn't appear to be a valid email address": "This doesn't appear to be a valid email address",
"This phone number is already in use": "This phone number is already in use",
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.",
"Unable to add email address": "Unable to add email address",
@ -116,15 +94,11 @@
"unknown error code": "unknown error code",
"Upload avatar": "Upload avatar",
"Upload Failed": "Upload Failed",
"Users": "Users",
"Verification Pending": "Verification Pending",
"Verified key": "Verified key",
"Warning!": "Warning!",
"Who can read history?": "Who can read history?",
"You cannot place a call with yourself.": "You cannot place a call with yourself.",
"You do not have permission to post to this room": "You do not have permission to post to this room",
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
"You need to be able to invite users to do that.": "You need to be able to invite users to do that.",
"You need to be logged in.": "You need to be logged in.",
"You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?",
@ -165,21 +139,16 @@
"This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.",
"This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.",
"The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
"You must join the room to see its files": "You must join the room to see its files",
"Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites",
"Failed to invite": "Failed to invite",
"Confirm Removal": "Confirm Removal",
"Unknown error": "Unknown error",
"Unable to restore session": "Unable to restore session",
"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.": "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.",
"Token incorrect": "Token incorrect",
"Please enter the code it contains:": "Please enter the code it contains:",
"Error decrypting image": "Error decrypting image",
"Error decrypting video": "Error decrypting video",
"Add an Integration": "Add an Integration",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
"URL Previews": "URL Previews",
"Drop file here to upload": "Drop file here to upload",
"Admin Tools": "Admin Tools",
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
"Create new room": "Create new room",
@ -187,26 +156,21 @@
"No display name": "No display name",
"%(roomName)s does not exist.": "%(roomName)s does not exist.",
"%(roomName)s is not accessible at this time.": "%(roomName)s is not accessible at this time.",
"Start authentication": "Start authentication",
"Uploading %(filename)s": "Uploading %(filename)s",
"Uploading %(filename)s and %(count)s others": {
"one": "Uploading %(filename)s and %(count)s other",
"other": "Uploading %(filename)s and %(count)s others"
},
"%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (power %(powerLevelNumber)s)",
"You must <a>register</a> to use this functionality": "You must <a>register</a> to use this functionality",
"(~%(count)s results)": {
"one": "(~%(count)s result)",
"other": "(~%(count)s results)"
},
"New Password": "New Password",
"Something went wrong!": "Something went wrong!",
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
"Not a valid %(brand)s keyfile": "Not a valid %(brand)s keyfile",
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
"Do you want to set an email address?": "Do you want to set an email address?",
"This will allow you to reset your password and receive notifications.": "This will allow you to reset your password and receive notifications.",
"Check for update": "Check for update",
"Unable to create widget.": "Unable to create widget.",
"You are not in this room.": "You are not in this room.",
"You do not have permission to do that in this room.": "You do not have permission to do that in this room.",
@ -218,7 +182,6 @@
"This Room": "This Room",
"Unavailable": "Unavailable",
"Source URL": "Source URL",
"No update available.": "No update available.",
"Tuesday": "Tuesday",
"Search…": "Search…",
"Unnamed room": "Unnamed room",
@ -232,7 +195,6 @@
"You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)",
"Thursday": "Thursday",
"Yesterday": "Yesterday",
"Error encountered (%(errorDetail)s).": "Error encountered (%(errorDetail)s).",
"Low Priority": "Low Priority",
"Permission Required": "Permission Required",
"You do not have permission to start a conference call in this room": "You do not have permission to start a conference call in this room",
@ -379,6 +341,17 @@
"heading": "Customize your appearance",
"timeline_image_size_default": "Default",
"image_size_default": "Default"
},
"sessions": {
"session_id": "Session ID"
},
"security": {
"export_megolm_keys": "Export E2E room keys",
"import_megolm_keys": "Import E2E room keys",
"cryptography_section": "Cryptography"
},
"general": {
"account_section": "Account"
}
},
"timeline": {
@ -511,7 +484,25 @@
"sign_in_or_register": "Sign In or Create Account",
"sign_in_or_register_description": "Use your account or create a new one to continue.",
"register_action": "Create Account",
"incorrect_credentials": "Incorrect username and/or password."
"incorrect_credentials": "Incorrect username and/or password.",
"phone_label": "Phone",
"session_logged_out_title": "Signed Out",
"session_logged_out_description": "For security, this session has been signed out. Please sign in again.",
"change_password_mismatch": "New passwords don't match",
"change_password_empty": "Passwords can't be empty",
"set_email_prompt": "Do you want to set an email address?",
"change_password_confirm_label": "Confirm password",
"change_password_current_label": "Current password",
"change_password_new_label": "New Password",
"change_password_action": "Change Password",
"email_field_label": "Email",
"uia": {
"msisdn_token_incorrect": "Token incorrect",
"msisdn_token_prompt": "Please enter the code it contains:",
"fallback_button": "Start authentication"
},
"msisdn_field_label": "Phone",
"identifier_label": "Sign in with"
},
"export_chat": {
"messages": "Messages"
@ -531,6 +522,48 @@
},
"update": {
"see_changes_button": "What's new?",
"release_notes_toast_title": "What's New"
"release_notes_toast_title": "What's New",
"error_encountered": "Error encountered (%(errorDetail)s).",
"no_update": "No update available.",
"check_action": "Check for update"
},
"composer": {
"autocomplete": {
"command_description": "Commands",
"user_description": "Users"
}
},
"room": {
"drop_file_prompt": "Drop file here to upload"
},
"file_panel": {
"guest_note": "You must <a>register</a> to use this functionality",
"peek_note": "You must join the room to see its files"
},
"space": {
"context_menu": {
"explore": "Explore rooms"
}
},
"room_settings": {
"permissions": {
"no_privileged_users": "No users have specific privileges in this room",
"privileged_users_section": "Privileged Users",
"banned_users_section": "Banned users",
"permissions_section": "Permissions"
},
"security": {
"history_visibility_legend": "Who can read history?",
"history_visibility_world_readable": "Anyone"
},
"general": {
"publish_toggle": "Publish this room to the public in %(domain)s's room directory?",
"user_url_previews_default_on": "You have <a>enabled</a> URL previews by default.",
"user_url_previews_default_off": "You have <a>disabled</a> URL previews by default.",
"url_previews_section": "URL Previews"
},
"advanced": {
"unfederated": "This room is not accessible by remote Matrix servers"
}
}
}

View file

@ -4,8 +4,6 @@
"Failed to verify email address: make sure you clicked the link in the email": "Kontrolo de via retpoŝtadreso malsukcesis: certigu, ke vi klakis la ligilon en la retmesaĝo",
"You cannot place a call with yourself.": "Vi ne povas voki vin mem.",
"Warning!": "Averto!",
"Sign in with": "Saluti per",
"For security, this session has been signed out. Please sign in again.": "Pro sekurecaj kialoj, la salutaĵo adiaŭiĝis. Bonvolu resaluti.",
"Upload Failed": "Alŝuto malsukcesis",
"Sun": "Dim",
"Mon": "Lun",
@ -64,19 +62,9 @@
"Authentication check failed: incorrect password?": "Aŭtentikiga kontrolo malsukcesis: ĉu pro malĝusta pasvorto?",
"Send": "Sendi",
"Incorrect verification code": "Malĝusta kontrola kodo",
"Phone": "Telefono",
"No display name": "Sen vidiga nomo",
"New passwords don't match": "Novaj pasvortoj ne akordas",
"Passwords can't be empty": "Pasvortoj ne povas esti malplenaj",
"Export E2E room keys": "Elporti tutvoje ĉifrajn ŝlosilojn de la ĉambro",
"Do you want to set an email address?": "Ĉu vi volas agordi retpoŝtadreson?",
"Current password": "Nuna pasvorto",
"New Password": "Nova pasvorto",
"Confirm password": "Konfirmu pasvorton",
"Change Password": "Ŝanĝi pasvorton",
"Authentication": "Aŭtentikigo",
"Failed to set display name": "Malsukcesis agordi vidigan nomon",
"Drop file here to upload": "Demetu dosieron tien ĉi por ĝin alŝuti",
"Unban": "Malforbari",
"Failed to ban user": "Malsukcesis forbari uzanton",
"Failed to mute user": "Malsukcesis silentigi uzanton",
@ -116,26 +104,10 @@
"Banned by %(displayName)s": "Forbarita de %(displayName)s",
"unknown error code": "nekonata kodo de eraro",
"Failed to forget room %(errCode)s": "Malsukcesis forgesi ĉambron %(errCode)s",
"Privileged Users": "Privilegiuloj",
"No users have specific privileges in this room": "Neniuj uzantoj havas specialajn privilegiojn en tiu ĉi ĉambro",
"Banned users": "Forbaritaj uzantoj",
"This room is not accessible by remote Matrix servers": "Ĉi tiu ĉambro ne atingeblas por foraj serviloj de Matrix",
"Favourite": "Elstarigi",
"Publish this room to the public in %(domain)s's room directory?": "Ĉu publikigi ĉi tiun ĉambron per la katalogo de ĉambroj de %(domain)s?",
"Who can read history?": "Kiu povas legi la historion?",
"Anyone": "Iu ajn",
"Members only (since the point in time of selecting this option)": "Nur ĉambranoj (ekde ĉi tiu elekto)",
"Members only (since they were invited)": "Nur ĉambranoj (ekde la invito)",
"Members only (since they joined)": "Nur ĉambranoj (ekde la aliĝo)",
"Permissions": "Permesoj",
"Jump to first unread message.": "Salti al unua nelegita mesaĝo.",
"not specified": "nespecifita",
"This room has no local addresses": "Ĉi tiu ĉambro ne havas lokajn adresojn",
"You have <a>enabled</a> URL previews by default.": "Vi <a>ŝaltis</a> implicitajn antaŭrigardojn al retpaĝoj.",
"You have <a>disabled</a> URL previews by default.": "Vi <a>malŝaltis</a> implicitajn antaŭrigardojn al retpaĝoj.",
"URL previews are enabled by default for participants in this room.": "Antaŭrigardoj de URL-oj estas implicite ŝaltitaj por anoj de tiu ĉi ĉambro.",
"URL previews are disabled by default for participants in this room.": "Antaŭrigardoj de URL-oj estas implicite malŝaltitaj por anoj de tiu ĉi ĉambro.",
"URL Previews": "Antaŭrigardoj al retpaĝoj",
"Error decrypting attachment": "Malĉifro de aldonaĵo eraris",
"Decrypt %(text)s": "Malĉifri %(text)s",
"Download %(text)s": "Elŝuti %(text)s",
@ -146,10 +118,6 @@
"Failed to copy": "Malsukcesis kopii",
"Add an Integration": "Aldoni kunigon",
"Failed to change password. Is your password correct?": "Malsukcesis ŝanĝi la pasvorton. Ĉu via pasvorto estas ĝusta?",
"Token incorrect": "Malĝusta peco",
"A text message has been sent to %(msisdn)s": "Tekstmesaĝo sendiĝîs al %(msisdn)s",
"Please enter the code it contains:": "Bonvolu enigi la enhavatan kodon:",
"Start authentication": "Komenci aŭtentikigon",
"Email address": "Retpoŝtadreso",
"Something went wrong!": "Io misokazis!",
"Delete Widget": "Forigi fenestraĵon",
@ -180,15 +148,10 @@
"Unable to add email address": "Ne povas aldoni retpoŝtadreson",
"Unable to verify email address.": "Retpoŝtadreso ne kontroleblas.",
"This will allow you to reset your password and receive notifications.": "Tio ĉi permesos al vi restarigi vian pasvorton kaj ricevi sciigojn.",
"You must <a>register</a> to use this functionality": "Vi devas <a>registriĝî</a> por uzi tiun ĉi funkcion",
"You must join the room to see its files": "Vi devas aliĝi al la ĉambro por vidi tie dosierojn",
"Reject invitation": "Rifuzi inviton",
"Are you sure you want to reject the invitation?": "Ĉu vi certe volas rifuzi la inviton?",
"Failed to reject invitation": "Malsukcesis rifuzi la inviton",
"Are you sure you want to leave the room '%(roomName)s'?": "Ĉu vi certe volas forlasi la ĉambron '%(roomName)s'?",
"Signed Out": "Adiaŭinta",
"Old cryptography data detected": "Malnovaj datumoj de ĉifroteĥnikaro troviĝis",
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Datumoj el malnova versio de %(brand)s troviĝis. Ĉi tio malfunkciigos tutvojan ĉifradon en la malnova versio. Tutvoje ĉifritaj mesaĝoj interŝanĝitaj freŝtempe per la malnova versio eble ne malĉifreblos. Tio povas kaŭzi malsukceson ankaŭ al mesaĝoj interŝanĝitaj kun tiu ĉi versio. Se vin trafos problemoj, adiaŭu kaj resalutu. Por reteni mesaĝan historion, elportu kaj reenportu viajn ŝlosilojn.",
"Connectivity to the server has been lost.": "Konekto al la servilo perdiĝis.",
"Sent messages will be stored until your connection has returned.": "Senditaj mesaĝoj konserviĝos ĝis via konekto refunkcios.",
"You seem to be uploading files, are you sure you want to quit?": "Ŝajne vi alŝutas dosierojn nun; ĉu vi tamen volas foriri?",
@ -207,29 +170,20 @@
"Uploading %(filename)s": "Alŝutante dosieron %(filename)s",
"Unable to remove contact information": "Ne povas forigi kontaktajn informojn",
"<not supported>": "<nesubtenata>",
"Import E2E room keys": "Enporti tutvoje ĉifrajn ĉambrajn ŝlosilojn",
"Cryptography": "Ĉifroteĥnikaro",
"Check for update": "Kontroli ĝisdatigojn",
"Reject all %(invitedRooms)s invites": "Rifuzi ĉiujn %(invitedRooms)s invitojn",
"No media permissions": "Neniuj permesoj pri aŭdvidaĵoj",
"You may need to manually permit %(brand)s to access your microphone/webcam": "Eble vi devos permane permesi al %(brand)s atingon de viaj mikrofono/kamerao",
"No Microphones detected": "Neniu mikrofono troviĝis",
"No Webcams detected": "Neniu kamerao troviĝis",
"Default Device": "Implicita aparato",
"Email": "Retpoŝto",
"Notifications": "Sciigoj",
"Profile": "Profilo",
"Account": "Konto",
"A new password must be entered.": "Vi devas enigi novan pasvorton.",
"New passwords must match each other.": "Novaj pasvortoj devas akordi.",
"Return to login screen": "Reiri al saluta paĝo",
"Please note you are logging into the %(hs)s server, not matrix.org.": "Rimarku ke vi salutas la servilon %(hs)s, ne matrix.org.",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Hejmservilo ne alkonekteblas per HTTP kun HTTPS URL en via adresbreto. Aŭ uzu HTTPS aŭ <a>ŝaltu malsekurajn skriptojn</a>.",
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Ne eblas konekti al hejmservilo bonvolu kontroli vian konekton, certigi ke <a>la SSL-atestilo de via hejmservilo</a> estas fidata, kaj ke neniu foliumila kromprogramo blokas petojn.",
"Commands": "Komandoj",
"Notify the whole room": "Sciigi la tutan ĉambron",
"Room Notification": "Ĉambra sciigo",
"Users": "Uzantoj",
"Session ID": "Identigilo de salutaĵo",
"Passphrases must match": "Pasfrazoj devas akordi",
"Passphrase must not be empty": "Pasfrazoj maldevas esti malplenaj",
@ -253,7 +207,6 @@
"Unavailable": "Nedisponebla",
"Source URL": "Fonta URL",
"Filter results": "Filtri rezultojn",
"No update available.": "Neniuj ĝisdatigoj haveblas.",
"Tuesday": "Mardo",
"Search…": "Serĉi…",
"Saturday": "Sabato",
@ -265,7 +218,6 @@
"All Rooms": "Ĉiuj ĉambroj",
"Thursday": "Ĵaŭdo",
"Yesterday": "Hieraŭ",
"Error encountered (%(errorDetail)s).": "Eraron renkonti (%(errorDetail)s).",
"Low Priority": "Malalta prioritato",
"Thank you!": "Dankon!",
"Logs sent": "Protokolo sendiĝis",
@ -280,12 +232,10 @@
"Unknown server error": "Nekonata servila eraro",
"Please contact your homeserver administrator.": "Bonvolu kontakti la administranton de via hejmservilo.",
"Delete Backup": "Forigi savkopion",
"Language and region": "Lingvo kaj regiono",
"General": "Ĝeneralaj",
"<a>In reply to</a> <pill>": "<a>Responde al</a> <pill>",
"You do not have permission to start a conference call in this room": "Vi ne havas permeson komenci grupvokon en ĉi tiu ĉambro",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "La dosiero '%(fileName)s' superas la grandecan limon de ĉi tiu hejmservilo",
"Got It": "Komprenite",
"Dog": "Hundo",
"Cat": "Kato",
"Lion": "Leono",
@ -352,15 +302,9 @@
"Email addresses": "Retpoŝtadresoj",
"Phone numbers": "Telefonnumeroj",
"Ignored users": "Malatentaj uzantoj",
"Security & Privacy": "Sekureco kaj Privateco",
"Voice & Video": "Voĉo kaj vido",
"Room information": "Informoj pri ĉambro",
"Room version": "Ĉambra versio",
"Room version:": "Ĉambra versio:",
"Room Addresses": "Adresoj de ĉambro",
"Muted Users": "Silentigitaj uzantoj",
"Roles & Permissions": "Roloj kaj Permesoj",
"Enable encryption?": "Ĉu ŝalti ĉifradon?",
"Share Link to User": "Kunhavigi ligilon al uzanto",
"Share room": "Kunhavigi ĉambron",
"Main address": "Ĉefa adreso",
@ -375,7 +319,6 @@
"Share User": "Kunhavigi uzanton",
"Share Room Message": "Kunhavigi ĉambran mesaĝon",
"Email (optional)": "Retpoŝto (malnepra)",
"Phone (optional)": "Telefono (malnepra)",
"Couldn't load page": "Ne povis enlegi paĝon",
"Could not load user profile": "Ne povis enlegi profilon de uzanto",
"Your password has been reset.": "Vi reagordis vian pasvorton.",
@ -390,10 +333,6 @@
"Unrecognised address": "Nerekonita adreso",
"The user must be unbanned before they can be invited.": "Necesas malforbari ĉi tiun uzanton antaŭ ol ĝin inviti.",
"The user's homeserver does not support the version of the room.": "Hejmservilo de ĉi tiu uzanto ne subtenas la version de la ĉambro.",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Sekuraj mesaĝoj kun ĉi tiu uzanto estas tutvoje ĉirfitaj kaj nelegeblaj al ceteruloj.",
"Verify this user by confirming the following emoji appear on their screen.": "Kontrolu ĉi tiun uzanton per konfirmo, ke la jenaj bildsignoj aperis sur ĝia ekrano.",
"Verify this user by confirming the following number appears on their screen.": "Kontrolu ĉu tiun uzanton per konfirmo, ke la jena numero aperis sur ĝia ekrano.",
"Unable to find a supported verification method.": "Ne povas trovi subtenatan metodon de kontrolo.",
"Santa": "Kristnaska viro",
"Thumbs up": "Dikfingro supren",
"Paperclip": "Paperkuntenilo",
@ -409,7 +348,6 @@
"Missing media permissions, click the button below to request.": "Mankas aŭdovidaj permesoj; klaku al la suba butono por peti.",
"Request media permissions": "Peti aŭdovidajn permesojn",
"Audio Output": "Sona eligo",
"View older messages in %(roomName)s.": "Montri pli malnovajn mesaĝojn en %(roomName)s.",
"Account management": "Administrado de kontoj",
"This event could not be displayed": "Ĉi tiu okazo ne povis montriĝi",
"This room is not public. You will not be able to rejoin without an invite.": "Ĉi tiu ĉambro ne estas publika. Vi ne povos re-aliĝi sen invito.",
@ -418,8 +356,6 @@
"Invited by %(sender)s": "Invitita de %(sender)s",
"Error updating main address": "Ĝisdatigo de la ĉefa adreso eraris",
"There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Ĝisdatigo de la ĉefa adreso de la ĉambro eraris. Aŭ la servilo tion ne permesas, aŭ io misfunkciis.",
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.": "En ĉifritaj ĉambroj, kiel ĉi tiu, antaŭrigardoj al URL-oj estas implicite malŝaltitaj por certigi, ke via hejmservilo (kie la antaŭrigardoj estas generataj) ne povas kolekti informojn pri ligiloj en ĉi tiu ĉambro.",
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "Kiam iu metas URL-on en sian mesaĝon, antaŭrigardo al tiu URL povas montriĝi, por doni pliajn informojn pri tiu ligilo, kiel ekzemple la titolon, priskribon, kaj bildon el la retejo.",
"edited": "redaktita",
"Popout widget": "Fenestrigi fenestraĵon",
"Rotate Left": "Turni maldekstren",
@ -479,21 +415,9 @@
"Remember my selection for this widget": "Memoru mian elekton por tiu ĉi fenestraĵo",
"Unable to load backup status": "Ne povas legi staton de savkopio",
"This homeserver would like to make sure you are not a robot.": "Ĉi tiu hejmservilo volas certigi, ke vi ne estas roboto.",
"Please review and accept all of the homeserver's policies": "Bonvolu tralegi kaj akcepti ĉioman politikon de ĉi tiu hejmservilo",
"Please review and accept the policies of this homeserver:": "Bonvolu tralegi kaj akcepti la politikon de ĉi tiu hejmservilo:",
"Use an email address to recover your account": "Uzu retpoŝtadreson por rehavi vian konton",
"Enter email address (required on this homeserver)": "Enigu retpoŝtadreson (ĉi tiu hejmservilo ĝin postulas)",
"Doesn't look like a valid email address": "Tio ne ŝajnas esti valida retpoŝtadreso",
"Enter password": "Enigu pasvorton",
"Password is allowed, but unsafe": "Pasvorto estas permesita, sed nesekura",
"Nice, strong password!": "Bona, forta pasvorto!",
"Join millions for free on the largest public server": "Senpage aliĝu al milionoj sur la plej granda publika servilo",
"This room is used for important messages from the Homeserver, so you cannot leave it.": "Ĉi tiu ĉambro uziĝas por gravaj mesaĝoj de la hejmservilo, kaj tial vi ne povas foriri.",
"Add room": "Aldoni ĉambron",
"You have %(count)s unread notifications in a prior version of this room.": {
"other": "Vi havas %(count)s nelegitajn sciigojn en antaŭa versio de ĉi tiu ĉambro.",
"one": "Vi havas %(count)s nelegitan sciigon en antaŭa versio de ĉi tiu ĉambro."
},
"Cannot reach homeserver": "Ne povas atingi hejmservilon",
"Ensure you have a stable internet connection, or get in touch with the server admin": "Certiĝu ke vi havas stabilan retkonekton, aŭ kontaktu la administranton de la servilo",
"Ask your %(brand)s admin to check <a>your config</a> for incorrect or duplicate entries.": "Petu vian %(brand)s-administranton kontroli <a>vian agordaron</a> je malĝustaj aŭ duoblaj eroj.",
@ -506,7 +430,6 @@
"Unexpected error resolving homeserver configuration": "Neatendita eraro eltrovi hejmservilajn agordojn",
"Unexpected error resolving identity server configuration": "Neatendita eraro eltrovi agordojn de identiga servilo",
"Start using Key Backup": "Ekuzi Savkopiadon de ŝlosiloj",
"Upgrade this room to the recommended room version": "Gradaltigi ĉi tiun ĉambron al rekomendata ĉambra versio",
"Uploaded sound": "Alŝutita sono",
"Sounds": "Sonoj",
"Notification sound": "Sono de sciigo",
@ -525,12 +448,6 @@
"No backup found!": "Neniu savkopio troviĝis!",
"Go to Settings": "Iri al agordoj",
"No Audio Outputs detected": "Neniu soneligo troviĝis",
"Send %(eventType)s events": "Sendi okazojn de tipo « %(eventType)s»",
"Select the roles required to change various parts of the room": "Elektu la rolojn postulatajn por ŝanĝado de diversaj partoj de la ĉambro",
"Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>": "Post ŝalto, ĉifrado de ĉambro ne povas esti malŝaltita. Mesaĝoj senditaj al ĉifrata ĉambro ne estas videblaj por la servilo, nur por la partoprenantoj de la ĉambro. Ŝalto de ĉifrado eble malfunkciigos iujn robotojn kaj pontojn. <a>Eksciu plion pri ĉifrado.</a>",
"Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Ŝanĝoj al legebleco de historio nur efektiviĝos por osaj mesaĝoj de ĉi tiu ĉambro. La videbleco de jama historio ne ŝanĝiĝos.",
"Encryption": "Ĉifrado",
"Once enabled, encryption cannot be disabled.": "Post ŝalto, ne plu eblas malŝalti ĉifradon.",
"The conversation continues here.": "La interparolo daŭras ĉi tie.",
"This room has been replaced and is no longer active.": "Ĉi tiu ĉambro estas anstataŭita, kaj ne plu aktivas.",
"Only room administrators will see this warning": "Nur administrantoj de ĉambro vidos ĉi tiun averton",
@ -557,15 +474,7 @@
"Failed to decrypt %(failedCount)s sessions!": "Malsukcesis malĉifri%(failedCount)s salutaĵojn!",
"<b>Warning</b>: you should only set up key backup from a trusted computer.": "<b>Averto</b>: vi agordu ŝlosilan savkopion nur per fidata komputilo.",
"Resend %(unsentCount)s reaction(s)": "Resendi %(unsentCount)s reago(j)n",
"Passwords don't match": "Pasvortoj ne akordas",
"Other users can invite you to rooms using your contact details": "Aliaj uzantoj povas inviti vin al ĉambroj per viaj kontaktaj detaloj",
"Enter phone number (required on this homeserver)": "Enigu telefonnumeron (bezonata sur ĉi tiu hejmservilo)",
"Use lowercase letters, numbers, dashes and underscores only": "Uzu nur malgrandajn leterojn, numerojn, streketojn kaj substrekojn",
"Enter username": "Enigu uzantonomon",
"Some characters not allowed": "Iuj signoj ne estas permesitaj",
"Terms and Conditions": "Uzokondiĉoj",
"To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Por daŭre uzadi la hejmservilon %(homeserverDomain)s, vi devas tralegi kaj konsenti niajn uzokondiĉojn.",
"Review terms and conditions": "Tralegi uzokondiĉojn",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Vi ne povas sendi mesaĝojn ĝis vi tralegos kaj konsentos <consentLink>niajn uzokondiĉojn</consentLink>.",
"Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.": "Via mesaĝo ne sendiĝis, ĉar tiu ĉi hejmservilo atingis sian monatan limon de aktivaj uzantoj. Bonvolu <a>kontakti vian administranton de servo</a> por plue uzadi la servon.",
"Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.": "Via mesaĝo ne sendiĝis, ĉar tiu ĉi hejmservilo atingis rimedan limon. Bonvolu <a>kontakti vian administranton de servo</a> por plue uzadi la servon.",
@ -595,10 +504,6 @@
"Invalid base_url for m.identity_server": "Nevalida base_url por m.identity_server",
"Find others by phone or email": "Trovu aliajn per telefonnumero aŭ retpoŝtadreso",
"Be found by phone or email": "Troviĝu per telefonnumero aŭ retpoŝtadreso",
"Use bots, bridges, widgets and sticker packs": "Uzu robotojn, pontojn, fenestraĵojn, kaj glumarkarojn",
"Terms of Service": "Uzokondiĉoj",
"Service": "Servo",
"Summary": "Resumo",
"Call failed due to misconfigured server": "Voko malsukcesis pro misagordita servilo",
"Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.": "Bonvolu peti la administranton de via hejmservilo (<code>%(homeserverDomain)s</code>) agordi TURN-servilon, por ke vokoj funkciu dependeble.",
"Use an identity server": "Uzi identigan servilon",
@ -695,26 +600,8 @@
"Hide advanced": "Kaŝi specialajn",
"Show advanced": "Montri specialajn",
"Command Help": "Helpo pri komando",
"To continue you need to accept the terms of this service.": "Por pluigi, vi devas akcepti la uzokondiĉojn de ĉi tiu servo.",
"Document": "Dokumento",
"%(creator)s created and configured the room.": "%(creator)s kreis kaj agordis la ĉambron.",
"Jump to first unread room.": "Salti al unua nelegita ĉambro.",
"Jump to first invite.": "Salti al unua invito.",
"Command Autocomplete": "Memkompletigo de komandoj",
"Emoji Autocomplete": "Memkompletigo de mienetoj",
"Notification Autocomplete": "Memkompletigo de sciigoj",
"Room Autocomplete": "Memkompletigo de ĉambroj",
"User Autocomplete": "Memkompletigo de uzantoj",
"Error subscribing to list": "Eraris abono al listo",
"Error removing ignored user/server": "Eraris forigo de la malatentata uzanto/servilo",
"Error unsubscribing from list": "Eraris malabono de la listo",
"Please try again or view your console for hints.": "Bonvolu reprovi aŭ serĉi helpilojn en via konzolo.",
"You have not ignored anyone.": "Vi neniun malatentis.",
"You are not subscribed to any lists": "Vi neniun liston abonis",
"View rules": "Montri regulojn",
"You are currently subscribed to:": "Vi nun abonas:",
"⚠ These settings are meant for advanced users.": "⚠ Ĉi tiuj agordoj celas spertajn uzantojn.",
"Subscribed lists": "Abonataj listoj",
"Your display name": "Via vidiga nomo",
"Your user ID": "Via identigilo de uzanto",
"Your theme": "Via haŭto",
@ -756,25 +643,14 @@
"Session already verified!": "Salutaĵo jam estas kontrolita!",
"WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "AVERTO: MALSUKCESIS KONTROLO DE ŜLOSILOJ! La subskriba ŝlosilo de %(userId)s kaj session %(deviceId)s estas «%(fprint)s», kiu ne akordas la donitan ŝlosilon «%(fingerprint)s». Tio povus signifi, ke via komunikado estas spionata!",
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "La subskriba ŝlosilo, kiun vi donis, akordas la subskribas ŝlosilon, kinu vi ricevis de la salutaĵo %(deviceId)s de la uzanto %(userId)s. Salutaĵo estis markita kontrolita.",
"Waiting for %(displayName)s to verify…": "Atendas kontrolon de %(displayName)s…",
"Cancelling…": "Nuligante…",
"Show more": "Montri pli",
"Not Trusted": "Nefidata",
"%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) salutis novan salutaĵon ne kontrolante ĝin:",
"Ask this user to verify their session, or manually verify it below.": "Petu, ke ĉi tiu la uzanto kontrolu sian salutaĵon, aŭ kontrolu ĝin permane sube.",
"This bridge was provisioned by <user />.": "Ĉi tiu ponto estas provizita de <user />.",
"This bridge is managed by <user />.": "Ĉi tiu ponto estas administrata de <user />.",
"Your homeserver does not support cross-signing.": "Via hejmservilo ne subtenas delegajn subskribojn.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Via konto havas identecon por delegaj subskriboj en sekreta deponejo, sed ĉi tiu salutaĵo ankoraŭ ne fidas ĝin.",
"Cross-signing public keys:": "Delegaj publikaj ŝlosiloj:",
"in memory": "en memoro",
"not found": "ne trovita",
"Cross-signing private keys:": "Delegaj privataj ŝlosiloj:",
"in secret storage": "en sekreta deponejo",
"Secret storage public key:": "Publika ŝlosilo de sekreta deponejo:",
"in account data": "en datumoj de konto",
"Homeserver feature support:": "Funkciaj kapabloj de hejmservilo:",
"exists": "ekzistas",
"Securely cache encrypted messages locally for them to appear in search results.": "Sekure kaŝmemori ĉifritajn mesaĝojn loke, por aperigi ilin en serĉrezultoj.",
"%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.": "%(brand)s malhavas kelkajn partojn bezonajn por sekura loka kaŝmemorado de ĉirfitaj mesaĝoj. Se vi volas eksperimenti pri ĉi tiu kapablo, kunmetu propran klienton «%(brand)s Dekstop» kun <nativeLink>aldonitaj serĉopartoj</nativeLink>.",
"This session is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.": "Ĉi tiu salutaĵo <b>ne savkopias viajn ŝlosilojn</b>, sed vi jam havas savkopion, el kiu vi povas rehavi datumojn, kaj ilin kreskigi plue.",
@ -785,22 +661,7 @@
"Your keys are <b>not being backed up from this session</b>.": "Viaj ŝlosiloj <b>ne estas savkopiataj el ĉi tiu salutaĵo</b>.",
"Manage integrations": "Administri kunigojn",
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "Por raparto de sekureca problemo rilata al Matrix, bonvolu legi la <a>Eldiran Politikon pri Sekureco</a> de Matrix.org.",
"Ignored/Blocked": "Malatentita/Blokita",
"Error adding ignored user/server": "Eraris aldono de malatentita uzanto/servilo",
"Something went wrong. Please try again or view your console for hints.": "Io eraris. Bonvolu reprovi aŭ serĉi helpilojn en via konzolo.",
"None": "Neniu",
"Ban list rules - %(roomName)s": "Reguloj de listo de forbaroj %(roomName)s",
"Server rules": "Servilaj reguloj",
"User rules": "Uzantulaj reguloj",
"You are currently ignoring:": "Vi nun malatentas:",
"Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "Malatentado de personoj okazas per listoj de forbaroj, kiuj enhavas regulojn pri tio, kiun forbari. Abonado de listo de forbaroj signifas, ke la uzantoj/serviloj blokataj de la listo estos kaŝitaj de vi.",
"Personal ban list": "Persona listo de forbaroj",
"Server or user ID to ignore": "Malatentota servilo aŭ identigilo de uzanto",
"eg: @bot:* or example.org": "ekz: @bot:* aŭ ekzemplo.org",
"Subscribing to a ban list will cause you to join it!": "Abono de listo de forbaroj aligos vin al ĝi!",
"If this isn't what you want, please use a different tool to ignore users.": "Se vi ne volas tion, bonvolu uzi alian ilon por malatenti uzantojn.",
"Session ID:": "Identigilo de salutaĵo:",
"Session key:": "Ŝlosilo de salutaĵo:",
"Message search": "Serĉado de mesaĝoj",
"This room is bridging messages to the following platforms. <a>Learn more.</a>": "Ĉi tiu ĉambro transpontigas mesaĝojn al la jenaj platformoj. <a>Eksciu plion.</a>",
"Bridges": "Pontoj",
@ -849,7 +710,6 @@
"Clear cross-signing keys": "Vakigi delege ĉifrajn ŝlosilojn",
"Clear all data in this session?": "Ĉu vakigi ĉiujn datumojn en ĉi tiu salutaĵo?",
"Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Vakigo de ĉiuj datumoj el ĉi tiu salutaĵo estas porĉiama. Ĉifritaj mesaĝoj perdiĝos, malse iliaj ŝlosiloj savkopiiĝis.",
"Verify session": "Kontroli salutaĵon",
"Session name": "Nomo de salutaĵo",
"Session key": "Ŝlosilo de salutaĵo",
"Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "Kontrolo de tiu ĉi uzanto markos ĝian salutaĵon fidata, kaj ankaŭ markos vian salutaĵon fidata por ĝi.",
@ -867,8 +727,6 @@
"Verification Request": "Kontrolpeto",
"Remove for everyone": "Forigi por ĉiuj",
"Country Dropdown": "Landa falmenuo",
"Confirm your identity by entering your account password below.": "Konfirmu vian identecon per enigo de la pasvorto de via konto sube.",
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Mankas publika ŝlosilo por testo de homeco en hejmservila agordaro. Bonvolu raporti tion al la administranto de via hejmservilo.",
"Enter your account password to confirm the upgrade:": "Enigu pasvorton de via konto por konfirmi la gradaltigon:",
"Restore your key backup to upgrade your encryption": "Rehavu vian savkopion de ŝlosiloj por gradaltigi vian ĉifradon",
"You'll need to authenticate with the server to confirm the upgrade.": "Vi devos aŭtentikigi kun la servilo por konfirmi la gradaltigon.",
@ -892,10 +750,6 @@
"Add a new server": "Aldoni novan servilon",
"Enter the name of a new server you want to explore.": "Enigu la nomon de nova servilo, kiun vi volas esplori.",
"Server name": "Nomo de servilo",
"Self signing private key:": "Memsubskriba privata ŝlosilo:",
"cached locally": "kaŝmemorita loke",
"not found locally": "ne trovita loke",
"User signing private key:": "Uzantosubskriba privata ŝlosilo:",
"a new master key signature": "nova ĉefŝlosila subskribo",
"a new cross-signing key signature": "nova subskribo de delega ŝlosilo",
"a device cross-signing signature": "delega subskribo de aparato",
@ -954,9 +808,6 @@
"Confirm encryption setup": "Konfirmi agordon de ĉifrado",
"Click the button below to confirm setting up encryption.": "Klaku sube la butonon por konfirmi agordon de ĉifrado.",
"IRC display name width": "Larĝo de vidiga nomo de IRC",
"Please verify the room ID or address and try again.": "Bonvolu kontroli identigilon aŭ adreson de la ĉambro kaj reprovi.",
"Room ID or address of ban list": "Ĉambra identigilo aŭ adreso de listo de forbaroj",
"To link to this room, please add an address.": "Por ligi al ĉi tiu ĉambro, bonvolu aldoni adreson.",
"Error creating address": "Eraris kreado de adreso",
"There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "Eraris kreado de tiu adreso. Eble ĝi ne estas permesata de la servilo, aŭ okazis portempa fiasko.",
"You don't have permission to delete the address.": "Vi ne rajtas forigi la adreson.",
@ -971,9 +822,7 @@
"Your homeserver has exceeded one of its resource limits.": "Via hejmservilo atingis iun limon de rimedoj.",
"Contact your <a>server admin</a>.": "Kontaktu <a>administranton de via servilo</a>.",
"Ok": "Bone",
"New version available. <a>Update now.</a>": "Nova versio estas disponebla. <a>Ĝisdatigu nun.</a>",
"%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.": "%(brand)s ne povas sekure kaŝkopii ĉifritajn mesaĝojn loke, funkciante per foliumilo. Uzu <desktopLink>%(brand)s Desktop</desktopLink> por aperigi ĉifritajn mesaĝojn en serĉrezultoj.",
"Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, <code>@bot:*</code> would ignore all users that have the name 'bot' on any server.": "Aldonu uzantojn kaj servilojn, kiujn vi volas malatenti, ĉi tien. Uzu steletojn por ke %(brand)s atendu iujn ajn signojn. Ekzemple, <code>@bot:*</code> malatentigus ĉiujn uzantojn, kiuj havas la nomon «bot» sur ĉiu ajn servilo.",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "La administranto de via servilo malŝaltis implicitan tutvojan ĉifradon en privataj kaj individuaj ĉambroj.",
"The authenticity of this encrypted message can't be guaranteed on this device.": "La aŭtentikeco de ĉi tiu ĉifrita mesaĝo ne povas esti garantiita sur ĉi tiu aparato.",
"No recently visited rooms": "Neniuj freŝdate vizititaj ĉambroj",
@ -986,8 +835,6 @@
"Security Phrase": "Sekureca frazo",
"Security Key": "Sekureca ŝlosilo",
"Use your Security Key to continue.": "Uzu vian sekurecan ŝlosilon por daŭrigi.",
"Switch to light mode": "Ŝalti helan reĝimon",
"Switch to dark mode": "Ŝalti malhelan reĝimon",
"Switch theme": "Ŝalti haŭton",
"All settings": "Ĉiuj agordoj",
"Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Malhelpu perdon de aliro al ĉifritaj mesaĝoj kaj datumoj per savkopiado de ĉifraj ŝlosiloj al via servilo.",
@ -1016,8 +863,6 @@
"A connection error occurred while trying to contact the server.": "Eraris konekto dum provo kontakti la servilon.",
"The server is not configured to indicate what the problem is (CORS).": "La servilo ne estas agordita por indiki la problemon (CORS).",
"Recent changes that have not yet been received": "Freŝaj ŝanĝoj ankoraŭ ne ricevitaj",
"No files visible in this room": "Neniuj dosieroj videblas en ĉi tiu ĉambro",
"Attach files from chat or just drag and drop them anywhere in a room.": "Kunsendu dosierojn per la babilujo, aŭ trenu ilin kien ajn en ĉambro vi volas.",
"Move right": "Movi dekstren",
"Move left": "Movi maldekstren",
"Revoke permissions": "Nuligi permesojn",
@ -1058,8 +903,6 @@
"Backup version:": "Repaŝa versio:",
"The operation could not be completed": "La ago ne povis finiĝi",
"Failed to save your profile": "Malsukcesis konservi vian profilon",
"Master private key:": "Ĉefa privata ŝlosilo:",
"not found in storage": "netrovite en deponejo",
"Cross-signing is not set up.": "Delegaj subskriboj ne estas agorditaj.",
"Cross-signing is ready for use.": "Delegaj subskriboj estas pretaj por uzado.",
"Safeguard against losing access to encrypted messages & data": "Malhelpu perdon de aliro al ĉifritaj mesaĝoj kaj datumoj",
@ -1330,20 +1173,11 @@
"one": "Sekure kaŝmemori ĉifritajn mesaĝojn loke por ke ili aperu inter serĉrezultoj, uzante %(size)s por deponi mesaĝojn el %(rooms)s ĉambroj.",
"other": "Sekure kaŝmemori ĉifritajn mesaĝojn loke por ke ili aperu inter serĉrezultoj, uzante %(size)s por deponi mesaĝojn el %(rooms)s ĉambroj."
},
"Channel: <channelLink/>": "Kanalo: <channelLink/>",
"This session has detected that your Security Phrase and key for Secure Messages have been removed.": "Tiu ĉi salutaĵo trovis, ke viaj Sekureca frazo kaj ŝlosilo por Sekuraj mesaĝoj foriĝis.",
"A new Security Phrase and key for Secure Messages have been detected.": "Novaj Sekureca frazo kaj ŝlosilo por Sekuraj mesaĝoj troviĝis.",
"Confirm your Security Phrase": "Konfirmu vian Sekurecan frazon",
"Great! This Security Phrase looks strong enough.": "Bonege! La Sekureca frazo ŝajnas sufiĉe forta.",
"There was a problem communicating with the homeserver, please try again later.": "Eraris komunikado kun la hejmservilo, bonvolu reprovi poste.",
"You have no visible notifications.": "Vi havas neniujn videblajn sciigojn.",
"Use email to optionally be discoverable by existing contacts.": "Uzu retpoŝtadreson por laŭplaĉe esti trovebla de jamaj kontaktoj.",
"Use email or phone to optionally be discoverable by existing contacts.": "Uzu retpoŝtadreson aŭ telefonnumeron por laŭplaĉe esti trovebla de jamaj kontaktoj.",
"Add an email to be able to reset your password.": "Aldonu retpoŝtadreson por ebligi rehavon de via pasvorto.",
"That phone number doesn't look quite right, please check and try again": "Tiu telefonnumero ne ŝajnas ĝusta, bonvolu kontroli kaj reprovi",
"Enter phone number": "Enigu telefonnumeron",
"Enter email address": "Enigu retpoŝtadreson",
"Something went wrong in confirming your identity. Cancel and try again.": "Io misokazis dum konfirmado de via identeco. Nuligu kaj reprovu.",
"Hold": "Paŭzigi",
"Resume": "Daŭrigi",
"If you've forgotten your Security Key you can <button>set up new recovery options</button>": "Se vi forgesis vian Sekurecan ŝlosilon, vi povas <button>agordi novajn elekteblojn de rehavo</button>",
@ -1368,15 +1202,6 @@
"This widget would like to:": "Ĉi tiu fenestraĵo volas:",
"Approve widget permissions": "Aprobi rajtojn de fenestraĵo",
"Recently visited rooms": "Freŝe vizititiaj ĉambroj",
"This is the start of <roomName/>.": "Jen la komenco de <roomName/>.",
"Add a photo, so people can easily spot your room.": "Aldonu foton, por ke oni facile trovu vian ĉambron.",
"%(displayName)s created this room.": "%(displayName)s kreis ĉi tiun ĉambron.",
"You created this room.": "Vi kreis ĉi tiun ĉambron.",
"<a>Add a topic</a> to help people know what it is about.": "<a>Aldonu temon</a>, por ke oni sciu, pri kio temas.",
"Topic: %(topic)s ": "Temo: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "Temo: %(topic)s (<a>redakti</a>)",
"This is the beginning of your direct message history with <displayName/>.": "Jen la komenco de historio de viaj rektaj mesaĝoj kun <displayName/>.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Nur vi du partoprenas ĉi tiun interparolon, se neniu el vi invitos aliulon.",
"There was an error looking up the phone number": "Eraris trovado de la telefonnumero",
"Unable to look up phone number": "Ne povas trovi telefonnumeron",
"Use app": "Uzu aplikaĵon",
@ -1384,7 +1209,6 @@
"Don't miss a reply": "Ne preterpasu respondon",
"We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.": "Ni petis la foliumilon memori, kiun hejmservilon vi uzas por saluti, sed domaĝe, via foliumilo forgesis. Iru al la saluta paĝo kaj reprovu.",
"We couldn't log you in": "Ni ne povis salutigi vin",
"%(creator)s created this DM.": "%(creator)s kreis ĉi tiun individuan ĉambron.",
"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>.": "Averte, se vi ne aldonos retpoŝtadreson kaj poste forgesos vian pasvorton, vi eble <b>por ĉiam perdos aliron al via konto</b>.",
"Continuing without email": "Daŭrigante sen retpoŝtadreso",
"Transfer": "Transdoni",
@ -1397,17 +1221,11 @@
"Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Security Key.": "Savkopiu viajn čifrajn šlosilojn kune kun la datumoj de via konto, okaze ke vi perdos aliron al viaj salutaĵoj. Viaj ŝlosiloj sekuriĝos per unika Sekureca ŝlosilo.",
"Dial pad": "Ciferplato",
"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.": "Ĉi tiu kutime influas nur traktadon de la ĉambro servil-flanke. Se vi spertas problemojn pri via %(brand)s, bonvolu raporti eraron.",
"Mark as suggested": "Marki rekomendata",
"Mark as not suggested": "Marki nerekomendata",
"Suggested": "Rekomendata",
"This room is suggested as a good one to join": "Ĉi tiu ĉambro estas rekomendata kiel aliĝinda",
"Suggested Rooms": "Rekomendataj ĉambroj",
"Your server does not support showing space hierarchies.": "Via servilo ne subtenas montradon de hierarĥioj de aroj.",
"Private space": "Privata aro",
"Public space": "Publika aro",
"<inviter/> invites you": "<inviter/> invitas vin",
"No results found": "Neniuj rezultoj troviĝis",
"Failed to remove some rooms. Try again later": "Malsukcesis forigi iujn arojn. Reprovu poste",
"%(count)s rooms": {
"one": "%(count)s ĉambro",
"other": "%(count)s ĉambroj"
@ -1446,8 +1264,6 @@
"Click to copy": "Klaku por kopii",
"You can change these anytime.": "Vi povas ŝanĝi ĉi tiujn kiam ajn vi volas.",
"Create a space": "Krei aron",
"Original event source": "Originala fonto de okazo",
"Decrypted event source": "Malĉifrita fonto de okazo",
"You may want to try a different search or check for typos.": "Eble vi provu serĉi alion, aŭ kontroli je mistajpoj.",
"You don't have permission": "Vi ne rajtas",
"Space options": "Agordoj de aro",
@ -1463,10 +1279,7 @@
"one": "Montri 1 anon",
"other": "Montri ĉiujn %(count)s anojn"
},
"Invite to just this room": "Inviti nur al ĉi tiu ĉambro",
"Failed to send": "Malsukcesis sendi",
"Workspace: <networkLink/>": "Laborspaco: <networkLink/>",
"Manage & explore rooms": "Administri kaj esplori ĉambrojn",
"unknown person": "nekonata persono",
"%(deviceId)s from %(ip)s": "%(deviceId)s de %(ip)s",
"Review to ensure your account is safe": "Kontrolu por certigi sekurecon de via konto",
@ -1493,16 +1306,13 @@
"Consult first": "Unue konsulti",
"Message search initialisation failed": "Malsukcesis komenci serĉadon de mesaĝoj",
"Enter your Security Phrase a second time to confirm it.": "Enigu vian Sekurecan frazon duafoje por ĝin konfirmi.",
"Space Autocomplete": "Memaga finfaro de aro",
"Verify your identity to access encrypted messages and prove your identity to others.": "Kontrolu vian identecon por aliri ĉifritajn mesaĝojn kaj pruvi vian identecon al aliuloj.",
"Search names and descriptions": "Serĉi nomojn kaj priskribojn",
"Select a room below first": "Unue elektu ĉambron de sube",
"You can select all or individual messages to retry or delete": "Vi povas elekti ĉiujn aŭ unuopajn mesaĝojn, por reprovi aŭ forigi",
"Sending": "Sendante",
"Retry all": "Reprovi ĉiujn",
"Delete all": "Forigi ĉiujn",
"Some of your messages have not been sent": "Kelkaj viaj mesaĝoj ne sendiĝis",
"Verification requested": "Kontrolpeto",
"You are the only person here. If you leave, no one will be able to join in the future, including you.": "Vi estas la nura persono tie ĉi. Se vi foriros, neniu alia plu povos aliĝi, inkluzive vin mem.",
"Avatar": "Profilbildo",
"If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "Se vi restarigos ĉion, vi rekomencos sen fidataj salutaĵoj, uzantoj, kaj eble ne povos vidi antaŭajn mesaĝojn.",
@ -1548,15 +1358,12 @@
"Hide sidebar": "Kaŝi flankan breton",
"This space has no local addresses": "Ĉi tiu aro ne havas lokajn adresojn",
"Stop recording": "Malŝalti registradon",
"End-to-end encryption isn't enabled": "Tutvoja ĉifrado ne estas ŝaltita",
"Send voice message": "Sendi voĉmesaĝon",
"Show %(count)s other previews": {
"one": "Montri %(count)s alian antaŭrigardon",
"other": "Montri %(count)s aliajn antaŭrigardojn"
},
"Access": "Aliro",
"People with supported clients will be able to join the room without having a registered account.": "Personoj kun subtenataj klientoj povos aliĝi al la ĉambro sen registrita konto.",
"Decide who can join %(roomName)s.": "Decidu, kiu povas aliĝi al %(roomName)s.",
"Space members": "Aranoj",
"Anyone in a space can find and join. You can select multiple spaces.": "Ĉiu en aro povas trovi kaj aliĝi. Vi povas elekti plurajn arojn.",
"Spaces with access": "Aroj kun aliro",
@ -1592,7 +1399,6 @@
"Collapse reply thread": "Maletendi respondan fadenon",
"Show preview": "Antaŭrigardi",
"View source": "Montri fonton",
"Settings - %(spaceName)s": "Agordoj %(spaceName)s",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>Sciu, ke gradaltigo kreos novan version de la ĉambro</b>. Ĉiuj nunaj mesaĝoj restos en ĉi tiu arĥivita ĉambro.",
"Automatically invite members from this room to the new one": "Memage inviti anojn de ĉi tiu ĉambro al la nova",
"Other spaces or rooms you might not know": "Aliaj aroj aŭ ĉambroj, kiujn vi eble ne konas",
@ -1638,7 +1444,6 @@
"The call is in an unknown state!": "La voko estas en nekonata stato!",
"Unknown failure: %(reason)s": "Malsukceso nekonata: %(reason)s",
"No answer": "Sen respondo",
"Enable encryption in settings.": "Ŝaltu ĉifradon per agordoj.",
"An unknown error occurred": "Okazis nekonata eraro",
"Their device couldn't start the camera or microphone": "Ĝia aparato ne povis startigi la filmilon aŭ la mikrofonon",
"Connection failed": "Malsukcesis konekto",
@ -1650,11 +1455,7 @@
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Se vi havas la bezonajn permesojn, malfermu la menuon sur ajna mesaĝo, kaj klaku al <b>Fiksi</b> por meti ĝin ĉi tien.",
"Nothing pinned, yet": "Ankoraŭ nenio fiksita",
"Set addresses for this space so users can find this space through your homeserver (%(localDomain)s)": "Agordu adresojn por ĉi tiu aro, por ke uzantoj trovu ĝin per via hejmservilo (%(localDomain)s)",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.": "Viaj privataj mesaĝoj normale estas ĉifrataj, sed ĉi tiu ĉambro ne estas ĉifrata. Plej ofte tio okazas pro uzo de nesubtenata aparato aŭ metodo, ekzemple retpoŝtaj invitoj.",
"Cross-signing is ready but keys are not backed up.": "Delegaj subskriboj pretas, sed ŝlosiloj ne estas savkopiitaj.",
"To avoid these issues, create a <a>new encrypted room</a> for the conversation you plan to have.": "Por eviti tiujn problemojn, kreu <a>novan ĉifritan ĉambron</a> por la planata interparolo.",
"Are you sure you want to add encryption to this public room?": "Ĉu vi certas, ke vi volas aldoni ĉifradon al ĉi tiu publika ĉambro?",
"Select the roles required to change various parts of the space": "Elekti rolojn bezonatajn por ŝanĝado de diversaj partoj de la aro",
"Anyone in <spaceName/> can find and join. You can select other spaces too.": "Ĉiu en <spaceName/> povas trovi kaj aliĝi. Vi povas elekti ankaŭ aliajn arojn.",
"To join a space you'll need an invite.": "Por aliĝi al aro, vi bezonas inviton.",
"Rooms and spaces": "Ĉambroj kaj aroj",
@ -1667,9 +1468,6 @@
"Some encryption parameters have been changed.": "Ŝanĝiĝis iuj parametroj de ĉifrado.",
"Role in <RoomName/>": "Rolo en <RoomName/>",
"Message didn't send. Click for info.": "Mesaĝo ne sendiĝis. Klaku por akiri informojn.",
"To avoid these issues, create a <a>new public room</a> for the conversation you plan to have.": "Por eviti ĉi tiujn problemojn, kreu <a>novan publikan ĉambron</a> por la dezirata interparolo.",
"<b>It's not recommended to make encrypted rooms public.</b> It will mean anyone can find and join the room, so anyone can read messages. You'll get none of the benefits of encryption. Encrypting messages in a public room will make receiving and sending messages slower.": "<b>Publikigo de ĉifrataj ĉambroj estas malrekomendata.</b> Ĝi implicas, ke ĉiu povos trovi la ĉambron kaj aliĝi al ĝi, kaj ĉiu do povos legi mesaĝojn. Vi havos neniujn avantaĝojn de ĉifrado. Ĉifrado de mesaĝoj en publika ĉambro malrapidigos iliajn ricevadon kaj sendadon.",
"Are you sure you want to make this encrypted room public?": "Ĉu vi certas, ke vi volas publikigi ĉi tiun ĉifratan ĉambron?",
"Unknown failure": "Nekonata malsukceso",
"Failed to update the join rules": "Malsukcesis ĝisdatigi regulojn pri aliĝo",
"Failed to invite users to %(roomName)s": "Malsukcesis inviti uzantojn al %(roomName)s",
@ -1686,14 +1484,6 @@
"Failed to end poll": "Malsukcesis fini balotenketon",
"The poll has ended. Top answer: %(topAnswer)s": "La balotado finiĝis. Plej alta respondo: %(topAnswer)s",
"The poll has ended. No votes were cast.": "La balotenketo finiĝis. Neniuj voĉoj estis ĵetitaj.",
"Results are only revealed when you end the poll": "Rezultoj estas malkaŝitaj nur kiam vi finas la balotenketo",
"What is your poll question or topic?": "Kio estas via balotenketo demando aŭ temo?",
"Poll type": "Balotspeco",
"Sorry, the poll you tried to create was not posted.": "Pardonu, la balotenketo, kiun vi provis krei, ne estis afiŝita.",
"Failed to post poll": "Malsukcesis afiŝi balotenketon",
"Edit poll": "Redaktu balotenketon",
"Create poll": "Krei balotenketon",
"Create Poll": "Krei Balotenketon",
"Results will be visible when the poll is ended": "Rezultoj estos videblaj kiam la balotenketo finiĝos",
"Sorry, you can't edit a poll after votes have been cast.": "Pardonu, vi ne povas redakti balotenketon post voĉdonado.",
"Can't edit poll": "Ne povas redakti balotenketon",
@ -1770,38 +1560,10 @@
"You have unverified sessions": "Vi havas nekontrolitajn salutaĵojn",
"Export chat": "Eksporti babilejon",
"Files": "Dosieroj",
"Other sessions": "Aliaj salutaĵoj",
"Verified sessions": "Kontrolitaj salutaĵoj",
"Renaming sessions": "Renomi salutaĵojn",
"Sessions": "Salutaĵoj",
"Close sidebar": "Fermu la flanka kolumno",
"Sidebar": "Flanka kolumno",
"Sign out of %(count)s sessions": {
"one": "Elsaluti el %(count)s salutaĵo",
"other": "Elsaluti el %(count)s salutaĵoj"
},
"%(count)s sessions selected": {
"one": "%(count)s salutaĵo elektita",
"other": "%(count)s salutaĵoj elektitaj"
},
"No sessions found.": "Neniuj salutaĵoj trovitaj.",
"No inactive sessions found.": "Neniuj neaktivaj salutaĵoj trovitaj.",
"No unverified sessions found.": "Neniuj nekontrolitaj salutaĵoj trovitaj.",
"No verified sessions found.": "Neniuj kontrolitaj salutaĵoj trovitaj.",
"Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore.": "Konsideru elsaluti de malnovaj salutaĵoj (%(inactiveAgeDays)s tagoj aŭ pli malnovaj), kiujn vi ne plu uzas.",
"Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.": "Por plia sekura komunikado, kontrolu viajn salutaĵojn aŭ elsalutu el ili se vi ne plu rekonas ilin.",
"Removing inactive sessions improves security and performance, and makes it easier for you to identify if a new session is suspicious.": "Forigi neaktivajn salutaĵojn plibonigas sekurecon, rendimenton kaj detekton de dubindaj novaj salutaĵoj.",
"Inactive sessions are sessions you have not used in some time, but they continue to receive encryption keys.": "Neaktivaj salutaĵoj estas salutaĵoj, kiujn vi ne uzis dum kelka tempo, sed ili daŭre ricevas ĉifrajn ŝlosilojn.",
"Inactive sessions": "Neaktivaj salutaĵoj",
"Unverified sessions": "Nekontrolitaj salutaĵoj",
"Public rooms": "Publikajn ĉambrojn",
"Show details": "Montri detalojn",
"Hide details": "Kaŝi detalojn",
"Sign out of this session": "Eliri el ĉi tiu salutaĵo",
"Receive push notifications on this session.": "Ricevi puŝajn sciigojn pri ĉi tiu sesio.",
"Push notifications": "Puŝaj sciigoj",
"IP address": "IP-adreso",
"Browser": "Retumilo",
"Add privileged users": "Aldoni rajtigitan uzanton",
"That's fine": "Tio estas bone",
"Developer": "Programisto",
@ -2031,7 +1793,11 @@
"group_encryption": "Ĉifrado",
"group_developer": "Programisto",
"leave_beta": "Ĉesi provadon",
"join_beta": "Aliĝi al provado"
"join_beta": "Aliĝi al provado",
"bridge_state_creator": "Ĉi tiu ponto estas provizita de <user />.",
"bridge_state_manager": "Ĉi tiu ponto estas administrata de <user />.",
"bridge_state_workspace": "Laborspaco: <networkLink/>",
"bridge_state_channel": "Kanalo: <channelLink/>"
},
"keyboard": {
"home": "Hejmo",
@ -2100,7 +1866,19 @@
"placeholder_reply_encrypted": "Sendi ĉifritan respondon…",
"placeholder_reply": "Sendi respondon…",
"placeholder_encrypted": "Sendi ĉifritan mesaĝon…",
"placeholder": "Sendi mesaĝon…"
"placeholder": "Sendi mesaĝon…",
"autocomplete": {
"command_description": "Komandoj",
"command_a11y": "Memkompletigo de komandoj",
"emoji_a11y": "Memkompletigo de mienetoj",
"@room_description": "Sciigi la tutan ĉambron",
"notification_description": "Ĉambra sciigo",
"notification_a11y": "Memkompletigo de sciigoj",
"room_a11y": "Memkompletigo de ĉambroj",
"space_a11y": "Memaga finfaro de aro",
"user_description": "Uzantoj",
"user_a11y": "Memkompletigo de uzantoj"
}
},
"Bold": "Grase",
"Code": "Kodo",
@ -2246,7 +2024,26 @@
"send_analytics": "Sendi statistikajn datumojn",
"strict_encryption": "Neniam sendi ĉifritajn mesaĝojn al nekontrolitaj salutaĵoj de ĉi tiu salutaĵo",
"enable_message_search": "Ŝalti serĉon de mesaĝoj en ĉifritaj ĉambroj",
"manually_verify_all_sessions": "Permane kontroli ĉiujn forajn salutaĵojn"
"manually_verify_all_sessions": "Permane kontroli ĉiujn forajn salutaĵojn",
"cross_signing_public_keys": "Delegaj publikaj ŝlosiloj:",
"cross_signing_in_memory": "en memoro",
"cross_signing_not_found": "ne trovita",
"cross_signing_private_keys": "Delegaj privataj ŝlosiloj:",
"cross_signing_in_4s": "en sekreta deponejo",
"cross_signing_not_in_4s": "netrovite en deponejo",
"cross_signing_master_private_Key": "Ĉefa privata ŝlosilo:",
"cross_signing_cached": "kaŝmemorita loke",
"cross_signing_not_cached": "ne trovita loke",
"cross_signing_self_signing_private_key": "Memsubskriba privata ŝlosilo:",
"cross_signing_user_signing_private_key": "Uzantosubskriba privata ŝlosilo:",
"cross_signing_homeserver_support": "Funkciaj kapabloj de hejmservilo:",
"cross_signing_homeserver_support_exists": "ekzistas",
"export_megolm_keys": "Elporti tutvoje ĉifrajn ŝlosilojn de la ĉambro",
"import_megolm_keys": "Enporti tutvoje ĉifrajn ĉambrajn ŝlosilojn",
"cryptography_section": "Ĉifroteĥnikaro",
"session_id": "Identigilo de salutaĵo:",
"session_key": "Ŝlosilo de salutaĵo:",
"encryption_section": "Ĉifrado"
},
"preferences": {
"room_list_heading": "Ĉambrolisto",
@ -2263,6 +2060,42 @@
},
"keyboard": {
"title": "Klavaro"
},
"sessions": {
"rename_form_learn_more": "Renomi salutaĵojn",
"session_id": "Identigilo de salutaĵo",
"browser": "Retumilo",
"ip": "IP-adreso",
"push_heading": "Puŝaj sciigoj",
"push_subheading": "Ricevi puŝajn sciigojn pri ĉi tiu sesio.",
"sign_out": "Eliri el ĉi tiu salutaĵo",
"hide_details": "Kaŝi detalojn",
"show_details": "Montri detalojn",
"verified_sessions": "Kontrolitaj salutaĵoj",
"unverified_sessions": "Nekontrolitaj salutaĵoj",
"inactive_sessions": "Neaktivaj salutaĵoj",
"inactive_sessions_explainer_1": "Neaktivaj salutaĵoj estas salutaĵoj, kiujn vi ne uzis dum kelka tempo, sed ili daŭre ricevas ĉifrajn ŝlosilojn.",
"inactive_sessions_explainer_2": "Forigi neaktivajn salutaĵojn plibonigas sekurecon, rendimenton kaj detekton de dubindaj novaj salutaĵoj.",
"verify_session": "Kontroli salutaĵon",
"unverified_sessions_list_description": "Por plia sekura komunikado, kontrolu viajn salutaĵojn aŭ elsalutu el ili se vi ne plu rekonas ilin.",
"inactive_sessions_list_description": "Konsideru elsaluti de malnovaj salutaĵoj (%(inactiveAgeDays)s tagoj aŭ pli malnovaj), kiujn vi ne plu uzas.",
"no_verified_sessions": "Neniuj kontrolitaj salutaĵoj trovitaj.",
"no_unverified_sessions": "Neniuj nekontrolitaj salutaĵoj trovitaj.",
"no_inactive_sessions": "Neniuj neaktivaj salutaĵoj trovitaj.",
"no_sessions": "Neniuj salutaĵoj trovitaj.",
"n_sessions_selected": {
"one": "%(count)s salutaĵo elektita",
"other": "%(count)s salutaĵoj elektitaj"
},
"sign_out_n_sessions": {
"one": "Elsaluti el %(count)s salutaĵo",
"other": "Elsaluti el %(count)s salutaĵoj"
},
"other_sessions_heading": "Aliaj salutaĵoj"
},
"general": {
"account_section": "Konto",
"language_section": "Lingvo kaj regiono"
}
},
"devtools": {
@ -2295,7 +2128,9 @@
"category_room": "Ĉambro",
"category_other": "Alia",
"widget_screenshots": "Ŝalti bildojn de fenestraĵoj por subtenataj fenestraĵoj",
"show_hidden_events": "Montri kaŝitajn okazojn en historio"
"show_hidden_events": "Montri kaŝitajn okazojn en historio",
"view_source_decrypted_event_source": "Malĉifrita fonto de okazo",
"original_event_source": "Originala fonto de okazo"
},
"export_chat": {
"html": "HTML",
@ -2611,7 +2446,9 @@
"io.element.voice_broadcast_info": {
"you": "Vi finis <a>voĉan elsendon</a>",
"user": "%(senderName)s finis <a>voĉan elsendon</a>"
}
},
"creation_summary_dm": "%(creator)s kreis ĉi tiun individuan ĉambron.",
"creation_summary_room": "%(creator)s kreis kaj agordis la ĉambron."
},
"slash_command": {
"spoiler": "Sendas la donitan mesaĝon kiel malkaŝon de intrigo",
@ -2784,13 +2621,58 @@
"state_default": "Ŝanĝi agordojn",
"ban": "Forbari uzantojn",
"redact": "Forigi mesaĝojn senditajn de aliaj",
"notifications.room": "Sciigi ĉiujn"
"notifications.room": "Sciigi ĉiujn",
"no_privileged_users": "Neniuj uzantoj havas specialajn privilegiojn en tiu ĉi ĉambro",
"privileged_users_section": "Privilegiuloj",
"muted_users_section": "Silentigitaj uzantoj",
"banned_users_section": "Forbaritaj uzantoj",
"send_event_type": "Sendi okazojn de tipo « %(eventType)s»",
"title": "Roloj kaj Permesoj",
"permissions_section": "Permesoj",
"permissions_section_description_space": "Elekti rolojn bezonatajn por ŝanĝado de diversaj partoj de la aro",
"permissions_section_description_room": "Elektu la rolojn postulatajn por ŝanĝado de diversaj partoj de la ĉambro"
},
"security": {
"strict_encryption": "Neniam sendi ĉifritajn mesaĝojn al nekontrolitaj salutaĵoj en ĉi tiu ĉambro de ĉi tiu salutaĵo",
"join_rule_invite": "Privata (nur invititoj)",
"join_rule_invite_description": "Nur invititoj povas aliĝi.",
"join_rule_public_description": "Ĉiu povas trovi kaj aliĝi."
"join_rule_public_description": "Ĉiu povas trovi kaj aliĝi.",
"enable_encryption_public_room_confirm_title": "Ĉu vi certas, ke vi volas aldoni ĉifradon al ĉi tiu publika ĉambro?",
"enable_encryption_public_room_confirm_description_2": "Por eviti tiujn problemojn, kreu <a>novan ĉifritan ĉambron</a> por la planata interparolo.",
"enable_encryption_confirm_title": "Ĉu ŝalti ĉifradon?",
"enable_encryption_confirm_description": "Post ŝalto, ĉifrado de ĉambro ne povas esti malŝaltita. Mesaĝoj senditaj al ĉifrata ĉambro ne estas videblaj por la servilo, nur por la partoprenantoj de la ĉambro. Ŝalto de ĉifrado eble malfunkciigos iujn robotojn kaj pontojn. <a>Eksciu plion pri ĉifrado.</a>",
"public_without_alias_warning": "Por ligi al ĉi tiu ĉambro, bonvolu aldoni adreson.",
"join_rule_description": "Decidu, kiu povas aliĝi al %(roomName)s.",
"encrypted_room_public_confirm_title": "Ĉu vi certas, ke vi volas publikigi ĉi tiun ĉifratan ĉambron?",
"encrypted_room_public_confirm_description_1": "<b>Publikigo de ĉifrataj ĉambroj estas malrekomendata.</b> Ĝi implicas, ke ĉiu povos trovi la ĉambron kaj aliĝi al ĝi, kaj ĉiu do povos legi mesaĝojn. Vi havos neniujn avantaĝojn de ĉifrado. Ĉifrado de mesaĝoj en publika ĉambro malrapidigos iliajn ricevadon kaj sendadon.",
"encrypted_room_public_confirm_description_2": "Por eviti ĉi tiujn problemojn, kreu <a>novan publikan ĉambron</a> por la dezirata interparolo.",
"history_visibility": {},
"history_visibility_warning": "Ŝanĝoj al legebleco de historio nur efektiviĝos por osaj mesaĝoj de ĉi tiu ĉambro. La videbleco de jama historio ne ŝanĝiĝos.",
"history_visibility_legend": "Kiu povas legi la historion?",
"guest_access_warning": "Personoj kun subtenataj klientoj povos aliĝi al la ĉambro sen registrita konto.",
"title": "Sekureco kaj Privateco",
"encryption_permanent": "Post ŝalto, ne plu eblas malŝalti ĉifradon.",
"history_visibility_shared": "Nur ĉambranoj (ekde ĉi tiu elekto)",
"history_visibility_invited": "Nur ĉambranoj (ekde la invito)",
"history_visibility_joined": "Nur ĉambranoj (ekde la aliĝo)",
"history_visibility_world_readable": "Iu ajn"
},
"general": {
"publish_toggle": "Ĉu publikigi ĉi tiun ĉambron per la katalogo de ĉambroj de %(domain)s?",
"user_url_previews_default_on": "Vi <a>ŝaltis</a> implicitajn antaŭrigardojn al retpaĝoj.",
"user_url_previews_default_off": "Vi <a>malŝaltis</a> implicitajn antaŭrigardojn al retpaĝoj.",
"default_url_previews_on": "Antaŭrigardoj de URL-oj estas implicite ŝaltitaj por anoj de tiu ĉi ĉambro.",
"default_url_previews_off": "Antaŭrigardoj de URL-oj estas implicite malŝaltitaj por anoj de tiu ĉi ĉambro.",
"url_preview_encryption_warning": "En ĉifritaj ĉambroj, kiel ĉi tiu, antaŭrigardoj al URL-oj estas implicite malŝaltitaj por certigi, ke via hejmservilo (kie la antaŭrigardoj estas generataj) ne povas kolekti informojn pri ligiloj en ĉi tiu ĉambro.",
"url_preview_explainer": "Kiam iu metas URL-on en sian mesaĝon, antaŭrigardo al tiu URL povas montriĝi, por doni pliajn informojn pri tiu ligilo, kiel ekzemple la titolon, priskribon, kaj bildon el la retejo.",
"url_previews_section": "Antaŭrigardoj al retpaĝoj"
},
"advanced": {
"unfederated": "Ĉi tiu ĉambro ne atingeblas por foraj serviloj de Matrix",
"room_upgrade_button": "Gradaltigi ĉi tiun ĉambron al rekomendata ĉambra versio",
"room_predecessor": "Montri pli malnovajn mesaĝojn en %(roomName)s.",
"room_version_section": "Ĉambra versio",
"room_version": "Ĉambra versio:"
}
},
"encryption": {
@ -2803,8 +2685,18 @@
"complete_description": "Vi sukcese kontrolis ĉi tiun uzanton.",
"qr_prompt": "Skanu ĉi tiun unikan kodon",
"sas_prompt": "Komparu unikajn bildsignojn",
"sas_description": "Komparu unikan aron de bildsignoj se vi ne havas kameraon sur la alia aparato"
}
"sas_description": "Komparu unikan aron de bildsignoj se vi ne havas kameraon sur la alia aparato",
"explainer": "Sekuraj mesaĝoj kun ĉi tiu uzanto estas tutvoje ĉirfitaj kaj nelegeblaj al ceteruloj.",
"complete_action": "Komprenite",
"sas_emoji_caption_user": "Kontrolu ĉi tiun uzanton per konfirmo, ke la jenaj bildsignoj aperis sur ĝia ekrano.",
"sas_caption_user": "Kontrolu ĉu tiun uzanton per konfirmo, ke la jena numero aperis sur ĝia ekrano.",
"unsupported_method": "Ne povas trovi subtenatan metodon de kontrolo.",
"waiting_other_user": "Atendas kontrolon de %(displayName)s…",
"cancelling": "Nuligante…"
},
"old_version_detected_title": "Malnovaj datumoj de ĉifroteĥnikaro troviĝis",
"old_version_detected_description": "Datumoj el malnova versio de %(brand)s troviĝis. Ĉi tio malfunkciigos tutvojan ĉifradon en la malnova versio. Tutvoje ĉifritaj mesaĝoj interŝanĝitaj freŝtempe per la malnova versio eble ne malĉifreblos. Tio povas kaŭzi malsukceson ankaŭ al mesaĝoj interŝanĝitaj kun tiu ĉi versio. Se vin trafos problemoj, adiaŭu kaj resalutu. Por reteni mesaĝan historion, elportu kaj reenportu viajn ŝlosilojn.",
"verification_requested_toast_title": "Kontrolpeto"
},
"emoji": {
"category_frequently_used": "Ofte uzataj",
@ -2844,11 +2736,13 @@
"reset_password_title": "Restarigu vian pasvorton",
"continue_with_sso": "Daŭrigi per %(ssoButtons)s",
"sso_or_username_password": "%(ssoButtons)s aŭ %(usernamePassword)s",
"sign_in_instead_prompt": "Aliĝu anstataŭe",
"sign_in_instead": "Aliĝu anstataŭe",
"account_clash": "Via nova konto (%(newAccountId)s) estas registrita, sed vi jam salutis per alia konto (%(loggedInUserId)s).",
"account_clash_previous_account": "Daŭrigi per antaŭa konto",
"log_in_new_account": "<a>Saluti</a> per via nova konto.",
"registration_successful": "Registro sukcesis",
"server_picker_title_registration": "Gastigi konton ĉe",
"server_picker_title": "Salutu vian hejmservilon",
"server_picker_dialog_title": "Decidu, kie via konto gastiĝos",
"footer_powered_by_matrix": "funkciigata de Matrix",
@ -2889,7 +2783,49 @@
"server_picker_explainer": "Uzu vian preferatan hejmservilon de Matrix se vi havas iun, aŭ gastigu vian propran.",
"server_picker_learn_more": "Pri hejmserviloj",
"incorrect_credentials": "Malĝusta uzantnomo kaj/aŭ pasvorto.",
"account_deactivated": "Tiu ĉi konto malaktiviĝis."
"account_deactivated": "Tiu ĉi konto malaktiviĝis.",
"registration_username_validation": "Uzu nur malgrandajn leterojn, numerojn, streketojn kaj substrekojn",
"phone_label": "Telefono",
"phone_optional_label": "Telefono (malnepra)",
"email_help_text": "Aldonu retpoŝtadreson por ebligi rehavon de via pasvorto.",
"email_phone_discovery_text": "Uzu retpoŝtadreson aŭ telefonnumeron por laŭplaĉe esti trovebla de jamaj kontaktoj.",
"email_discovery_text": "Uzu retpoŝtadreson por laŭplaĉe esti trovebla de jamaj kontaktoj.",
"session_logged_out_title": "Adiaŭinta",
"session_logged_out_description": "Pro sekurecaj kialoj, la salutaĵo adiaŭiĝis. Bonvolu resaluti.",
"change_password_mismatch": "Novaj pasvortoj ne akordas",
"change_password_empty": "Pasvortoj ne povas esti malplenaj",
"set_email_prompt": "Ĉu vi volas agordi retpoŝtadreson?",
"change_password_confirm_label": "Konfirmu pasvorton",
"change_password_confirm_invalid": "Pasvortoj ne akordas",
"change_password_current_label": "Nuna pasvorto",
"change_password_new_label": "Nova pasvorto",
"change_password_action": "Ŝanĝi pasvorton",
"email_field_label": "Retpoŝto",
"email_field_label_required": "Enigu retpoŝtadreson",
"email_field_label_invalid": "Tio ne ŝajnas esti valida retpoŝtadreso",
"uia": {
"password_prompt": "Konfirmu vian identecon per enigo de la pasvorto de via konto sube.",
"recaptcha_missing_params": "Mankas publika ŝlosilo por testo de homeco en hejmservila agordaro. Bonvolu raporti tion al la administranto de via hejmservilo.",
"terms_invalid": "Bonvolu tralegi kaj akcepti ĉioman politikon de ĉi tiu hejmservilo",
"terms": "Bonvolu tralegi kaj akcepti la politikon de ĉi tiu hejmservilo:",
"msisdn_token_incorrect": "Malĝusta peco",
"msisdn": "Tekstmesaĝo sendiĝîs al %(msisdn)s",
"msisdn_token_prompt": "Bonvolu enigi la enhavatan kodon:",
"sso_failed": "Io misokazis dum konfirmado de via identeco. Nuligu kaj reprovu.",
"fallback_button": "Komenci aŭtentikigon"
},
"password_field_label": "Enigu pasvorton",
"password_field_strong_label": "Bona, forta pasvorto!",
"password_field_weak_label": "Pasvorto estas permesita, sed nesekura",
"username_field_required_invalid": "Enigu uzantonomon",
"msisdn_field_required_invalid": "Enigu telefonnumeron",
"msisdn_field_number_invalid": "Tiu telefonnumero ne ŝajnas ĝusta, bonvolu kontroli kaj reprovi",
"msisdn_field_label": "Telefono",
"identifier_label": "Saluti per",
"reset_password_email_field_description": "Uzu retpoŝtadreson por rehavi vian konton",
"reset_password_email_field_required_invalid": "Enigu retpoŝtadreson (ĉi tiu hejmservilo ĝin postulas)",
"msisdn_field_description": "Aliaj uzantoj povas inviti vin al ĉambroj per viaj kontaktaj detaloj",
"registration_msisdn_field_required_invalid": "Enigu telefonnumeron (bezonata sur ĉi tiu hejmservilo)"
},
"room_list": {
"sort_unread_first": "Montri ĉambrojn kun nelegitaj mesaĝoj kiel unuajn",
@ -3082,13 +3018,28 @@
"see_changes_button": "Kio novas?",
"release_notes_toast_title": "Kio novas",
"toast_title": "Ĝisdatigi %(brand)s",
"toast_description": "Nova versio de %(brand)s disponeblas"
"toast_description": "Nova versio de %(brand)s disponeblas",
"error_encountered": "Eraron renkonti (%(errorDetail)s).",
"no_update": "Neniuj ĝisdatigoj haveblas.",
"new_version_available": "Nova versio estas disponebla. <a>Ĝisdatigu nun.</a>",
"check_action": "Kontroli ĝisdatigojn"
},
"theme": {
"light_high_contrast": "Malpeza alta kontrasto"
},
"space": {
"landing_welcome": "Bonvenu al <name/>"
"landing_welcome": "Bonvenu al <name/>",
"suggested_tooltip": "Ĉi tiu ĉambro estas rekomendata kiel aliĝinda",
"suggested": "Rekomendata",
"select_room_below": "Unue elektu ĉambron de sube",
"unmark_suggested": "Marki nerekomendata",
"mark_suggested": "Marki rekomendata",
"failed_remove_rooms": "Malsukcesis forigi iujn arojn. Reprovu poste",
"incompatible_server_hierarchy": "Via servilo ne subtenas montradon de hierarĥioj de aroj.",
"context_menu": {
"explore": "Esplori ĉambrojn",
"manage_and_explore": "Administri kaj esplori ĉambrojn"
}
},
"location_sharing": {
"MapStyleUrlNotConfigured": "Ĉi tiu hejmservilo ne estas agordita por montri mapojn.",
@ -3103,7 +3054,34 @@
},
"labs_mjolnir": {
"room_name": "Mia listo de forbaroj",
"room_topic": "Ĉi tio estas la listo de uzantoj/serviloj, kiujn vi blokis ne eliru el la ĉambro!"
"room_topic": "Ĉi tio estas la listo de uzantoj/serviloj, kiujn vi blokis ne eliru el la ĉambro!",
"ban_reason": "Malatentita/Blokita",
"error_adding_ignore": "Eraris aldono de malatentita uzanto/servilo",
"something_went_wrong": "Io eraris. Bonvolu reprovi aŭ serĉi helpilojn en via konzolo.",
"error_adding_list_title": "Eraris abono al listo",
"error_adding_list_description": "Bonvolu kontroli identigilon aŭ adreson de la ĉambro kaj reprovi.",
"error_removing_ignore": "Eraris forigo de la malatentata uzanto/servilo",
"error_removing_list_title": "Eraris malabono de la listo",
"error_removing_list_description": "Bonvolu reprovi aŭ serĉi helpilojn en via konzolo.",
"rules_title": "Reguloj de listo de forbaroj %(roomName)s",
"rules_server": "Servilaj reguloj",
"rules_user": "Uzantulaj reguloj",
"personal_empty": "Vi neniun malatentis.",
"personal_section": "Vi nun malatentas:",
"no_lists": "Vi neniun liston abonis",
"view_rules": "Montri regulojn",
"lists": "Vi nun abonas:",
"title": "Malatentaj uzantoj",
"advanced_warning": "⚠ Ĉi tiuj agordoj celas spertajn uzantojn.",
"explainer_1": "Aldonu uzantojn kaj servilojn, kiujn vi volas malatenti, ĉi tien. Uzu steletojn por ke %(brand)s atendu iujn ajn signojn. Ekzemple, <code>@bot:*</code> malatentigus ĉiujn uzantojn, kiuj havas la nomon «bot» sur ĉiu ajn servilo.",
"explainer_2": "Malatentado de personoj okazas per listoj de forbaroj, kiuj enhavas regulojn pri tio, kiun forbari. Abonado de listo de forbaroj signifas, ke la uzantoj/serviloj blokataj de la listo estos kaŝitaj de vi.",
"personal_heading": "Persona listo de forbaroj",
"personal_new_label": "Malatentota servilo aŭ identigilo de uzanto",
"personal_new_placeholder": "ekz: @bot:* aŭ ekzemplo.org",
"lists_heading": "Abonataj listoj",
"lists_description_1": "Abono de listo de forbaroj aligos vin al ĝi!",
"lists_description_2": "Se vi ne volas tion, bonvolu uzi alian ilon por malatenti uzantojn.",
"lists_new_label": "Ĉambra identigilo aŭ adreso de listo de forbaroj"
},
"create_space": {
"name_required": "Bonvolu enigi nomon por la aro",
@ -3134,5 +3112,64 @@
"setup_rooms_community_heading": "Pri kio volus vi diskuti en %(spaceName)s?",
"setup_rooms_community_description": "Kreu ni ĉambron por ĉiu el ili.",
"setup_rooms_description": "Vi povas aldoni pliajn poste, inkluzive tiujn, kiuj jam ekzistas."
},
"user_menu": {
"switch_theme_light": "Ŝalti helan reĝimon",
"switch_theme_dark": "Ŝalti malhelan reĝimon"
},
"notif_panel": {
"empty_description": "Vi havas neniujn videblajn sciigojn."
},
"room": {
"drop_file_prompt": "Demetu dosieron tien ĉi por ĝin alŝuti",
"intro": {
"start_of_dm_history": "Jen la komenco de historio de viaj rektaj mesaĝoj kun <displayName/>.",
"dm_caption": "Nur vi du partoprenas ĉi tiun interparolon, se neniu el vi invitos aliulon.",
"topic_edit": "Temo: %(topic)s (<a>redakti</a>)",
"topic": "Temo: %(topic)s ",
"no_topic": "<a>Aldonu temon</a>, por ke oni sciu, pri kio temas.",
"you_created": "Vi kreis ĉi tiun ĉambron.",
"user_created": "%(displayName)s kreis ĉi tiun ĉambron.",
"room_invite": "Inviti nur al ĉi tiu ĉambro",
"no_avatar_label": "Aldonu foton, por ke oni facile trovu vian ĉambron.",
"start_of_room": "Jen la komenco de <roomName/>.",
"private_unencrypted_warning": "Viaj privataj mesaĝoj normale estas ĉifrataj, sed ĉi tiu ĉambro ne estas ĉifrata. Plej ofte tio okazas pro uzo de nesubtenata aparato aŭ metodo, ekzemple retpoŝtaj invitoj.",
"enable_encryption_prompt": "Ŝaltu ĉifradon per agordoj.",
"unencrypted_warning": "Tutvoja ĉifrado ne estas ŝaltita"
},
"unread_notifications_predecessor": {
"other": "Vi havas %(count)s nelegitajn sciigojn en antaŭa versio de ĉi tiu ĉambro.",
"one": "Vi havas %(count)s nelegitan sciigon en antaŭa versio de ĉi tiu ĉambro."
}
},
"file_panel": {
"guest_note": "Vi devas <a>registriĝî</a> por uzi tiun ĉi funkcion",
"peek_note": "Vi devas aliĝi al la ĉambro por vidi tie dosierojn",
"empty_heading": "Neniuj dosieroj videblas en ĉi tiu ĉambro",
"empty_description": "Kunsendu dosierojn per la babilujo, aŭ trenu ilin kien ajn en ĉambro vi volas."
},
"terms": {
"integration_manager": "Uzu robotojn, pontojn, fenestraĵojn, kaj glumarkarojn",
"tos": "Uzokondiĉoj",
"intro": "Por pluigi, vi devas akcepti la uzokondiĉojn de ĉi tiu servo.",
"column_service": "Servo",
"column_summary": "Resumo",
"column_document": "Dokumento",
"tac_title": "Uzokondiĉoj",
"tac_description": "Por daŭre uzadi la hejmservilon %(homeserverDomain)s, vi devas tralegi kaj konsenti niajn uzokondiĉojn.",
"tac_button": "Tralegi uzokondiĉojn"
},
"space_settings": {
"title": "Agordoj %(spaceName)s"
},
"poll": {
"create_poll_title": "Krei balotenketon",
"create_poll_action": "Krei Balotenketon",
"edit_poll_title": "Redaktu balotenketon",
"failed_send_poll_title": "Malsukcesis afiŝi balotenketon",
"failed_send_poll_description": "Pardonu, la balotenketo, kiun vi provis krei, ne estis afiŝita.",
"type_heading": "Balotspeco",
"topic_heading": "Kio estas via balotenketo demando aŭ temo?",
"notes": "Rezultoj estas malkaŝitaj nur kiam vi finas la balotenketo"
}
}
}

File diff suppressed because it is too large Load diff

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