diff --git a/.eslintrc.js b/.eslintrc.js index 4959b133a0..9ae51f9bc5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,24 @@ module.exports = { "quotes": "off", "no-extra-boolean-cast": "off", + "no-restricted-properties": [ + "error", + ...buildRestrictedPropertiesOptions( + ["window.innerHeight", "window.innerWidth", "window.visualViewport"], + "Use UIStore to access window dimensions instead", + ), + ], }, }], }; + +function buildRestrictedPropertiesOptions(properties, message) { + return properties.map(prop => { + const [object, property] = prop.split("."); + return { + object, + property, + message, + }; + }); +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2582668ef9..f3d9afd51d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,116 @@ +Changes in [3.22.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.22.0) (2021-05-24) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.22.0-rc.1...v3.22.0) + + * Upgrade to JS SDK 11.1.0 + * [Release] Bump libolm version + [\#6087](https://github.com/matrix-org/matrix-react-sdk/pull/6087) + +Changes in [3.22.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.22.0-rc.1) (2021-05-19) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.21.0...v3.22.0-rc.1) + + * Upgrade to JS SDK 11.1.0-rc.1 + * Translations update from Weblate + [\#6068](https://github.com/matrix-org/matrix-react-sdk/pull/6068) + * Show DMs in space for invited members too, to match Android impl + [\#6062](https://github.com/matrix-org/matrix-react-sdk/pull/6062) + * Support filtering by alias in add existing to space dialog + [\#6057](https://github.com/matrix-org/matrix-react-sdk/pull/6057) + * Fix issue when a room without a name or alias is marked as suggested + [\#6064](https://github.com/matrix-org/matrix-react-sdk/pull/6064) + * Fix space room hierarchy not updating when removing a room + [\#6055](https://github.com/matrix-org/matrix-react-sdk/pull/6055) + * Revert "Try putting room list handling behind a lock" + [\#6060](https://github.com/matrix-org/matrix-react-sdk/pull/6060) + * Stop assuming encrypted messages are decrypted ahead of time + [\#6052](https://github.com/matrix-org/matrix-react-sdk/pull/6052) + * Add error detail when languges fail to load + [\#6059](https://github.com/matrix-org/matrix-react-sdk/pull/6059) + * Add space invaders chat effect + [\#6053](https://github.com/matrix-org/matrix-react-sdk/pull/6053) + * Create SpaceProvider and hide Spaces from the RoomProvider autocompleter + [\#6051](https://github.com/matrix-org/matrix-react-sdk/pull/6051) + * Don't mark a room as unread when redacted event is present + [\#6049](https://github.com/matrix-org/matrix-react-sdk/pull/6049) + * Add support for MSC2873: Client information for Widgets + [\#6023](https://github.com/matrix-org/matrix-react-sdk/pull/6023) + * Support UI for MSC2762: Widgets reading events from rooms + [\#5960](https://github.com/matrix-org/matrix-react-sdk/pull/5960) + * Fix crash on opening notification panel + [\#6047](https://github.com/matrix-org/matrix-react-sdk/pull/6047) + * Remove custom LoggedInView::shouldComponentUpdate logic + [\#6046](https://github.com/matrix-org/matrix-react-sdk/pull/6046) + * Fix edge cases with the new add reactions prompt button + [\#6045](https://github.com/matrix-org/matrix-react-sdk/pull/6045) + * Add ids to homeserver and passphrase fields + [\#6043](https://github.com/matrix-org/matrix-react-sdk/pull/6043) + * Update space order field validity requirements to match msc update + [\#6042](https://github.com/matrix-org/matrix-react-sdk/pull/6042) + * Try putting room list handling behind a lock + [\#6024](https://github.com/matrix-org/matrix-react-sdk/pull/6024) + * Improve progress bar progression for smaller voice messages + [\#6035](https://github.com/matrix-org/matrix-react-sdk/pull/6035) + * Fix share space edge case where space is public but not invitable + [\#6039](https://github.com/matrix-org/matrix-react-sdk/pull/6039) + * Add missing 'rel' to image view download button + [\#6033](https://github.com/matrix-org/matrix-react-sdk/pull/6033) + * Improve visible waveform for voice messages + [\#6034](https://github.com/matrix-org/matrix-react-sdk/pull/6034) + * Fix roving tab index intercepting home/end in space create menu + [\#6040](https://github.com/matrix-org/matrix-react-sdk/pull/6040) + * Decorate room avatars with publicity in add existing to space flow + [\#6030](https://github.com/matrix-org/matrix-react-sdk/pull/6030) + * Improve Spaces "Just Me" wizard + [\#6025](https://github.com/matrix-org/matrix-react-sdk/pull/6025) + * Increase hover feedback on room sub list buttons + [\#6037](https://github.com/matrix-org/matrix-react-sdk/pull/6037) + * Show alternative button during space creation wizard if no rooms + [\#6029](https://github.com/matrix-org/matrix-react-sdk/pull/6029) + * Swap rotation buttons in the image viewer + [\#6032](https://github.com/matrix-org/matrix-react-sdk/pull/6032) + * Typo: initilisation -> initialisation + [\#5915](https://github.com/matrix-org/matrix-react-sdk/pull/5915) + * Save edited state of a message when switching rooms + [\#6001](https://github.com/matrix-org/matrix-react-sdk/pull/6001) + * Fix shield icon in Untrusted Device Dialog + [\#6022](https://github.com/matrix-org/matrix-react-sdk/pull/6022) + * Do not eagerly decrypt breadcrumb rooms + [\#6028](https://github.com/matrix-org/matrix-react-sdk/pull/6028) + * Update spaces.png + [\#6031](https://github.com/matrix-org/matrix-react-sdk/pull/6031) + * Encourage more diverse reactions to content + [\#6027](https://github.com/matrix-org/matrix-react-sdk/pull/6027) + * Wrap decodeURIComponent in try-catch to protect against malformed URIs + [\#6026](https://github.com/matrix-org/matrix-react-sdk/pull/6026) + * Iterate beta feedback dialog + [\#6021](https://github.com/matrix-org/matrix-react-sdk/pull/6021) + * Disable space fields whilst their form is busy + [\#6020](https://github.com/matrix-org/matrix-react-sdk/pull/6020) + * Add missing space on beta feedback dialog + [\#6018](https://github.com/matrix-org/matrix-react-sdk/pull/6018) + * Fix colours used for the back button in space create menu + [\#6017](https://github.com/matrix-org/matrix-react-sdk/pull/6017) + * Prioritise and reduce the amount of events decrypted on application startup + [\#5980](https://github.com/matrix-org/matrix-react-sdk/pull/5980) + * Linkify topics in space room directory results + [\#6015](https://github.com/matrix-org/matrix-react-sdk/pull/6015) + * Persistent space collapsed states + [\#5972](https://github.com/matrix-org/matrix-react-sdk/pull/5972) + * Catch another instance of unlabeled avatars. + [\#6010](https://github.com/matrix-org/matrix-react-sdk/pull/6010) + * Rescale and smooth voice message playback waveform to better match + expectation + [\#5996](https://github.com/matrix-org/matrix-react-sdk/pull/5996) + * Scale voice message clock with user's font size + [\#5993](https://github.com/matrix-org/matrix-react-sdk/pull/5993) + * Remove "in development" flag from voice messages + [\#5995](https://github.com/matrix-org/matrix-react-sdk/pull/5995) + * Support voice messages on Safari + [\#5989](https://github.com/matrix-org/matrix-react-sdk/pull/5989) + * Translations update from Weblate + [\#6011](https://github.com/matrix-org/matrix-react-sdk/pull/6011) + Changes in [3.21.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.21.0) (2021-05-17) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.21.0-rc.1...v3.21.0) diff --git a/package.json b/package.json index f8d94e2d21..13047b69cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.21.0", + "version": "3.22.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -121,6 +121,7 @@ "@babel/preset-typescript": "^7.12.7", "@babel/register": "^7.12.10", "@babel/traverse": "^7.12.12", + "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz", "@peculiar/webcrypto": "^1.1.4", "@sinonjs/fake-timers": "^7.0.2", "@types/classnames": "^2.2.11", @@ -161,7 +162,6 @@ "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.2.2", "matrix-web-i18n": "github:matrix-org/matrix-web-i18n", - "olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", "react-test-renderer": "^16.14.0", "rimraf": "^3.0.2", "stylelint": "^13.9.0", diff --git a/res/css/_common.scss b/res/css/_common.scss index d6f85edb86..a05ec7eadd 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -45,6 +45,8 @@ html { N.B. Breaks things when we have legitimate horizontal overscroll */ height: 100%; overflow: hidden; + // Stop similar overscroll bounce in Firefox Nightly for macOS + overscroll-behavior: none; } body { diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index 503fe72414..4bc4af467c 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -328,6 +328,7 @@ $SpaceRoomViewInnerWidth: 428px; font-size: $font-15px; margin-top: 12px; margin-bottom: 16px; + white-space: pre; } > hr { diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index d41ac3a4ba..e2fafe6c62 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -20,11 +20,12 @@ limitations under the License. visibility: hidden; cursor: pointer; display: flex; - height: 24px; + height: 32px; line-height: $font-24px; - border-radius: 4px; - background: $message-action-bar-bg-color; - top: -26px; + border-radius: 8px; + background: $primary-bg-color; + border: 1px solid $input-border-color; + top: -32px; right: 8px; user-select: none; // Ensure the action bar appears above over things, like the read marker. @@ -51,31 +52,19 @@ limitations under the License. white-space: nowrap; display: inline-block; position: relative; - border: 1px solid $message-action-bar-border-color; - margin-left: -1px; + margin: 2px; &:hover { - border-color: $message-action-bar-hover-border-color; + background: $roomlist-button-bg-color; + border-radius: 6px; z-index: 1; } - - &:first-child { - border-radius: 3px 0 0 3px; - } - - &:last-child { - border-radius: 0 3px 3px 0; - } - - &:only-child { - border-radius: 3px; - } } } - .mx_MessageActionBar_maskButton { - width: 27px; + width: 28px; + height: 28px; } .mx_MessageActionBar_maskButton::after { @@ -88,7 +77,11 @@ limitations under the License. mask-size: 18px; mask-repeat: no-repeat; mask-position: center; - background-color: $message-action-bar-fg-color; + background-color: $secondary-fg-color; +} + +.mx_MessageActionBar_maskButton:hover::after { + background-color: $primary-fg-color; } .mx_MessageActionBar_reactButton::after { diff --git a/res/css/views/rooms/_RoomSublist.scss b/res/css/views/rooms/_RoomSublist.scss index 1aafa8da0e..bae469ab87 100644 --- a/res/css/views/rooms/_RoomSublist.scss +++ b/res/css/views/rooms/_RoomSublist.scss @@ -61,8 +61,8 @@ limitations under the License. &.mx_RoomSublist_headerContainer_sticky { position: fixed; height: 32px; // to match the header container - // width set by JS - width: calc(100% - 22px); + // width set by JS because of a compat issue between Firefox and Chrome + width: calc(100% - 15px); } // We don't have a top style because the top is dependent on the room list header's diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 63966d96fa..22280b8a28 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -43,6 +43,7 @@ import TypingStore from "../stores/TypingStore"; import { EventIndexPeg } from "../indexing/EventIndexPeg"; import {VoiceRecordingStore} from "../stores/VoiceRecordingStore"; import PerformanceMonitor from "../performance"; +import UIStore from "../stores/UIStore"; declare global { interface Window { @@ -82,6 +83,7 @@ declare global { mxEventIndexPeg: EventIndexPeg; mxPerformanceMonitor: PerformanceMonitor; mxPerformanceEntryNames: any; + mxUIStore: UIStore; } interface Document { diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index 0268ebfe46..90a631ab7f 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -462,6 +462,9 @@ export default class CallHandler extends EventEmitter { if (call.hangupReason === CallErrorCode.UserHangup) { title = _t("Call Declined"); description = _t("The other party declined the call."); + } else if (call.hangupReason === CallErrorCode.UserBusy) { + title = _t("User Busy"); + description = _t("The user you called is busy."); } else if (call.hangupReason === CallErrorCode.InviteTimeout) { title = _t("Call Failed"); // XXX: full stop appended as some relic here, but these diff --git a/src/CountlyAnalytics.ts b/src/CountlyAnalytics.ts index 974c08df18..aac53b188b 100644 --- a/src/CountlyAnalytics.ts +++ b/src/CountlyAnalytics.ts @@ -22,6 +22,7 @@ import SdkConfig from './SdkConfig'; import {MatrixClientPeg} from "./MatrixClientPeg"; import {sleep} from "./utils/promise"; import RoomViewStore from "./stores/RoomViewStore"; +import { Action } from "./dispatcher/actions"; // polyfill textencoder if necessary import * as TextEncodingUtf8 from 'text-encoding-utf-8'; @@ -265,7 +266,7 @@ interface ICreateRoomEvent extends IEvent { } interface IJoinRoomEvent extends IEvent { - key: "join_room"; + key: Action.JoinRoom; dur: number; // how long it took to join (until remote echo) segmentation: { room_id: string; // hashed @@ -684,7 +685,9 @@ export default class CountlyAnalytics { } private getOrientation = (): Orientation => { - return window.innerWidth > window.innerHeight ? Orientation.Landscape : Orientation.Portrait; + return window.matchMedia("(orientation: landscape)").matches + ? Orientation.Landscape + : Orientation.Portrait }; private reportOrientation = () => { @@ -858,7 +861,7 @@ export default class CountlyAnalytics { } public trackRoomJoin(startTime: number, roomId: string, type: IJoinRoomEvent["segmentation"]["type"]) { - this.track("join_room", { type }, roomId, { + this.track(Action.JoinRoom, { type }, roomId, { dur: CountlyAnalytics.getTimestamp() - startTime, }); } diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index d956189f0d..9497d9de4c 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -21,7 +21,6 @@ import MultiInviter from './utils/MultiInviter'; import { _t } from './languageHandler'; import {MatrixClientPeg} from './MatrixClientPeg'; import GroupStore from './stores/GroupStore'; -import {allSettled} from "./utils/promise"; import StyledCheckbox from './components/views/elements/StyledCheckbox'; export function showGroupInviteDialog(groupId) { @@ -120,7 +119,7 @@ function _onGroupInviteFinished(groupId, addrs) { function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) { const matrixClient = MatrixClientPeg.get(); const errorList = []; - return allSettled(addrs.map((addr) => { + return Promise.allSettled(addrs.map((addr) => { return GroupStore .addRoomToGroup(groupId, addr.address, addRoomsPublicly) .catch(() => { errorList.push(addr.address); }) diff --git a/src/Login.ts b/src/Login.ts index d584df7dfe..7caab22d88 100644 --- a/src/Login.ts +++ b/src/Login.ts @@ -31,12 +31,12 @@ interface IPasswordFlow { } export enum IdentityProviderBrand { - Gitlab = "org.matrix.gitlab", - Github = "org.matrix.github", - Apple = "org.matrix.apple", - Google = "org.matrix.google", - Facebook = "org.matrix.facebook", - Twitter = "org.matrix.twitter", + Gitlab = "gitlab", + Github = "github", + Apple = "apple", + Google = "google", + Facebook = "facebook", + Twitter = "twitter", } export interface IIdentityProvider { @@ -48,7 +48,8 @@ export interface IIdentityProvider { export interface ISSOFlow { type: "m.login.sso" | "m.login.cas"; - "org.matrix.msc2858.identity_providers": IIdentityProvider[]; // Unstable prefix for MSC2858 + // eslint-disable-next-line camelcase + identity_providers: IIdentityProvider[]; } export type LoginFlow = ISSOFlow | IPasswordFlow; diff --git a/src/Terms.ts b/src/Terms.ts index 1bdff36cbc..1b1c152fdd 100644 --- a/src/Terms.ts +++ b/src/Terms.ts @@ -36,14 +36,18 @@ export class Service { } } -interface Policy { +export interface LocalisedPolicy { + name: string; + url: string; +} + +export interface Policy { // @ts-ignore: No great way to express indexed types together with other keys version: string; - [lang: string]: { - url: string; - }; + [lang: string]: LocalisedPolicy; } -type Policies = { + +export type Policies = { [policy: string]: Policy, }; diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index ad0f75e162..9d8665c176 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -23,6 +23,7 @@ import classNames from "classnames"; import {Key} from "../../Keyboard"; import {Writeable} from "../../@types/common"; import {replaceableComponent} from "../../utils/replaceableComponent"; +import UIStore from "../../stores/UIStore"; // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and @@ -410,12 +411,12 @@ export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None const buttonBottom = elementRect.bottom + window.pageYOffset; const buttonTop = elementRect.top + window.pageYOffset; // Align the right edge of the menu to the right edge of the button - menuOptions.right = window.innerWidth - buttonRight; + menuOptions.right = UIStore.instance.windowWidth - buttonRight; // Align the menu vertically on whichever side of the button has more space available. - if (buttonBottom < window.innerHeight / 2) { + if (buttonBottom < UIStore.instance.windowHeight / 2) { menuOptions.top = buttonBottom + vPadding; } else { - menuOptions.bottom = (window.innerHeight - buttonTop) + vPadding; + menuOptions.bottom = (UIStore.instance.windowHeight - buttonTop) + vPadding; } return menuOptions; @@ -430,12 +431,12 @@ export const alwaysAboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFac const buttonBottom = elementRect.bottom + window.pageYOffset; const buttonTop = elementRect.top + window.pageYOffset; // Align the right edge of the menu to the right edge of the button - menuOptions.right = window.innerWidth - buttonRight; + menuOptions.right = UIStore.instance.windowWidth - buttonRight; // Align the menu vertically on whichever side of the button has more space available. - if (buttonBottom < window.innerHeight / 2) { + if (buttonBottom < UIStore.instance.windowHeight / 2) { menuOptions.top = buttonBottom + vPadding; } else { - menuOptions.bottom = (window.innerHeight - buttonTop) + vPadding; + menuOptions.bottom = (UIStore.instance.windowHeight - buttonTop) + vPadding; } return menuOptions; @@ -451,7 +452,7 @@ export const alwaysAboveRightOf = (elementRect: DOMRect, chevronFace = ChevronFa // Align the left edge of the menu to the left edge of the button menuOptions.left = buttonLeft; // Align the menu vertically above the menu - menuOptions.bottom = (window.innerHeight - buttonTop) + vPadding; + menuOptions.bottom = (UIStore.instance.windowHeight - buttonTop) + vPadding; return menuOptions; }; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 3ab009d7b8..3a2c611cc9 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -36,7 +36,7 @@ import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks"; import {Group} from "matrix-js-sdk/src/models/group"; -import {allSettled, sleep} from "../../utils/promise"; +import {sleep} from "../../utils/promise"; import RightPanelStore from "../../stores/RightPanelStore"; import AutoHideScrollbar from "./AutoHideScrollbar"; import {mediaFromMxc} from "../../customisations/Media"; @@ -99,7 +99,7 @@ class CategoryRoomList extends React.Component { onFinished: (success, addrs) => { if (!success) return; const errorList = []; - allSettled(addrs.map((addr) => { + Promise.allSettled(addrs.map((addr) => { return GroupStore .addRoomToGroupSummary(this.props.groupId, addr.address) .catch(() => { errorList.push(addr.address); }); @@ -274,7 +274,7 @@ class RoleUserList extends React.Component { onFinished: (success, addrs) => { if (!success) return; const errorList = []; - allSettled(addrs.map((addr) => { + Promise.allSettled(addrs.map((addr) => { return GroupStore .addUserToGroupSummary(addr.address) .catch(() => { errorList.push(addr.address); }); diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 7f9ef7516e..7df4bcadf3 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -43,6 +43,7 @@ import {replaceableComponent} from "../../utils/replaceableComponent"; import {mediaFromMxc} from "../../customisations/Media"; import SpaceStore, {UPDATE_SELECTED_SPACE} from "../../stores/SpaceStore"; import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager"; +import UIStore from "../../stores/UIStore"; interface IProps { isMinimized: boolean; @@ -66,6 +67,7 @@ const cssClasses = [ @replaceableComponent("structures.LeftPanel") export default class LeftPanel extends React.Component { + private ref: React.RefObject = createRef(); private listContainerRef: React.RefObject = createRef(); private groupFilterPanelWatcherRef: string; private bgImageWatcherRef: string; @@ -90,10 +92,11 @@ export default class LeftPanel extends React.Component { this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => { this.setState({showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel")}); }); + } - // We watch the middle panel because we don't actually get resized, the middle panel does. - // We listen to the noisy channel to avoid choppy reaction times. - this.props.resizeNotifier.on("middlePanelResizedNoisy", this.onResize); + public componentDidMount() { + UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current); + UIStore.instance.on("ListContainer", this.refreshStickyHeaders); } public componentWillUnmount() { @@ -103,7 +106,14 @@ export default class LeftPanel extends React.Component { RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate); SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace); - this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize); + UIStore.instance.stopTrackingElementDimensions("ListContainer"); + UIStore.instance.removeListener("ListContainer", this.refreshStickyHeaders); + } + + public componentDidUpdate(prevProps: IProps, prevState: IState): void { + if (prevState.activeSpace !== this.state.activeSpace) { + this.refreshStickyHeaders(); + } } private updateActiveSpace = (activeSpace: Room) => { @@ -114,6 +124,11 @@ export default class LeftPanel extends React.Component { dis.fire(Action.ViewRoomDirectory); }; + private refreshStickyHeaders = () => { + if (!this.listContainerRef.current) return; // ignore: no headers to sticky + this.handleStickyHeaders(this.listContainerRef.current); + } + private onBreadcrumbsUpdate = () => { const newVal = BreadcrumbsStore.instance.visible; if (newVal !== this.state.showBreadcrumbs) { @@ -156,9 +171,6 @@ export default class LeftPanel extends React.Component { const bottomEdge = list.offsetHeight + list.scrollTop; const sublists = list.querySelectorAll(".mx_RoomSublist:not(.mx_RoomSublist_hidden)"); - const headerRightMargin = 15; // calculated from margins and widths to align with non-sticky tiles - const headerStickyWidth = list.clientWidth - headerRightMargin; - // We track which styles we want on a target before making the changes to avoid // excessive layout updates. const targetStyles = new Map { header.classList.add("mx_RoomSublist_headerContainer_stickyBottom"); } - const offset = window.innerHeight - (list.parentElement.offsetTop + list.parentElement.offsetHeight); + const offset = UIStore.instance.windowHeight - + (list.parentElement.offsetTop + list.parentElement.offsetHeight); const newBottom = `${offset}px`; if (header.style.bottom !== newBottom) { header.style.bottom = newBottom; @@ -247,14 +260,20 @@ export default class LeftPanel extends React.Component { header.classList.add("mx_RoomSublist_headerContainer_sticky"); } - const newWidth = `${headerStickyWidth}px`; - if (header.style.width !== newWidth) { - header.style.width = newWidth; + const listDimensions = UIStore.instance.getElementDimensions("ListContainer"); + if (listDimensions) { + const headerRightMargin = 15; // calculated from margins and widths to align with non-sticky tiles + const headerStickyWidth = listDimensions.width - headerRightMargin; + const newWidth = `${headerStickyWidth}px`; + if (header.style.width !== newWidth) { + header.style.width = newWidth; + } } } else if (!style.stickyTop && !style.stickyBottom) { if (header.classList.contains("mx_RoomSublist_headerContainer_sticky")) { header.classList.remove("mx_RoomSublist_headerContainer_sticky"); } + if (header.style.width) { header.style.removeProperty('width'); } @@ -281,11 +300,6 @@ export default class LeftPanel extends React.Component { this.handleStickyHeaders(list); }; - private onResize = () => { - if (!this.listContainerRef.current) return; // ignore: no headers to sticky - this.handleStickyHeaders(this.listContainerRef.current); - }; - private onFocus = (ev: React.FocusEvent) => { this.focusedElement = ev.target; }; @@ -420,8 +434,8 @@ export default class LeftPanel extends React.Component { onFocus={this.onFocus} onBlur={this.onBlur} isMinimized={this.props.isMinimized} - onResize={this.onResize} activeSpace={this.state.activeSpace} + onListCollapse={this.refreshStickyHeaders} />; const containerClasses = classNames({ @@ -435,13 +449,13 @@ export default class LeftPanel extends React.Component { ); return ( -
+
{leftLeftPanel}
); diff --git a/src/components/structures/LeftPanelWidget.tsx b/src/components/structures/LeftPanelWidget.tsx index e88af282ba..16142069c4 100644 --- a/src/components/structures/LeftPanelWidget.tsx +++ b/src/components/structures/LeftPanelWidget.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useContext, useEffect, useMemo} from "react"; +import React, {useContext, useMemo} from "react"; import {Resizable} from "re-resizable"; import classNames from "classnames"; @@ -27,16 +27,13 @@ import WidgetUtils, {IWidgetEvent} from "../../utils/WidgetUtils"; import {useAccountData} from "../../hooks/useAccountData"; import AppTile from "../views/elements/AppTile"; import {useSettingValue} from "../../hooks/useSettings"; - -interface IProps { - onResize(): void; -} +import UIStore from "../../stores/UIStore"; const MIN_HEIGHT = 100; const MAX_HEIGHT = 500; // or 50% of the window height const INITIAL_HEIGHT = 280; -const LeftPanelWidget: React.FC = ({ onResize }) => { +const LeftPanelWidget: React.FC = () => { const cli = useContext(MatrixClientContext); const mWidgetsEvent = useAccountData>(cli, "m.widgets"); @@ -56,7 +53,6 @@ const LeftPanelWidget: React.FC = ({ onResize }) => { const [height, setHeight] = useLocalStorageState("left-panel-widget-height", INITIAL_HEIGHT); const [expanded, setExpanded] = useLocalStorageState("left-panel-widget-expanded", true); - useEffect(onResize, [expanded, onResize]); const [onFocus, isActive, ref] = useRovingTabIndex(); const tabIndex = isActive ? 0 : -1; @@ -68,8 +64,7 @@ const LeftPanelWidget: React.FC = ({ onResize }) => { content = { setHeight(height + d.height); }} diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 49386c5f65..d5e8e6a1f8 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -87,6 +87,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher"; import SecurityCustomisations from "../../customisations/Security"; import PerformanceMonitor, { PerformanceEntryNames } from "../../performance"; +import UIStore, { UI_EVENTS } from "../../stores/UIStore"; /** constants for MatrixChat.state.view */ export enum Views { @@ -225,13 +226,13 @@ export default class MatrixChat extends React.PureComponent { firstSyncPromise: IDeferred; private screenAfterLogin?: IScreen; - private windowWidth: number; private pageChanging: boolean; private tokenLogin?: boolean; private accountPassword?: string; private accountPasswordTimer?: NodeJS.Timeout; private focusComposer: boolean; private subTitleStatus: string; + private prevWindowWidth: number; private readonly loggedInView: React.RefObject; private readonly dispatcherRef: any; @@ -277,9 +278,8 @@ export default class MatrixChat extends React.PureComponent { } } - this.windowWidth = 10000; - this.handleResize(); - window.addEventListener('resize', this.handleResize); + this.prevWindowWidth = UIStore.instance.windowWidth || 1000; + UIStore.instance.on(UI_EVENTS.Resize, this.handleResize); this.pageChanging = false; @@ -436,7 +436,7 @@ export default class MatrixChat extends React.PureComponent { dis.unregister(this.dispatcherRef); this.themeWatcher.stop(); this.fontWatcher.stop(); - window.removeEventListener('resize', this.handleResize); + UIStore.destroy(); this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize); if (this.accountPasswordTimer !== null) clearTimeout(this.accountPasswordTimer); @@ -1820,18 +1820,19 @@ export default class MatrixChat extends React.PureComponent { } handleResize = () => { - const hideLhsThreshold = 1000; - const showLhsThreshold = 1000; + const LHS_THRESHOLD = 1000; + const width = UIStore.instance.windowWidth; - if (this.windowWidth > hideLhsThreshold && window.innerWidth <= hideLhsThreshold) { - dis.dispatch({ action: 'hide_left_panel' }); - } - if (this.windowWidth <= showLhsThreshold && window.innerWidth > showLhsThreshold) { + if (this.prevWindowWidth < LHS_THRESHOLD && width >= LHS_THRESHOLD) { dis.dispatch({ action: 'show_left_panel' }); } + if (this.prevWindowWidth >= LHS_THRESHOLD && width < LHS_THRESHOLD) { + dis.dispatch({ action: 'hide_left_panel' }); + } + + this.prevWindowWidth = width; this.state.resizeNotifier.notifyWindowResized(); - this.windowWidth = window.innerWidth; }; private dispatchTimelineResize() { @@ -2090,6 +2091,7 @@ export default class MatrixChat extends React.PureComponent { onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined} onServerConfigChange={this.onServerConfigChange} fragmentAfterLogin={fragmentAfterLogin} + defaultUsername={this.props.startingFragmentQueryParams.defaultUsername} {...this.getServerProperties()} /> ); diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index dcb671b184..0e04b17fb0 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -82,6 +82,7 @@ import { objectHasDiff } from "../../utils/objects"; import SpaceRoomView from "./SpaceRoomView"; import { IOpts } from "../../createRoom"; import {replaceableComponent} from "../../utils/replaceableComponent"; +import UIStore from "../../stores/UIStore"; const DEBUG = false; let debuglog = function(msg: string) {}; @@ -1111,7 +1112,8 @@ export default class RoomView extends React.Component { Promise.resolve().then(() => { const signUrl = this.props.threepidInvite?.signUrl; dis.dispatch({ - action: 'join_room', + action: Action.JoinRoom, + roomId: this.getRoomId(), opts: { inviteSignUrl: signUrl }, _type: "unknown", // TODO: instrumentation }); @@ -1570,7 +1572,7 @@ export default class RoomView extends React.Component { // a maxHeight on the underlying remote video tag. // header + footer + status + give us at least 120px of scrollback at all times. - let auxPanelMaxHeight = window.innerHeight - + let auxPanelMaxHeight = UIStore.instance.windowHeight - (54 + // height of RoomHeader 36 + // height of the status area 51 + // minimum height of the message compmoser diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index dde8dd8331..8d59fe6c68 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -101,15 +101,13 @@ const Tile: React.FC = ({ numChildRooms, children, }) => { - const name = room.name || room.canonical_alias || room.aliases?.[0] + const cli = MatrixClientPeg.get(); + const joinedRoom = cli.getRoom(room.room_id)?.getMyMembership() === "join" ? cli.getRoom(room.room_id) : null; + const name = joinedRoom?.name || room.name || room.canonical_alias || room.aliases?.[0] || (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room")); const [showChildren, toggleShowChildren] = useStateToggle(true); - const cli = MatrixClientPeg.get(); - const cliRoom = cli.getRoom(room.room_id); - const myMembership = cliRoom?.getMyMembership(); - const onPreviewClick = (ev: ButtonEvent) => { ev.preventDefault(); ev.stopPropagation(); @@ -122,7 +120,7 @@ const Tile: React.FC = ({ } let button; - if (myMembership === "join") { + if (joinedRoom) { button = { _t("View") } ; @@ -146,17 +144,27 @@ const Tile: React.FC = ({ } } - let url: string; - if (room.avatar_url) { - url = mediaFromMxc(room.avatar_url).getSquareThumbnailHttp(20); + let avatar; + if (joinedRoom) { + avatar = ; + } else { + avatar = ; } let description = _t("%(count)s members", { count: room.num_joined_members }); if (numChildRooms !== undefined) { description += " · " + _t("%(count)s rooms", { count: numChildRooms }); } - if (room.topic) { - description += " · " + room.topic; + + const topic = joinedRoom?.currentState?.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic || room.topic; + if (topic) { + description += " · " + topic; } let suggestedSection; @@ -167,7 +175,7 @@ const Tile: React.FC = ({ } const content = - + { avatar }
{ name } { suggestedSection } @@ -311,7 +319,7 @@ export const HierarchyLevel = ({ key={roomId} room={rooms.get(roomId)} numChildRooms={Array.from(relations.get(roomId)?.values() || []) - .filter(ev => rooms.get(ev.state_key)?.room_type !== RoomType.Space).length} + .filter(ev => rooms.has(ev.state_key) && !rooms.get(ev.state_key).room_type).length} suggested={relations.get(spaceId)?.get(roomId)?.content.suggested} selected={selectedMap?.get(spaceId)?.has(roomId)} onViewRoomClick={(autoJoin) => { @@ -429,7 +437,7 @@ export const SpaceHierarchy: React.FC = ({ let content; if (roomsMap) { - const numRooms = Array.from(roomsMap.values()).filter(r => r.room_type !== RoomType.Space).length; + const numRooms = Array.from(roomsMap.values()).filter(r => !r.room_type).length; const numSpaces = roomsMap.size - numRooms - 1; // -1 at the end to exclude the space we are looking at let countsStr; diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index ea4c75e25c..06d2bda16e 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -417,9 +417,13 @@ const SpaceLanding = ({ space }) => { { inviteButton } { settingsButton }
-
- -
+ + {(topic, ref) => ( +
+ { topic } +
+ )} +

@@ -437,7 +441,6 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { const [error, setError] = useState(""); const numFields = 3; const placeholders = [_t("General"), _t("Random"), _t("Support")]; - // TODO vary default prefills for "Just Me" spaces const [roomNames, setRoomName] = useStateArray(numFields, [_t("General"), _t("Random"), ""]); const fields = new Array(numFields).fill(0).map((_, i) => { const name = "roomName" + i; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index 65861624e6..fb4829f879 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -57,7 +57,8 @@ import { IHostSignupConfig } from "../views/dialogs/HostSignupDialogTypes"; import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore"; import RoomName from "../views/elements/RoomName"; import {replaceableComponent} from "../../utils/replaceableComponent"; - +import InlineSpinner from "../views/elements/InlineSpinner"; +import TooltipButton from "../views/elements/TooltipButton"; interface IProps { isMinimized: boolean; } @@ -68,6 +69,7 @@ interface IState { contextMenuPosition: PartialDOMRect; isDarkTheme: boolean; selectedSpace?: Room; + pendingRoomJoin: Set; } @replaceableComponent("structures.UserMenu") @@ -84,6 +86,7 @@ export default class UserMenu extends React.Component { this.state = { contextMenuPosition: null, isDarkTheme: this.isUserOnDarkTheme(), + pendingRoomJoin: new Set(), }; OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate); @@ -103,6 +106,7 @@ export default class UserMenu extends React.Component { this.dispatcherRef = defaultDispatcher.register(this.onAction); this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged); this.tagStoreRef = GroupFilterOrderStore.addListener(this.onTagStoreUpdate); + MatrixClientPeg.get().on("Room", this.onRoom); } public componentWillUnmount() { @@ -114,6 +118,11 @@ export default class UserMenu extends React.Component { if (SettingsStore.getValue("feature_spaces")) { SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate); } + MatrixClientPeg.get().removeListener("Room", this.onRoom); + } + + private onRoom = (room: Room): void => { + this.removePendingJoinRoom(room.roomId); } private onTagStoreUpdate = () => { @@ -147,15 +156,39 @@ export default class UserMenu extends React.Component { }; private onAction = (ev: ActionPayload) => { - if (ev.action !== Action.ToggleUserMenu) return; // not interested - - if (this.state.contextMenuPosition) { - this.setState({contextMenuPosition: null}); - } else { - if (this.buttonRef.current) this.buttonRef.current.click(); + switch (ev.action) { + case Action.ToggleUserMenu: + if (this.state.contextMenuPosition) { + this.setState({contextMenuPosition: null}); + } else { + if (this.buttonRef.current) this.buttonRef.current.click(); + } + break; + case Action.JoinRoom: + this.addPendingJoinRoom(ev.roomId); + break; + case Action.JoinRoomReady: + case Action.JoinRoomError: + this.removePendingJoinRoom(ev.roomId); + break; } }; + private addPendingJoinRoom(roomId: string): void { + this.setState({ + pendingRoomJoin: new Set(this.state.pendingRoomJoin) + .add(roomId), + }); + } + + private removePendingJoinRoom(roomId: string): void { + if (this.state.pendingRoomJoin.delete(roomId)) { + this.setState({ + pendingRoomJoin: new Set(this.state.pendingRoomJoin), + }) + } + } + private onOpenMenuClick = (ev: React.MouseEvent) => { ev.preventDefault(); ev.stopPropagation(); @@ -617,6 +650,14 @@ export default class UserMenu extends React.Component { /> {name} + {this.state.pendingRoomJoin.size > 0 && ( + + + + )} {dnd} {buttons}
diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index 34a5410928..d34582b0c3 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -59,6 +59,7 @@ interface IProps { fallbackHsUrl?: string; defaultDeviceDisplayName?: string; fragmentAfterLogin?: string; + defaultUsername?: string; // Called when the user has logged in. Params: // - The object returned by the login API @@ -119,7 +120,7 @@ export default class LoginComponent extends React.PureComponent flows: null, - username: "", + username: props.defaultUsername? props.defaultUsername: '', phoneCountry: null, phoneNumber: "", diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 96fb9bdc82..e4515dd627 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -223,7 +223,8 @@ export default class Registration extends React.Component { this.setState({ flows: e.data.flows, }); - } else if (e.httpStatus === 403 && e.errcode === "M_UNKNOWN") { + } else if (e.httpStatus === 403 || e.errcode === "M_FORBIDDEN") { + // Check for 403 or M_FORBIDDEN, Synapse used to send 403 M_UNKNOWN but now sends 403 M_FORBIDDEN. // At this point registration is pretty much disabled, but before we do that let's // quickly check to see if the server supports SSO instead. If it does, we'll send // the user off to the login page to figure their account out. @@ -467,7 +468,7 @@ export default class Registration extends React.Component { let ssoSection; if (this.state.ssoFlow) { let continueWithSection; - const providers = this.state.ssoFlow["org.matrix.msc2858.identity_providers"] || []; + const providers = this.state.ssoFlow.identity_providers || []; // when there is only a single (or 0) providers we show a wide button with `Continue with X` text if (providers.length > 1) { // i18n: ssoButtons is a placeholder to help translators understand context diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.js b/src/components/views/auth/InteractiveAuthEntryComponents.tsx similarity index 72% rename from src/components/views/auth/InteractiveAuthEntryComponents.js rename to src/components/views/auth/InteractiveAuthEntryComponents.tsx index e34349c474..e819e1e59c 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.js +++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx @@ -1,7 +1,5 @@ /* -Copyright 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd -Copyright 2019, 2020 The Matrix.org Foundation C.I.C. +Copyright 2016-2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import React, { ChangeEvent, createRef, FormEvent, MouseEvent } from 'react'; +import classNames from 'classnames'; +import { MatrixClient } from "matrix-js-sdk/src/client"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; @@ -27,6 +25,7 @@ import AccessibleButton from "../elements/AccessibleButton"; import Spinner from "../elements/Spinner"; import CountlyAnalytics from "../../../CountlyAnalytics"; import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { LocalisedPolicy, Policies } from '../../../Terms'; /* This file contains a collection of components which are used by the * InteractiveAuth to prompt the user to enter the information needed @@ -74,36 +73,72 @@ import {replaceableComponent} from "../../../utils/replaceableComponent"; * focus: set the input focus appropriately in the form. */ +enum AuthType { + Password = "m.login.password", + Recaptcha = "m.login.recaptcha", + Terms = "m.login.terms", + Email = "m.login.email.identity", + Msisdn = "m.login.msisdn", + Sso = "m.login.sso", + SsoUnstable = "org.matrix.login.sso", +} + +/* eslint-disable camelcase */ +interface IAuthDict { + type?: AuthType; + // TODO: Remove `user` once servers support proper UIA + // See https://github.com/vector-im/element-web/issues/10312 + user?: string; + identifier?: any; + password?: string; + response?: string; + // TODO: Remove `threepid_creds` once servers support proper UIA + // See https://github.com/vector-im/element-web/issues/10312 + // See https://github.com/matrix-org/matrix-doc/issues/2220 + threepid_creds?: any; + threepidCreds?: any; +} +/* eslint-enable camelcase */ + export const DEFAULT_PHASE = 0; -@replaceableComponent("views.auth.PasswordAuthEntry") -export class PasswordAuthEntry extends React.Component { - static LOGIN_TYPE = "m.login.password"; +interface IAuthEntryProps { + matrixClient: MatrixClient; + loginType: string; + authSessionId: string; + errorText?: string; + // Is the auth logic currently waiting for something to happen? + busy?: boolean; + onPhaseChange: (phase: number) => void; + submitAuthDict: (auth: IAuthDict) => void; +} - static propTypes = { - matrixClient: PropTypes.object.isRequired, - submitAuthDict: PropTypes.func.isRequired, - errorText: PropTypes.string, - // is the auth logic currently waiting for something to - // happen? - busy: PropTypes.bool, - onPhaseChange: PropTypes.func.isRequired, - }; +interface IPasswordAuthEntryState { + password: string; +} + +@replaceableComponent("views.auth.PasswordAuthEntry") +export class PasswordAuthEntry extends React.Component { + static LOGIN_TYPE = AuthType.Password; + + constructor(props) { + super(props); + + this.state = { + password: "", + }; + } componentDidMount() { this.props.onPhaseChange(DEFAULT_PHASE); } - state = { - password: "", - }; - - _onSubmit = e => { + private onSubmit = (e: FormEvent) => { e.preventDefault(); if (this.props.busy) return; this.props.submitAuthDict({ - type: PasswordAuthEntry.LOGIN_TYPE, + type: AuthType.Password, // TODO: Remove `user` once servers support proper UIA // See https://github.com/vector-im/element-web/issues/10312 user: this.props.matrixClient.credentials.userId, @@ -115,7 +150,7 @@ export class PasswordAuthEntry extends React.Component { }); }; - _onPasswordFieldChange = ev => { + private onPasswordFieldChange = (ev: ChangeEvent) => { // enable the submit button iff the password is non-empty this.setState({ password: ev.target.value, @@ -123,7 +158,7 @@ export class PasswordAuthEntry extends React.Component { }; render() { - const passwordBoxClass = classnames({ + const passwordBoxClass = classNames({ "error": this.props.errorText, }); @@ -155,7 +190,7 @@ export class PasswordAuthEntry extends React.Component { return (

{ _t("Confirm your identity by entering your account password below.") }

-
+
{ submitButtonOrSpinner } @@ -175,26 +210,26 @@ export class PasswordAuthEntry extends React.Component { } } -@replaceableComponent("views.auth.RecaptchaAuthEntry") -export class RecaptchaAuthEntry extends React.Component { - static LOGIN_TYPE = "m.login.recaptcha"; - - static propTypes = { - submitAuthDict: PropTypes.func.isRequired, - stageParams: PropTypes.object.isRequired, - errorText: PropTypes.string, - busy: PropTypes.bool, - onPhaseChange: PropTypes.func.isRequired, +/* eslint-disable camelcase */ +interface IRecaptchaAuthEntryProps extends IAuthEntryProps { + stageParams?: { + public_key?: string; }; +} +/* eslint-enable camelcase */ + +@replaceableComponent("views.auth.RecaptchaAuthEntry") +export class RecaptchaAuthEntry extends React.Component { + static LOGIN_TYPE = AuthType.Recaptcha; componentDidMount() { this.props.onPhaseChange(DEFAULT_PHASE); } - _onCaptchaResponse = response => { + private onCaptchaResponse = (response: string) => { CountlyAnalytics.instance.track("onboarding_grecaptcha_submit"); this.props.submitAuthDict({ - type: RecaptchaAuthEntry.LOGIN_TYPE, + type: AuthType.Recaptcha, response: response, }); }; @@ -230,7 +265,7 @@ export class RecaptchaAuthEntry extends React.Component { return (
{ errorSection }
@@ -238,18 +273,28 @@ export class RecaptchaAuthEntry extends React.Component { } } -@replaceableComponent("views.auth.TermsAuthEntry") -export class TermsAuthEntry extends React.Component { - static LOGIN_TYPE = "m.login.terms"; - - static propTypes = { - submitAuthDict: PropTypes.func.isRequired, - stageParams: PropTypes.object.isRequired, - errorText: PropTypes.string, - busy: PropTypes.bool, - showContinue: PropTypes.bool, - onPhaseChange: PropTypes.func.isRequired, +interface ITermsAuthEntryProps extends IAuthEntryProps { + stageParams?: { + policies?: Policies; }; + showContinue: boolean; +} + +interface LocalisedPolicyWithId extends LocalisedPolicy { + id: string; +} + +interface ITermsAuthEntryState { + policies: LocalisedPolicyWithId[]; + toggledPolicies: { + [policy: string]: boolean; + }; + errorText?: string; +} + +@replaceableComponent("views.auth.TermsAuthEntry") +export class TermsAuthEntry extends React.Component { + static LOGIN_TYPE = AuthType.Terms; constructor(props) { super(props); @@ -294,8 +339,11 @@ export class TermsAuthEntry extends React.Component { initToggles[policyId] = false; - langPolicy.id = policyId; - pickedPolicies.push(langPolicy); + pickedPolicies.push({ + id: policyId, + name: langPolicy.name, + url: langPolicy.url, + }); } this.state = { @@ -311,11 +359,11 @@ export class TermsAuthEntry extends React.Component { this.props.onPhaseChange(DEFAULT_PHASE); } - tryContinue = () => { - this._trySubmit(); + public tryContinue = () => { + this.trySubmit(); }; - _togglePolicy(policyId) { + private togglePolicy(policyId: string) { const newToggles = {}; for (const policy of this.state.policies) { let checked = this.state.toggledPolicies[policy.id]; @@ -326,7 +374,7 @@ export class TermsAuthEntry extends React.Component { this.setState({"toggledPolicies": newToggles}); } - _trySubmit = () => { + private trySubmit = () => { let allChecked = true; for (const policy of this.state.policies) { const checked = this.state.toggledPolicies[policy.id]; @@ -334,7 +382,7 @@ export class TermsAuthEntry extends React.Component { } if (allChecked) { - this.props.submitAuthDict({type: TermsAuthEntry.LOGIN_TYPE}); + this.props.submitAuthDict({type: AuthType.Terms}); CountlyAnalytics.instance.track("onboarding_terms_complete"); } else { this.setState({errorText: _t("Please review and accept all of the homeserver's policies")}); @@ -356,7 +404,7 @@ export class TermsAuthEntry extends React.Component { checkboxes.push( // XXX: replace with StyledCheckbox , ); @@ -375,7 +423,7 @@ export class TermsAuthEntry extends React.Component { if (this.props.showContinue !== false) { // XXX: button classes submitButton = ; + onClick={this.trySubmit} disabled={!allChecked}>{_t("Accept")}; } return ( @@ -389,21 +437,18 @@ export class TermsAuthEntry extends React.Component { } } -@replaceableComponent("views.auth.EmailIdentityAuthEntry") -export class EmailIdentityAuthEntry extends React.Component { - static LOGIN_TYPE = "m.login.email.identity"; - - static propTypes = { - matrixClient: PropTypes.object.isRequired, - submitAuthDict: PropTypes.func.isRequired, - authSessionId: PropTypes.string.isRequired, - clientSecret: PropTypes.string.isRequired, - inputs: PropTypes.object.isRequired, - stageState: PropTypes.object.isRequired, - fail: PropTypes.func.isRequired, - setEmailSid: PropTypes.func.isRequired, - onPhaseChange: PropTypes.func.isRequired, +interface IEmailIdentityAuthEntryProps extends IAuthEntryProps { + inputs?: { + emailAddress?: string; }; + stageState?: { + emailSid: string; + }; +} + +@replaceableComponent("views.auth.EmailIdentityAuthEntry") +export class EmailIdentityAuthEntry extends React.Component { + static LOGIN_TYPE = AuthType.Email; componentDidMount() { this.props.onPhaseChange(DEFAULT_PHASE); @@ -427,7 +472,7 @@ export class EmailIdentityAuthEntry extends React.Component { return (

{ _t("A confirmation email has been sent to %(emailAddress)s", - { emailAddress: (sub) => { this.props.inputs.emailAddress } }, + { emailAddress: { this.props.inputs.emailAddress } }, ) }

{ _t("Open the link in the email to continue registration.") }

@@ -437,37 +482,44 @@ export class EmailIdentityAuthEntry extends React.Component { } } +interface IMsisdnAuthEntryProps extends IAuthEntryProps { + inputs: { + phoneCountry: string; + phoneNumber: string; + }; + clientSecret: string; + fail: (error: Error) => void; +} + +interface IMsisdnAuthEntryState { + token: string; + requestingToken: boolean; + errorText: string; +} + @replaceableComponent("views.auth.MsisdnAuthEntry") -export class MsisdnAuthEntry extends React.Component { - static LOGIN_TYPE = "m.login.msisdn"; +export class MsisdnAuthEntry extends React.Component { + static LOGIN_TYPE = AuthType.Msisdn; - static propTypes = { - inputs: PropTypes.shape({ - phoneCountry: PropTypes.string, - phoneNumber: PropTypes.string, - }), - fail: PropTypes.func, - clientSecret: PropTypes.func, - submitAuthDict: PropTypes.func.isRequired, - matrixClient: PropTypes.object, - onPhaseChange: PropTypes.func.isRequired, - }; + private submitUrl: string; + private sid: string; + private msisdn: string; - state = { - token: '', - requestingToken: false, - }; + constructor(props) { + super(props); + + this.state = { + token: '', + requestingToken: false, + errorText: '', + }; + } componentDidMount() { this.props.onPhaseChange(DEFAULT_PHASE); - this._submitUrl = null; - this._sid = null; - this._msisdn = null; - this._tokenBox = null; - this.setState({requestingToken: true}); - this._requestMsisdnToken().catch((e) => { + this.requestMsisdnToken().catch((e) => { this.props.fail(e); }).finally(() => { this.setState({requestingToken: false}); @@ -477,26 +529,26 @@ export class MsisdnAuthEntry extends React.Component { /* * Requests a verification token by SMS. */ - _requestMsisdnToken() { + private requestMsisdnToken(): Promise { return this.props.matrixClient.requestRegisterMsisdnToken( this.props.inputs.phoneCountry, this.props.inputs.phoneNumber, this.props.clientSecret, 1, // TODO: Multiple send attempts? ).then((result) => { - this._submitUrl = result.submit_url; - this._sid = result.sid; - this._msisdn = result.msisdn; + this.submitUrl = result.submit_url; + this.sid = result.sid; + this.msisdn = result.msisdn; }); } - _onTokenChange = e => { + private onTokenChange = (e: ChangeEvent) => { this.setState({ token: e.target.value, }); }; - _onFormSubmit = async e => { + private onFormSubmit = async (e: FormEvent) => { e.preventDefault(); if (this.state.token == '') return; @@ -506,20 +558,20 @@ export class MsisdnAuthEntry extends React.Component { try { let result; - if (this._submitUrl) { + if (this.submitUrl) { result = await this.props.matrixClient.submitMsisdnTokenOtherUrl( - this._submitUrl, this._sid, this.props.clientSecret, this.state.token, + this.submitUrl, this.sid, this.props.clientSecret, this.state.token, ); } else { throw new Error("The registration with MSISDN flow is misconfigured"); } if (result.success) { const creds = { - sid: this._sid, + sid: this.sid, client_secret: this.props.clientSecret, }; this.props.submitAuthDict({ - type: MsisdnAuthEntry.LOGIN_TYPE, + type: AuthType.Msisdn, // TODO: Remove `threepid_creds` once servers support proper UIA // See https://github.com/vector-im/element-web/issues/10312 // See https://github.com/matrix-org/matrix-doc/issues/2220 @@ -543,7 +595,7 @@ export class MsisdnAuthEntry extends React.Component { return ; } else { const enableSubmit = Boolean(this.state.token); - const submitClasses = classnames({ + const submitClasses = classNames({ mx_InteractiveAuthEntryComponents_msisdnSubmit: true, mx_GeneralButton: true, }); @@ -558,16 +610,16 @@ export class MsisdnAuthEntry extends React.Component { return (

{ _t("A text message has been sent to %(msisdn)s", - { msisdn: { this._msisdn } }, + { msisdn: { this.msisdn } }, ) }

{ _t("Please enter the code it contains:") }

- +
@@ -584,40 +636,40 @@ export class MsisdnAuthEntry extends React.Component { } } -@replaceableComponent("views.auth.SSOAuthEntry") -export class SSOAuthEntry extends React.Component { - static propTypes = { - matrixClient: PropTypes.object.isRequired, - authSessionId: PropTypes.string.isRequired, - loginType: PropTypes.string.isRequired, - submitAuthDict: PropTypes.func.isRequired, - errorText: PropTypes.string, - onPhaseChange: PropTypes.func.isRequired, - continueText: PropTypes.string, - continueKind: PropTypes.string, - onCancel: PropTypes.func, - }; +interface ISSOAuthEntryProps extends IAuthEntryProps { + continueText?: string; + continueKind?: string; + onCancel?: () => void; +} - static LOGIN_TYPE = "m.login.sso"; - static UNSTABLE_LOGIN_TYPE = "org.matrix.login.sso"; +interface ISSOAuthEntryState { + phase: number; + attemptFailed: boolean; +} + +@replaceableComponent("views.auth.SSOAuthEntry") +export class SSOAuthEntry extends React.Component { + static LOGIN_TYPE = AuthType.Sso; + static UNSTABLE_LOGIN_TYPE = AuthType.SsoUnstable; static PHASE_PREAUTH = 1; // button to start SSO static PHASE_POSTAUTH = 2; // button to confirm SSO completed - _ssoUrl: string; + private ssoUrl: string; + private popupWindow: Window; constructor(props) { super(props); // We actually send the user through fallback auth so we don't have to // deal with a redirect back to us, losing application context. - this._ssoUrl = props.matrixClient.getFallbackAuthUrl( + this.ssoUrl = props.matrixClient.getFallbackAuthUrl( this.props.loginType, this.props.authSessionId, ); - this._popupWindow = null; - window.addEventListener("message", this._onReceiveMessage); + this.popupWindow = null; + window.addEventListener("message", this.onReceiveMessage); this.state = { phase: SSOAuthEntry.PHASE_PREAUTH, @@ -625,44 +677,44 @@ export class SSOAuthEntry extends React.Component { }; } - componentDidMount(): void { + componentDidMount() { this.props.onPhaseChange(SSOAuthEntry.PHASE_PREAUTH); } componentWillUnmount() { - window.removeEventListener("message", this._onReceiveMessage); - if (this._popupWindow) { - this._popupWindow.close(); - this._popupWindow = null; + window.removeEventListener("message", this.onReceiveMessage); + if (this.popupWindow) { + this.popupWindow.close(); + this.popupWindow = null; } } - attemptFailed = () => { + public attemptFailed = () => { this.setState({ attemptFailed: true, }); }; - _onReceiveMessage = event => { + private onReceiveMessage = (event: MessageEvent) => { if (event.data === "authDone" && event.origin === this.props.matrixClient.getHomeserverUrl()) { - if (this._popupWindow) { - this._popupWindow.close(); - this._popupWindow = null; + if (this.popupWindow) { + this.popupWindow.close(); + this.popupWindow = null; } } }; - onStartAuthClick = () => { + private onStartAuthClick = () => { // Note: We don't use PlatformPeg's startSsoAuth functions because we almost // certainly will need to open the thing in a new tab to avoid losing application // context. - this._popupWindow = window.open(this._ssoUrl, "_blank"); + this.popupWindow = window.open(this.ssoUrl, "_blank"); this.setState({phase: SSOAuthEntry.PHASE_POSTAUTH}); this.props.onPhaseChange(SSOAuthEntry.PHASE_POSTAUTH); }; - onConfirmClick = () => { + private onConfirmClick = () => { this.props.submitAuthDict({}); }; @@ -716,46 +768,37 @@ export class SSOAuthEntry extends React.Component { } @replaceableComponent("views.auth.FallbackAuthEntry") -export class FallbackAuthEntry extends React.Component { - static propTypes = { - matrixClient: PropTypes.object.isRequired, - authSessionId: PropTypes.string.isRequired, - loginType: PropTypes.string.isRequired, - submitAuthDict: PropTypes.func.isRequired, - errorText: PropTypes.string, - onPhaseChange: PropTypes.func.isRequired, - }; +export class FallbackAuthEntry extends React.Component { + private popupWindow: Window; + private fallbackButton = createRef(); constructor(props) { super(props); // we have to make the user click a button, as browsers will block // the popup if we open it immediately. - this._popupWindow = null; - window.addEventListener("message", this._onReceiveMessage); - - this._fallbackButton = createRef(); + this.popupWindow = null; + window.addEventListener("message", this.onReceiveMessage); } - componentDidMount() { this.props.onPhaseChange(DEFAULT_PHASE); } componentWillUnmount() { - window.removeEventListener("message", this._onReceiveMessage); - if (this._popupWindow) { - this._popupWindow.close(); + window.removeEventListener("message", this.onReceiveMessage); + if (this.popupWindow) { + this.popupWindow.close(); } } - focus = () => { - if (this._fallbackButton.current) { - this._fallbackButton.current.focus(); + public focus = () => { + if (this.fallbackButton.current) { + this.fallbackButton.current.focus(); } }; - _onShowFallbackClick = e => { + private onShowFallbackClick = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); @@ -763,10 +806,10 @@ export class FallbackAuthEntry extends React.Component { this.props.loginType, this.props.authSessionId, ); - this._popupWindow = window.open(url, "_blank"); + this.popupWindow = window.open(url, "_blank"); }; - _onReceiveMessage = event => { + private onReceiveMessage = (event: MessageEvent) => { if ( event.data === "authDone" && event.origin === this.props.matrixClient.getHomeserverUrl() @@ -786,27 +829,31 @@ export class FallbackAuthEntry extends React.Component { } return ( ); } } -const AuthEntryComponents = [ - PasswordAuthEntry, - RecaptchaAuthEntry, - EmailIdentityAuthEntry, - MsisdnAuthEntry, - TermsAuthEntry, - SSOAuthEntry, -]; - -export default function getEntryComponentForLoginType(loginType) { - for (const c of AuthEntryComponents) { - if (c.LOGIN_TYPE === loginType || c.UNSTABLE_LOGIN_TYPE === loginType) { - return c; - } +export default function getEntryComponentForLoginType(loginType: AuthType): typeof React.Component { + switch (loginType) { + case AuthType.Password: + return PasswordAuthEntry; + case AuthType.Recaptcha: + return RecaptchaAuthEntry; + case AuthType.Email: + return EmailIdentityAuthEntry; + case AuthType.Msisdn: + return MsisdnAuthEntry; + case AuthType.Terms: + return TermsAuthEntry; + case AuthType.Sso: + case AuthType.SsoUnstable: + return SSOAuthEntry; + default: + return FallbackAuthEntry; } - return FallbackAuthEntry; } diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index f15538eabf..42aef24086 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -119,7 +119,10 @@ export default class DecoratedRoomAvatar extends React.PureComponent +Copyright 2018-2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,14 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState, useEffect} from 'react'; -import PropTypes from 'prop-types'; +import React, { useState, useEffect, ChangeEvent, MouseEvent } from 'react'; import * as sdk from '../../../index'; import SyntaxHighlight from '../elements/SyntaxHighlight'; import { _t } from '../../../languageHandler'; import Field from "../elements/Field"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {useEventEmitter} from "../../../hooks/useEventEmitter"; +import { useEventEmitter } from "../../../hooks/useEventEmitter"; import { PHASE_UNSENT, @@ -30,27 +30,33 @@ import { PHASE_DONE, PHASE_STARTED, PHASE_CANCELLED, + VerificationRequest, } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; -import WidgetStore from "../../../stores/WidgetStore"; -import {UPDATE_EVENT} from "../../../stores/AsyncStore"; -import {SETTINGS} from "../../../settings/Settings"; -import SettingsStore, {LEVEL_ORDER} from "../../../settings/SettingsStore"; +import WidgetStore, { IApp } from "../../../stores/WidgetStore"; +import { UPDATE_EVENT } from "../../../stores/AsyncStore"; +import { SETTINGS } from "../../../settings/Settings"; +import SettingsStore, { LEVEL_ORDER } from "../../../settings/SettingsStore"; import Modal from "../../../Modal"; import ErrorDialog from "./ErrorDialog"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {Room} from "matrix-js-sdk/src/models/room"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { SettingLevel } from '../../../settings/SettingLevel'; -class GenericEditor extends React.PureComponent { - // static propTypes = {onBack: PropTypes.func.isRequired}; +interface IGenericEditorProps { + onBack: () => void; +} - constructor(props) { - super(props); - this._onChange = this._onChange.bind(this); - this.onBack = this.onBack.bind(this); - } +interface IGenericEditorState { + message?: string; + [inputId: string]: boolean | string; +} - onBack() { +abstract class GenericEditor< + P extends IGenericEditorProps = IGenericEditorProps, + S extends IGenericEditorState = IGenericEditorState, +> extends React.PureComponent { + protected onBack = () => { if (this.state.message) { this.setState({ message: null }); } else { @@ -58,47 +64,60 @@ class GenericEditor extends React.PureComponent { } } - _onChange(e) { + protected onChange = (e: ChangeEvent) => { + // @ts-ignore: Unsure how to convince TS this is okay when the state + // type can be extended. this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value}); } - _buttons() { + protected abstract send(); + + protected buttons(): React.ReactNode { return
- { !this.state.message && } + { !this.state.message && }
; } - textInput(id, label) { + protected textInput(id: string, label: string): React.ReactNode { return ; } } -export class SendCustomEvent extends GenericEditor { - static getLabel() { return _t('Send Custom Event'); } - - static propTypes = { - onBack: PropTypes.func.isRequired, - room: PropTypes.instanceOf(Room).isRequired, - forceStateEvent: PropTypes.bool, - forceGeneralEvent: PropTypes.bool, - inputs: PropTypes.object, +interface ISendCustomEventProps extends IGenericEditorProps { + room: Room; + forceStateEvent?: boolean; + forceGeneralEvent?: boolean; + inputs?: { + eventType?: string; + stateKey?: string; + evContent?: string; }; +} + +interface ISendCustomEventState extends IGenericEditorState { + isStateEvent: boolean; + eventType: string; + stateKey: string; + evContent: string; +} + +export class SendCustomEvent extends GenericEditor { + static getLabel() { return _t('Send Custom Event'); } static contextType = MatrixClientContext; constructor(props) { super(props); - this._send = this._send.bind(this); const {eventType, stateKey, evContent} = Object.assign({ eventType: '', @@ -115,7 +134,7 @@ export class SendCustomEvent extends GenericEditor { }; } - send(content) { + private doSend(content: object): Promise { const cli = this.context; if (this.state.isStateEvent) { return cli.sendStateEvent(this.props.room.roomId, this.state.eventType, content, this.state.stateKey); @@ -124,7 +143,7 @@ export class SendCustomEvent extends GenericEditor { } } - async _send() { + protected send = async () => { if (this.state.eventType === '') { this.setState({ message: _t('You must specify an event type!') }); return; @@ -133,7 +152,7 @@ export class SendCustomEvent extends GenericEditor { let message; try { const content = JSON.parse(this.state.evContent); - await this.send(content); + await this.doSend(content); message = _t('Event sent!'); } catch (e) { message = _t('Failed to send custom event.') + ' (' + e.toString() + ')'; @@ -147,7 +166,7 @@ export class SendCustomEvent extends GenericEditor {
{ this.state.message }
- { this._buttons() } + { this.buttons() }
; } @@ -163,35 +182,51 @@ export class SendCustomEvent extends GenericEditor {
+ autoComplete="off" value={this.state.evContent} onChange={this.onChange} element="textarea" />
- { !this.state.message && } + { !this.state.message && } { showTglFlip &&
- -
}
; } } -class SendAccountData extends GenericEditor { - static getLabel() { return _t('Send Account Data'); } - - static propTypes = { - room: PropTypes.instanceOf(Room).isRequired, - isRoomAccountData: PropTypes.bool, - forceMode: PropTypes.bool, - inputs: PropTypes.object, +interface ISendAccountDataProps extends IGenericEditorProps { + room: Room; + isRoomAccountData: boolean; + forceMode: boolean; + inputs?: { + eventType?: string; + evContent?: string; }; +} + +interface ISendAccountDataState extends IGenericEditorState { + isRoomAccountData: boolean; + eventType: string; + evContent: string; +} + +class SendAccountData extends GenericEditor { + static getLabel() { return _t('Send Account Data'); } static contextType = MatrixClientContext; constructor(props) { super(props); - this._send = this._send.bind(this); const {eventType, evContent} = Object.assign({ eventType: '', @@ -206,7 +241,7 @@ class SendAccountData extends GenericEditor { }; } - send(content) { + private doSend(content: object): Promise { const cli = this.context; if (this.state.isRoomAccountData) { return cli.setRoomAccountData(this.props.room.roomId, this.state.eventType, content); @@ -214,7 +249,7 @@ class SendAccountData extends GenericEditor { return cli.setAccountData(this.state.eventType, content); } - async _send() { + protected send = async () => { if (this.state.eventType === '') { this.setState({ message: _t('You must specify an event type!') }); return; @@ -223,7 +258,7 @@ class SendAccountData extends GenericEditor { let message; try { const content = JSON.parse(this.state.evContent); - await this.send(content); + await this.doSend(content); message = _t('Event sent!'); } catch (e) { message = _t('Failed to send custom event.') + ' (' + e.toString() + ')'; @@ -237,7 +272,7 @@ class SendAccountData extends GenericEditor {
{ this.state.message }
- { this._buttons() } + { this.buttons() }
; } @@ -247,14 +282,23 @@ class SendAccountData extends GenericEditor {
+ autoComplete="off" value={this.state.evContent} onChange={this.onChange} element="textarea" />
- { !this.state.message && } + { !this.state.message && } { !this.state.message &&
- -
}
; @@ -264,17 +308,22 @@ class SendAccountData extends GenericEditor { const INITIAL_LOAD_TILES = 20; const LOAD_TILES_STEP_SIZE = 50; -class FilteredList extends React.PureComponent { - static propTypes = { - children: PropTypes.any, - query: PropTypes.string, - onChange: PropTypes.func, - }; +interface IFilteredListProps { + children: React.ReactElement[]; + query: string; + onChange: (value: string) => void; +} - static filterChildren(children, query) { +interface IFilteredListState { + filteredChildren: React.ReactElement[]; + truncateAt: number; +} + +class FilteredList extends React.PureComponent { + static filterChildren(children: React.ReactElement[], query: string): React.ReactElement[] { if (!query) return children; const lcQuery = query.toLowerCase(); - return children.filter((child) => child.key.toLowerCase().includes(lcQuery)); + return children.filter((child) => child.key.toString().toLowerCase().includes(lcQuery)); } constructor(props) { @@ -295,27 +344,27 @@ class FilteredList extends React.PureComponent { }); } - showAll = () => { + private showAll = () => { this.setState({ truncateAt: this.state.truncateAt + LOAD_TILES_STEP_SIZE, }); }; - createOverflowElement = (overflowCount: number, totalCount: number) => { + private createOverflowElement = (overflowCount: number, totalCount: number) => { return ; }; - onQuery = (ev) => { + private onQuery = (ev: ChangeEvent) => { if (this.props.onChange) this.props.onChange(ev.target.value); }; - getChildren = (start: number, end: number) => { + private getChildren = (start: number, end: number): React.ReactElement[] => { return this.state.filteredChildren.slice(start, end); }; - getChildCount = (): number => { + private getChildCount = (): number => { return this.state.filteredChildren.length; }; @@ -336,28 +385,31 @@ class FilteredList extends React.PureComponent { } } -class RoomStateExplorer extends React.PureComponent { - static getLabel() { return _t('Explore Room State'); } +interface IExplorerProps { + room: Room; + onBack: () => void; +} - static propTypes = { - onBack: PropTypes.func.isRequired, - room: PropTypes.instanceOf(Room).isRequired, - }; +interface IRoomStateExplorerState { + eventType?: string; + event?: MatrixEvent; + editing: boolean; + queryEventType: string; + queryStateKey: string; +} + +class RoomStateExplorer extends React.PureComponent { + static getLabel() { return _t('Explore Room State'); } static contextType = MatrixClientContext; - roomStateEvents: Map>; + private roomStateEvents: Map>; constructor(props) { super(props); this.roomStateEvents = this.props.room.currentState.events; - this.onBack = this.onBack.bind(this); - this.editEv = this.editEv.bind(this); - this.onQueryEventType = this.onQueryEventType.bind(this); - this.onQueryStateKey = this.onQueryStateKey.bind(this); - this.state = { eventType: null, event: null, @@ -368,19 +420,19 @@ class RoomStateExplorer extends React.PureComponent { }; } - browseEventType(eventType) { + private browseEventType(eventType: string) { return () => { this.setState({ eventType }); }; } - onViewSourceClick(event) { + private onViewSourceClick(event: MatrixEvent) { return () => { this.setState({ event }); }; } - onBack() { + private onBack = () => { if (this.state.editing) { this.setState({ editing: false }); } else if (this.state.event) { @@ -392,15 +444,15 @@ class RoomStateExplorer extends React.PureComponent { } } - editEv() { + private editEv = () => { this.setState({ editing: true }); } - onQueryEventType(filterEventType) { + private onQueryEventType = (filterEventType: string) => { this.setState({ queryEventType: filterEventType }); } - onQueryStateKey(filterStateKey) { + private onQueryStateKey = (filterStateKey: string) => { this.setState({ queryStateKey: filterStateKey }); } @@ -472,24 +524,22 @@ class RoomStateExplorer extends React.PureComponent { } } -class AccountDataExplorer extends React.PureComponent { - static getLabel() { return _t('Explore Account Data'); } +interface IAccountDataExplorerState { + isRoomAccountData: boolean; + event?: MatrixEvent; + editing: boolean; + queryEventType: string; + [inputId: string]: boolean | string; +} - static propTypes = { - onBack: PropTypes.func.isRequired, - room: PropTypes.instanceOf(Room).isRequired, - }; +class AccountDataExplorer extends React.PureComponent { + static getLabel() { return _t('Explore Account Data'); } static contextType = MatrixClientContext; constructor(props) { super(props); - this.onBack = this.onBack.bind(this); - this.editEv = this.editEv.bind(this); - this._onChange = this._onChange.bind(this); - this.onQueryEventType = this.onQueryEventType.bind(this); - this.state = { isRoomAccountData: false, event: null, @@ -499,20 +549,20 @@ class AccountDataExplorer extends React.PureComponent { }; } - getData() { + private getData(): Record { if (this.state.isRoomAccountData) { return this.props.room.accountData; } return this.context.store.accountData; } - onViewSourceClick(event) { + private onViewSourceClick(event: MatrixEvent) { return () => { this.setState({ event }); }; } - onBack() { + private onBack = () => { if (this.state.editing) { this.setState({ editing: false }); } else if (this.state.event) { @@ -522,15 +572,15 @@ class AccountDataExplorer extends React.PureComponent { } } - _onChange(e) { + private onChange = (e: ChangeEvent) => { this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value}); } - editEv() { + private editEv = () => { this.setState({ editing: true }); } - onQueryEventType(queryEventType) { + private onQueryEventType = (queryEventType: string) => { this.setState({ queryEventType }); } @@ -580,30 +630,39 @@ class AccountDataExplorer extends React.PureComponent {
- { !this.state.message &&
- -
} +
+ +
; } } -class ServersInRoomList extends React.PureComponent { +interface IServersInRoomListState { + query: string; +} + +class ServersInRoomList extends React.PureComponent { static getLabel() { return _t('View Servers in Room'); } - static propTypes = { - onBack: PropTypes.func.isRequired, - room: PropTypes.instanceOf(Room).isRequired, - }; - static contextType = MatrixClientContext; + private servers: React.ReactElement[]; + constructor(props) { super(props); const room = this.props.room; - const servers = new Set(); + const servers = new Set(); room.currentState.getStateEvents("m.room.member").forEach(ev => servers.add(ev.getSender().split(":")[1])); this.servers = Array.from(servers).map(s => + @@ -1091,7 +1179,11 @@ class SettingsExplorer extends React.Component { } } -const Entries = [ +type DevtoolsDialogEntry = React.JSXElementConstructor & { + getLabel: () => string; +}; + +const Entries: DevtoolsDialogEntry[] = [ SendCustomEvent, RoomStateExplorer, SendAccountData, @@ -1102,43 +1194,36 @@ const Entries = [ SettingsExplorer, ]; -@replaceableComponent("views.dialogs.DevtoolsDialog") -export default class DevtoolsDialog extends React.PureComponent { - static propTypes = { - roomId: PropTypes.string.isRequired, - onFinished: PropTypes.func.isRequired, - }; +interface IProps { + roomId: string; + onFinished: (finished: boolean) => void; +} +interface IState { + mode?: DevtoolsDialogEntry; +} + +@replaceableComponent("views.dialogs.DevtoolsDialog") +export default class DevtoolsDialog extends React.PureComponent { constructor(props) { super(props); - this.onBack = this.onBack.bind(this); - this.onCancel = this.onCancel.bind(this); this.state = { mode: null, }; } - componentWillUnmount() { - this._unmounted = true; - } - - _setMode(mode) { + private setMode(mode: DevtoolsDialogEntry) { return () => { this.setState({ mode }); }; } - onBack() { - if (this.prevMode) { - this.setState({ mode: this.prevMode }); - this.prevMode = null; - } else { - this.setState({ mode: null }); - } + private onBack = () => { + this.setState({ mode: null }); } - onCancel() { + private onCancel = () => { this.props.onFinished(false); } @@ -1165,7 +1250,7 @@ export default class DevtoolsDialog extends React.PureComponent {
{ Entries.map((Entry) => { const label = Entry.getLabel(); - const onClick = this._setMode(Entry); + const onClick = this.setMode(Entry); return ; }) }
diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index ec9c71ccbe..b00b45bf60 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -47,10 +47,18 @@ import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import {replaceableComponent} from "../../../utils/replaceableComponent"; import {mediaFromMxc} from "../../../customisations/Media"; import {getAddressType} from "../../../UserAddress"; +import BaseAvatar from '../avatars/BaseAvatar'; +import AccessibleButton from '../elements/AccessibleButton'; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ +interface IRecentUser { + userId: string, + user: RoomMember, + lastActive: number, +} + export const KIND_DM = "dm"; export const KIND_INVITE = "invite"; export const KIND_CALL_TRANSFER = "call_transfer"; @@ -61,43 +69,41 @@ const INCREMENT_ROOMS_SHOWN = 5; // Number of rooms to add when 'show more' is c // This is the interface that is expected by various components in this file. It is a bit // awkward because it also matches the RoomMember class from the js-sdk with some extra support // for 3PIDs/email addresses. -// -// XXX: We should use TypeScript interfaces instead of this weird "abstract" class. -class Member { +abstract class Member { /** * The display name of this Member. For users this should be their profile's display * name or user ID if none set. For 3PIDs this should be the 3PID address (email). */ - get name(): string { throw new Error("Member class not implemented"); } + public abstract get name(): string; /** * The ID of this Member. For users this should be their user ID. For 3PIDs this should * be the 3PID address (email). */ - get userId(): string { throw new Error("Member class not implemented"); } + public abstract get userId(): string; /** * Gets the MXC URL of this Member's avatar. For users this should be their profile's * avatar MXC URL or null if none set. For 3PIDs this should always be null. */ - getMxcAvatarUrl(): string { throw new Error("Member class not implemented"); } + public abstract getMxcAvatarUrl(): string; } class DirectoryMember extends Member { - _userId: string; - _displayName: string; - _avatarUrl: string; + private readonly _userId: string; + private readonly displayName: string; + private readonly avatarUrl: string; constructor(userDirResult: {user_id: string, display_name: string, avatar_url: string}) { super(); this._userId = userDirResult.user_id; - this._displayName = userDirResult.display_name; - this._avatarUrl = userDirResult.avatar_url; + this.displayName = userDirResult.display_name; + this.avatarUrl = userDirResult.avatar_url; } // These next class members are for the Member interface get name(): string { - return this._displayName || this._userId; + return this.displayName || this._userId; } get userId(): string { @@ -105,32 +111,32 @@ class DirectoryMember extends Member { } getMxcAvatarUrl(): string { - return this._avatarUrl; + return this.avatarUrl; } } class ThreepidMember extends Member { - _id: string; + private readonly id: string; constructor(id: string) { super(); - this._id = id; + this.id = id; } // This is a getter that would be falsey on all other implementations. Until we have // better type support in the react-sdk we can use this trick to determine the kind // of 3PID we're dealing with, if any. get isEmail(): boolean { - return this._id.includes('@'); + return this.id.includes('@'); } // These next class members are for the Member interface get name(): string { - return this._id; + return this.id; } get userId(): string { - return this._id; + return this.id; } getMxcAvatarUrl(): string { @@ -140,11 +146,11 @@ class ThreepidMember extends Member { interface IDMUserTileProps { member: RoomMember; - onRemove: (RoomMember) => any; + onRemove(member: RoomMember): void; } class DMUserTile extends React.PureComponent { - _onRemove = (e) => { + private onRemove = (e) => { // Stop the browser from highlighting text e.preventDefault(); e.stopPropagation(); @@ -153,9 +159,6 @@ class DMUserTile extends React.PureComponent { }; render() { - const BaseAvatar = sdk.getComponent("views.avatars.BaseAvatar"); - const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); - const avatarSize = 20; const avatar = this.props.member.isEmail ? { closeButton = ( {_t('Remove')} { interface IDMRoomTileProps { member: RoomMember; lastActiveTs: number; - onToggle: (RoomMember) => any; + onToggle(member: RoomMember): void; highlightWord: string; isSelected: boolean; } class DMRoomTile extends React.PureComponent { - _onClick = (e) => { + private onClick = (e) => { // Stop the browser from highlighting text e.preventDefault(); e.stopPropagation(); @@ -215,7 +218,7 @@ class DMRoomTile extends React.PureComponent { this.props.onToggle(this.props.member); }; - _highlightName(str: string) { + private highlightName(str: string) { if (!this.props.highlightWord) return str; // We convert things to lowercase for index searching, but pull substrings from @@ -252,8 +255,6 @@ class DMRoomTile extends React.PureComponent { } render() { - const BaseAvatar = sdk.getComponent("views.avatars.BaseAvatar"); - let timestamp = null; if (this.props.lastActiveTs) { const humanTs = humanizeTime(this.props.lastActiveTs); @@ -291,13 +292,13 @@ class DMRoomTile extends React.PureComponent { const caption = this.props.member.isEmail ? _t("Invite by email") - : this._highlightName(this.props.member.userId); + : this.highlightName(this.props.member.userId); return ( -
+
{stackedAvatar} -
{this._highlightName(this.props.member.name)}
+
{this.highlightName(this.props.member.name)}
{caption}
{timestamp} @@ -308,7 +309,7 @@ class DMRoomTile extends React.PureComponent { interface IInviteDialogProps { // Takes an array of user IDs/emails to invite. - onFinished: (toInvite?: string[]) => any; + onFinished: (toInvite?: string[]) => void; // The kind of invite being performed. Assumed to be KIND_DM if // not provided. @@ -349,8 +350,9 @@ export default class InviteDialog extends React.PureComponent(); + private unmounted = false; constructor(props) { super(props); @@ -378,7 +380,7 @@ export default class InviteDialog extends React.PureComponent { this.setState({consultFirst: ev.target.checked}); } - static buildRecents(excludedTargetIds: Set): {userId: string, user: RoomMember, lastActive: number}[] { + public static buildRecents(excludedTargetIds: Set): IRecentUser[] { const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals(); // map of userId => js-sdk Room // Also pull in all the rooms tagged as DefaultTagID.DM so we don't miss anything. Sometimes the @@ -467,7 +471,7 @@ export default class InviteDialog extends React.PureComponent): {userId: string, user: RoomMember}[] { + private buildSuggestions(excludedTargetIds: Set): {userId: string, user: RoomMember}[] { const maxConsideredMembers = 200; const joinedRooms = MatrixClientPeg.get().getRooms() .filter(r => r.getMyMembership() === 'join' && r.getJoinedMemberCount() <= maxConsideredMembers); @@ -585,7 +589,7 @@ export default class InviteDialog extends React.PureComponent ({userId: m.member.userId, user: m.member})); } - _shouldAbortAfterInviteError(result): boolean { + private shouldAbortAfterInviteError(result): boolean { const failedUsers = Object.keys(result.states).filter(a => result.states[a] === 'error'); if (failedUsers.length > 0) { console.log("Failed to invite users: ", result); @@ -600,7 +604,7 @@ export default class InviteDialog extends React.PureComponent { + private startDm = async () => { this.setState({busy: true}); const client = MatrixClientPeg.get(); - const targets = this._convertFilter(); + const targets = this.convertFilter(); const targetIds = targets.map(t => t.userId); // Check if there is already a DM with these people and reuse it if possible. @@ -694,11 +698,11 @@ export default class InviteDialog extends React.PureComponent { + private inviteUsers = async () => { const startTime = CountlyAnalytics.getTimestamp(); this.setState({busy: true}); - this._convertFilter(); - const targets = this._convertFilter(); + this.convertFilter(); + const targets = this.convertFilter(); const targetIds = targets.map(t => t.userId); const cli = MatrixClientPeg.get(); @@ -715,7 +719,7 @@ export default class InviteDialog extends React.PureComponent { - this._convertFilter(); - const targets = this._convertFilter(); + private transferCall = async () => { + this.convertFilter(); + const targets = this.convertFilter(); const targetIds = targets.map(t => t.userId); if (targetIds.length > 1) { this.setState({ @@ -790,26 +794,26 @@ export default class InviteDialog extends React.PureComponent { + private onKeyDown = (e) => { if (this.state.busy) return; const value = e.target.value.trim(); const hasModifiers = e.ctrlKey || e.shiftKey || e.metaKey; if (!value && this.state.targets.length > 0 && e.key === Key.BACKSPACE && !hasModifiers) { // when the field is empty and the user hits backspace remove the right-most target e.preventDefault(); - this._removeMember(this.state.targets[this.state.targets.length - 1]); + this.removeMember(this.state.targets[this.state.targets.length - 1]); } else if (value && e.key === Key.ENTER && !hasModifiers) { // when the user hits enter with something in their field try to convert it e.preventDefault(); - this._convertFilter(); + this.convertFilter(); } else if (value && e.key === Key.SPACE && !hasModifiers && value.includes("@") && !value.includes(" ")) { // when the user hits space and their input looks like an e-mail/MXID then try to convert it e.preventDefault(); - this._convertFilter(); + this.convertFilter(); } }; - _updateSuggestions = async (term) => { + private updateSuggestions = async (term) => { MatrixClientPeg.get().searchUserDirectory({term}).then(async r => { if (term !== this.state.filterText) { // Discard the results - we were probably too slow on the server-side to make @@ -918,30 +922,30 @@ export default class InviteDialog extends React.PureComponent { + private updateFilter = (e) => { const term = e.target.value; this.setState({filterText: term}); // Debounce server lookups to reduce spam. We don't clear the existing server // results because they might still be vaguely accurate, likewise for races which // could happen here. - if (this._debounceTimer) { - clearTimeout(this._debounceTimer); + if (this.debounceTimer) { + clearTimeout(this.debounceTimer); } - this._debounceTimer = setTimeout(() => { - this._updateSuggestions(term); + this.debounceTimer = setTimeout(() => { + this.updateSuggestions(term); }, 150); // 150ms debounce (human reaction time + some) }; - _showMoreRecents = () => { + private showMoreRecents = () => { this.setState({numRecentsShown: this.state.numRecentsShown + INCREMENT_ROOMS_SHOWN}); }; - _showMoreSuggestions = () => { + private showMoreSuggestions = () => { this.setState({numSuggestionsShown: this.state.numSuggestionsShown + INCREMENT_ROOMS_SHOWN}); }; - _toggleMember = (member: Member) => { + private toggleMember = (member: Member) => { if (!this.state.busy) { let filterText = this.state.filterText; const targets = this.state.targets.map(t => t); // cheap clone for mutation @@ -954,13 +958,13 @@ export default class InviteDialog extends React.PureComponent { + private removeMember = (member: Member) => { const targets = this.state.targets.map(t => t); // cheap clone for mutation const idx = targets.indexOf(member); if (idx >= 0) { @@ -968,12 +972,12 @@ export default class InviteDialog extends React.PureComponent { + private onPaste = async (e) => { if (this.state.filterText) { // if the user has already typed something, just let them // paste normally. @@ -1027,6 +1031,7 @@ export default class InviteDialog extends React.PureComponent 0) { const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); @@ -1043,17 +1048,17 @@ export default class InviteDialog extends React.PureComponent { + private onClickInputArea = (e) => { // Stop the browser from highlighting text e.preventDefault(); e.stopPropagation(); - if (this._editorRef && this._editorRef.current) { - this._editorRef.current.focus(); + if (this.editorRef && this.editorRef.current) { + this.editorRef.current.focus(); } }; - _onUseDefaultIdentityServerClick = (e) => { + private onUseDefaultIdentityServerClick = (e) => { e.preventDefault(); // Update the IS in account data. Actually using it may trigger terms. @@ -1062,21 +1067,21 @@ export default class InviteDialog extends React.PureComponent { + private onManageSettingsClick = (e) => { e.preventDefault(); dis.fire(Action.ViewUserSettings); this.props.onFinished(); }; - _onCommunityInviteClick = (e) => { + private onCommunityInviteClick = (e) => { this.props.onFinished(); showCommunityInviteDialog(CommunityPrototypeStore.instance.getSelectedCommunityId()); }; - _renderSection(kind: "recents"|"suggestions") { + private renderSection(kind: "recents"|"suggestions") { let sourceMembers = kind === 'recents' ? this.state.recents : this.state.suggestions; let showNum = kind === 'recents' ? this.state.numRecentsShown : this.state.numSuggestionsShown; - const showMoreFn = kind === 'recents' ? this._showMoreRecents.bind(this) : this._showMoreSuggestions.bind(this); + const showMoreFn = kind === 'recents' ? this.showMoreRecents.bind(this) : this.showMoreSuggestions.bind(this); const lastActive = (m) => kind === 'recents' ? m.lastActive : null; let sectionName = kind === 'recents' ? _t("Recent Conversations") : _t("Suggestions"); let sectionSubname = null; @@ -1156,7 +1161,7 @@ export default class InviteDialog extends React.PureComponent t.userId === r.userId)} /> @@ -1171,32 +1176,32 @@ export default class InviteDialog extends React.PureComponent ( - + )); const input = ( ); return ( -
+
{targets} {input}
); } - _renderIdentityServerWarning() { + private renderIdentityServerWarning() { if (!this.state.tryingIdentityServer || this.state.canUseIdentityServer || !SettingsStore.getValue(UIFeature.IdentityServer) ) { @@ -1214,8 +1219,8 @@ export default class InviteDialog extends React.PureComponent {sub}, - settings: sub => {sub}, + default: sub => {sub}, + settings: sub => {sub}, }, )}
); @@ -1225,7 +1230,7 @@ export default class InviteDialog extends React.PureComponentSettings.", {}, { - settings: sub => {sub}, + settings: sub => {sub}, }, )}
); @@ -1298,7 +1303,7 @@ export default class InviteDialog extends React.PureComponent{sub} ); }, @@ -1309,7 +1314,7 @@ export default class InviteDialog extends React.PureComponent; } buttonText = _t("Go"); - goButtonFn = this._startDm; + goButtonFn = this.startDm; } else if (this.props.kind === KIND_INVITE) { const room = MatrixClientPeg.get()?.getRoom(this.props.roomId); const isSpace = SettingsStore.getValue("feature_spaces") && room?.isSpaceRoom(); @@ -1348,7 +1353,7 @@ export default class InviteDialog extends React.PureComponent
); } diff --git a/src/components/views/elements/SSOButtons.tsx b/src/components/views/elements/SSOButtons.tsx index a9eb04d4ec..a531abdf83 100644 --- a/src/components/views/elements/SSOButtons.tsx +++ b/src/components/views/elements/SSOButtons.tsx @@ -112,7 +112,7 @@ interface IProps { const MAX_PER_ROW = 6; const SSOButtons: React.FC = ({matrixClient, flow, loginType, fragmentAfterLogin, primary}) => { - const providers = flow["org.matrix.msc2858.identity_providers"] || []; + const providers = flow.identity_providers || []; if (providers.length < 2) { return
{ // we need so that we're still centered. offset = Math.floor(parentBox.height - MIN_TOOLTIP_HEIGHT); } - + const width = UIStore.instance.windowWidth; const baseTop = (parentBox.top - 2 + this.props.yOffset) + window.pageYOffset; const top = baseTop + offset; - const right = window.innerWidth - parentBox.right - window.pageXOffset - 16; + const right = width - parentBox.right - window.pageXOffset - 16; const left = parentBox.right + window.pageXOffset + 6; const horizontalCenter = parentBox.right - window.pageXOffset - (parentBox.width / 2); switch (this.props.alignment) { case Alignment.Natural: - if (parentBox.right > window.innerWidth / 2) { + if (parentBox.right > width / 2) { style.right = right; style.top = top; break; diff --git a/src/components/views/elements/TooltipButton.js b/src/components/views/elements/TooltipButton.tsx similarity index 80% rename from src/components/views/elements/TooltipButton.js rename to src/components/views/elements/TooltipButton.tsx index c5ebb3b1aa..191018cc19 100644 --- a/src/components/views/elements/TooltipButton.js +++ b/src/components/views/elements/TooltipButton.tsx @@ -19,19 +19,30 @@ import React from 'react'; import * as sdk from '../../../index'; import {replaceableComponent} from "../../../utils/replaceableComponent"; -@replaceableComponent("views.elements.TooltipButton") -export default class TooltipButton extends React.Component { - state = { - hover: false, - }; +interface IProps { + helpText: string; +} - onMouseOver = () => { +interface IState { + hover: boolean; +} + +@replaceableComponent("views.elements.TooltipButton") +export default class TooltipButton extends React.Component { + constructor(props) { + super(props); + this.state = { + hover: false, + }; + } + + private onMouseOver = () => { this.setState({ hover: true, }); }; - onMouseLeave = () => { + private onMouseLeave = () => { this.setState({ hover: false, }); diff --git a/src/components/views/messages/MVoiceMessageBody.tsx b/src/components/views/messages/MVoiceMessageBody.tsx index 4a2a83465d..d65de7697a 100644 --- a/src/components/views/messages/MVoiceMessageBody.tsx +++ b/src/components/views/messages/MVoiceMessageBody.tsx @@ -71,10 +71,14 @@ export default class MVoiceMessageBody extends React.PureComponent { constructor(props, context) { super(props, context); - if (props.reactions) { - props.reactions.on("Relations.add", this.onReactionsChange); - props.reactions.on("Relations.remove", this.onReactionsChange); - props.reactions.on("Relations.redaction", this.onReactionsChange); - } - this.state = { myReactions: this.getMyReactions(), showAll: false, }; } - componentDidUpdate(prevProps) { + componentDidMount() { + const { mxEvent, reactions } = this.props; + + if (mxEvent.isBeingDecrypted() || mxEvent.shouldAttemptDecryption()) { + mxEvent.once("Event.decrypted", this.onDecrypted); + } + + if (reactions) { + reactions.on("Relations.add", this.onReactionsChange); + reactions.on("Relations.remove", this.onReactionsChange); + reactions.on("Relations.redaction", this.onReactionsChange); + } + } + + componentWillUnmount() { + const { mxEvent, reactions } = this.props; + + mxEvent.off("Event.decrypted", this.onDecrypted); + + if (reactions) { + reactions.off("Relations.add", this.onReactionsChange); + reactions.off("Relations.remove", this.onReactionsChange); + reactions.off("Relations.redaction", this.onReactionsChange); + } + } + + componentDidUpdate(prevProps: IProps) { if (prevProps.reactions !== this.props.reactions) { this.props.reactions.on("Relations.add", this.onReactionsChange); this.props.reactions.on("Relations.remove", this.onReactionsChange); @@ -102,24 +122,12 @@ export default class ReactionsRow extends React.PureComponent { } } - componentWillUnmount() { - if (this.props.reactions) { - this.props.reactions.removeListener( - "Relations.add", - this.onReactionsChange, - ); - this.props.reactions.removeListener( - "Relations.remove", - this.onReactionsChange, - ); - this.props.reactions.removeListener( - "Relations.redaction", - this.onReactionsChange, - ); - } + private onDecrypted = () => { + // Decryption changes whether the event is actionable + this.forceUpdate(); } - onReactionsChange = () => { + private onReactionsChange = () => { // TODO: Call `onHeightChanged` as needed this.setState({ myReactions: this.getMyReactions(), @@ -130,7 +138,7 @@ export default class ReactionsRow extends React.PureComponent { this.forceUpdate(); } - getMyReactions() { + private getMyReactions() { const reactions = this.props.reactions; if (!reactions) { return null; @@ -143,7 +151,7 @@ export default class ReactionsRow extends React.PureComponent { return [...myReactions.values()]; } - onShowAllClick = () => { + private onShowAllClick = () => { this.setState({ showAll: true, }); diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index b963e741a1..dc644f1009 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -36,6 +36,7 @@ import {toRightOf} from "../../structures/ContextMenu"; import {copyPlaintext} from "../../../utils/strings"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import {replaceableComponent} from "../../../utils/replaceableComponent"; +import UIStore from "../../../stores/UIStore"; @replaceableComponent("views.messages.TextualBody") export default class TextualBody extends React.Component { @@ -143,7 +144,7 @@ export default class TextualBody extends React.Component { _addCodeExpansionButton(div, pre) { // Calculate how many percent does the pre element take up. // If it's less than 30% we don't add the expansion button. - const percentageOfViewport = pre.offsetHeight / window.innerHeight * 100; + const percentageOfViewport = pre.offsetHeight / UIStore.instance.windowHeight * 100; if (percentageOfViewport < 30) return; const button = document.createElement("span"); diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index 88928290f4..937037f644 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -46,6 +46,7 @@ import WidgetContextMenu from "../context_menus/WidgetContextMenu"; import {useRoomMemberCount} from "../../../hooks/useRoomMembers"; import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; import RoomName from "../elements/RoomName"; +import UIStore from "../../../stores/UIStore"; interface IProps { room: Room; @@ -116,8 +117,8 @@ const AppRow: React.FC = ({ app, room }) => { const rect = handle.current.getBoundingClientRect(); contextMenu = ; diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 9798b282f6..6e56b9259b 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -66,6 +66,7 @@ import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRight import RoomAvatar from "../avatars/RoomAvatar"; import RoomName from "../elements/RoomName"; import {mediaFromMxc} from "../../../customisations/Media"; +import UIStore from "../../../stores/UIStore"; export interface IDevice { deviceId: string; @@ -1448,8 +1449,8 @@ const UserInfoHeader: React.FC<{ = ({ room, widgetId, onClose }) => { contextMenu = ( { return null; } const eventId = this.props.mxEvent.getId(); - if (!eventId) { - // XXX: Temporary diagnostic logging for https://github.com/vector-im/element-web/issues/11120 - console.error("EventTile attempted to get relations for an event without an ID"); - // Use event's special `toJSON` method to log key data. - console.log(JSON.stringify(this.props.mxEvent, null, 4)); - console.trace("Stacktrace for https://github.com/vector-im/element-web/issues/11120"); - } return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction"); }; diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index 7b0dadeca5..8b36341ed0 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -55,7 +55,7 @@ interface IProps { onKeyDown: (ev: React.KeyboardEvent) => void; onFocus: (ev: React.FocusEvent) => void; onBlur: (ev: React.FocusEvent) => void; - onResize: () => void; + onListCollapse?: (isExpanded: boolean) => void; resizeNotifier: ResizeNotifier; isMinimized: boolean; activeSpace: Room; @@ -404,9 +404,7 @@ export default class RoomList extends React.PureComponent { const newSublists = objectWithOnly(newLists, newListIds); const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); - this.setState({sublists, isNameFiltering}, () => { - this.props.onResize(); - }); + this.setState({sublists, isNameFiltering}); } }; @@ -537,11 +535,11 @@ export default class RoomList extends React.PureComponent { addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel} addRoomContextMenu={aesthetics.addRoomContextMenu} isMinimized={this.props.isMinimized} - onResize={this.props.onResize} showSkeleton={showSkeleton} extraTiles={extraTiles} resizeNotifier={this.props.resizeNotifier} alwaysVisible={ALWAYS_VISIBLE_TAGS.includes(orderedTagId)} + onListCollapse={this.props.onListCollapse} /> }); } diff --git a/src/components/views/rooms/RoomListNumResults.tsx b/src/components/views/rooms/RoomListNumResults.tsx index 01cbecf05d..19023e361c 100644 --- a/src/components/views/rooms/RoomListNumResults.tsx +++ b/src/components/views/rooms/RoomListNumResults.tsx @@ -14,14 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState} from "react"; +import React, {useEffect, useState} from "react"; import { _t } from "../../../languageHandler"; import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; import {useEventEmitter} from "../../../hooks/useEventEmitter"; import SpaceStore from "../../../stores/SpaceStore"; -const RoomListNumResults: React.FC = () => { +interface IProps { + onVisibilityChange?: () => void +} + +const RoomListNumResults: React.FC = ({ onVisibilityChange }) => { const [count, setCount] = useState(null); useEventEmitter(RoomListStore.instance, LISTS_UPDATE_EVENT, () => { if (RoomListStore.instance.getFirstNameFilterCondition()) { @@ -32,6 +36,12 @@ const RoomListNumResults: React.FC = () => { } }); + useEffect(() => { + if (onVisibilityChange) { + onVisibilityChange(); + } + }, [count, onVisibilityChange]); + if (typeof count !== "number") return null; return
diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index f9881d33ae..df00524b3b 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -74,11 +74,11 @@ interface IProps { addRoomLabel: string; isMinimized: boolean; tagId: TagID; - onResize: () => void; showSkeleton?: boolean; alwaysVisible?: boolean; resizeNotifier: ResizeNotifier; extraTiles?: ReactComponentElement[]; + onListCollapse?: (isExpanded: boolean) => void; // TODO: Account for https://github.com/vector-im/element-web/issues/14179 } @@ -473,7 +473,9 @@ export default class RoomSublist extends React.Component { private toggleCollapsed = () => { this.layout.isCollapsed = this.state.isExpanded; this.setState({isExpanded: !this.layout.isCollapsed}); - setImmediate(() => this.props.onResize()); // needs to happen when the DOM is updated + if (this.props.onListCollapse) { + this.props.onListCollapse(!this.layout.isCollapsed) + } }; private onHeaderKeyDown = (ev: React.KeyboardEvent) => { @@ -530,7 +532,6 @@ export default class RoomSublist extends React.Component { tiles.push(; @@ -106,9 +104,6 @@ export default class RoomTile extends React.PureComponent { this.notificationState = RoomNotificationStateStore.instance.getRoomState(this.props.room); this.roomProps = EchoChamber.forRoom(this.props.room); - if (this.props.resizeNotifier) { - this.props.resizeNotifier.on("middlePanelResized", this.onResize); - } } private countUnsentEvents(): number { @@ -123,12 +118,6 @@ export default class RoomTile extends React.PureComponent { this.forceUpdate(); // notification state changed - update }; - private onResize = () => { - if (this.showMessagePreview && !this.state.messagePreview) { - this.generatePreview(); - } - }; - private onLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { if (!room?.roomId === this.props.room.roomId) return; this.setState({hasUnsentEvents: this.countUnsentEvents() > 0}); @@ -148,7 +137,9 @@ export default class RoomTile extends React.PureComponent { } public componentDidUpdate(prevProps: Readonly, prevState: Readonly) { - if (prevProps.showMessagePreview !== this.props.showMessagePreview && this.showMessagePreview) { + const showMessageChanged = prevProps.showMessagePreview !== this.props.showMessagePreview; + const minimizedChanged = prevProps.isMinimized !== this.props.isMinimized; + if (showMessageChanged || minimizedChanged) { this.generatePreview(); } if (prevProps.room?.roomId !== this.props.room?.roomId) { @@ -208,9 +199,6 @@ export default class RoomTile extends React.PureComponent { ); this.props.room.off("Room.name", this.onRoomNameUpdate); } - if (this.props.resizeNotifier) { - this.props.resizeNotifier.off("middlePanelResized", this.onResize); - } ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate); defaultDispatcher.unregister(this.dispatcherRef); this.notificationState.off(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 82e8cf640c..3d2300b83c 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -40,7 +40,7 @@ const STICKERPICKER_Z_INDEX = 3500; const PERSISTED_ELEMENT_KEY = "stickerPicker"; @replaceableComponent("views.rooms.Stickerpicker") -export default class Stickerpicker extends React.Component { +export default class Stickerpicker extends React.PureComponent { static currentWidget; constructor(props) { @@ -341,21 +341,27 @@ export default class Stickerpicker extends React.Component { * @param {Event} ev Event that triggered the function call */ _onHideStickersClick(ev) { - this.setState({showStickers: false}); + if (this.state.showStickers) { + this.setState({showStickers: false}); + } } /** * Called when the window is resized */ _onResize() { - this.setState({showStickers: false}); + if (this.state.showStickers) { + this.setState({showStickers: false}); + } } /** * The stickers picker was hidden */ _onFinished() { - this.setState({showStickers: false}); + if (this.state.showStickers) { + this.setState({showStickers: false}); + } } /** diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.tsx similarity index 76% rename from src/components/views/rooms/WhoIsTypingTile.js rename to src/components/views/rooms/WhoIsTypingTile.tsx index a25b43fc3a..21afbc30f4 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.tsx @@ -16,36 +16,44 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; +import Room from "matrix-js-sdk/src/models/room"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; + import * as WhoIsTyping from '../../../WhoIsTyping'; import Timer from '../../../utils/Timer'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import MemberAvatar from '../avatars/MemberAvatar'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; + +interface IProps { + // the room this statusbar is representing. + room: Room; + onShown?: () => void; + onHidden?: () => void; + // Number of names to display in typing indication. E.g. set to 3, will + // result in "X, Y, Z and 100 others are typing." + whoIsTypingLimit: number; +} + +interface IState { + usersTyping: RoomMember[]; + // a map with userid => Timer to delay + // hiding the "x is typing" message for a + // user so hiding it can coincide + // with the sent message by the other side + // resulting in less timeline jumpiness + delayedStopTypingTimers: Record; +} @replaceableComponent("views.rooms.WhoIsTypingTile") -export default class WhoIsTypingTile extends React.Component { - static propTypes = { - // the room this statusbar is representing. - room: PropTypes.object.isRequired, - onShown: PropTypes.func, - onHidden: PropTypes.func, - // Number of names to display in typing indication. E.g. set to 3, will - // result in "X, Y, Z and 100 others are typing." - whoIsTypingLimit: PropTypes.number, - }; - +export default class WhoIsTypingTile extends React.Component { static defaultProps = { whoIsTypingLimit: 3, }; state = { usersTyping: WhoIsTyping.usersTypingApartFromMe(this.props.room), - // a map with userid => Timer to delay - // hiding the "x is typing" message for a - // user so hiding it can coincide - // with the sent message by the other side - // resulting in less timeline jumpiness delayedStopTypingTimers: {}, }; @@ -71,37 +79,39 @@ export default class WhoIsTypingTile extends React.Component { client.removeListener("RoomMember.typing", this.onRoomMemberTyping); client.removeListener("Room.timeline", this.onRoomTimeline); } - Object.values(this.state.delayedStopTypingTimers).forEach((t) => t.abort()); + Object.values(this.state.delayedStopTypingTimers).forEach((t) => (t as Timer).abort()); } - _isVisible(state) { + private _isVisible(state: IState): boolean { return state.usersTyping.length !== 0 || Object.keys(state.delayedStopTypingTimers).length !== 0; } - isVisible = () => { + public isVisible = (): boolean => { return this._isVisible(this.state); }; - onRoomTimeline = (event, room) => { + private onRoomTimeline = (event: MatrixEvent, room: Room): void => { if (room?.roomId === this.props.room?.roomId) { const userId = event.getSender(); // remove user from usersTyping const usersTyping = this.state.usersTyping.filter((m) => m.userId !== userId); - this.setState({usersTyping}); + if (usersTyping.length !== this.state.usersTyping.length) { + this.setState({usersTyping}); + } // abort timer if any - this._abortUserTimer(userId); + this.abortUserTimer(userId); } }; - onRoomMemberTyping = (ev, member) => { + private onRoomMemberTyping = (): void => { const usersTyping = WhoIsTyping.usersTypingApartFromMeAndIgnored(this.props.room); this.setState({ - delayedStopTypingTimers: this._updateDelayedStopTypingTimers(usersTyping), + delayedStopTypingTimers: this.updateDelayedStopTypingTimers(usersTyping), usersTyping, }); }; - _updateDelayedStopTypingTimers(usersTyping) { + private updateDelayedStopTypingTimers(usersTyping: RoomMember[]): Record { const usersThatStoppedTyping = this.state.usersTyping.filter((a) => { return !usersTyping.some((b) => a.userId === b.userId); }); @@ -129,7 +139,7 @@ export default class WhoIsTypingTile extends React.Component { delayedStopTypingTimers[m.userId] = timer; timer.start(); timer.finished().then( - () => this._removeUserTimer(m.userId), // on elapsed + () => this.removeUserTimer(m.userId), // on elapsed () => {/* aborted */}, ); } @@ -139,15 +149,15 @@ export default class WhoIsTypingTile extends React.Component { return delayedStopTypingTimers; } - _abortUserTimer(userId) { + private abortUserTimer(userId: string): void { const timer = this.state.delayedStopTypingTimers[userId]; if (timer) { timer.abort(); - this._removeUserTimer(userId); + this.removeUserTimer(userId); } } - _removeUserTimer(userId) { + private removeUserTimer(userId: string): void { const timer = this.state.delayedStopTypingTimers[userId]; if (timer) { const delayedStopTypingTimers = Object.assign({}, this.state.delayedStopTypingTimers); @@ -156,7 +166,7 @@ export default class WhoIsTypingTile extends React.Component { } } - _renderTypingIndicatorAvatars(users, limit) { + private renderTypingIndicatorAvatars(users: RoomMember[], limit: number): JSX.Element[] { let othersCount = 0; if (users.length > limit) { othersCount = users.length - limit + 1; @@ -210,7 +220,7 @@ export default class WhoIsTypingTile extends React.Component { return (
  • - { this._renderTypingIndicatorAvatars(usersTyping, this.props.whoIsTypingLimit) } + { this.renderTypingIndicatorAvatars(usersTyping, this.props.whoIsTypingLimit) }
    { typingString } diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx index 411b0f9b5e..eb63b21f0e 100644 --- a/src/components/views/spaces/SpacePanel.tsx +++ b/src/components/views/spaces/SpacePanel.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState} from "react"; +import React, { useEffect, useState } from "react"; import classNames from "classnames"; import {Room} from "matrix-js-sdk/src/models/room"; @@ -127,6 +127,12 @@ const SpacePanel = () => { const [invites, spaces, activeSpace] = useSpaces(); const [isPanelCollapsed, setPanelCollapsed] = useState(true); + useEffect(() => { + if (!isPanelCollapsed && menuDisplayed) { + closeMenu(); + } + }, [isPanelCollapsed]); // eslint-disable-line react-hooks/exhaustive-deps + const newClasses = classNames("mx_SpaceButton_new", { mx_SpaceButton_newCancel: menuDisplayed, }); @@ -235,18 +241,15 @@ const SpacePanel = () => { className={newClasses} tooltip={menuDisplayed ? _t("Cancel") : _t("Create a space")} onClick={menuDisplayed ? closeMenu : () => { - openMenu(); if (!isPanelCollapsed) setPanelCollapsed(true); + openMenu(); }} isNarrow={isPanelCollapsed} /> { - setPanelCollapsed(!isPanelCollapsed); - if (menuDisplayed) closeMenu(); - }} + onClick={() => setPanelCollapsed(!isPanelCollapsed)} title={expandCollapseButtonTitle} /> { contextMenu } diff --git a/src/createRoom.ts b/src/createRoom.ts index 75219ef656..c6507b1380 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -34,6 +34,7 @@ import { isJoinedOrNearlyJoined } from "./utils/membership"; import { VIRTUAL_ROOM_EVENT_TYPE } from "./CallHandler"; import SpaceStore from "./stores/SpaceStore"; import { makeSpaceParentEvent } from "./utils/space"; +import { Action } from "./dispatcher/actions" // we define a number of interfaces which take their names from the js-sdk /* eslint-disable camelcase */ @@ -243,7 +244,8 @@ export default function createRoom(opts: IOpts): Promise { // We also failed to join the room (this sets joining to false in RoomViewStore) dis.dispatch({ - action: 'join_room_error', + action: Action.JoinRoomError, + roomId, }); console.error("Failed to create room " + roomId + " " + err); let description = _t("Server may be unavailable, overloaded, or you hit a bug."); diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index cd32c3743f..9fc0b54eea 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -138,4 +138,19 @@ export enum Action { * Fired when an upload is cancelled by the user. Should be used with UploadCanceledPayload. */ UploadCanceled = "upload_canceled", + + /** + * Fired when requesting to join a room + */ + JoinRoom = "join_room", + + /** + * Fired when successfully joining a room + */ + JoinRoomReady = "join_room_ready", + + /** + * Fired when joining a room failed + */ + JoinRoomError = "join_room_error", } diff --git a/src/i18n/strings/cs.json b/src/i18n/strings/cs.json index 9701afa0e5..75472b4d38 100644 --- a/src/i18n/strings/cs.json +++ b/src/i18n/strings/cs.json @@ -3284,5 +3284,13 @@ "Add reaction": "Přidat reakci", "Send and receive voice messages": "Odeslat a přijmout hlasové zprávy", "Your feedback will help make spaces better. The more detail you can go into, the better.": "Vaše zpětná vazba pomůže zlepšit prostory. Čím podrobnější bude, tím lépe.", - "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Pokud odejdete, %(brand)s se znovu načte s vypnutými Prostory. Skupiny a vlastní značky budou opět viditelné." + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Pokud odejdete, %(brand)s se znovu načte s vypnutými Prostory. Skupiny a vlastní značky budou opět viditelné.", + "Space Autocomplete": "Automatické dokončení prostoru", + "Go to my space": "Přejít do mého prostoru", + "sends space invaders": "pošle space invaders", + "Sends the given message with a space themed effect": "Odešle zadanou zprávu s efektem vesmíru", + "See when people join, leave, or are invited to your active room": "Zjistěte, kdy se lidé připojí, odejdou nebo jsou pozváni do vaší aktivní místnosti", + "Kick, ban, or invite people to this room, and make you leave": "Vykopnout, vykázat, pozvat lidi do této místnosti nebo odejít", + "Kick, ban, or invite people to your active room, and make you leave": "Vykopnout, vykázat, pozvat lidi do vaší aktivní místnosti nebo odejít", + "See when people join, leave, or are invited to this room": "Zjistěte, kdy se lidé připojí, odejdou nebo jsou pozváni do této místnosti" } diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index cfe87ad823..dcc5343af4 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -980,7 +980,7 @@ "Enable Emoji suggestions while typing": "Emojivorschläge während Eingabe", "Show a placeholder for removed messages": "Platzhalter für gelöschte Nachrichten", "Show join/leave messages (invites/kicks/bans unaffected)": "Betreten oder Verlassen von Benutzern (ausgen. Einladungen/Rauswürfe/Banne)", - "Show avatar changes": "Avataränderungen anzeigen", + "Show avatar changes": "Avataränderungen", "Show display name changes": "Änderungen von Anzeigenamen", "Send typing notifications": "Tippbenachrichtigungen senden", "Show avatars in user and room mentions": "Avatare in Benutzer- und Raumerwähnungen", @@ -1200,11 +1200,11 @@ "Scissors": "Schere", "Upgrade to your own domain": "Upgrade zu deiner eigenen Domain", "Accept all %(invitedRooms)s invites": "Akzeptiere alle %(invitedRooms)s Einladungen", - "Change room avatar": "Ändere Raumbild", - "Change room name": "Ändere Raumname", - "Change main address for the room": "Ändere Hauptadresse für den Raum", + "Change room avatar": "Raumbild ändern", + "Change room name": "Raumname ändern", + "Change main address for the room": "Hauptadresse ändern", "Change history visibility": "Sichtbarkeit des Verlaufs ändern", - "Change permissions": "Ändere Berechtigungen", + "Change permissions": "Berechtigungen ändern", "Change topic": "Thema ändern", "Modify widgets": "Widgets bearbeiten", "Default role": "Standard-Rolle", @@ -2378,7 +2378,7 @@ "A connection error occurred while trying to contact the server.": "Beim Versuch, den Server zu kontaktieren, ist ein Verbindungsfehler aufgetreten.", "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Du hast sie ggf. in einem anderen Client als %(brand)s konfiguriert. Du kannst sie nicht in %(brand)s verändern, aber sie werden trotzdem angewandt.", "Master private key:": "Privater Hauptschlüssel:", - "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Setze den Schriftnamen auf eine in deinem System installierte Schriftart & %(brand)s wird versuchen, sie zu verwenden.", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Setze den Schriftnamen auf eine in deinem System installierte Schriftart und %(brand)s wird versuchen, sie zu verwenden.", "Custom Tag": "Benutzerdefinierter Tag", "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Du bist bereits eingeloggt und kannst loslegen. Allerdings kannst du auch die neuesten Versionen der App für alle Plattformen unter element.io/get-started herunterladen.", "You're all caught up.": "Alles gesichtet.", @@ -2521,7 +2521,7 @@ "Ignored attempt to disable encryption": "Versuch, die Verschlüsselung zu deaktivieren, wurde ignoriert", "Failed to save your profile": "Speichern des Profils fehlgeschlagen", "The operation could not be completed": "Die Operation konnte nicht abgeschlossen werden", - "Remove messages sent by others": "Nachrichten von anderen entfernen", + "Remove messages sent by others": "Nachrichten von anderen löschen", "Starting camera...": "Starte Kamera...", "Call connecting...": "Verbinde den Anruf...", "Calling...": "Rufe an...", @@ -2699,21 +2699,21 @@ "Switzerland": "Schweiz", "Sweden": "Schweden", "Swaziland": "Swasiland", - "Svalbard & Jan Mayen": "Spitzbergen & Jan Mayen", + "Svalbard & Jan Mayen": "Spitzbergen und Jan Mayen", "Suriname": "Surinam", "Sudan": "Sudan", "St. Vincent & Grenadines": "St. Vincent und die Grenadinen", - "St. Pierre & Miquelon": "St. Pierre & Miquelon", + "St. Pierre & Miquelon": "St. Pierre und Miquelon", "St. Martin": "St. Martin", "St. Lucia": "St. Lucia", - "St. Kitts & Nevis": "St. Kitts & Nevis", + "St. Kitts & Nevis": "St. Kitts und Nevis", "St. Helena": "St. Helena", "St. Barthélemy": "St. Barthélemy", "Sri Lanka": "Sri Lanka", "Spain": "Spanien", "South Sudan": "Südsudan", "South Korea": "Südkorea", - "South Georgia & South Sandwich Islands": "Südgeorgien & Südliche Sandwichinseln", + "South Georgia & South Sandwich Islands": "Südgeorgien und Südliche Sandwichinseln", "South Africa": "Südafrika", "Somalia": "Somalia", "Solomon Islands": "Salomonen", @@ -2815,7 +2815,7 @@ "Hungary": "Ungarn", "Hong Kong": "Hongkong", "Honduras": "Honduras", - "Heard & McDonald Islands": "Heard & McDonald-Inseln", + "Heard & McDonald Islands": "Heard und McDonald-Inseln", "Haiti": "Haiti", "Guyana": "Guyana", "Guinea-Bissau": "Guinea-Bissau", @@ -2961,9 +2961,9 @@ "%(peerName)s held the call": "%(peerName)s hält den Anruf", "You held the call Resume": "Du hältst den Anruf Fortsetzen", "sends fireworks": "sendet Feuerwerk", - "Sends the given message with fireworks": "Sendet die gewählte Nachricht mit Feuerwerk", + "Sends the given message with fireworks": "Sendet die Nachricht mit Feuerwerk", "sends confetti": "sendet Konfetti", - "Sends the given message with confetti": "Sendet die gewählte Nachricht mit Konfetti", + "Sends the given message with confetti": "Sendet die Nachricht mit Konfetti", "Show chat effects": "Chat-Effekte anzeigen", "Prepends ┬──┬ ノ( ゜-゜ノ) to a plain-text message": "Stellt ┬──┬ ノ( ゜-゜ノ) einer Klartextnachricht voran", "Prepends (╯°□°)╯︵ ┻━┻ to a plain-text message": "Stellt (╯°□°)╯︵ ┻━┻ einer Klartextnachricht voran", @@ -2976,7 +2976,7 @@ "%(name)s on hold": "%(name)s wird gehalten", "You held the call Switch": "Du hältst den Anruf Wechseln", "sends snowfall": "sendet Schneeflocken", - "Sends the given message with snowfall": "Sendet die gewählte Nachricht mit Schneeflocken", + "Sends the given message with snowfall": "Sendet die Nachricht mit Schneeflocken", "Transfer": "Übertragen", "Failed to transfer call": "Anruf-Übertragung fehlgeschlagen", "A call can only be transferred to a single user.": "Ein Anruf kann nur auf einen einzelnen Nutzer übertragen werden.", @@ -3089,7 +3089,7 @@ "Apply": "Anwenden", "Create a new room": "Neuen Raum erstellen", "Suggested Rooms": "Vorgeschlagene Räume", - "Add existing room": "Existierenden Raum", + "Add existing room": "Existierenden Raum hinzufügen", "Send message": "Nachricht senden", "New room": "Neuer Raum", "Share invite link": "Einladungslink teilen", @@ -3253,7 +3253,7 @@ "What are some things you want to discuss in %(spaceName)s?": "Welche Themen willst du in %(spaceName)s besprechen?", "Inviting...": "Einladen...", "Failed to create initial space rooms": "Fehler beim Initialisieren des Space", - "You are the only person here. If you leave, no one will be able to join in the future, including you.": "Du bist die einzige Person hier. Wenn du den Space verlässt, ist er für immer verloren (eine lange Zeit).", + "You are the only person here. If you leave, no one will be able to join in the future, including you.": "Du bist die einzige Person hier. Wenn du ihn jetzt verlässt, ist er für immer verloren (eine lange Zeit).", "Edit settings relating to your space.": "Einstellungen vom Space bearbeiten.", "Please choose a strong password": "Bitte gib ein sicheres Passwort ein", "If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "Wenn du alles zurücksetzt, gehen alle verifizierten Anmeldungen, Benutzer und verschlüsselte Nachrichten verloren.", @@ -3324,8 +3324,8 @@ "Beta available for web, desktop and Android. Thank you for trying the beta.": "Die Betaversion ist für Browser, Desktop und Android verfügbar. Danke, dass Du die Betaversion testest.", "%(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "%(brand)s wird mit deaktivierten Spaces neuladen und du kannst Communities und Custom Tags wieder verwenden können.", "Spaces are a beta feature.": "Spaces sind in der Beta.", - "Spaces are a new way to group rooms and people. To join an existing space you'll need an invite.": "Wir haben Spaces entwickelt, damit ihr eure vielen Räume besser organisieren könnt. Um einen existierenden Space beitreten zu können musst du (noch) von jemandem eingeladen werden.", - "Spaces are a new way to group rooms and people.": "Wir haben Spaces entwickelt, damit ihr eure vielen Räume besser organisieren könnt.", + "Spaces are a new way to group rooms and people. To join an existing space you'll need an invite.": "Wir haben Spaces entwickelt, damit ihr eure Räume besser organisieren könnt. Um einen existierenden Space beitreten zu können musst du (noch) von jemandem eingeladen werden.", + "Spaces are a new way to group rooms and people.": "Wir haben Spaces entwickelt, damit ihr eure Räume besser organisieren könnt.", "Message search initialisation failed": "Initialisierung der Nachrichtensuche fehlgeschlagen", "Send and receive voice messages": "Sprachnachrichten", "Search names and descriptions": "Nach Name und Beschreibung filtern", @@ -3341,5 +3341,7 @@ "Your access token gives full access to your account. Do not share it with anyone.": "Dein Zugriffstoken gibt vollen Zugriff auf dein Konto. Teile es niemals mit jemanden anderen.", "Access Token": "Zugriffstoken", "Your feedback will help make spaces better. The more detail you can go into, the better.": "Dein Feedback hilfst uns, die Spaces zu verbessern. Je genauer, desto besser.", - "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Durchs Verlassen lädt %(brand)s mit deaktivierten Spaces neu. Danach kannst du wieder Communities und Custom Tags verwenden." + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Durchs Verlassen lädt %(brand)s mit deaktivierten Spaces neu. Danach kannst du Communities und Custom Tags wieder verwenden.", + "sends space invaders": "sendet Space Invaders", + "Sends the given message with a space themed effect": "Sendet die Nachricht mit Raumschiffen" } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 817765ca69..5bc1e66b71 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -37,6 +37,8 @@ "Call Failed": "Call Failed", "Call Declined": "Call Declined", "The other party declined the call.": "The other party declined the call.", + "User Busy": "User Busy", + "The user you called is busy.": "The user you called is busy.", "The remote side failed to pick up": "The remote side failed to pick up", "The call could not be established": "The call could not be established", "Answered Elsewhere": "Answered Elsewhere", @@ -2758,6 +2760,8 @@ "Switch theme": "Switch theme", "User menu": "User menu", "Community and user menu": "Community and user menu", + "Currently joining %(count)s rooms|other": "Currently joining %(count)s rooms", + "Currently joining %(count)s rooms|one": "Currently joining %(count)s room", "Could not load user profile": "Could not load user profile", "Decrypted event source": "Decrypted event source", "Original event source": "Original event source", diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index f4d30b40b7..fc8c00fd19 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -324,7 +324,7 @@ "Add rooms to this community": "Aldoni ĉambrojn al ĉi tiu komunumo", "An email has been sent to %(emailAddress)s": "Retletero sendiĝis al %(emailAddress)s", "Please check your email to continue registration.": "Bonvolu kontroli vian retpoŝton por daŭrigi la registriĝon.", - "Token incorrect": "Malĝusta ĵetono", + "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", @@ -769,7 +769,7 @@ "Failed to invite users to the room:": "Malsukcesis inviti uzantojn al la ĉambro:", "Opens the Developer Tools dialog": "Maflermas evoluigistan interagujon", "This homeserver has hit its Monthly Active User limit.": "Tiu ĉi hejmservilo atingis sian monatan limon de aktivaj uzantoj.", - "This homeserver has exceeded one of its resource limits.": "Tiu ĉi hejmservilo superis je unu el siaj risurcaj limoj.", + "This homeserver has exceeded one of its resource limits.": "Tiu ĉi hejmservilo superis je unu el siaj rimedaj limoj.", "Unable to connect to Homeserver. Retrying...": "Ne povas konektiĝi al hejmservilo. Reprovante…", "You do not have permission to invite people to this room.": "Vi ne havas permeson inviti personojn al la ĉambro.", "User %(user_id)s does not exist": "Uzanto %(user_id)s ne ekzistas", @@ -1569,7 +1569,7 @@ "Block users on other matrix homeservers from joining this room (This setting cannot be changed later!)": "Bloki aliĝojn al ĉi tiu ĉambro de uzantoj el aliaj Matrix-serviloj (Ĉi tiun agordon ne eblas poste ŝanĝi!)", "Please fill why you're reporting.": "Bonvolu skribi, kial vi raportas.", "Report Content to Your Homeserver Administrator": "Raporti enhavon al la administrantode via hejmservilo", - "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "Per raporto de ĉi tiu mesaĝo vi sendos ĝian unikan « eventan identigilon » al la administranto de via hejmservilo. Se mesaĝoj en ĉi tiu ĉambro estas ĉifrataj, la administranto de via hejmservilo ne povos legi la tekston de la mesaĝo, nek rigardi dosierojn aŭ bildojn.", + "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "Per raporto de ĉi tiu mesaĝo vi sendos ĝian unikan «identigilon de okazo» al la administranto de via hejmservilo. Se mesaĝoj en ĉi tiu ĉambro estas ĉifrataj, la administranto de via hejmservilo ne povos legi la tekston de la mesaĝo, nek rigardi dosierojn aŭ bildojn.", "Send report": "Sendi raporton", "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.", @@ -1653,7 +1653,7 @@ "Unencrypted": "Neĉifrita", "Send a reply…": "Sendi respondon…", "Send a message…": "Sendi mesaĝon…", - "Direct Messages": "Rektaj ĉambroj", + "Direct Messages": "Individuaj ĉambroj", " wants to chat": " volas babili", "Start chatting": "Ekbabili", "Reject & Ignore user": "Rifuzi kaj malatenti uzanton", @@ -1665,7 +1665,7 @@ "Start Verification": "Komenci kontrolon", "Trusted": "Fidata", "Not trusted": "Nefidata", - "Direct message": "Rekta ĉambro", + "Direct message": "Individua ĉambro", "Security": "Sekureco", "Reactions": "Reagoj", "More options": "Pliaj elektebloj", @@ -1919,7 +1919,7 @@ "Failed to find the following users": "Malsukcesis trovi la jenajn uzantojn", "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "La jenaj uzantoj eble ne ekzistas aŭ ne validas, kaj ne povas invitiĝi: %(csvNames)s", "Recent Conversations": "Freŝaj interparoloj", - "Recently Direct Messaged": "Freŝaj rektaj ĉambroj", + "Recently Direct Messaged": "Freŝe uzitaj individuaj ĉambroj", "Go": "Iri", "Your account is not secure": "Via konto ne estas sekura", "Your password": "Via pasvorto", @@ -2312,7 +2312,7 @@ "Customise your appearance": "Adaptu vian aspekton", "Appearance Settings only affect this %(brand)s session.": "Agordoj de aspekto nur efikos sur ĉi tiun salutaĵon de %(brand)s.", "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* 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, @bot:* 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 rektaj ĉambroj.", + "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.", "Make this room low priority": "Doni al la ĉambro malaltan prioritaton", "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Ĉambroj kun malalta prioritato montriĝas en aparta sekcio, en la suba parto de via ĉambrobreto,", "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.", @@ -2391,7 +2391,7 @@ "The person who invited you already left the room.": "La persono, kiu vin invitis, jam foriris de la ĉambro.", "The person who invited you already left the room, or their server is offline.": "Aŭ la persono, kiu vin invitis, jam foriris de la ĉambro, aŭ ĝia servilo estas eksterreta.", "Change notification settings": "Ŝanĝi agordojn pri sciigoj", - "Show message previews for reactions in DMs": "Montri antaŭrigardojn al mesaĝoj ĉe reagoj en rektaj ĉambroj", + "Show message previews for reactions in DMs": "Montri antaŭrigardojn al mesaĝoj ĉe reagoj en individuaj ĉambroj", "Show message previews for reactions in all rooms": "Montri antaŭrigardojn al mesaĝoj ĉe reagoj en ĉiuj ĉambroj", "Your server isn't responding to some requests.": "Via servilo ne respondas al iuj petoj.", "Server isn't responding": "Servilo ne respondas", @@ -2729,10 +2729,10 @@ "Send images as you in your active room": "Sendi bildojn kiel vi en via aktiva ĉambro", "Send images as you in this room": "Sendi bildojn kiel vi en ĉi tiu ĉambro", "The %(capability)s capability": "La kapablo %(capability)s", - "See %(eventType)s events posted to your active room": "Vidi eventojn de speco %(eventType)s afiŝitajn al via aktiva ĉambro", - "Send %(eventType)s events as you in your active room": "Sendi eventojn de speco %(eventType)s kiel vi en via aktiva ĉambro", - "See %(eventType)s events posted to this room": "Vidi eventojn de speco %(eventType)s afiŝitajn al ĉi tiu ĉambro", - "Send %(eventType)s events as you in this room": "Sendi eventojn de speco %(eventType)s kiel vi en ĉi tiu ĉambro", + "See %(eventType)s events posted to your active room": "Vidi okazojn de speco %(eventType)s afiŝitajn al via aktiva ĉambro", + "Send %(eventType)s events as you in your active room": "Sendi okazojn de speco %(eventType)s kiel vi en via aktiva ĉambro", + "See %(eventType)s events posted to this room": "Vidi okazojn de speco %(eventType)s afiŝitajn al ĉi tiu ĉambro", + "Send %(eventType)s events as you in this room": "Sendi okazojn de speco %(eventType)s kiel vi en ĉi tiu ĉambro", "See messages posted to your active room": "Vidi mesaĝojn senditajn al via aktiva ĉambro", "See messages posted to this room": "Vidi mesaĝojn senditajn al ĉi tiu ĉambro", "Send messages as you in your active room": "Sendi mesaĝojn kiel vi en via aktiva ĉambro", @@ -3000,14 +3000,14 @@ "Send text messages as you in this room": "Sendi tekstajn mesaĝojn kiel vi en ĉi tiu ĉambro", "Change which room, message, or user you're viewing": "Ŝanĝu, kiun ĉambron, mesaĝon, aŭ uzanton vi rigardas", "%(senderName)s has updated the widget layout": "%(senderName)s ĝisdatigis la aranĝon de la fenestrajoj", - "Converts the DM to a room": "Igas la ĉambron nerekta", - "Converts the room to a DM": "Igas la ĉambron rekta", + "Converts the DM to a room": "Malindividuigas la ĉambron", + "Converts the room to a DM": "Individuigas la ĉambron", "Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.": "Via hejmservilo rifuzis vian saluton. Eble tio okazis, ĉar ĝi simple daŭris tro longe. Bonvolu reprovi. Se tio daŭros, bonvolu kontakti la administranton de via hejmservilo.", "Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.": "Via hejmservilo estis neatingebla kaj ne povis vin salutigi. Bonvolu reprovi. Se tio daŭros, bonvolu kontakti la administranton de via hejmservilo.", "Try again": "Reprovu", "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 rektan ĉambron.", + "%(creator)s created this DM.": "%(creator)s kreis ĉi tiun individuan ĉambron.", "Invalid URL": "Nevalida URL", "Unable to validate homeserver": "Ne povas validigi hejmservilon", "Just a heads up, if you don't add an email and forget your password, you could permanently lose access to your account.": "Averte, se vi ne aldonos retpoŝtadreson kaj poste forgesos vian pasvorton, vi eble por ĉiam perdos aliron al via konto.", @@ -3156,8 +3156,8 @@ "Spaces prototype. Incompatible with Communities, Communities v2 and Custom Tags. Requires compatible homeserver for some features.": "Pratipo de Aroj. Malkonforma kun Komunumoj, Komunumoj v2, kaj Propraj etikedoj. Bezonas konforman hejmservilon por iuj funkcioj.", "Verify this login to access your encrypted messages and prove to others that this login is really you.": "Kontrolu ĉi tiun saluton por aliri viajn ĉifritajn mesaĝojn, kaj pruvi al aliuloj, ke la salutanto vere estas vi.", "Verify with another session": "Knotroli per alia salutaĵo", - "Original event source": "Originala fonto de evento", - "Decrypted event source": "Malĉifrita fonto de evento", + "Original event source": "Originala fonto de okazo", + "Decrypted event source": "Malĉifrita fonto de okazo", "We'll create rooms for each of them. You can add more later too, including already existing ones.": "Por ĉiu el ili ni kreos ĉambron. Vi povos aldoni pliajn pli poste, inkluzive jam ekzistantajn.", "What projects are you working on?": "Kiujn projektojn vi prilaboras?", "Let's create a room for each of them. You can add more later too, including already existing ones.": "Ni kreu ĉambron por ĉiu el ili. Vi povas aldoni pliajn poste, inkluzive jam ekzistantajn.", @@ -3218,5 +3218,107 @@ "Show options to enable 'Do not disturb' mode": "Montri elekteblojn por ŝalti sendistran reĝimon", "%(deviceId)s from %(ip)s": "%(deviceId)s de %(ip)s", "Review to ensure your account is safe": "Kontrolu por certigi sekurecon de via konto", - "Sends the given message as a spoiler": "Sendas la donitan mesaĝon kiel malkaŝon de intrigo" + "Sends the given message as a spoiler": "Sendas la donitan mesaĝon kiel malkaŝon de intrigo", + "Are you sure you wish to abort creation of the host? The process cannot be continued.": "Ĉu vi certe volas nuligi kreadon de la gastiganto? Ĉi tiu procedo ne estos daŭrigebla.", + "Confirm abort of host creation": "Konfirmu nuligon de kreado de gastiganto", + "Feeling experimental? Labs are the best way to get things early, test out new features and help shape them before they actually launch. Learn more.": "Ĉu vi eksperimentemas? Laboratorioj estas la plej bona maniero frue akiri kaj testi novajn funkciojn, kaj helpi ilin formi antaŭ ilia plena ekuzo. Eksciu plion.", + "Your access token gives full access to your account. Do not share it with anyone.": "Via alirpeco donas plenan aliron al via konto. Donu ĝin al neniu.", + "We couldn't create your DM.": "Ni ne povis krei vian individuan ĉambron.", + "You may contact me if you have any follow up questions": "Vi povas min kontakti okaze de pliaj demandoj", + "To leave the beta, visit your settings.": "Por foriri de la prova versio, iru al viaj agordoj.", + "Your platform and username will be noted to help us use your feedback as much as we can.": "Via platformo kaj uzantonomo helpos al ni pli bone uzi viajn prikomentojn.", + "Your feedback will help make spaces better. The more detail you can go into, the better.": "Viaj prikomentoj helpos plibonigi arojn. Kiom pli detale vi skribos, tiom pli bonos.", + "%(featureName)s beta feedback": "Komentoj pri la prova versio de %(featureName)s", + "Thank you for your feedback, we really appreciate it.": "Dankon pro viaj prikomentoj, ni vere ilin ŝatas.", + "Beta feedback": "Komentoj pri la prova versio", + "Want to add a new room instead?": "Ĉu vi volas anstataŭe aldoni novan ĉambron?", + "You can add existing spaces to a space.": "Vi povas arigi arojn.", + "Feeling experimental?": "Ĉu vi eksperimentemas?", + "Adding rooms... (%(progress)s out of %(count)s)|one": "Aldonante ĉambron…", + "Adding rooms... (%(progress)s out of %(count)s)|other": "Aldonante ĉambrojn… (%(progress)s el %(count)s)", + "Not all selected were added": "Ne ĉiuj elektitoj aldoniĝis", + "You are not allowed to view this server's rooms list": "Vi ne rajtas vidi liston de ĉambroj de tu ĉi servilo", + "Add reaction": "Aldoni reagon", + "Error processing voice message": "Eraris traktado de voĉmesaĝo", + "Delete recording": "Forigi registraĵon", + "Stop the recording": "Ĉesigi la registradon", + "We didn't find a microphone on your device. Please check your settings and try again.": "Ni ne trovis mikrofonon en via aparato. Bonvolu kontroli viajn agordojn kaj reprovi.", + "No microphone found": "Neniu mikrofono troviĝis", + "We were unable to access your microphone. Please check your browser settings and try again.": "Ni ne povis aliri vian mikrofonon. Bonvolu kontroli la agordojn de via foliumilo kaj reprovi.", + "Unable to access your microphone": "Ne povas aliri vian mikrofonon", + "%(count)s results in all spaces|one": "%(count)s rezulto en ĉiuj aroj", + "%(count)s results in all spaces|other": "%(count)s rezultoj en ĉiuj aroj", + "You have no ignored users.": "Vi malatentas neniujn uzantojn.", + "Spaces are a new way to group rooms and people. To join an existing space you'll need an invite.": "Aroj prezentas novan manieron grupigi ĉambrojn kaj personojn. Por aliĝi al jama spaco, vi bezonos inviton.", + "Please enter a name for the space": "Bonvolu enigi nomon por la aro", + "Play": "Ludi", + "Pause": "Paŭzigi", + "Connecting": "Konektante", + "Sends the given message with a space themed effect": "Sendas mesaĝon kun la efekto de kosmo", + "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Permesi samtavolajn individuajn vokojn (kaj do videbligi vian IP-adreson al la alia vokanto)", + "Send and receive voice messages": "Sendi kaj ricevi voĉmesaĝojn", + "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Prova versio disponeblas por reto, labortablo, kaj Androido. Iuj funkcioj eble ne disponeblas per via hejmservilo.", + "You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "Vi povas forlasi la provan version iam ajn per la agordoj, aŭ per tuŝeto al la prova insigno, kiel tiu ĉi-supre.", + "%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "%(brand)s estos enlegita kun subetno de Aroj. Komunumoj kaj propraj etikedoj iĝos kaŝitaj.", + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Se vi foriros, %(brand)s estos enlegita sen subteno de Aroj. Komunumoj kaj propraj etikedoj ree estos videblaj.", + "Spaces are a new way to group rooms and people.": "Aroj prezentas novan manieron grupigi ĉambrojn kaj homojn.", + "See when people join, leave, or are invited to your active room": "Vidu kiam oni aliĝas, foriras, aŭ invitiĝas al via aktiva ĉambro", + "See when people join, leave, or are invited to this room": "Vidu kiam oni aliĝas, foriras, aŭ invitiĝas al la ĉambro", + "This homeserver has been blocked by it's administrator.": "Tiu ĉi hejmservilo estas blokita de sia administranto.", + "This homeserver has been blocked by its administrator.": "Tiu ĉi hejmservilo estas blokita de sia administranto.", + "Modal Widget": "Reĝima fenestraĵo", + "Your message wasn't sent because this homeserver has been blocked by it's administrator. Please contact your service administrator to continue using the service.": "Via mesaĝo ne sendiĝis, ĉar ĉi tiu hejmservilo estas blokita de ĝia administranto. Bonvolu kontakti la administranton de via servo por daŭre uzadi la servon.", + "Element Web is experimental on mobile. For a better experience and the latest features, use our free native app.": "Elemento por la reto estas eksperimenta sur telefono. Por pli bona sperto kaj freŝaj funkcioj, uzu nian senpagan malfremdan aplikaĵon.", + "Kick, ban, or invite people to your active room, and make you leave": "Forpeli, forbari, aŭ inviti homojn al via aktiva ĉambro, kaj foririgi vin", + "Kick, ban, or invite people to this room, and make you leave": "Forpeli, forbari, aŭ inviti personojn al la ĉambro, kaj foririgi vin", + "Consult first": "Unue konsulti", + "Continuing temporarily allows the %(hostSignupBrand)s setup process to access your account to fetch verified email addresses. This data is not stored.": "Provizora daŭrigo permesas al la agorda procedo de %(hostSignupBrand)s aliri vian konton por preni kontrolitajn retpoŝtadresojn. Tiuj ĉi datumoj de konserviĝos.", + "Access Token": "Alirpeco", + "Message search initialisation failed": "Malsukcesis komenci serĉadon de mesaĝoj", + "Consulting with %(transferTarget)s. Transfer to %(transferee)s": "Konsultante kun %(transferTarget)s. Transdono al %(transferee)s", + "sends space invaders": "sendas imiton de ludo « Space Invaders »", + "Beta available for web, desktop and Android. Thank you for trying the beta.": "Prova versio disponeblas por reto, labortablo, kaj Androido. Dankon pro via provo.", + "Enter your Security Phrase a second time to confirm it.": "Enigu vian Sekurecan frazon duafoje por ĝin konfirmi.", + "Space Autocomplete": "Memaga finfaro de aro", + "Without verifying, you won’t have access to all your messages and may appear as untrusted to others.": "Sen kontrolo, vi ne povos aliri al ĉiuj viaj mesaĝoj, kaj aliuloj vin povos vidi nefidata.", + "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.", + "Use another login": "Uzi alian saluton", + "Please choose a strong password": "Bonvolu elekti fortan pasvorton", + "You can add more later too, including already existing ones.": "Vi povas aldoni pliajn poste, inkluzive tiujn, kiuj jam ekzistas.", + "Let's create a room for each of them.": "Kreu ni ĉambron por ĉiu el ili.", + "What are some things you want to discuss in %(spaceName)s?": "Pri kio volus vi diskuti en %(spaceName)s?", + "This is an experimental feature. For now, new users receiving an invite will have to open the invite on to actually join.": "Ĉi tio estas prova funkcio. Uzantoj, kiuj nun ricevos inviton, devos ĝin malfermi per por efektive aliĝi.", + "Go to my space": "Iri al mia aro", + "Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "Elektu aldonotajn ĉambrojn aŭ interparolojn. Ĉi tiu aro estas nur por vi, neniu estos informita. Vi povas aldoni pliajn pli poste.", + "What do you want to organise?": "Kion vi volas organizi?", + "Skip for now": "Preterpasi ĉi-foje", + "To join %(spaceName)s, turn on the Spaces beta": "Por aliĝi al %(spaceName)s, ŝaltu la provan version de Aroj", + "To view %(spaceName)s, turn on the Spaces beta": "Por vidi %(spaceName)s, ŝaltu la provan version de Aroj", + "Spaces are a beta feature.": "Aroj estas prova funkcio.", + "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", + "Filter all spaces": "Filtri ĉiujn arojn", + "Communities are changing to Spaces": "Komunumoj iĝas Aroj", + "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", + "Join the beta": "Aliĝi al provado", + "Leave the beta": "Ĉesi provadon", + "Beta": "Prova", + "Tap for more info": "Klaku por pliaj informoj", + "Spaces is a beta feature": "Aroj estas prova funkcio", + "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.", + "Only do this if you have no other device to complete verification with.": "Faru tion ĉi nur se vi ne havas alian aparaton, per kiu vi kontrolus ceterajn.", + "Forgotten or lost all recovery methods? Reset all": "Ĉu vi forgesis aŭ perdis ĉiujn manierojn de rehavo? Restarigu ĉion", + "Reset everything": "Restarigi ĉion", + "Verify other login": "Kontroli alian saluton", + "Reset event store": "Restarigi deponejon de okazoj", + "If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated": "Se vi tamen tion faras, sciu ke neniu el viaj mesaĝoj foriĝos, sed via sperto pri serĉado povas malboniĝi momente, dum la indekso estas refarata", + "You most likely do not want to reset your event index store": "Plej probable, vi ne volas restarigi vian deponejon de indeksoj de okazoj", + "Reset event store?": "Ĉu restarigi deponejon de okazoj?" } diff --git a/src/i18n/strings/es.json b/src/i18n/strings/es.json index 0e4d50210a..60f5d06bec 100644 --- a/src/i18n/strings/es.json +++ b/src/i18n/strings/es.json @@ -192,7 +192,7 @@ "Add a topic": "Añadir un tema", "No media permissions": "Sin permisos para el medio", "You may need to manually permit %(brand)s to access your microphone/webcam": "Probablemente necesites dar permisos manualmente a %(brand)s para tu micrófono/cámara", - "Are you sure you want to leave the room '%(roomName)s'?": "¿Salir de la sala «%(roomName)s?", + "Are you sure you want to leave the room '%(roomName)s'?": "¿Salir de la sala «%(roomName)s»?", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "No se puede conectar al servidor base. Por favor, comprueba tu conexión, asegúrate de que el certificado SSL del servidor es de confiaza, y comprueba que no haya extensiones de navegador bloqueando las peticiones.", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s eliminó el nombre de la sala.", "Drop File Here": "Deje el fichero aquí", @@ -1357,7 +1357,7 @@ "Compare a unique set of emoji if you don't have a camera on either device": "Comparar un conjunto de iconos si no tienes cámara en ninguno de los dispositivos", "Start": "Empezar", "Waiting for %(displayName)s to verify…": "Esperando la verificación de %(displayName)s…", - "Review": "Revise", + "Review": "Revisar", "in secret storage": "en almacén secreto", "Secret storage public key:": "Clave pública del almacén secreto:", "in account data": "en datos de cuenta", @@ -1544,7 +1544,7 @@ "Theme added!": "¡Se añadió el tema!", "Custom theme URL": "URL de tema personalizado", "Add theme": "Añadir tema", - "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "Para informar de un problema de seguridad relacionado con Matrix, por favor lea Security Disclosure Policy de Matrix.or.", + "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "Para informar de un problema de seguridad relacionado con Matrix, lee la Política de divulgación de seguridad de Matrix.org.", "Keyboard Shortcuts": "Atajos de teclado", "Customise your experience with experimental labs features. Learn more.": "Personaliza tu experiencia con funciones experimentales. Más información.", "Something went wrong. Please try again or view your console for hints.": "Algo salió mal. Por favor, inténtalo de nuevo o mira tu consola para encontrar pistas.", @@ -2279,8 +2279,8 @@ "Create community": "Crear comunidad", "Failed to find the general chat for this community": "No se pudo encontrar el chat general de esta comunidad", "Security & privacy": "Seguridad y privacidad", - "All settings": "Todos los ajustes", - "Feedback": "Realimentación", + "All settings": "Ajustes", + "Feedback": "Danos tu opinión", "Community settings": "Configuración de la comunidad", "User settings": "Ajustes de usuario", "Switch to light mode": "Cambiar al tema claro", @@ -3305,5 +3305,15 @@ "Feeling experimental? Labs are the best way to get things early, test out new features and help shape them before they actually launch. Learn more.": "¿Te apetece probar cosas nuevas? Los experimentos son la mejor manera de conseguir acceso anticipado a nuevas funcionalidades, probarlas y ayudar a mejorarlas antes de su lanzamiento. Más información.", "Send and receive voice messages": "Enviar y recibir mensajes de voz", "Your feedback will help make spaces better. The more detail you can go into, the better.": "Tus comentarios ayudarán a mejorar los espacios. Cuanto más detalle incluyas, mejor.", - "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta disponible para la versión web, de escritorio o Android. Puede que algunas funcionalidades no estén disponibles en tu servidor base." + "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta disponible para la versión web, de escritorio o Android. Puede que algunas funcionalidades no estén disponibles en tu servidor base.", + "Space Autocomplete": "Autocompletar espacios", + "Go to my space": "Ir a mi espacio", + "sends space invaders": "enviar space invaders", + "Sends the given message with a space themed effect": "Envía un mensaje con efectos espaciales", + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Si sales, %(brand)s volverá a cargarse con los espacios desactivados. Las comunidades y las etiquetas personalizadas serán visibles de nuevo.", + "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Permitir conexión directa (peer-to-peer) en las llamadas individuales (si lo activas, la otra parte podría ver tu dirección IP)", + "See when people join, leave, or are invited to your active room": "Ver cuando alguien se una, salga o se le invite a tu sala activa", + "Kick, ban, or invite people to this room, and make you leave": "Expulsar, vetar o invitar personas a esta sala, y hacerte salir de ella", + "Kick, ban, or invite people to your active room, and make you leave": "Expulsar, vetar o invitar a gente a tu sala activa, o hacerte salir", + "See when people join, leave, or are invited to this room": "Ver cuando alguien se une, sale o se le invita a la sala" } diff --git a/src/i18n/strings/fa.json b/src/i18n/strings/fa.json index e248bc4c0f..46dde79945 100644 --- a/src/i18n/strings/fa.json +++ b/src/i18n/strings/fa.json @@ -73,7 +73,7 @@ "(HTTP status %(httpStatus)s)": "(HTTP وضعیت %(httpStatus)s)", "Failed to forget room %(errCode)s": "فراموش کردن اتاق با خطا مواجه شد %(errCode)s", "Wednesday": "چهارشنبه", - "Quote": "گفتآورد", + "Quote": "نقل قول", "Send": "ارسال", "Error": "خطا", "Send logs": "ارسال گزارش‌ها", @@ -355,7 +355,7 @@ "You are not in this room.": "شما در این اتاق نیستید.", "Power level must be positive integer.": "سطح قدرت باید عدد صحیح مثبت باشد.", "This room is not recognised.": "این اتاق شناخته نشده است.", - "Missing roomId.": "شناسه‌ی اتاق گم‌شده", + "Missing roomId.": "شناسه‌ی اتاق گم‌شده.", "Unable to create widget.": "ایجاد ابزارک امکان پذیر نیست.", "You need to be able to invite users to do that.": "نیاز است که شما قادر به دعوت کاربران به آن باشید.", "You need to be logged in.": "شما باید وارد شوید.", @@ -658,5 +658,2354 @@ "Bans user with given id": "تحریم کاربر با شناسه‌ی مذکور", "Kicks user with given id": "اخراج کاربر با شناسه‌ی مذکور", "Unrecognised room address:": "آدرس اتاق قابل تشخیص نیست:", - "Leave room": "ترک اتاق" + "Leave room": "ترک اتاق", + "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "کلید امضای ارائه شده با کلید امضای دریافت شده از جلسه %(deviceId)s کاربر %(userId)s مطابقت دارد. نشست به عنوان تأیید شده علامت گذاری شد.", + "Verified key": "کلید تأیید شده", + "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!": "هشدار: تایید کلید ناموفق بود! کلید امضا کننده %(userId)s در نشست %(deviceId)s برابر %(fprint)s است که با کلید %(fingerprint)s تطابق ندارد. این می تواند به معنی رهگیری ارتباطات شما باشد!", + "Send a bug report with logs": "گزارش یک اشکال به همراه سیاهه‌های مربوط", + "Displays information about a user": "اطلاعات مربوط به کاربر را نمایش می دهد", + "Displays list of commands with usages and descriptions": "لیست دستورات را با کاربردها و توضیحات نمایش می دهد", + "Sends the given message coloured as a rainbow": "پیام داده شده را به صورت رنگین کمان ارسال می کند", + "Forces the current outbound group session in an encrypted room to be discarded": "جلسه گروه خروجی فعلی را در یک اتاق رمزگذاری شده مجبور می کند که کنار گذاشته شود", + "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s دعوتنامه %(displayName)s را پذیرفت.", + "Reason": "دلیل", + "Displays action": "عملکرد را نمایش می دهد", + "Places the call in the current room on hold": "تماس را در اتاق فعلی در حالت تعلیق قرار می دهد", + "Sends a message to the given user": "برای کاربر داده شده پیامی ارسال می کند", + "Opens chat with the given user": "گپ با کاربر داده شده را باز می کند", + "%(targetName)s accepted an invitation.": "%(targetName)s دعوتنامه را پذیرفت.", + "%(senderName)s invited %(targetName)s.": "%(senderName)s %(targetName)s را دعوت کرد.", + "%(senderName)s banned %(targetName)s.": "%(senderName)s %(targetName)s را ممنوع کرد.", + "See when anyone posts a sticker to your active room": "ببینید چه وقتی برچسب به اتاق فعال شما ارسال می شود", + "Send stickers to your active room as you": "همانطور که هستید ، برچسب ها را به اتاق فعال خود ارسال کنید", + "See when a sticker is posted in this room": "زمان نصب برچسب در این اتاق را ببینید", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s این اتاق را ارتقا داد.", + "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s نام اتاق را به %(roomName)s تغییر داد.", + "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": "%(senderDisplayName)s نام اتاق را از %(oldRoomName)s به %(newRoomName)s تغییر داد.", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s موضوع را به %(topic)s تغییر داد.", + "%(senderName)s kicked %(targetName)s.": "%(senderName)s %(targetName)s را اخراج کرد.", + "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s دعوت %(targetName)s را پس گرفت.", + "%(senderName)s unbanned %(targetName)s.": "%(senderName)s از %(targetName)s رفع مسدودیت کرد.", + "%(targetName)s left the room.": "%(targetName)s اتاق را ترک کرد.", + "%(targetName)s rejected the invitation.": "%(targetName)s دعوت را رد کرد.", + "%(targetName)s joined the room.": "%(targetName)s به اتاق پیوست.", + "%(senderName)s made no change.": "%(senderName)s تغییری نداد.", + "%(senderName)s set a profile picture.": "%(senderName)s عکس نمایه ای تنظیم کرد.", + "%(senderName)s removed their profile picture.": "%(senderName)s عکس نمایه خود را حذف کرد.", + "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s نام نمایشی خود %(oldDisplayName)s را حذف کرد.", + "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s نام نمایشی خود را به %(displayName)s تنظیم کرد.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s نام نمایشی خود را به %(displayName)s تغییر داد.", + "Repeats like \"aaa\" are easy to guess": "تکرارهایی مانند بببب به راحتی قابل حدس هستند", + "with an empty state key": "با یک کلید حالت خالی", + "🎉 All servers are banned from participating! This room can no longer be used.": "🎉 شرکت همه سرورها ممنوع است! دیگر نمی توان از این اتاق استفاده کرد.", + "Converts the DM to a room": "DM را به اتاق تبدیل می کند", + "Converts the room to a DM": "اتاق را به DM تبدیل می کند", + "Takes the call in the current room off hold": "تماس را در اتاق فعلی خاموش نگه می دارد", + "Sends the given emote coloured as a rainbow": "emote داده شده را به صورت رنگین کمان می فرستد", + "%(senderDisplayName)s changed the server ACLs for this room.": "%(senderDisplayName)s ACL های سرور را برای این اتاق تغییر داد.", + "%(senderDisplayName)s set the server ACLs for this room.": "%(senderDisplayName)s ACL های سرور را برای این اتاق تنظیم کرده است.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s دسترسی مهمانان را به %(rule)s تغییر داد", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s از پیوستن مهمان به اتاق جلوگیری کرد.", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s به مهمانان اجازه عضویت در اتاق را داد.", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s قانون عضویت را به %(rule)s تغییر داد", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s این اتاق را مخصوص دعوت شدگان قرار داد.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s اتاق را برای هر کسی که پیوند را می داند عمومی کرد.", + "See when people join, leave, or are invited to this room": "ببینید که کی مردم در این اتاق عضو شده اند، ترک کرده اند یا به آن دعوت شده اند", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s flair را برای %(groups)s در این اتاق غیر فعال کرد.", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s flair را برای گروه %(groups)s در این اتاق فعال کرد.", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s پیام های پین شده را برای اتاق تغییر داد.", + "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s سطح قدرت %(powerLevelDiffText)s تغییر داد.", + "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s از %(fromPowerLevel)s به %(toPowerLevel)s", + "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s تاریخچه از این به بعد این اتاق را به وضعیت ناشناخته %(visibility)s تغییر داد.", + "%(senderName)s made future room history visible to anyone.": "%(senderName)s تاریخچه از بعد این اتاق را برای همه قابل مشاهده کرد.", + "%(senderName)s made future room history visible to all room members.": "%(senderName)s تاریخچه اتاق را برای همه اعضای اتاق قابل مشاهده کرده است.", + "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s تاریخچه اتاق آینده را از همان نقطه ای که به آن پیوسته اند ، برای همه اعضای اتاق قابل مشاهده کرد.", + "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s تاریخچه اتاق آینده را از همان جایی که دعوت شده اند برای همه اعضای اتاق قابل مشاهده کرد.", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s %(targetDisplayName)s را به اتاق دعوت کرد.", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s دعوت نامه %(targetDisplayName)s را برای پیوستن به اتاق باطل کرد.", + "%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s تماس تصویری برقرار کرد. (توسط این مرورگر پشتیبانی نمی شود)", + "%(senderName)s placed a video call.": "%(senderName)s تماس تصویری برقرار کرد.", + "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s تماس صوتی برقرار کرد. (توسط این مرورگر پشتیبانی نمی شود)", + "%(senderName)s placed a voice call.": "%(senderName)s تماس صوتی برقرار کرد.", + "%(senderName)s declined the call.": "%(senderName)s تماس را رد کرد.", + "(unknown failure: %(reason)s)": "(خطای ناشناخته: %(reason)s)", + "%(senderName)s changed the addresses for this room.": "%(senderName)s آدرس های این اتاق را تغییر داد.", + "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s آدرس اصلی و جایگزین این اتاق را تغییر داد.", + "%(senderName)s changed the alternative addresses for this room.": "%(senderName)s آدرس های جایگزین این اتاق را تغییر داد.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s آدرس جایگزین %(addresses)s این اتاق را حذف کرد.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "%(senderName)s آدرس های جایگزین %(addresses)s این اتاق را حذف کرد.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": "%(senderName)s آدرس جایگزین %(addresses)s را برای این اتاق اضافه کرد.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": "%(senderName)s آدرس های جایگزین %(addresses)s را برای این اتاق اضافه کرد.", + "%(senderName)s removed the main address for this room.": "%(senderName)s آدرس اصلی این اتاق را حذف کرد.", + "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s آدرس اصلی این اتاق را روی %(address)s تنظیم کرد.", + "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s تصویری ارسال کرد.", + "(no answer)": "(بدون پاسخ)", + "(an error occurred)": "(خطایی رخ داده است)", + "(their device couldn't start the camera / microphone)": "(دستگاه آنها نمی تواند دوربین / میکروفون را راه اندازی کند)", + "(connection failed)": "(ارتباط ناموفق بود)", + "(could not connect media)": "(امکان اتصال رسانه وجود ندارد)", + "(not supported by this browser)": "(توسط این مرورگر پشتیبانی نمی شود)", + "Someone": "کسی", + "Your %(brand)s is misconfigured": "%(brand)s‌ی شما به درستی پیکربندی نشده‌است", + "Ensure you have a stable internet connection, or get in touch with the server admin": "از اتصال اینترنت پایدار اطمینان حاصل‌کرده و سپس با مدیر سرور ارتباط بگیرید", + "Cannot reach homeserver": "دسترسی به سرور میسر نیست", + "See %(msgtype)s messages posted to your active room": "پیام های %(msgtype)s ارسال شده به اتاق فعال خودتان را مشاهده کنید", + "See %(msgtype)s messages posted to this room": "پیام های %(msgtype)s ارسال شده به این اتاق را مشاهده کنید", + "Send %(msgtype)s messages as you in your active room": "همانطور که در اتاق فعال خودتان هستید پیام های %(msgtype)s را ارسال کنید", + "Send %(msgtype)s messages as you in this room": "همانطور که در این اتاق هستید پیام های %(msgtype)s را ارسال کنید", + "See general files posted to your active room": "فایل‌های ارسال شده در اتاق فعال خودتان را مشاهده کنید", + "See general files posted to this room": "فایل‌های ارسال شده در این اتاق را مشاهده کنید", + "Send general files as you in your active room": "همانطور که در اتاق فعال خود هستید فایل ارسال کنید", + "Send general files as you in this room": "همانطور که در این اتاق هستید فایل ارسال کنید", + "See videos posted to your active room": "فیلم های ارسال شده در اتاق فعال خودتان را مشاهده کنید", + "See videos posted to this room": "فیلم های ارسال شده در این اتاق را مشاهده کنید", + "Send videos as you in your active room": "همانطور که در اتاق فعال خود هستید فیلم ارسال کنید", + "Send videos as you in this room": "همانطور که در این اتاق هستید فیلم ارسال کنید", + "See images posted to your active room": "تصاویری را که در اتاق فعال خودتان ارسال شده‌اند، مشاهده کنید", + "See images posted to this room": "تصاویری را که در این اتاق ارسال شده‌اند، مشاهده کنید", + "Send images as you in your active room": "همانطور که در اتاق فعال خود هستید تصاویر را ارسال کنید", + "Send images as you in this room": "همانطور که در این اتاق هستید تصاویر را ارسال کنید", + "Send emotes as you in your active room": "همانطور که در اتاق فعال خود هستید شکلک‌های خود را ارسال کنید", + "Send emotes as you in this room": "همانطور که در این اتاق هستید شکلک‌های خود را ارسال کنید", + "Send text messages as you in your active room": "همانطور که در اتاق فعال خود هستید پیام های متنی ارسال کنید", + "Send text messages as you in this room": "همانطور که در این اتاق هستید پیام های متنی ارسال کنید", + "Send messages as you in your active room": "همانطور که در اتاق فعال خود هستید پیام ارسال کنید", + "Send messages as you in this room": "همانطور که در این اتاق هستید پیام ارسال کنید", + "See emotes posted to your active room": "شکلک‌های ارسال‌شده در اتاق فعال خودتان را مشاهده کنید", + "See emotes posted to this room": "شکلک‌های ارسال‌شده در این اتاق را مشاهده کنید", + "See text messages posted to your active room": "پیام‌های متنی که در اتاق فعال شما ارسال شده‌اند را مشاهده کنید", + "See text messages posted to this room": "پیام‌های متنی که در این گروه ارسال شده‌اند را مشاهده کنید", + "See messages posted to your active room": "مشاهده‌ی پیام‌هایی که در اتاق فعال شما ارسال شده‌اند", + "See messages posted to this room": "مشاهده‌ی پیام‌هایی که در این اتاق ارسال شده‌اند", + "The %(capability)s capability": "قابلیت %(capability)s", + "See %(eventType)s events posted to your active room": "رخدادهای %(eventType)s را که در اتاق فعال شما ارسال شده، مشاهده کنید", + "See %(eventType)s events posted to this room": "رخداد‌های %(eventType)s را که در این اتاق ارسال شده‌اند مشاهده کنید", + "with state key %(stateKey)s": "با کلید وضعیت (state key) %(stateKey)s", + "Send stickers to this room as you": "با مشخصات کاربری خودتان در این گروه استیکر ارسال نمائید", + "See when people join, leave, or are invited to your active room": "هنگامی که افراد به اتاق فعال شما دعوت می‌شوند، آن را ترک می‌کنند و لیست افراد دعوت شده به آن را مشاهده کنید", + "See when the avatar changes in your active room": "تغییرات نمایه‌ی اتاق فعال خود را مشاهده کنید", + "Change the avatar of your active room": "نمایه‌ی اتاق فعال خود را تغییر دهید", + "See when the avatar changes in this room": "تغییرات نمایه‌ی این اتاق را مشاهده کنید", + "Change the avatar of this room": "نمایه‌ی این اتاق را تغییر دهید", + "See when the name changes in your active room": "تغییرات نام اتاق فعال خود را مشاهده کنید", + "Change the name of your active room": "نام اتاق فعال خود را تغییر دهید", + "See when the name changes in this room": "تغییرات نام این اتاق را مشاهده کنید", + "Change the name of this room": "نام این اتاق را تغییر دهید", + "See when the topic changes in your active room": "تغییرات عنوان را در اتاق فعال خود مشاهده کنید", + "Change the topic of your active room": "عنوان اتاق فعال خود را تغییر دهید", + "See when the topic changes in this room": "تغییرات عنوان این اتاق را مشاهده کنید", + "Change the topic of this room": "عنوان این اتاق را تغییر دهید", + "Change which room, message, or user you're viewing": "اتاق، پیام و کاربرانی را که مشاهده می‌کنید، تغییر دهید", + "Change which room you're viewing": "اتاق‌هایی را که مشاهده می‌کنید تغییر دهید", + "Send stickers into your active room": "در اتاق‌های فعال خود استیکر ارسال کنید", + "Send stickers into this room": "در این اتاق استیکر ارسال کنید", + "%(names)s and %(lastPerson)s are typing …": "%(names)s و %(lastPerson)s در حال نوشتن…", + "%(names)s and %(count)s others are typing …|one": "%(names)s و یک نفر دیگر در حال نوشتن…", + "%(names)s and %(count)s others are typing …|other": "%(names)s و %(count)s نفر دیگر در حال نوشتن…", + "%(displayName)s is typing …": "%(displayName)s در حال نوشتن…", + "Dark": "تاریک", + "Light": "روشن", + "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s یک قاعده تحریم را که با %(oldGlob)s تطابق داشت، به دلیل (دلایل) %(reason)s به گونه‌ای به‌روزرسانی کرد که با %(newGlob)s تطابق داشته باشد", + "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s یک قاعده تحریم سرورها را که با %(oldGlob)s تطابق داشت، به دلیل (دلایل) %(reason)s به گونه‌ای تغییر داد که با %(newGlob)s تطابق داشته باشد", + "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s یک قاعده تحریم اتاق‌ها را که با %(oldGlob)s تطابق داشت، به دلیل (دلایل) %(reason)s به گونه‌ای تغییر داد که با %(newGlob)s تطابق داشته باشد", + "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s یک قاعده تحریم کاربران را که با %(oldGlob)s تطابق داشت، به دلیل (دلایل) %(reason)s به گونه‌ای تغییر داد که با %(newGlob)s تطابق داشته باشد", + "%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s یک قاعده تحریم را که با %(glob)s تطابق دارد، به دلیل (دلایل) %(reason)s ایجاد کرد", + "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s یک قاعده تحریم سرورها را که با %(glob)s تطابق دارد، به دلیل (دلایل) %(reason)s ایجاد کرد", + "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s یک قاعده تحریم اتاق‌ها را که با %(glob)s تطابق دارد، به دلیل (دلایل) %(reason)s ایجاد کرد", + "%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s یک قاعده تحریم کاربران را که با %(glob)s تطابق دارد، به دلیل (دلایل) %(reason)s ایجاد کرد", + "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s یک قاعده تحریم را که با %(glob)s تطابق داشت، به دلیل (دلایل) %(reason)s به‌روزرسانی کرد", + "%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s قاعده تحریم سرورها را که با %(glob)s تطابق داشت، به دلیل (دلایل) %(reason)s به‌روزرسانی کرد", + "%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s قاعده تحریم اتاق‌ها را که با %(glob)s تطابق داشت، به دلیل (دلایل) %(reason)s به‌روزرسانی کرد", + "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s قاعده تحریم کاربران را که با %(glob)s تطابق داشت، به دلیل (دلایل) %(reason)s به‌روزرسانی کرد", + "%(senderName)s updated an invalid ban rule": "%(senderName)s یک قاعده‌ی تحریم نامعتبر را به‌روزرسانی کرد", + "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s قاعده تحریمی را که با %(glob)s تطابق داشت، حذف کرد", + "%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s قاعده تحریم سرورها را که با %(glob)s تطابق داشت، حذف کرد", + "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s قاعده تحریم اتاق‌ها را که با %(glob)s تطابق داشت، حذف کرد", + "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s قاعده تحریم کاربران را که با %(glob)s تطابق داشت، حذف کرد", + "%(senderName)s has updated the widget layout": "%(senderName)s چیدمان ویجت را به‌روز کرد", + "%(widgetName)s widget removed by %(senderName)s": "ویجت %(widgetName)s توسط %(senderName)s حذف گردید", + "%(widgetName)s widget added by %(senderName)s": "ویجت %(widgetName)s توسط %(senderName)s اضافه شد", + "%(widgetName)s widget modified by %(senderName)s": "ویجت %(widgetName)s توسط %(senderName)s تغییر کرد", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s قابلیت flair را در این اتاق برای %(newGroups)s فعال و برای %(oldGroups)s غیر فعال کرد.", + "The server has denied your request.": "سرور درخواست شما را رد کرده است.", + "Use your Security Key to continue.": "برای ادامه از کلید امنیتی خود استفاده کنید.", + "This session, or the other session": "این نشست، یا نشست دیگر", + "%(creator)s created and configured the room.": "%(creator)s اتاق را ایجاد و پیکربندی کرد.", + "Report Content to Your Homeserver Administrator": "گزارش محتوا به مدیر سرور خود", + "Be found by phone or email": "از طریق تلفن یا ایمیل پیدا شوید", + "Find others by phone or email": "دیگران را از طریق تلفن یا ایمیل پیدا کنید", + "Sign out and remove encryption keys?": "خروج از حساب کاربری و حذف کلیدهای رمزنگاری؟", + "Remember my selection for this widget": "انتخاب من برای این ابزارک را بخاطر بسپار", + "I don't want my encrypted messages": "پیام‌های رمزشده‌ی خود را نمی‌خواهم", + "Upgrade this room to version %(version)s": "این اتاق را به نسخه %(version)s ارتقا دهید", + "Please enter the code it contains:": "لطفا کدی را که در آن وجود دارد وارد کنید:", + "Failed to save space settings.": "تنظیمات فضای کاری ذخیره نشد.", + "Not a valid Security Key": "کلید امنیتی معتبری نیست", + "This widget would like to:": "این ابزارک تمایل دارد:", + "Unable to set up keys": "تنظیم کلیدها امکان پذیر نیست", + "%(completed)s of %(total)s keys restored": "%(completed)s از %(total)s کلید بازیابی شدند", + "a new cross-signing key signature": "یک کلید امضای متقابل جدید", + "a new master key signature": "یک شاه‌کلید جدید", + "Close dialog or context menu": "بستن پنجره یا منو", + "Your account is not secure": "حساب کاربری شما امن نیست", + "Please fill why you're reporting.": "لطفا توضیح دهید که چرا گزارش می‌دهید.", + "Password is allowed, but unsafe": "گذرواژه مجاز است ، اما ناامن است", + "Upload files (%(current)s of %(total)s)": "بارگذاری فایل‌ها (%(current)s از %(total)s)", + "Failed to decrypt %(failedCount)s sessions!": "رمزگشایی %(failedCount)s نشست موفقیت‌آمیز نبود!", + "Unable to load backup status": "بارگیری و نمایش وضعیت نسخه‌ی پشتیبان امکان‌پذیر نیست", + "Link to most recent message": "پیوند به آخرین پیام", + "Clear Storage and Sign Out": "فضای ذخیره‌سازی را پاک کرده و از حساب کاربری خارج شوید", + "Error whilst fetching joined communities": "هنگام واکشی اجتماع‌هایی که عضو آن‌ها هستید، خطایی رخ داد", + "Make this space private": "این فضای کاری را خصوصی کن", + "Unable to validate homeserver": "تأیید اعتبار سرور امکان‌پذیر نیست", + "Sign into your homeserver": "وارد سرور خود شوید", + "%(creator)s created this DM.": "%(creator)s این گفتگو را ایجاد کرد.", + "You’re all caught up": "همه‌ی کارها را انجام دادید", + "The server is offline.": "سرور آفلاین است.", + "You're all caught up.": "همه‌ی کارها را انجام دادید.", + "Successfully restored %(sessionCount)s keys": "کلیدهای %(sessionCount)s با موفقیت بازیابی شدند", + "Fetching keys from server...": "واکشی کلیدها از سرور ...", + "Restoring keys from backup": "بازیابی کلیدها از نسخه پشتیبان", + "Interactively verify by Emoji": "تأیید تعاملی با استفاده از شکلک", + "Manually Verify by Text": "تائید دستی با استفاده از متن", + "a device cross-signing signature": "کلید امضای متقابل یک دستگاه", + "Upload %(count)s other files|one": "بارگذاری %(count)s فایل دیگر", + "Upload %(count)s other files|other": "بارگذاری %(count)s فایل دیگر", + "Room Settings - %(roomName)s": "تنظیمات اتاق - %(roomName)s", + "Start using Key Backup": "شروع استفاده از نسخه‌ی پشتیبان کلید", + "Unable to restore backup": "بازیابی نسخه پشتیبان امکان پذیر نیست", + "Clear cache and resync": "پاک کردن حافظه‌ی کش و همگام سازی مجدد", + "Failed to upgrade room": "اتاق ارتقاء نیافت", + "Link to selected message": "پیوند به پیام انتخاب شده", + "Failed to load %(groupId)s": "بارگیری و نمایش %(groupId)s انجام نشد", + "Community %(groupId)s not found": "اجتماع %(groupId)s یافت نشد", + "Unable to restore session": "امکان بازیابی نشست وجود ندارد", + "Verify other login": "ورود دیگر را تائید کنید", + "Reset event store": "پاک‌کردن مخزن رخداد", + "Reset event store?": "پاک‌کردن مخزن رخداد؟", + "%(count)s messages deleted.|one": "%(count)s پیام پاک شد.", + "%(count)s messages deleted.|other": "%(count)s پیام پاک شد.", + "Invite to %(roomName)s": "دعوت به %(roomName)s", + "View dev tools": "مشاهده ابزارهای توسعه", + "Upgrade to %(hostSignupBrand)s": "ارتقاء به %(hostSignupBrand)s", + "Enter Security Key": "کلید امنیتی را وارد کنید", + "Enter Security Phrase": "عبارت امنیتی را وارد کنید", + "Incorrect Security Phrase": "عبارت امنیتی نادرست است", + "Security Key mismatch": "عدم تطابق کلید امنیتی", + "Invalid Security Key": "کلید امنیتی نامعتبر است", + "Wrong Security Key": "کلید امنیتی اشتباه است", + "Specify a homeserver": "یک سرور مشخص کنید", + "Continuing without email": "ادامه بدون ایمیل", + "Approve widget permissions": "دسترسی‌های ابزارک را تائید کنید", + "Server isn't responding": "سرور پاسخ نمی دهد", + "Unable to upload": "بارگذاری امکان پذیر نیست", + "Signature upload failed": "بارگذاری امضا انجام نشد", + "Signature upload success": "موفقیت در بارگذاری امضا", + "Cancelled signature upload": "بارگذاری امضا لغو شد", + "a key signature": "یک امضای کلیدی", + "Clear cross-signing keys": "کلیدهای امضای متقابل را پاک کن", + "Destroy cross-signing keys?": "کلیدهای امضای متقابل نابود شود؟", + "This wasn't me": "این من نبودم", + "Recently Direct Messaged": "گفتگوهای خصوصی اخیر", + "Upgrade public room": "ارتقاء اتاق عمومی", + "Upgrade private room": "ارتقاء اتاق خصوصی", + "Automatically invite users": "به طور خودکار کاربران را دعوت کن", + "Resend %(unsentCount)s reaction(s)": "بازارسال %(unsentCount)s واکنش", + "Missing session data": "داده‌های نشست از دست رفته است", + "Manually export keys": "کلیدها را به صورت دستی استخراج (Export)کن", + "No backup found!": "نسخه پشتیبان یافت نشد!", + "Incompatible local cache": "حافظه‌ی محلی ناسازگار", + "Upgrade Room Version": "ارتقاء نسخه‌ی اتاق", + "Share Room Message": "به اشتراک گذاشتن پیام اتاق", + "Collapse Reply Thread": "جمع کردن ریسه‌ی پاسخ", + "Reset everything": "همه چیز را بازراه‌اندازی (reset) کنید", + "Consult first": "ابتدا مشورت کنید", + "Save Changes": "ذخیره تغییرات", + "Leave Space": "ترک فضای کاری", + "Space settings": "تنظیمات فضای کاری", + "Unnamed Space": "فضای کاری بدون نام", + "Remember this": "این را به یاد داشته باش", + "Invalid URL": "آدرس URL نامعتبر", + "About homeservers": "درباره سرورها", + "Learn more": "بیشتر بدانید", + "Other homeserver": "سرور دیگر", + "Decline All": "رد کردن همه", + "Modal Widget": "ابزارک کمکی", + "Updating %(brand)s": "به‌روزرسانی %(brand)s", + "Looks good!": "به نظر خوب میاد!", + "Security Key": "کلید امنیتی", + "Security Phrase": "عبارت امنیتی", + "Keys restored": "کلیدها بازیابی شدند", + "Upload completed": "بارگذاری انجام شد", + "Your password": "گذرواژه شما", + "Not Trusted": "قابل اعتماد نیست", + "Session key": "کلید نشست", + "Session name": "نام نشست", + "Verify session": "تائید نشست", + "New session": "نشست جدید", + "Country Dropdown": "لیست کشور", + "Verification Request": "درخواست تأیید", + "Send report": "ارسال گزارش", + "Integration Manager": "مدیر یکپارچه‌سازی", + "Command Help": "راهنمای دستور", + "Message edits": "ویرایش پیام", + "Upload all": "بارگذاری همه", + "Upload Error": "خطای بارگذاری", + "Cancel All": "لغو همه", + "Upload files": "بارگذاری فایل‌ها", + "Phone (optional)": "شماره تلفن (اختیاری)", + "Email (optional)": "ایمیل (اختیاری)", + "Share Community": "به اشتراک‌گذاری اجتماع", + "Share User": "به اشتراک‌گذاری کاربر", + "Share Room": "به اشتراک‌گذاری اتاق", + "Send Logs": "ارسال گزارش ها", + "Suggestions": "پیشنهادات", + "Recent Conversations": "گفتگوهای اخیر", + "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "این کاربران ممکن است وجود نداشته یا نامعتبر باشند و نمی‌توان آنها را دعوت کرد: %(csvNames)s", + "Failed to find the following users": "این کاربران یافت نشدند", + "Failed to transfer call": "انتقال تماس انجام نشد", + "A call can only be transferred to a single user.": "تماس فقط می تواند به یک کاربر منتقل شود.", + "We couldn't invite those users. Please check the users you want to invite and try again.": "ما نتوانستیم آن کاربران را دعوت کنیم. لطفاً کاربرانی را که می خواهید دعوت کنید بررسی کرده و دوباره امتحان کنید.", + "Something went wrong trying to invite the users.": "در تلاش برای دعوت از کاربران مشکلی پیش آمد.", + "We couldn't create your DM.": "نتوانستیم گفتگوی خصوصی مد نظرتان را ایجاد کنیم.", + "Failed to invite the following users to chat: %(csvUsers)s": "دعوت از این کاربران برای شروع گفتگو موفقیت‌آمیز نبود: %(csvUsers)s", + "Invite by email": "دعوت از طریق ایمیل", + "Click the button below to confirm your identity.": "برای تأیید هویت خود بر روی دکمه زیر کلیک کنید.", + "Confirm to continue": "برای ادامه تأیید کنید", + "To continue, use Single Sign On to prove your identity.": "برای ادامه از احراز هویت یکپارچه جهت اثبات هویت خود استفاده نمائید.", + "Your %(brand)s doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "%(brand)s شما اجازه استفاده از سیستم مدیریت ادغام را برای این کار نمی دهد. لطفا با ادمین تماس بگیرید.", + "Integrations not allowed": "یکپارچه‌سازی‌ها اجازه داده نشده‌اند", + "Enable 'Manage Integrations' in Settings to do this.": "برای انجام این کار 'مدیریت پکپارچه‌سازی‌ها' را در تنظیمات فعال نمائید.", + "Integrations are disabled": "پکپارچه‌سازی‌ها غیر فعال هستند", + "Incoming Verification Request": "درخواست تأیید دریافتی", + "Waiting for partner to confirm...": "منتظر تائید طرف مقابل...", + "Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "با تأیید این دستگاه، آن را به عنوان مورد اعتماد علامت‌گذاری کرده و کاربرانی که شما را تأیید کرده اند، به این دستگاه اعتماد خواهند کرد.", + "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "این دستگاه را تأیید کنید تا به عنوان مورد اعتماد علامت‌گذاری شود. اعتماد به این دستگاه در هنگام استفاده از رمزنگاری سرتاسر آرامش و اطمینان بیشتری را برای شما به ارمغان می‌آورد.", + "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "با تأیید این کاربر ، نشست وی به عنوان مورد اعتماد علامت‌گذاری شده و همچنین نشست شما به عنوان مورد اعتماد برای وی علامت‌گذاری خواهد شد.", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "این کاربر را تأیید کنید تا به عنوان کاربر مورد اعتماد علامت‌گذاری شود. اعتماد به کاربران آرامش و اطمینان بیشتری به شما در استفاده از رمزنگاری سرتاسر می‌دهد.", + "Minimize dialog": "کوچک‌کردن پنجره", + "Maximize dialog": "بزرگ‌کردن پنجره", + "%(hostSignupBrand)s Setup": "راه‌اندازی %(hostSignupBrand)s", + "You should know": "باید بدانید", + "Terms of Service": "شرایط استفاده از خدمات", + "Privacy Policy": "سیاست حفظ حریم خصوصی", + "Cookie Policy": "سیاست کوکی", + "Learn more in our , and .": "درباره‌ی ، و بیشتر بدانید.", + "Continuing temporarily allows the %(hostSignupBrand)s setup process to access your account to fetch verified email addresses. This data is not stored.": "ادامه‌ی موقت به فرآیند راه‌اندازی%(hostSignupBrand)s اجازه می‌دهد به حساب کاربری شما برای تائید آدرس‌های ایمیلتان دسترسی داشته باشد. این داده‌ها ذخیره نمی‌شوند.", + "Failed to connect to your homeserver. Please close this dialog and try again.": "اتصال به سرور شما انجام نشد. لطفاً این پنجره را بسته و دوباره امتحان کنید.", + "Abort": "لغوکردن", + "Are you sure you wish to abort creation of the host? The process cannot be continued.": "آیا مطمئن هستید که می‌خواهید ایجاد هاست را لغو کنید؟ این فرآیند را نمی‌توان ادامه داد.", + "Confirm abort of host creation": "لغو ایجاد هاست را تأیید کنید", + "Please view existing bugs on Github first. No match? Start a new one.": "لطفاً ابتدا اشکالات موجود را در گیتهاب برنامه را مشاهده کنید. با اشکال شما مطابقتی وجود ندارد؟ مورد جدیدی را ثبت کنید.", + "Report a bug": "گزارش اشکال", + "PRO TIP: If you start a bug, please submit debug logs to help us track down the problem.": "نکته‌ای برای کاربران حرفه‌ای: اگر به مشکل نرم‌افزاری در برنامه برخورد کردید، لطفاً لاگ‌های مشکل را ارسال کنید تا به ما در ردیابی و رفع آن کمک کند.", + "There are two ways you can provide feedback and help us improve %(brand)s.": "به دو روش می توانید بازخوردهای خود را برای کمک به ما در بهبود %(brand)s برسانید.", + "Comment": "نظر", + "Add comment": "افزودن نظر", + "Please go into as much detail as you like, so we can track down the problem.": "لطفاً به اندازه دلخواه با جزئیات توضیح دهید تا بتوانیم مشکل را ردیابی و حل کنیم.", + "Tell us below how you feel about %(brand)s so far.": "در زیر به ما بگویید که تاکنون چه احساسی نسبت به %(brand)s داشته‌اید.", + "Rate %(brand)s": "به %(brand)s امتیاز دهید", + "Feedback sent": "بازخورد ارسال شد", + "Update community": "به‌روزرسانی اجتماع", + "There was an error updating your community. The server is unable to process your request.": "در به‌روزرسانی اجتماع شما خطایی روی داد. سرور قادر به پردازش درخواست شما نیست.", + "Developer Tools": "ابزارهای توسعه‌دهنده", + "Toolbox": "جعبه ابزار", + "Edit Values": "ویرایش مقادیر", + "Values at explicit levels in this room:": "مقادیر در سطوح مشخص در این اتاق:", + "Values at explicit levels:": "مقدار در سطوح مشخص:", + "Value in this room:": "مقدار در این اتاق:", + "Value:": "مقدار:", + "Save setting values": "ذخیره مقادیر تنظیمات", + "Values at explicit levels in this room": "مقادیر در سطوح مشخص در این اتاق", + "Values at explicit levels": "مقادیر در سطوح مشخص", + "Settable at room": "قابل تنظیم در اتاق", + "Settable at global": "قابل تنظیم به شکل سراسری", + "Level": "سطح", + "Setting definition:": "تعریف تنظیم:", + "This UI does NOT check the types of the values. Use at your own risk.": "این واسط کاربری تایپ مقادیر را بررسی نمی‌کند. با مسئولیت خود استفاده کنید.", + "Caution:": "احتیاط:", + "Setting:": "تنظیم:", + "Value in this room": "مقدار در این اتاق", + "Value": "مقدار", + "Setting ID": "شناسه تنظیم", + "Failed to save settings": "تنظیمات ذخیره نشد", + "Settings Explorer": "تنظیمات جستجوگر", + "There was an error finding this widget.": "هنگام یافتن این ابزارک خطایی روی داد.", + "Active Widgets": "ابزارک‌های فعال", + "Search names and descriptions": "جستجوی نام‌ها و توضیحات", + "If you can't find the room you're looking for, ask for an invite or create a new room.": "اگر نمی‌توانید اتاقی را که به دنبال آن می‌گردید پیدا کنید ، بخواهید که شما را به آن دعوت کنند یا یک اتاق جدید بسازید.", + "To view %(spaceName)s, turn on the Spaces beta": "برای مشاهده %(spaceName)s، قابلیت فضای کاری بتا را فعال نمائید", + "To join %(spaceName)s, turn on the Spaces beta": "برای پیوستن به %(spaceName)s، قابلیت فضای کاری بتا را فعال نمائید", + "Failed to create initial space rooms": "ایجاد اتاق‌های اولیه در فضای کاری موفق نبود", + "What do you want to organise?": "چه چیزی را می‌خواهید سازماندهی کنید؟", + "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "اگر اتاق فقط برای همکاری با تیم های داخلی در سرور خانه شما استفاده شود ، ممکن است این قابلیت را فعال کنید. این بعدا نمی تواند تغییر کند.", + "Enable end-to-end encryption": "فعال کردن رمزنگاری سرتاسر", + "Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "گفتگوهای خصوصی یا اتاق‌هایی را برای افزودن انتخاب کنید. این فقط یک فضای کاری برای شماست، هیچ کس از وجود آن مطلع نخواهد شد. می‌توانید موارد بیشتری را بعدا اضافه کنید.", + "Your server requires encryption to be enabled in private rooms.": "سرور شما به گونه‌ای تنظیم شده‌است که فعال بودن رمزنگاری سرتاسر در اتاق‌های خصوصی اجباری می‌باشد.", + "You can’t disable this later. Bridges & most bots won’t work yet.": "بعداً نمی توانید این را لغو کنید. پل‌ها و بیشتر ربات‌ها هنوز کار نمی کنند.", + "Share %(name)s": "به اشتراک‌گذاری %(name)s", + "It's just you at the moment, it will be even better with others.": "در حال حاضر فقط شما حضور دارید ، با دیگران حتی بهتر هم خواهد بود.", + "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "اتاق‌های خصوصی را فقط با دعوت می‌توان یافت و به آن‌ها پیوست. اتاق‌های عمومی را هر کسی در این اجتماع می‌تواند بیابد و به آن بپیوندد.", + "Go to my first room": "برو به اتاق اول من", + "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "اتاق‌های خصوصی را فقط با دعوت می‌توان یافت و به آن‌ها پیوست. اما اتاق‌های عمومی را هر کسی می تواند را پیدا کند و به آن‌ها ملحق شود.", + "Please enter a name for the room": "لطفاً نامی برای اتاق وارد کنید", + "Community ID": "شناسه اجتماع", + "Community Name": "نام اجتماع", + "Create Community": "ایجاد اجتماع", + "Something went wrong whilst creating your community": "هنگام ایجاد اجتماع مشکلی پیش آمد", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "شناسه اجتماع باید فقط حاوی کاراکتر‌های a-z، 0-9 یا '=_-./' باشد", + "Community IDs cannot be empty.": "شناسه اجتماع نمی تواند خالی باشد.", + "An image will help people identify your community.": "تصویر به افراد کمک می کند تا با سهولت بیشتری اجتماع شما پیدا کنند.", + "Add image (optional)": "افزودن تصویر (اختیاری)", + "Enter name": "ورود نام", + "What's the name of your community or team?": "نام اجتماع یا تیم شما چیست؟", + "You can change this later if needed.": "در صورت نیاز می توانید بعداً این مورد را تغییر دهید.", + "Use this when referencing your community to others. The community ID cannot be changed.": "هنگام ارجاع دادن دیگران به اجتماع خود، از این مورد استفاده کنید. شناسه اجتماع قابل تغییر نیست.", + "Community ID: +:%(domain)s": "شناسه اجتماع: %(domain)s:+", + "There was an error creating your community. The name may be taken or the server is unable to process your request.": "هنگام ایجاد اجتماع خطایی روی داد. ممکن است نام گرفته شده‌باشد و یا اینکه سرور نتواند درخواست شما را پردازش کند.", + "Clear all data": "پاک کردن همه داده ها", + "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "پاک کردن همه داده های این جلسه غیرقابل بازگشت است. پیامهای رمزگذاری شده از بین می‌روند مگر اینکه از کلیدهای آنها پشتیبان تهیه شده باشد.", + "Clear all data in this session?": "همه داده‌های این نشست پاک شود؟", + "Go to my space": "برو به محیط کاری من", + "Who are you working with?": "با چه کسانی کار می‌کنید؟", + "Make sure the right people have access to %(name)s": "اطمینان حاصل کنید که افراد مناسب به %(name)s دسترسی دارند", + "Just me": "فقط من", + "A private space to organise your rooms": "یک فضای کار خصوصی برای منظم‌کردن اتاق‌هایتان", + "Me and my teammates": "من و هم‌تیمی‌هایم", + "A private space for you and your teammates": "یک فضای کار خصوصی برای شما و هم تیمی‌هایتان", + "Reason (optional)": "دلیل (اختیاری)", + "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "آیا مطمئن هستید که می خواهید این رویداد را حذف کنید؟ توجه داشته باشید که اگر نام اتاق یا تغییر موضوع را حذف کنید، این تغییر می تواند لغو شود.", + "Failed to invite the following users to your space: %(csvUsers)s": "امکان دعوت کاربرانی که در ادامه آمده‌اند به فضای کاری شما میسر نیست: %(csvUsers)s", + "Invite your teammates": "هم‌تیمی‌های خود را دعوت کنید", + "Make sure the right people have access. You can invite more later.": "اطمینان حاصل کنید که افراد مناسب دسترسی دارند. بعداً می توانید افراد بیشتری دعوت کنید.", + "This is an experimental feature. For now, new users receiving an invite will have to open the invite on to actually join.": "این یک قابلیت آزمایشی است. برای الان، کاربران جدیدی که دعوتنامه دریافت می‌کنند باید آن را بر روی باز کنند تا بتوانند عضو شوند.", + "Invite by username": "دعوت به نام کاربری", + "What are some things you want to discuss in %(spaceName)s?": "برخی از مواردی که می خواهید درباره‌ی آن‌ها در %(spaceName)s بحث کنید، چیست؟", + "Let's create a room for each of them.": "بیایید برای هر یک از آنها یک اتاق درست کنیم.", + "You can add more later too, including already existing ones.": "بعداً می توانید موارد بیشتری را اضافه کنید ، از جمله موارد موجود.", + "What projects are you working on?": "روی چه پروژه‌هایی کار می‌کنید؟", + "Confirm Removal": "تأیید حذف", + "Removing…": "در حال حذف…", + "Invite people to join %(communityName)s": "از افراد برای پیوستن به %(communityName)s دعوت کنید", + "Send %(count)s invites|one": "ارسال %(count)s دعوت", + "Send %(count)s invites|other": "ارسال %(count)s دعوت", + "Show": "نمایش", + "Hide": "پنهان کردن", + "People you know on %(brand)s": "افرادی که در %(brand)s می‌شناسید", + "Add another email": "ایمیل دیگری اضافه کنید", + "Unable to load commit detail: %(msg)s": "بارگیری جزئیات commit انجام نشد: %(msg)s", + "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "اگر زمینه دیگری وجود دارد که می تواند به تجزیه و تحلیل مسئله کمک کند، مانند آنچه در آن زمان انجام می دادید، شناسه اتاق، شناسه کاربر و غیره ، لطفاً موارد ذکر شده را در اینجا وارد کنید.", + "Notes": "یادداشت‌ها", + "We'll create rooms for each of them. You can add more later too, including already existing ones.": "ما برای هر یک از آنها اتاق ایجاد خواهیم کرد. بعداً می توانید موارد دیگر را اضافه کنید ، از جمله موارد موجود.", + "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "سعی شد یک نقطه‌ی زمانی خاص در پیام‌های این اتاق بارگیری و نمایش داده شود، اما شما دسترسی لازم برای مشاهده‌ی پیام را ندارید.", + "GitHub issue": "مسئله GitHub", + "Download logs": "دانلود گزارش‌ها", + "Before submitting logs, you must create a GitHub issue to describe your problem.": "قبل از ارسال گزارش‌ها، برای توصیف مشکل خود باید یک مسئله در GitHub ایجاد کنید.", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "سعی شد یک نقطه‌ی زمانی خاص در پیام‌های این اتاق بارگیری و نمایش داده شود، اما پیداکردن آن میسر نیست.", + "Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "گزارش‌های اشکال زدایی حاوی داده‌های استفاده از برنامه شامل نام کاربری شما، شناسه‌ها یا نام مستعار اتاق‌ها یا گروه‌هایی است که بازدید کرده‌اید و همچنین نام‌ کاربری کاربران دیگر. این گزارش‌ها حاوی پیام‌های شما نمی‌باشند.", + "Failed to load timeline position": "بارگیری و نمایش پیام‌ها با مشکل مواجه شد", + "Uploading %(filename)s and %(count)s others|other": "در حال بارگذاری %(filename)s و %(count)s مورد دیگر", + "Uploading %(filename)s and %(count)s others|zero": "در حال بارگذاری %(filename)s", + "Uploading %(filename)s and %(count)s others|one": "در حال بارگذاری %(filename)s و %(count)s مورد دیگر", + "Failed to find the general chat for this community": "گفتگوی عمومی برای این اجتماع پیدا نشد", + "Reminder: Your browser is unsupported, so your experience may be unpredictable.": "یادآوری: مرورگر شما پشتیبانی نمی شود ، بنابراین ممکن است تجربه شما غیرقابل پیش بینی باشد.", + "Preparing to download logs": "در حال آماده سازی برای بارگیری گزارش ها", + "Got an account? Sign in": "حساب کاربری دارید؟ وارد شوید", + "Failed to send logs: ": "ارسال گزارش با خطا مواجه شد: ", + "New here? Create an account": "تازه وارد هستید؟ یک حساب کاربری ایجاد کنید", + "Thank you!": "با سپاس!", + "The email address linked to your account must be entered.": "آدرس ایمیلی که به حساب کاربری شما متصل است، باید وارد شود.", + "Logs sent": "گزارش‌های مربوط ارسال شد", + "Preparing to send logs": "در حال آماده سازی برای ارسال گزارش ها", + "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "لطفاً به ما بگویید چه مشکلی پیش آمد و یا اینکه لطف کنید و یک مسئله GitHub ایجاد کنید که مشکل را توصیف کند.", + "Changing your password will reset any end-to-end encryption keys on all of your sessions, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another session before resetting your password.": "تغییر گذرواژه ، تمام کلیدهای رمزنگاریِ سرتاسر در تمام نشست‌های شما را پاک کرده و تاریخچه چت‌های رمزشده را غیرقابل خواندن می‌کند. قبل از تغییر گذرواژه خود ، پشتیبان‌گیری از کلید‌ها را تنظیم یا کلیدهای اتاق‌های خود را از نشست دیگری استخراج (Export) کنید.", + "Send feedback": "ارسال بازخورد", + "You may contact me if you have any follow up questions": "در صورت داشتن هرگونه سوال پیگیری ممکن است با من تماس بگیرید", + "Feedback": "بازخورد", + "To leave the beta, visit your settings.": "برای خروج از بتا به بخش تنظیمات مراجعه کنید.", + "Your platform and username will be noted to help us use your feedback as much as we can.": "سیستم‌عامل و نام کاربری شما ثبت خواهد شد تا به ما کمک کند تا جایی که می توانیم از نظرات شما استفاده کنیم.", + "%(featureName)s beta feedback": "بازخورد بتا برای %(featureName)s", + "A verification email will be sent to your inbox to confirm setting your new password.": "برای تأیید تنظیم گذرواژه جدید ، یک ایمیل تأیید به صندوق ورودی شما ارسال می شود.", + "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "یک ایمیل به %(emailAddress)s ارسال شده‌است. بعد از کلیک بر روی لینک داخل آن ایمیل، روی مورد زیر کلیک کنید.", + "Done": "انجام شد", + "Thank you for your feedback, we really appreciate it.": "از بازخورد شما متشکریم ، ما واقعاً از آن استقبال می کنیم.", + "Beta feedback": "بازخورد بتا", + "Close dialog": "بستن گفتگو", + "Invite anyway": "به هر حال دعوت کن", + "You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "شما از همه نشست‌ها خارج شده و دیگر اعلان پیام‌ها را دریافت نخواهید کرد. برای فعال کردن مجدد اعلان‌ها در هر دستگاه، دوباره وارد شوید.", + "Invite anyway and never warn me again": "به هر حال دعوت کن و دیگر هرگز به من هشدار نده", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "برای شناسه‌های ماتریکس زیر، پروفایلی پیدا نشد - آیا به هر حال می خواهید آنها را دعوت کنید؟", + "Invalid homeserver discovery response": "پاسخ جستجوی سرور معتبر نیست", + "Failed to get autodiscovery configuration from server": "دریافت پیکربندیِ جستجوی خودکار از سرور موفقیت‌آمیز نبود", + "The following users may not exist": "کاربران زیر ممکن است وجود نداشته باشند", + "Use an identity server to invite by email. Manage in Settings.": "از یک سرور هویت‌سنجی برای دعوت از طریق ایمیل استفاده کنید. اینکار را می‌توانید از طریق بخش تنظیمات انجام دهید.", + "Invalid base_url for m.homeserver": "base_url نامعتبر برای m.homeserver", + "Homeserver URL does not appear to be a valid Matrix homeserver": "به نظر می‌رسد که آدرس سرور، متعلق به یک سرور معتبر نباشد", + "Use an identity server to invite by email. Use the default (%(defaultIdentityServerName)s) or manage in Settings.": "از یک سرور هویت‌سنجی برای دعوت از طریق ایمیل استفاده کنید. از پیش فرض (%(defaultIdentityServerName)s) استفاده کنید یا آن را در بخش تنظیمات مدیریت کنید.", + "Invalid identity server discovery response": "پاسخ نامعتبر برای جستجوی سرور هویت‌سنجی", + "Invalid base_url for m.identity_server": "base_url نامعتبر برای سرور m.identity_server", + "Identity server URL does not appear to be a valid identity server": "به نظر می‌رسد آدرس سرور هویت‌سنجی، متعلق به یک سرور هویت‌سنجی معتبر نیست", + "Try using one of the following valid address types: %(validTypesList)s.": "از یکی از انواع آدرس‌های معتبر زیر استفاده کنید: %(validTypesList)s.", + "Wrong file type": "نوع فایل اشتباه است", + "Confirm encryption setup": "راه‌اندازی رمزگذاری را تأیید کنید", + "You have entered an invalid address.": "آدرسی که وارد کرده‌اید نامعتبر است.", + "General failure": "خطای عمومی", + "That doesn't look like a valid email address": "آدرس ایمیل نامعتبر است", + "This homeserver does not support login using email address.": "این سرور از ورود با استفاده از آدرس ایمیل پشتیبانی نمی کند.", + "Please contact your service administrator to continue using this service.": "لطفاً برای ادامه استفاده از این سرویس با مدیر سرور خود تماس بگیرید .", + "email address": "آدرس ایمیل", + "Matrix Room ID": "شناسه اتاق ماتریکس", + "Matrix ID": "شناسه ماتریکس", + "Create a new room": "ایجاد اتاق جدید", + "This account has been deactivated.": "این حساب غیر فعال شده است.", + "Please note you are logging into the %(hs)s server, not matrix.org.": "لطفا توجه کنید شما به سرور %(hs)s وارد شده‌اید، و نه سرور matrix.org.", + "Want to add a new room instead?": "آیا می‌خواهید یک اتاق جدید را بیفزایید؟", + "Add existing rooms": "افزودن اتاق‌های موجود", + "Space selection": "انتخاب فضای کاری", + "There was a problem communicating with the homeserver, please try again later.": "در برقراری ارتباط با سرور مشکلی پیش آمده، لطفاً چند لحظه‌ی دیگر مجددا امتحان کنید.", + "Filter your rooms and spaces": "اتاق‌ها و فضاهای کاری خود را فیلتر کنید", + "Adding rooms... (%(progress)s out of %(count)s)|one": "در حال افزودن اتاق‌ها...", + "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "امکان اتصال به سرور از طریق پروتکل‌های HTTP و HTTPS در مروگر شما میسر نیست. یا از HTTPS استفاده کرده و یا حالت اجرای غیرامن اسکریپت‌ها را فعال کنید.", + "Adding rooms... (%(progress)s out of %(count)s)|other": "در حال افزودن اتاق‌ها... (%(progress)s از %(count)s)", + "Not all selected were added": "همه‌ی موارد انتخاب شده، اضافه نشدند", + "Matrix rooms": "اتاق‌های ماتریکس", + "%(networkName)s rooms": "اتاق‌های %(networkName)s", + "Add a new server...": "افزودن سرور جدید ...", + "Server name": "نام سرور", + "Enter the name of a new server you want to explore.": "نام سرور جدیدی که می خواهید در آن کاوش کنید را وارد کنید.", + "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "اتصال به سرور میسر نیست - لطفا اتصال اینترنت خود را بررسی کنید؛ اطمینان حاصل کنید گواهینامه‌ی SSL سرور شما قابل اعتماد است، و اینکه پلاگینی بر روی مرورگر شما مانع از ارسال درخواست به سرور نمی‌شود.", + "Add a new server": "افزودن سرور جدید", + "Matrix": "ماتریکس", + "Remove server": "حذف سرور", + "Are you sure you want to remove %(serverName)s": "آیا مطمئن هستید که می خواهید %(serverName)s را حذف کنید", + "Your server": "سرور شما", + "Can't find this server or its room list": "این سرور و یا لیست اتاق‌های آن پیدا نمی شود", + "You are not allowed to view this server's rooms list": "شما مجاز به مشاهده لیست اتاق‌های این سرور نمی‌باشید", + "Looks good": "به نظر خوب میاد", + "Unable to query for supported registration methods.": "درخواست از روش‌های پشتیبانی‌شده‌ی ثبت‌نام میسر نیست.", + "Enter a server name": "نام سرور را وارد کنید", + "And %(count)s more...|other": "و %(count)s مورد بیشتر ...", + "Sign in with single sign-on": "با احراز هویت یکپارچه وارد شوید", + "This server does not support authentication with a phone number.": "این سرور از قابلیت احراز با شماره تلفن پشتیبانی نمی کند.", + "Continue with %(provider)s": "با %(provider)s ادامه دهید", + "That username already exists, please try another.": "این نام کاربری از قبل وجود دارد ، لطفاً نام دیگری را امتحان کنید.", + "Homeserver": "سرور", + "Continue with %(ssoButtons)s": "با %(ssoButtons)s ادامه بده", + "Join millions for free on the largest public server": "به بزرگترین سرور عمومی با میلیون ها نفر کاربر بپیوندید", + "%(ssoButtons)s Or %(usernamePassword)s": "%(ssoButtons)s یا %(usernamePassword)s", + "Your new account (%(newAccountId)s) is registered, but you're already logged into a different account (%(loggedInUserId)s).": "حساب جدید شما (%(newAccountId)s) s) ثبت شده‌است ، اما شما قبلاً به حساب کاربری دیگری (%(loggedInUserId)s) وارد شده‌اید.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Element with an existing Matrix account on a different homeserver.": "می توانید از طریق گزینه‌ی سرور سفارشی با استفاده از آدرس سروری دیگر، به دیگر سرورهای Matrix متصل شوید. با این کار می توانید از Element جهت اتصال به یک اکانت ماتریکس بر روی سروری دیگر استفاده کنید.", + "Continue with previous account": "با حساب کاربری قبلی ادامه دهید", + "Log in to your new account.": "به حساب کاربری جدید خود وارد شوید.", + "You can now close this window or log in to your new account.": "اکنون می توانید این پنجره را ببندید یا به حساب کاربری جدید خود وارد شوید.", + "Use another login": "از ورود دیگری استفاده کنید", + "Failed to re-authenticate due to a homeserver problem": "به دلیل مشکلی که در سرور وجود دارد ، احراز هویت مجدد انجام نشد", + "You cannot sign in to your account. Please contact your homeserver admin for more information.": "نمی توانید وارد حساب کاربری خود شوید. لطفا برای اطلاعات بیشتر با مدیر سرور خود تماس بگیرید.", + "Server Options": "گزینه های سرور", + "This address is already in use": "این آدرس قبلاً استفاده شده‌است", + "Warning: Your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.": "هشدار: داده های شخصی شما (از جمله کلیدهای رمزنگاری) هنوز در این نشست ذخیره می شوند. اگر استفاده از این نشست را به پایان رسانده‌اید یا می‌خواهید وارد حساب کاربری دیگری شوید ، آن را پاک کنید.", + "This address is available to use": "این آدرس برای استفاده در دسترس است", + "Please provide a room address": "لطفاً آدرس اتاق را ارائه تعیین کنید", + "e.g. my-room": "به عنوان مثال، my-room", + "Some characters not allowed": "برخی از کاراکترها مجاز نیستند", + "Command Autocomplete": "تکمیل خودکار دستور", + "Community Autocomplete": "تکمیل خودکار اجتماع", + "Room address": "آدرس اتاق", + "Results from DuckDuckGo": "نتایج از موتور جستجوی DuckDuckGo", + "In reply to ": "در پاسخ به", + "DuckDuckGo Results": "نتایج موتور جستجوی DuckDuckGo", + "Emoji Autocomplete": "تکمیل خودکار شکلک", + "Notify the whole room": "به کل اتاق اطلاع بده", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "بارگیری رویدادی که به آن پاسخ داده شد امکان پذیر نیست، یا وجود ندارد یا شما اجازه مشاهده آن را ندارید.", + "Room Notification": "اعلان اتاق", + "Notification Autocomplete": "تکمیل خودکار اعلان", + "Room Autocomplete": "تکمیل خودکار اتاق", + "Space Autocomplete": "تکمیل خودکار فضای کاری", + "User Autocomplete": "تکمیل خودکار کاربر", + "We'll store an encrypted copy of your keys on our server. Secure your backup with a Security Phrase.": "ما یک نسخه رمزگذاری شده از کلیدهای شما را در سرور خود ذخیره خواهیم کرد. پشتیبان خود را با یک عبارت امنیتی ایمن کنید.", + "For maximum security, this should be different from your account password.": "برای حداکثر امنیت ، این باید با گذرواژه‌ی حساب شما متفاوت باشد.", + "Enter a Security Phrase": "یک عبارت امنیتی وارد کنید", + "Great! This Security Phrase looks strong enough.": "عالی! این عبارت امنیتی به اندازه کافی قوی به نظر می رسد.", + "QR Code": "کد QR", + "Custom level": "سطح دلخواه", + "Set up with a Security Key": "یک کلید امنیتی تنظیم کنید", + "Power level": "سطح قدرت", + "%(oneUser)smade no changes %(count)s times|one": "%(oneUser)s هیچ تغییری ایجاد نکرد", + "%(oneUser)smade no changes %(count)s times|other": "%(oneUser)s %(count)s مرتبه هیچ تغییری ایجاد نکرد", + "That matches!": "مطابقت دارد!", + "Use a different passphrase?": "از عبارت امنیتی دیگری استفاده شود؟", + "That doesn't match.": "مطابقت ندارد.", + "Go back to set it again.": "برای تنظیم مجدد آن به عقب برگردید.", + "%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)s هیچ تغییری ایجاد نکردند", + "%(severalUsers)smade no changes %(count)s times|other": "%(severalUsers)s %(count)s تغییری ایجاد نکردند", + "Enter your Security Phrase a second time to confirm it.": "عبارت امنیتی خود را برای تائید مجددا وارد کنید.", + "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s آواتار خود را تغییر داد", + "Repeat your Security Phrase...": "عبارت امنیتی خود را تکرار کنید ...", + "Your Security Key is a safety net - you can use it to restore access to your encrypted messages if you forget your Security Phrase.": "کلید امنیتی شما یک راهکار امنیتی است - اگر عبارت امنیتی خود را فراموش کنید ، می توانید از آن برای بازیابی دسترسی به پیام‌های رمز‌شده خود استفاده کنید.", + "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)s آواتار خود را %(count)s مرتبه تغییر داده‌است", + "Keep a copy of it somewhere secure, like a password manager or even a safe.": "یک نسخه از آن را در جایی امن نگهداری کنید.", + "Your Security Key": "کلید امنیتی شما", + "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s آواتار خود را تغییر دادند", + "Your Security Key has been copied to your clipboard, paste it to:": "از کلید امنیتی شما رونوشت گرفته شده است، آن را الصاق کنید به:", + "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s %(count)s مرتبه آواتار خود را تغییر دادند", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s نام خود را تغییر داد", + "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s نام خود را %(count)s مرتبه تغییر داد", + "Your Security Key is in your Downloads folder.": "کلید امنیتی شما در پوشه‌ Downloads قرار دارد.", + "Print it and store it somewhere safe": "این را پرینت کرده و در جایی امن نگهداری کنید", + "Save it on a USB key or backup drive": "بر روی فلش مموری یا پارتیشن پشتیبان ذخیره کنید", + "Copy it to your personal cloud storage": "روی فضای شخصی خودتان نسخه‌ی رونوشت بگیرید", + "Your keys are being backed up (the first backup could take a few minutes).": "در حال پیشتیبان‌گیری از کلیدهای شما (اولین نسخه پشتیبان ممکن است چند دقیقه طول بکشد).", + "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s نام خود را تغییر دادند", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.": "بدون تنظیم امکان پشتیبان‌گیریِ امن پیام‌ها، در صورت ورود به سیستم یا استفاده از نشست دیگر ، نمی توانید تاریخچه‌ی پیام‌های رمزشده خود را بازیابی کنید.", + "Set up Secure Message Recovery": "امکان بازیابی پیام‌های امن را تنظیم کنید", + "Secure your backup with a Security Phrase": "نسخه‌ی پشتیبان خود را با استفاده از عبارت امنیتی امن کنید", + "Confirm your Security Phrase": "عبارت امنیتی خود را تأیید کنیدعبارت امنیتی خود را تائید نمائید", + "Make a copy of your Security Key": "از کلید امنیتی خود رونوشت بگیرید", + "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s نام خود را %(count)s بار تغییر دادند", + "was kicked %(count)s times|one": "اخراج شد", + "Starting backup...": "آغاز پشتیبان‌گیری...", + "Success!": "موفقیت‌آمیز بود!", + "Create key backup": "ساختن نسخه‌ی پشتیبان کلید", + "Unable to create key backup": "ایجاد کلید پشتیبان‌گیری امکان‌پذیر نیست", + "Generate a Security Key": "یک کلید امنیتی ایجاد کنید", + "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "ما یک کلید امنیتی برای شما تولید کردیم تا آن را در یک جای امن ذخیره کنید.", + "was kicked %(count)s times|other": "%(count)s بار اخراج شد", + "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "از یک عبارت محرمانه که فقط خودتان می‌دانید استفاده کنید، و محض احتیاط کلید امینی خود را برای استفاده هنگام پشتیبان‌گیری ذخیره نمائید.", + "were kicked %(count)s times|one": "اخراج شدند", + "were kicked %(count)s times|other": "%(count)s بار اخراج شدند", + "was unbanned %(count)s times|one": "رفع تحریم شد", + "was unbanned %(count)s times|other": "%(count)s بار رفع تحریم شد", + "were unbanned %(count)s times|one": "رفع تحریم شد", + "were unbanned %(count)s times|other": "%(count)s بار رفع تحریم شد", + "Verification Requests": "درخواست های تأیید", + "View Servers in Room": "مشاهده سرورها در اتاق", + "Explore Account Data": "کاوش داده‌های حساب کاربری", + "Explore Room State": "کاوش حالت اتاق", + "Filter results": "پالایش نتایج", + "Send Account Data": "ارسال اطلاعات حساب کاربری", + "Event Content": "محتوای رخداد", + "State Key": "کلید حالت", + "Event Type": "نوع رخداد", + "Failed to send custom event.": "رخداد سفارشی ارسال نشد.", + "Event sent!": "رخداد ارسال شد!", + "You must specify an event type!": "شما باید نوع رخداد را مشخص کنید!", + "Send Custom Event": "ارسال رخداد سفارشی", + "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "لطفا بعد از غیرفعال کردن حساب کاربری، تمام پیام‌هایی را که ارسال کرده‌ام، فراموش کن ( هشدار: این امر باعث می شود کاربران آینده نمای ناقصی از مکالماتی که شما در آن‌ها حضور داشته‌اید را مشاهده کنند)", + "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "قابلیت مشاهده پیام در پروتکل ماتریکس مانند ایمیل است. فراموش کردن پیام‌های شما به این معنی است که پیام‌هایی که ارسال کرده‌اید با هیچ کاربر جدید یا ثبت نشده‌ای به اشتراک گذاشته نخواهد شد ، اما کاربران ثبت نام شده‌ای که از قبل به این پیام ها دسترسی دارند همچنان دسترسی خود را خواهند داشت.", + "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "غیرفعال کردن حساب شما به طور پیش فرض باعث نمی شود پیام‌های ارسالی شما را فراموش کنیم. اگر می‌خواهید پیام های شما را فراموش کنیم ، لطفاً کادر زیر را علامت بزنید.", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "این کار باعث می شود حساب کاربری شما برای همیشه غیرقابل استفاده شود. شما قادر به ورود به برنامه نخواهید بود و هیچ کس نمی تواند همان شناسه کاربری مشابه را دوباره ثبت کند. این باعث می شود که حساب شما از همه اتاق هایی که در آن‌ها عضو بودید خارج شده و جزئیات حساب شما از سرور هویت‌سنجی حذف گردد. این عمل برگشت‌ناپذیر است.", + "Server did not return valid authentication information.": "سرور اطلاعات احراز هویت معتبری را باز نگرداند.", + "Server did not require any authentication": "سرور به احراز هویت احتیاج نداشت", + "There was a problem communicating with the server. Please try again.": "مشکلی در برقراری ارتباط با سرور وجود داشت. لطفا دوباره تلاش کنید.", + "To continue, please enter your password:": "برای ادامه لطفا گذرواژه خود را وارد کنید:", + "Confirm account deactivation": "غیرفعال کردن حساب کاربری را تأیید کنید", + "Are you sure you want to deactivate your account? This is irreversible.": "آیا از غیرفعال‌کردن حساب کاربری خود اطمینان دارید؟ این کار غیر قابل بازگشت است.", + "Confirm your account deactivation by using Single Sign On to prove your identity.": "برای غیرفعال‌کردن حساب کاربری خود ابتدا باید هویت خود را ثابت کنید که برای این کار می‌توانید از احراز هویت یکپارچه استفاده کنید.", + "Continue With Encryption Disabled": "با رمزنگاری غیرفعال ادامه بده", + "Incompatible Database": "پایگاه داده ناسازگار", + "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "شما قبلاً با این نشست از نسخه جدیدتر %(brand)s استفاده کرده‌اید. برای استفاده مجدد از این نسخه با قابلیت رمزنگاری سرتاسر ، باید از حسابتان خارج شده و دوباره وارد برنامه شوید.", + "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": "برای جلوگیری از دست دادن تاریخچه‌ی گفتگوی خود باید قبل از ورود به برنامه ، کلیدهای اتاق خود را استخراج (Export) کنید. برای این کار باید از نسخه جدیدتر %(brand)s استفاده کنید", + "Sign out": "خروج از حساب کاربری", + "Block anyone not part of %(serverName)s from ever joining this room.": "از عضوشدن کاربرانی در این اتاق که حساب آن‌ها متعلق به سرور %(serverName)s است، جلوگیری کن.", + "Make this room public": "این اتاق را عمومی کنید", + "Topic (optional)": "موضوع (اختیاری)", + "Create a room in %(communityName)s": "یک اتاق در %(communityName)s بسازید", + "Create a private room": "ساختن اتاق خصوصی", + "Create a public room": "ساختن اتاق عمومی", + "You might disable this if the room will be used for collaborating with external teams who have their own homeserver. This cannot be changed later.": "اگر از اتاق برای همکاری با تیم های خارجی که سرور خود را دارند استفاده شود ، ممکن است این را غیرفعال کنید. این نمی‌تواند بعدا تغییر کند.", + "If you can't find the room you're looking for, ask for an invite or Create a new room.": "اگر نمی توانید اتاقی را که به دنبال آن می گردید پیدا کنید ، از یکی از اعضای آن بخواهید شما را دعوت کند و یا یک اتاق جدید بسازید.", + "You can't send any messages until you review and agree to our terms and conditions.": "تا زمانی که شرایط و ضوابط سرویس ما را مطالعه و با آن موافقت نکنید، نمی توانید هیچ پیامی ارسال کنید.", + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "پیام شما ارسال نشد زیرا این سرور به محدودیت تعداد کاربر فعال ماهانه‌ی خود رسیده است. لطفاً برای ادامه استفاده از سرویس با مدیر سرور خود تماس بگیرید .", + "Your message wasn't sent because this homeserver has been blocked by it's administrator. Please contact your service administrator to continue using the service.": "پیام شما ارسال نشد زیرا این سرور توسط مدیر آن مسدود شده است. لطفاً برای ادامه استفاده از سرویس با مدیر سرور خود تماس بگیرید .", + "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "پیام شما ارسال نشد زیرا این سرور از محدودیت منابع فراتر رفته است. لطفاً برای ادامه استفاده از سرویس با مدیر سرور خود تماس بگیرید .", + "Some of your messages have not been sent": "بعضی از پیام‌های شما ارسال نشده‌اند", + "You can select all or individual messages to retry or delete": "شما می‌توانید یک یا همه‌ی پیام‌ها را برای تلاش مجدد یا حذف انتخاب کنید", + "Sent messages will be stored until your connection has returned.": "پیام‌های ارسالی تا زمان بازگشت اتصال شما ذخیره خواهند ماند.", + "Server may be unavailable, overloaded, or search timed out :(": "سرور ممکن است در دسترس نباشد ، بار زیادی روی آن قرار گرفته یا زمان جستجو به پایان رسیده‌باشد :(", + "You have %(count)s unread notifications in a prior version of this room.|other": "شما %(count)s اعلان خوانده‌نشده در نسخه‌ی قبلی این اتاق دارید.", + "You have %(count)s unread notifications in a prior version of this room.|one": "شما %(count)s اعلان خوانده‌نشده در نسخه‌ی قبلی این اتاق دارید.", + "%(count)s members|other": "%(count)s عضو", + "%(count)s members|one": "%(count)s عضو", + "%(count)s rooms|other": "%(count)s اتاق", + "%(count)s rooms|one": "%(count)s اتاق", + "This room is suggested as a good one to join": "این اتاق به عنوان یک گزینه‌ی خوب برای عضویت پیشنهاد می شود", + "Suggested": "پیشنهادی", + "Your server does not support showing space hierarchies.": "سرور شما از نمایش سلسله مراتبی فضاهای کاری پشتیبانی نمی کند.", + "%(count)s rooms and %(numSpaces)s spaces|other": "%(count)s اتاق و %(numSpaces)s فضای کاری", + "%(count)s rooms and %(numSpaces)s spaces|one": "%(count)s اتاق و %(numSpaces)s فضای کاری", + "%(count)s rooms and 1 space|other": "%(count)s اتاق و یک فضای کاری", + "%(count)s rooms and 1 space|one": "%(count)s اتاق و یک فضای‌کاری", + "Select a room below first": "ابتدا یک اتاق از لیست زیر انتخاب کنید", + "Failed to remove some rooms. Try again later": "حذف برخی اتاق‌ها با مشکل همراه بود. لطفا بعدا تلاش فرمائید", + "Mark as not suggested": "علامت‌گذاری به عنوان پیشنهاد‌نشده", + "Mark as suggested": "علامت‌گذاری به عنوان پیشنهاد‌شده", + "You may want to try a different search or check for typos.": "ممکن است بخواهید یک جستجوی دیگر انجام دهید یا غلط‌های املایی را بررسی کنید.", + "was banned %(count)s times|one": "تحریم شد", + "was banned %(count)s times|other": "%(count)s بار تحریم شد", + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "برای در امان ماندن در برابر از دست‌دادن پیام‌ها و داده‌های رمزشده‌ی خود، از کلید‌های رمزنگاری خود یک نسخه‌ی پشتیبان بر روی سرور قرار دهید.", + "were banned %(count)s times|one": "تحریم شد", + "were banned %(count)s times|other": "%(count)s بار تحریم شد", + "was invited %(count)s times|one": "دعوت شد", + "was invited %(count)s times|other": "%(count)s بار دعوت شده است", + "Enter your account password to confirm the upgrade:": "گذرواژه‌ی خود را جهت تائيد عملیات ارتقاء وارد کنید:", + "were invited %(count)s times|one": "دعوت شدند", + "were invited %(count)s times|other": "%(count)s بار دعوت شده‌اند", + "Restore your key backup to upgrade your encryption": "برای ارتقاء رمزنگاری، ابتدا نسخه‌ی پشتیبان خود را بازیابی کنید", + "%(oneUser)shad their invitation withdrawn %(count)s times|one": "%(oneUser)s دعوت خود را پس گرفته است", + "%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)s دعوت خود را %(count)s مرتبه پس‌گرفته‌است", + "Restore": "بازیابی", + "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "%(severalUsers)s دعوت‌های خود را پس‌گرفتند", + "%(name)s cancelled verifying": "%(name)s تأیید هویت را لغو کرد", + "You cancelled verifying %(name)s": "شما تأیید هویت %(name)s را لغو کردید", + "You verified %(name)s": "شما هویت %(name)s را تأیید کردید", + "You have ignored this user, so their message is hidden. Show anyways.": "شما این کاربر را نادیده گرفته‌اید، بنابراین پیام او نمایش داده نمی‌شود. نمایش بده.", + "Video conference started by %(senderName)s": "کنفرانس ویدئویی توسط %(senderName)s آغاز شده است", + "Video conference updated by %(senderName)s": "کنفرانس ویدیویی توسط %(senderName)s به روز شد", + "Video conference ended by %(senderName)s": "کنفرانس ویدیویی توسط %(senderName)s به پایان رسید", + "Join the conference from the room information card on the right": "از طریق کارت اطلاعات اتاق در سمت راست، به کنفرانس بپیوندید", + "Join the conference at the top of this room": "از بالای این اتاق به کنفرانس بپوندید", + "Show image": "نمایش تصویر", + "Error decrypting image": "خطا در رمزگشایی تصویر", + "Invalid file%(extra)s": "پرونده نامعتبر%(extra)s", + "Message Actions": "اقدامات پیام", + "Reply": "پاسخ", + "Retry": "تلاش مجدد", + "Edit": "ویرایش", + "React": "واکنش", + "Error decrypting audio": "خطا در رمزگشایی صدا", + "The encryption used by this room isn't supported.": "رمزگذاری استفاده شده توسط این اتاق پشتیبانی نمی شود.", + "Encryption not enabled": "رمزگذاری فعال نیست", + "Ignored attempt to disable encryption": "تلاش برای غیرفعال کردن رمزگذاری نادیده گرفته شد", + "Encryption enabled": "رمزگذاری فعال است", + "Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "پیام های موجود در این اتاق به صورت سرتاسر رمزگذاری شده‌اند. هنگام ورود افراد، می توانید آن‌ها را از طریق نمایه آن‌ها تأیید کنید، کافی است روی آواتار آن‌ها ضربه بزنید.", + "Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "پیام های اینجا به صورت سرتاسر رمزگذاری شده هستند. %(displayName)s را در نمایه خود تأیید کنید - روی آواتار او ضربه بزنید.", + "Compare emoji": "مقایسه شکلک", + "Verification cancelled": "تأیید هویت لغو شد", + "You cancelled verification.": "شما تأیید هویت را لغو کردید.", + "%(displayName)s cancelled verification.": "%(displayName)s تایید هویت را لغو کرد.", + "You cancelled verification on your other session.": "شما تأیید صحت جلسه دیگر خود را لغو کردید.", + "Verification timed out.": "مهلت تأیید تمام شد.", + "Start verification again from their profile.": "دوباره تأیید را از نمایه آنها شروع کنید.", + "Start verification again from the notification.": "از اعلان دوباره تأیید را شروع کنید.", + "Got it": "فهمیدم", + "Verified": "تأیید شد", + "You've successfully verified %(displayName)s!": "شما%(displayName)s را با موفقیت تأیید کردید!", + "You've successfully verified %(deviceName)s (%(deviceId)s)!": "شما با موفقیت %(deviceName)s (%(deviceId)s) را تأیید کردید!", + "You've successfully verified your device!": "شما با موفقیت دستگاه خود را تأیید کردید!", + "In encrypted rooms, verify all users to ensure it’s secure.": "در اتاق های رمزگذاری شده ، برای اطمینان از امنیت اتاق، همه کاربران را تأیید هویت کنید.", + "Verify all users in a room to ensure it's secure.": "برای اطمینان از امنیت اتاق، هویت همه‌ی کاربران حاضر در اتاق را تأیید کنید.", + "Almost there! Is %(displayName)s showing the same shield?": "تقریباً تمام شد! آیا %(displayName)s نیز سپر مشابهی را نشان می‌دهد؟", + "Almost there! Is your other session showing the same shield?": "تقریباً انجام شد! آیا نشست دیگر شما همان سپر را نشان می دهد؟", + "Verify by emoji": "تأیید توسط شکلک", + "Verify by comparing unique emoji.": "با مقایسه شکلک تأیید کنید.", + "If you can't scan the code above, verify by comparing unique emoji.": "اگر نمی توانید کد بالا را اسکن کنید ، با مقایسه شکلک منحصر به فرد، او را تأیید کنید.", + "Ask %(displayName)s to scan your code:": "از %(displayName)s بخواهید که کد شما را اسکن کند:", + "Verify by scanning": "با اسکن تأیید کنید", + "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "نشستی که می خواهید تأیید کنید از اسکن کد QR یا تأیید شکلک پشتیبانی نمی کند ، یعنی همان چیزی که %(brand)s پشتیبانی می کند. با کلاینت دیگری امتحان کنید.", + "Security": "امنیت", + "Edit devices": "ویرایش دستگاه‌ها", + "This client does not support end-to-end encryption.": "این کلاینت از رمزگذاری سرتاسر پشتیبانی نمی کند.", + "Role": "نقش", + "Failed to deactivate user": "غیرفعال کردن کاربر انجام نشد", + "Deactivate user": "غیرفعال کردن کاربر", + "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "با غیرفعال کردن این کاربر، او از سیستم خارج شده و از ورود مجدد وی جلوگیری می‌شود. علاوه بر این، او تمام اتاق هایی را که در آن هست ترک می کند. این عمل قابل برگشت نیست. آیا مطمئن هستید که می خواهید این کاربر را غیرفعال کنید؟", + "Deactivate user?": "کاربر غیرفعال شود؟", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "شما نمی توانید این تغییر را باطل کنید زیرا در حال ارتقا سطح قدرت یک کاربر به سطح قدرت خود هستید.", + "Failed to change power level": "تغییر سطح قدرت انجام نشد", + "Failed to remove user from community": "کاربر از اجتماع حذف نشد", + "Failed to withdraw invitation": "دعوت پس گرفته نشد", + "Remove this user from community?": "این کاربر از اجتماع حذف شود؟", + "Disinvite this user from community?": "دعوت این کاربر به اجتماع لغو شود؟", + "Remove from community": "حذف از اجتماع", + "Unmute": "صدادار", + "Failed to mute user": "کاربر بی صدا نشد", + "Ban this user?": "کاربر تحریم شود؟", + "Unban this user?": "لغو تحریم این کاربر؟", + "Ban": "تحریم", + "Remove recent messages": "حذف پیام‌های اخیر", + "Remove %(count)s messages|one": "حذف ۱ پیام", + "Remove %(count)s messages|other": "حذف %(count)s پیام", + "For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.": "برای مقدار زیادی پیام ممکن است مدتی طول بکشد. لطفا در این بین مرورگر خود را refresh نکنید.", + "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|one": "شما در شرف حذف ۱ پیام از کاربر %(user)s هستید. این قابل بازگشت نیست. آیا مایل هستید ادامه دهید؟", + "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|other": "شما در شرف حذف %(count)s پیام از کاربر %(user)s هستید. این قابل بازگشت نیست. آیا مایل هستید ادامه دهید؟", + "Remove recent messages by %(user)s": "حذف پیام‌های اخیر %(user)s", + "Try scrolling up in the timeline to see if there are any earlier ones.": "در پیام‌ها بالا بروید تا ببینید آیا موارد قدیمی وجود دارد یا خیر.", + "No recent messages by %(user)s found": "هیچ پیام جدیدی برای %(user)s یافت نشد", + "Failed to kick": "اخراج انجام نشد", + "Kick this user?": "اخراج این کاربر؟", + "Disinvite this user?": "عدم دعوت این کاربر؟", + "Kick": "اخراج", + "Demote": "تنزل رتبه", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "شما نمی توانید این تغییر را لغو کنید زیرا در حال تنزل خود هستید، اگر آخرین کاربر ممتاز در اتاق باشید بازپس گیری امتیازات غیرممکن است.", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the space it will be impossible to regain privileges.": "شما نمی توانید این تغییر را لغو کنید زیرا در حال تنزل خود هستید، اگر آخرین کاربر ممتاز در فضای کاری باشید، بازپس گیری امتیازات غیرممکن است.", + "Demote yourself?": "خودتان را تنزل می‌دهید؟", + "Direct message": "پیام مستقیم", + "Share Link to User": "اشتراک لینک برای کاربر", + "Invite": "دعوت", + "Mention": "اشاره", + "Jump to read receipt": "پرش به آخرین پیام خوانده شده", + "Hide sessions": "مخفی کردن نشست‌ها", + "%(count)s sessions|one": "%(count)s نشست", + "%(count)s sessions|other": "%(count)s نشست", + "Hide verified sessions": "مخفی کردن نشست‌های تأیید شده", + "%(count)s verified sessions|one": "1 نشست تأیید شده", + "%(count)s verified sessions|other": "%(count)s نشست تایید شده", + "Not trusted": "غیرقابل اعتماد", + "Trusted": "قابل اعتماد", + "Room settings": "تنظیمات اتاق", + "Share room": "به اشتراک گذاری اتاق", + "Show files": "نمایش پرونده ها", + "%(count)s people|one": "نفر %(count)s", + "%(count)s people|other": "نفر %(count)s", + "About": "درباره", + "Not encrypted": "رمزگذاری نشده", + "Add widgets, bridges & bots": "افزودن ابزارک‌ها، پل‌ها و ربات‌ها", + "Edit widgets, bridges & bots": "ویرایش ابزارک ها ، پل ها و ربات ها", + "Widgets": "ابزارک ها", + "Set my room layout for everyone": "چیدمان اتاق من را برای همه تنظیم کن", + "Options": "گزینه ها", + "Unpin a widget to view it in this panel": "برای مشاهده ویجت در این صفحه، پین آن را بردارید", + "Unpin": "برداشتن پین", + "You can only pin up to %(count)s widgets|other": "فقط می توانید تا %(count)s ابزارک را پین کنید", + "Room Info": "اطلاعات اتاق", + "One of the following may be compromised:": "ممکن است یکی از موارد زیر به در معرض خطر باشد:", + "Yours, or the other users’ session": "نشست شما و یا کاربران دیگر", + "Yours, or the other users’ internet connection": "اتصال اینترنت شما و یا کاربران دیگر", + "The homeserver the user you’re verifying is connected to": "سروی که کاربری که شما تأیید کرده‌اید به آن متصل هستند", + "Your homeserver": "سرور شما", + "Your messages are not secure": "پیام های شما ایمن نیستند", + "For extra security, verify this user by checking a one-time code on both of your devices.": "برای امنیت بیشتر، با بررسی کد یکبارمصرف در هر دو دستگاه، این کاربر را تأیید کنید.", + "Verify User": "تأیید هویت کاربر", + "In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "در اتاق‌های رمزگذاری شده، پیام‌های شما امن هستند و فقط شما و گیرنده کلیدهای منحصر به فرد برای باز کردن قفل آن‌ها را دارید.", + "Messages in this room are not end-to-end encrypted.": "پیام های موجود در این اتاق به صورت سرتاسر رمزگذاری نشده‌اند.", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "پیام‌های شما امن هستند و فقط شما و گیرنده کلیدهای منحصر به فرد برای باز کردن قفل آنها را دارید.", + "Failed to perform homeserver discovery": "جستجوی سرور با موفقیت انجام نشد", + "Direct Messages": "پیام مستقیم", + "You can add existing spaces to a space.": "شما می‌توانید فضاهای کاری موجود را به یک فضای کاری اضافه کنید.", + "This homeserver doesn't offer any login flows which are supported by this client.": "این سرور هیچ سازوکار ورودی را که توسط این کلاینت پشتیبانی شود، ارائه نمی‌دهد.", + "Feeling experimental?": "آیا می‌خواهید قابلیت‌های آزمایشی را تجربه کنید؟", + "Messages in this room are end-to-end encrypted.": "پیام‌های موجود در این اتاق به صورت سرتاسر رمزگذاری شده‌اند.", + "Start Verification": "شروع تایید هویت", + "Accepting…": "پذیرش…", + "Waiting for %(displayName)s to accept…": "منتظر قبول کردن توسط %(displayName)s…", + "Accept on your other login…": "در نشست دیگر خود قبول کنید…", + "Back": "بازگشت", + "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 disabled URL previews by default.": "شما به طور پیش فرض پیش نمایش url را غیر فعال کرده اید.", + "You have enabled URL previews by default.": "شما به طور پیش فرض پیش نمایش url را فعال کرده اید.", + "Publish this room to the public in %(domain)s's room directory?": "این اتاق را در فهرست اتاق %(domain)s برای عموم منتشر شود؟", + "Room avatar": "آواتار اتاق", + "Room Topic": "موضوع اتاق", + "Room Name": "نام اتاق", + "New community ID (e.g. +foo:%(localDomain)s)": "شناسه جدید اجتماع (به عنوان مثال %(localDomain)s+foo::)", + "Show %(count)s more|other": "نمایش %(count)s مورد بیشتر", + "Show %(count)s more|one": "نمایش %(count)s مورد بیشتر", + "Jump to first invite.": "به اولین دعوت بروید.", + "Jump to first unread room.": "به اولین اتاق خوانده نشده بروید.", + "List options": "لیست گزینه‌ها", + "A-Z": "حروف الفبا", + "Activity": "فعالیت", + "Sort by": "مرتب سازی بر اساس", + "Show previews of messages": "مشاهده پیش‌نمایش پیام‌ها", + "Show rooms with unread messages first": "ابتدا اتاق های با پیام خوانده نشده را نمایش بده", + "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.": "%(errcode)s هنگام تلاش برای دسترسی به اتاق بازگردانده شد. اگر فکر می کنید این پیام را به اشتباه مشاهده می کنید ، لطفا گزارش خطا ارسال کنید.", + "Try again later, or ask a room admin to check if you have access.": "بعداً دوباره امتحان کنید، یا از مدیر اتاق بخواهید که دسترسی شما را بررسی کند.", + "%(roomName)s is not accessible at this time.": "در حال حاضر %(roomName)s قابل دسترسی نیست.", + "This room doesn't exist. Are you sure you're at the right place?": "این اتاق وجود ندارد آیا مطمئن هستید که در جای مناسب قرار دارید؟", + "%(roomName)s does not exist.": "%(roomName)s وجود ندارد.", + "%(roomName)s can't be previewed. Do you want to join it?": "پیش بینی %(roomName)s امکان پذیر نیست. آیا می خواهید به آن بپیوندید؟", + "You're previewing %(roomName)s. Want to join it?": "شما در حال پیش نمایش %(roomName)s هستید. می خواهید به آن بپیوندید؟", + "Reject & Ignore user": "رد کردن و نادیده گرفتن کاربر", + " invited you": " شما را دعوت کرد", + "Do you want to join %(roomName)s?": "آیا می خواهید ب %(roomName)s بپیوندید؟", + "Start chatting": "گپ زدن را شروع کن", + " wants to chat": " می‌خواهد چت کند", + "Do you want to chat with %(user)s?": "آیا می خواهید با %(user)s چت کنید؟", + "Share this email in Settings to receive invites directly in %(brand)s.": "برای دریافت مستقیم دعوت در %(brand)s این ایمیل را در تنظیمات به اشتراک بگذارید.", + "Use an identity server in Settings to receive invites directly in %(brand)s.": "برای دریافت مستقیم دعوت در %(brand)s یک سرور هویت‌سنجی در تنظیمات مشخص کنید.", + "This invite to %(roomName)s was sent to %(email)s": "این دعوت به %(roomName)s به %(email)s ارسال شد", + "Link this email with your account in Settings to receive invites directly in %(brand)s.": "برای دریافت مستقیم دعوت در %(brand)s این ایمیل را به حساب خود در تنظیمات متصل کنید.", + "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "این دعوت به %(roomName)s به %(email)s ارسال شده است که با حساب شما مرتبط نیست", + "Join the discussion": "به بحث بپیوندید", + "You can still join it because this is a public room.": "هنوز می توانید به آن بپیوندید زیرا این یک اتاق عمومی است.", + "Try to join anyway": "به هر حال عضو شدن را تلاش کن", + "You can only join it with a working invite.": "فقط با یک دعوت نامه معتبر می توانید به آن بپیوندید.", + "An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to a room admin.": "هنگام تلاش برای تأیید دعوت شما، خطایی (%(errcode)s) رخ داده است. می توانید این اطلاعات را به مدیر اتاق منتقل کنید.", + "Something went wrong with your invite to %(roomName)s": "در دعوت شما به %(roomName)s مشکلی پیش آمده است", + "You were banned from %(roomName)s by %(memberName)s": "شما از %(roomName)s توسط %(memberName)s محروم شدید", + "Re-join": "دوباره بپیوندید", + "Forget this room": "فراموش کردن این اتاق", + "Reason: %(reason)s": "دلیل: %(reason)s", + "You were kicked from %(roomName)s by %(memberName)s": "شما توسط %(memberName)s از %(roomName)s اخراج شدید", + "Loading room preview": "در حال بارگیری پیش نمایش اتاق", + "Sign Up": "ثبت نام", + "Join the conversation with an account": "پیوستن به گفتگو با یک حساب کاربری", + "Rejecting invite …": "رد کردن دعوت …", + "Loading …": "بارگذاری …", + "Joining room …": "در حال پیوستن به اتاق …", + "This room": "این اتاق", + "%(count)s results|one": "%(count)s نتیجه", + "%(count)s results|other": "%(count)s نتیجه", + "%(count)s results in all spaces|one": "%(count)s نتیجه در تمامی فضا‌های کاری", + "%(count)s results in all spaces|other": "%(count)s نتیجه در تمامی فضا‌های کاری", + "Use the + to make a new room or explore existing ones below": "از + برای ایجاد یک اتاق جدید استفاده کنید و یا در اتاق های موجود زیر کاوش کنید", + "Quick actions": "اقدامات سریع", + "Explore all public rooms": "کاوش در تمام اتاق‌های عمومی", + "Start a new chat": "چت جدیدی را شروع کنید", + "Can't see what you’re looking for?": "نمی توانید چیزی را که به دنبال آن می‌گردید، ببینید؟", + "Empty room": "اتاق خالی", + "Custom Tag": "برچسب سفارشی", + "Suggested Rooms": "اتاق‌های پیشنهادی", + "Historical": "تاریخی", + "System Alerts": "هشدارهای سیستم", + "Low priority": "اولویت کم", + "Explore public rooms": "کاوش در اتاق‌های عمومی", + "Explore community rooms": "کاوش در اتاق‌های اجتماع", + "You do not have permissions to add rooms to this space": "شما اجازه افزودن اتاق به این فضای کاری را ندارید", + "You do not have permissions to create new rooms in this space": "شما اجازه ایجاد اتاق جدید در این فضای کاری را ندارید", + "Add room": "افزودن اتاق", + "Rooms": "اتاق‌ها", + "Start chat": "شروع چت", + "People": "افراد", + "Favourites": "موردعلاقه‌ها", + "Invites": "دعوت‌ها", + "Open dial pad": "باز کردن صفحه شماره‌گیری", + "Start a Conversation": "شروع مکالمه", + "Video call": "تماس تصویری", + "Voice call": "تماس صوتی", + "Show Widgets": "نمایش ابزارک‌ها", + "Hide Widgets": "پنهان‌کردن ابزارک‌ها", + "Join Room": "به اتاق بپیوندید", + "(~%(count)s results)|one": "(~%(count)s نتیجه)", + "(~%(count)s results)|other": "(~%(count)s نتیجه)", + "No recently visited rooms": "اخیراً از اتاقی بازدید نشده است", + "Recently visited rooms": "اتاق‌هایی که به تازگی بازدید کرده‌اید", + "Room %(name)s": "اتاق %(name)s", + "Replying": "پاسخ دادن", + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "دیده شده توسط %(displayName)s (%(userName)s در %(dateTime)s)", + "Seen by %(userName)s at %(dateTime)s": "دیده شده توسط %(userName)s در %(dateTime)s", + "Unknown": "ناشناخته", + "Offline": "آفلاین", + "Idle": "بلااستفاده", + "Online": "آنلاین", + "Unknown for %(duration)s": "ناشناخته به مدت %(duration)s", + "Offline for %(duration)s": "آفلاین به مدت %(duration)s", + "Idle for %(duration)s": "بلااستفاده برای مدت %(duration)s", + "Online for %(duration)s": "آنلاین برای مدت %(duration)s", + "%(duration)sd": "%(duration)s روز", + "%(duration)sh": "%(duration)s ساعت", + "%(duration)sm": "%(duration)s دقیقه", + "%(duration)ss": "%(duration)s ثانیه", + "Jump to message": "رفتن به پیام", + "Unpin Message": "لغو پین پیام", + "Pinned Messages": "پیام‌های پین شده", + "Loading...": "بارگذاری...", + "No pinned messages.": "هیچ پیام پین شده‌ای وجود ندارد.", + "This is the start of .": "این شروع است.", + "Add a photo, so people can easily spot your room.": "عکس اضافه کنید تا افراد بتوانند به راحتی اتاق شما را ببینند.", + "Invite to just this room": "فقط به این اتاق دعوت کنید", + "%(displayName)s created this room.": "%(displayName)s این اتاق را ایجاد کرده است.", + "You created this room.": "شما این اتاق را ایجاد کردید.", + "Add a topic to help people know what it is about.": "یک موضوع اضافه کنید تا به افراد کمک کنید از آنچه در آن است مطلع شوند.", + "Topic: %(topic)s ": "موضوع: %(topic)s ", + "Topic: %(topic)s (edit)": "موضوع: %(topic)s (ویرایش)", + "This is the beginning of your direct message history with .": "این ابتدای تاریخچه پیام مستقیم شما با است.", + "Only the two of you are in this conversation, unless either of you invites anyone to join.": "فقط شما دو نفر در این مکالمه حضور دارید ، مگر اینکه یکی از شما کس دیگری را به عضویت دعوت کند.", + "Code block": "بلوک کد", + "Strikethrough": "خط روی متن", + "Italics": "مورب", + "Bold": "پررنگ", + "%(seconds)ss left": "%(seconds)s ثانیه باقی‌مانده", + "You do not have permission to post to this room": "شما اجازه ارسال در این اتاق را ندارید", + "This room has been replaced and is no longer active.": "این اتاق جایگزین شده‌است و دیگر فعال نیست.", + "The conversation continues here.": "گفتگو در اینجا ادامه دارد.", + "Send a message…": "ارسال یک پیام…", + "Send an encrypted message…": "ارسال پیام رمزگذاری شده …", + "Send a reply…": "ارسال پاسخ …", + "Send an encrypted reply…": "ارسال پاسخ رمزگذاری شده …", + "Upload file": "آپلود فایل", + "Emoji picker": "انتخاب کننده شکلک", + "Send message": "ارسال پیام", + "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (سطح قدرت %(powerLevelNumber)s)", + "Invited": "دعوت شد", + "Invite to this space": "به این فضای کاری دعوت کنید", + "Invite to this community": "به این انجمن دعوت کنید", + "and %(count)s others...|one": "و یکی دیگر ...", + "and %(count)s others...|other": "و %(count)s مورد دیگر ...", + "Close preview": "بستن پیش نمایش", + "Scroll to most recent messages": "به جدیدترین پیام‌ها بروید", + "Please select the destination room for this message": "لطفاً اتاق مقصد را برای این پیام انتخاب کنید", + "Failed to send": "ارسال با خطا مواجه شد", + "Your message was sent": "پیام شما ارسال شد", + "Encrypting your message...": "رمزگذاری پیام شما ...", + "Sending your message...": "در حال ارسال پیام شما ...", + "The authenticity of this encrypted message can't be guaranteed on this device.": "صحت این پیام رمزگذاری شده در این دستگاه تضمین نمی شود.", + "Encrypted by a deleted session": "با یک نشست حذف شده رمزگذاری شده است", + "Unencrypted": "رمزگذاری نشده", + "Encrypted by an unverified session": "توسط یک نشست تأیید نشده رمزگذاری شده است", + "This message cannot be decrypted": "این پیام نمی‌تواند رمزگشایی شود", + "Export room keys": "استخراج کلیدهای اتاق", + "%(nameList)s %(transitionList)s": "%(nameList)s.%(transitionList)s", + "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.": "این فرآیند به شما این امکان را می‌دهد تا کلیدهایی را که برای رمزگشایی پیام‌هایتان در اتاق‌های رمزشده نیاز دارید، در قالب یک فایل محلی استخراج کنید. بعد از آن می‌توانید این فایل را در هر کلاینت دیگری وارد (Import) کرده و قادر به رمزگشایی و مشاهده‌ی پیام‌های رمزشده‌ی مذکور باشید.", + "Language Dropdown": "منو زبان", + "View message": "مشاهده پیام", + "Information": "اطلاعات", + "Download": "دانلود", + "Rotate Right": "چرخش به راست", + "Rotate Left": "چرخش به چپ", + "Zoom in": "بزرگنمایی", + "Zoom out": "کوچک نمایی", + "%(count)s people you know have already joined|one": "%(count)s نفر از افرادی که می شناسید قبلاً پیوسته‌اند", + "%(count)s people you know have already joined|other": "%(count)s نفر از افرادی که می شناسید قبلاً به آن پیوسته‌اند", + "%(count)s members including %(commaSeparatedMembers)s|one": "%(commaSeparatedMembers)s", + "%(count)s members including %(commaSeparatedMembers)s|other": "%(count)s عضو شامل %(commaSeparatedMembers)s", + "Including %(commaSeparatedMembers)s": "شامل %(commaSeparatedMembers)s", + "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "فایل استخراج‌شده به هر کسی که به آن دسترسی داشته باشد اجازه می‌دهد تا تمام پیام‌هایی که شما می‌توانید آن‌ها را ببینید، مشاهده کند؛ پس باید مراقب باشید و آن را امن نگه دارید. به این منظور، شما باید عبارت امنیتی را در زیر وارد کنید.. این عبارت برای رمزکردن داده‌های استخراج‌شده‌ی شما استفاده می‌شود. در این صورت تنها راه واردکردن (Import) این داده‌ها و مشاهده‌ی آن‌ها استفاده از همین عبارت امنیتی خواهد بود.", + "View all %(count)s members|one": "نمایش ۱ عضو", + "View all %(count)s members|other": "نمایش همه %(count)s عضو", + "expand": "گشودن", + "collapse": "بستن", + "Please create a new issue on GitHub so that we can investigate this bug.": "لطفا در GitHub یک مسئله جدید ایجاد کنید تا بتوانیم این اشکال را بررسی کنیم.", + "No results": "بدون نتیجه", + "Join": "پیوستن", + "Windows": "پنجره‌ها", + "Enter passphrase": "عبارت امنیتی را وارد کنید", + "Screens": "صفحه نمایش‌ها", + "Share your screen": "به اشتراک‌گذاری صفحه نمایش", + "Confirm passphrase": "عبارت امنیتی را تائید کنید", + "This version of %(brand)s does not support searching encrypted messages": "این نسخه از %(brand)s از جستجوی پیام های رمزگذاری شده پشتیبانی نمی کند", + "Import room keys": "واردکردن (Import) کلیدهای اتاق", + "This version of %(brand)s does not support viewing some encrypted files": "این نسخه از %(brand)s از مشاهده برخی از پرونده های رمزگذاری شده پشتیبانی نمی کند", + "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.": "این فرآیند به شما اجازه می‌دهد تا کلیدهای امنیتی را وارد (Import) کنید، کلیدهایی که قبلا از کلاینت‌های دیگر خود استخراج (Export) کرده‌اید. پس از آن شما می‌توانید هر پیامی را که کلاینت دیگر قادر به رمزگشایی آن بوده را، رمزگشایی و مشاهده کنید.", + "Use the Desktop app to search encrypted messages": "برای جستجوی میان پیام‌های رمز شده از نسخه دسکتاپ استفاده کنید", + "Use the Desktop app to see all encrypted files": "برای مشاهده همه پرونده های رمز شده از نسخه دسکتاپ استفاده کنید", + "Widget added by": "ابزارک اضافه شده توسط", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "فایل استخراج‌شده با یک عبارت امنیتی محافظت می‌شود. برای رمزگشایی فایل باید عبارت امنیتی را وارد کنید.", + "Popout widget": "بیرون انداختن ابزارک", + "This widget may use cookies.": "این ابزارک ممکن است از کوکی استفاده کند.", + "Widgets do not use message encryption.": "ابزارک ها از رمزگذاری پیام استفاده نمی کنند.", + "File to import": "فایل برای واردکردن (Import)", + "Using this widget may share data with %(widgetDomain)s.": "استفاده از این ابزارک ممکن است داده‌هایی را با %(widgetDomain)s به اشتراک بگذارد.", + "New Recovery Method": "روش بازیابی جدید", + "A new Security Phrase and key for Secure Messages have been detected.": "یک عبارت امنیتی و کلید جدید برای پیام‌رسانی امن شناسایی شد.", + "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "استفاده از این ابزارک ممکن است داده‌هایی را با %(widgetDomain)s و سیستم مدیریت ادغام به اشتراک بگذارد.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "اگر روش بازیابی جدیدی را تنظیم نکرده‌اید، ممکن است حمله‌کننده‌ای تلاش کند به حساب کاربری شما دسترسی پیدا کند. لطفا گذرواژه حساب کاربری خود را تغییر داده و فورا یک روش جدیدِ بازیابی در بخش تنظیمات انتخاب کنید.", + "Widget ID": "شناسه ابزارک", + "Room ID": "شناسه اتاق", + "%(brand)s URL": "آدرس %(brand)s", + "Your theme": "پوسته شما", + "Your user ID": "شناسه کاربری شما", + "Your avatar URL": "URL آواتار شما", + "Your display name": "نام نمایشی شما", + "Any of the following data may be shared:": "هر یک از داده های زیر ممکن است به اشتراک گذاشته شود:", + "This session is encrypting history using the new recovery method.": "این نشست تاریخچه‌ی پیام‌های رمزشده را با استفاده از روش جدیدِ بازیابی، رمز می‌کند.", + "Unknown Address": "آدرس ناشناخته", + "Cancel search": "لغو جستجو", + "Quick Reactions": "واکنش سریع", + "Categories": "دسته بندی ها", + "Flags": "پرچم ها", + "Symbols": "نمادها", + "Objects": "اشیاء", + "Go to Settings": "برو به تنظیمات", + "Travel & Places": "سفر و اماکن", + "Activities": "فعالیت ها", + "Set up Secure Messages": "پیام‌رسانی امن را تنظیم کنید", + "Food & Drink": "غذا و نوشیدنی", + "Recovery Method Removed": "روش بازیابی حذف شد", + "Animals & Nature": "حیوانات و طبیعت", + "Smileys & People": "لبخند و افراد", + "This session has detected that your Security Phrase and key for Secure Messages have been removed.": "نشست فعلی تشخیص داده که عبارت امنیتی و کلید لازم شما برای پیام‌رسانی امن حذف شده‌است.", + "Frequently Used": "متداول", + "You're not currently a member of any communities.": "شما در حال حاضر عضو هیچ اجتماعی نیستید.", + "Display your community flair in rooms configured to show it.": "عنوان شما در اجتماع را در اتاق‌هایی که برای نمایش آن پیکربندی شده‌اند، نمایش بده.", + "If you did this accidentally, you can setup Secure Messages on this session which will re-encrypt this session's message history with a new recovery method.": "اگر این کار را به صورت تصادفی انجام دادید، می‌توانید سازوکار پیام امن را برای این نشست تنظیم کرده که باعث می‌شود تمام تاریخچه‌ی این نشست با استفاده از یک روش جدیدِ بازیابی، مجددا رمزشود.", + "Something went wrong when trying to get your communities.": "هنگام تلاش برای دریافت اجتماع‌های شما مشکلی پیش آمد.", + "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.": "اگر متد بازیابی را حذف نکرده‌اید، ممکن است حمله‌کننده‌ای سعی در دسترسی به حساب‌کاربری شما داشته باشد. گذرواژه حساب کاربری خود را تغییر داده و فورا یک روش بازیابی را از بخش تنظیمات خود تنظیم کنید.", + "Filter community rooms": "فیلتر اتاق های اجتماع", + "Add rooms to this community": "افزودن اتاق به این اجتماع", + "Only visible to community members": "قابل مشاهده فقط برای اعضای اجتماع", + "Visible to everyone": "قابل مشاهده برای همه", + "Visibility in Room List": "قابل مشاهده بودن در لیست اتاق", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "قابلیت مشاهده %(roomName)s در %(groupId)s بروز نشد.", + "Message downloading sleep time(ms)": "زمان خواب بارگیری پیام (ms)", + "Something went wrong!": "مشکلی پیش آمد!", + "Failed to remove '%(roomName)s' from %(groupId)s": "حذف %(roomName)s از %(groupId)s انجام نشد", + "Toggle this dialog": "کلیک کنید", + "Failed to remove room from community": "حذف اتاق از اجتماع انجام نشد", + "Removing a room from the community will also remove it from the community page.": "حذف یک اتاق از اجتماع، آن را از صفحه اجتماع نیز حذف می کند.", + "Move autocomplete selection up/down": "انتخاب تکمیل‌کننده خودکار را بالا/پایین ببرید", + "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "آیا مطمئن هستید که می خواهید %(roomName)s را از %(groupId)s حذف کنید؟", + "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)s عضو شدند", + "example": "مثال", + "Example": "مثال", + "Skip": "بیخیال", + "Import": "واردکردن (Import)", + "Export": "استخراج (Export)", + "Space": "فضای کاری", + "Esc": "خروج", + "Super": "فوق العاده", + "Theme added!": "پوسته اضافه شد!", + "Find a room…": "یافتن اتاق…", + "If you've joined lots of rooms, this might take a while": "اگر عضو اتاق‌های بسیار زیادی هستید، ممکن است این فرآیند مقدای به طول بیانجامد", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "مدیر سرور شما قابلیت رمزنگاری سرتاسر برای اتاق‌ها و گفتگوهای خصوصی را به صورت پیش‌فرض غیرفعال کرده‌است.", + "To link to this room, please add an address.": "برای لینک دادن به این اتاق، لطفا یک نشانی برای آن اضافه کنید.", + "Filter community members": "فیلتر اعضای اجتماع", + "Failed to load group members": "اعضای گروه بارگیری نشد", + "Can't load this message": "بارگیری این پیام امکان پذیر نیست", + "Submit logs": "ارسال لاگ‌ها", + "edited": "ویرایش شده", + "Edited at %(date)s. Click to view edits.": "ویرایش شده در %(date)s. برای مشاهده ویرایش ها کلیک کنید.", + "Click to view edits": "برای مشاهده ویرایش ها کلیک کنید", + "Edited at %(date)s": "ویرایش شده در %(date)s", + "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 احراز هویت کنید. آیا مایل هستید ادامه دهید؟", + "Add an Integration": "یکپارچه سازی اضافه کنید", + "This room is a continuation of another conversation.": "این اتاق ادامه گفتگوی دیگر است.", + "Click here to see older messages.": "برای دیدن پیام های قدیمی اینجا کلیک کنید.", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s آواتار اتاق را به تغییر داد", + "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s آواتار اتاق را حذف کرد.", + "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s آواتار خود را در %(roomName)s تغییر داد", + "Message deleted on %(date)s": "پیام در %(date)s حذف شد", + "Message deleted by %(name)s": "پیام توسط %(name)s حذف شد", + "Message deleted": "پیغام پاک شد", + "reacted with %(shortName)s": " واکنش نشان داد با %(shortName)s", + " reacted with %(content)s": " واکنش نشان داد با %(content)s", + "Reactions": "واکنش ها", + "Show all": "نمایش همه", + "Add reaction": "افزودن واکنش", + "Error processing voice message": "خطا در پردازش پیام صوتی", + "Error decrypting video": "خطا در رمزگشایی ویدیو", + "You sent a verification request": "شما یک درخواست تأیید هویت ارسال کرده‌اید", + "%(name)s wants to verify": "%(name)s می‌خواهد تأیید هویت کند", + "Declining …": "در حال رد کردن …", + "Accepting …": "در حال پذیرش …", + "%(name)s cancelled": "%(name)s لغو کرد", + "%(name)s declined": "%(name)s رد کرد", + "You cancelled": "شما لغو کردید", + "You declined": "شما رد کردید", + "%(name)s accepted": "%(name)s پذیرفت", + "You accepted": "پذیرفتید", + "Re-request encryption keys from your other sessions.": "درخواست مجدد کلید‌های رمزنگاری از نشست‌های دیگر شما.", + "Mod": "معاون", + "Hint: Begin your message with // to start it with a slash.": "نکته: پیام خود را با // شروع کنید تا با یک اسلش شروع شود.", + "You can use /help to list available commands. Did you mean to send this as a message?": "برای لیست کردن دستورات موجود می توانید از /help استفاده کنید. آیا قصد داشتید این پیام را به عنوان متم ارسال کنید؟", + "Read Marker off-screen lifetime (ms)": "خواندن نشانگر طول عمر خارج از صفحه نمایش (میلی ثانیه)", + "Notifications on the following keywords follow rules which can’t be displayed here:": "اعلان‌های مخصوص کلمات کلیدی زیر از قوانینی پیروی می کنند که نمی توانند در اینجا نمایش داده شوند:", + "sends space invaders": "ارسال مهاجمان فضایی", + "Sends the given message with a space themed effect": "پیام داده شده را به صورت مضمون فضای کاری ارسال می کند", + "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "ارسال داده‌ها به صورت ناشناس به ما در بهبود %(brand)s کمک می‌کند. برای این مورد از کوکی استفاده می‌شود.", + "If disabled, messages from encrypted rooms won't appear in search results.": "اگر غیر فعال شود، پیام‌های اتاق‌های رمزشده در نتایج جستجوها نمایش داده نمی‌شوند.", + "Disable": "غیرفعال‌کردن", + "Currently indexing: %(currentRoom)s": "هم‌اکنون ایندکس می‌شوند: %(currentRoom)s", + "%(brand)s is securely caching encrypted messages locally for them to appear in search results:": "%(brand)s پیام‌های رمزشده را به صورت امن و محلی ذخیره کرده تا در نتایج جستجو نمایش دهد:", + "Short keyboard patterns are easy to guess": "الگوهای کوتاه صفحه کلید به راحتی قابل حدس هستند", + "Straight rows of keys are easy to guess": "ردیف کلیدهای مستقیم به راحتی قابل حدس هستند", + "Common names and surnames are easy to guess": "نام و نام خانوادگی‌های متداول به راحتی قابل حدس زدن هستند", + "Names and surnames by themselves are easy to guess": "به راحتی می توان نام و نام خانوادگی را حدس زد", + "Predictable substitutions like '@' instead of 'a' don't help very much": "جایگزین‌های قابل پیش بینی مانند '@' به جای 'a' کمک زیادی نمی کند", + "Send %(eventType)s events as you in your active room": "رویدادهای %(eventType)s هنگامی که در اتاق فعال خود هستید ارسال شود", + "Unrecognised command: %(commandText)s": "دستور نامفهوم: %(commandText)s", + "Unknown Command": "دستور ناشناس", + "Server unavailable, overloaded, or something else went wrong.": "سرور در دسترس نیست، یا حجم بار روی آن زیاد شده و یا خطای دیگری رخ داده است.", + "Server error": "خطای سرور", + "Everyone in this room is verified": "همه‌ی اعضای این اتاق تائید شده‌اند", + "This room is end-to-end encrypted": "این اتاق به صورت سرتاسر رمزشده است", + "Someone is using an unknown session": "فردی از یک نشست ناشناس استفاده می‌کند", + "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.": "این کاربر هیچ‌کدام از نشست‌های خود را تائید نکرده است.", + "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 را پاک می‌کنید؟", + "Email Address": "آدرس ایمیل", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "جهت تائيد آدرس ایمیل، ما یک ایمیل برای شما ارسال کردیم. لطفا فرآیند موجود در ایمیل را پی گرفته و سپس بر روی دکمه‌ی زیر کلیک نمائید.", + "Unable to add email address": "امکان اضافه‌کردن آدرس ایمیل وجود ندارد", + "This doesn't appear to be a valid email address": "به نظر می‌رسد این یک آدرس ایمیل معتبر نیست", + "Invalid Email Address": "آدرس ایمیل نامعتبر", + "Remove %(email)s?": "%(email)s را پاک می‌کنید؟", + "Unable to remove contact information": "حذف اطلاعات تماس امکان‌پذیر نیست", + "Discovery options will appear once you have added a phone number above.": "امکانات کاوش و جستجو بلافاصله بعد از اضافه‌کردن شماره تلفن در بالا ظاهر خواهند شد.", + "Verification code": "کد تائید", + "Please enter verification code sent via text.": "لطفا کد تائیدی را که از طریق متن ارسال شده‌است، وارد کنید.", + "Unable to verify phone number.": "امکان تائید شماره تلفن وجود ندارد.", + "Unable to share phone number": "امکان به اشتراک‌گذاری شماره تلفن وجود ندارد", + "Unable to revoke sharing for phone number": "لغو اشتراک‌گذاری شماره تلفن امکان‌پذیر نیست", + "Discovery options will appear once you have added an email above.": "امکانات کاوش و جستجو بلافاصله بعد از اضافه‌کردن یک ایمیل در بالا ظاهر خواهند شد.", + "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. Learn more about encryption.": "پس از فعال‌کردن رمزنگاری برای یک اتاق، امکان غیرفعال‌کردن آن وجود ندارد. پیام‌هایی که در اتاق‌های رمزشده ارسال می‌شوند، توسط سرور دیده نشده و فقط اعضای اتاق امکان مشاهده‌ی آن‌ها را دارند. فعال‌کردن رمزنگاری برای یک اتاق می‌تواند باعث از کار افتادن بسیاری از بات‌ها و پل‌های ارتباطی (bridges) شود. در مورد رمزنگاری بیشتری بدانید.", + "Send %(eventType)s events": "ارسال رخدادهای %(eventType)s", + "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "در تغییر الزامات سطح دسترسی اتاق خطایی رخ داد. از داشتن دسترسی‌های کافی اطمینان حاصل کرده و مجددا امتحان کنید.", + "Error changing power level requirement": "خطا در تغییر الزامات سطح دسترسی", + "Banned by %(displayName)s": "توسط %(displayName)s تحریم شد", + "Change server ACLs": "لیست‌های کنترل دسترسی (ACL) سرور را تغییر دهید", + "This room is bridging messages to the following platforms. Learn more.": "این اتاق، ارتباط بین پیام‌ها و پلتفورم‌های زیر را ایجاد می‌کند. بیشتر بدانید.", + "This room isn’t bridging messages to any platforms. Learn more.": "این اتاق پیام‌های شما را با هیچ پلتفورمی ارتباط نمی‌دهد. بیشتر بدانید.", + "View older messages in %(roomName)s.": "پیام‌های قدیمی اتاق %(roomName)s را مشاهده کنید.", + "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. 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.": "هشدار: به‌روزرسانی یک اتاق، اعضای آن را به صورت خودکار به نسخه‌ی جدید همان اتاق اضافه نمی‌کند. ما یک لینک به نسخه‌ی جدید اتاق را در نسخه‌ی قدیمی اتاق قرار می‌دهیم - اعضای اتاق برای اضافه‌شدن به نسخه‌ی جدید اتاق باید بر روی آن لینک کلیک کنند.", + "You may need to manually permit %(brand)s to access your microphone/webcam": "ممکن است لازم باشد دسترسی %(brand)s به میکروفون/دوربین را به صورت دستی فعال کنید", + "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "نام نشست‌های زیر و خارج‌شدن از آن‌ها را مدیریت کرده و یا آن‌ها از در پروفایل کاربری خود تائید کنید.", + "%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s داده‌های تجزیه و تحلیلی را به صورت غیرمشهود و جهت بهبود برنامه جمع‌آوری می‌کند.", + "Accept all %(invitedRooms)s invites": "همه‌ی دعوت‌های %(invitedRooms)s را قبول کن", + "Reject all %(invitedRooms)s invites": "همه‌ی دعوت‌های %(invitedRooms)s را رد کن", + "Bulk options": "گزینه‌های دسته‌جمعی", + "Read Marker lifetime (ms)": "مدت‌زمان نشانه‌ی خوانده‌شده (ms)", + "Composer": "سازنده", + "Show tray icon and minimize window to it on close": "آیکون جعبه را نشان داده و هنگام بسته‌شدن، پنجره را در قالب آن کوچک کن", + "Always show the window menu bar": "همیشه نوار فهرست پنجره را نشان بده", + "Warn before quitting": "قبل از خروج هشدا بده", + "Start automatically after system login": "پس از ورود به سیستم به صورت خودکار آغاز کن", + "Subscribe": "اضافه‌شدن", + "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!": "ثبت‌نام کردن در یک لیست تحریم باعث می‌شود شما هم عضو آن شوید!", + "eg: @bot:* or example.org": "برای مثال: @bot:* یا example.org", + "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 'My Ban List' - stay in this room to keep the ban list in effect.": "لیست تحریم شخصی شما همه‌ی کاربران و سرورهایی را که شما تمایلی به دیدن پیام‌های آن‌ها ندارید را در خود جای می‌دهد. بعد از نادیده‌گرفتن اولین کاربر یا سرور، یک اتاق جدید در لیست اتاق‌های شما با نام 'لیست تحریم من' نمایش داده می‌شود - برای اینکه لیست تحریم‌ها کار کند، اتاق را ترک نکنید.", + "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.": "نادیده‌گرفتن افراد توسط لیست تحریم صورت می‌گیرد که حاوی قوانینی برای تشخیص این است که چه کسی را تحریم کند. اضافه‌شدن به لیست تحریم به این معناست که کاربر/سرور بلاک شده و از دید شما پنهان خواهد بود.", + "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.": "شما می‌توانید گذرواژه‌ی خود را تغییر دهید، اما برخی از قابلیت ها تا زمان بازگشت سرور هویت‌سنجی در دسترس نخواهند بود. اگر مدام این هشدار را می‌بینید، پیکربندی خود را بررسی کرده یا با مدیر سرور تماس بگیرید.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "کاربران و سرورهایی که قصد نادیده گرفتن آن‌ها را دارید در این‌جا اضافه کنید. در %(brand)s از ستاره (*) برای مچ‌شدن با هر کاراکتری استفاده کنید. برای مثال، @bot:* همه‌ی کاربران یا سرورهایی را که نام 'bot' در آن‌ها وجود دارد، نادیده می‌گیرد.", + "⚠ These settings are meant for advanced users.": "⚠ این تنظیمات برای کاربران حرفه‌ای قرار داده شده‌است.", + "You are currently subscribed to:": "شما هم‌اکنون مشترک شده‌اید در:", + "You are currently ignoring:": "شما در حال حاضر این موارد را نادیده گرفته‌اید:", + "Ban list rules - %(roomName)s": "قوانین لیست تحریم - %(roomName)s", + "Feeling experimental? Labs are the best way to get things early, test out new features and help shape them before they actually launch. Learn more.": "تمایل به آزمایش‌کردن دارید؟ آزمایشگاه بهترین مکان برای دریافت چیزهای جدید، تست قابلیت‌های نو و کمک به رفع مشکلات آن‌ها قبل از انتشار نهایی است. بیشتر بدانید.", + "%(brand)s version:": "نسخه‌ی %(brand)s:", + "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "برای گزارش مشکلات امنیتی مربوط به ماتریکس، لطفا سایت Matrix.org بخش Security Disclosure Policy را مطالعه فرمائید.", + "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "اگر از طریق گیتهاب مشکلی را ثبت کرده‌اید، لاگ این مشکلات می‌تواند به ما در جهت کشف و حل آن‌ها کمک کند. لاگ مشکلات حاوی داده‌های مورد استفاده برنامه نظیر نام کاربری، شناسه یا نام مستعار اتاق‌ها یا فضاهای کاری که به آن‌ها سر زده‌اید و یا نام کاربری سایر کاربران می‌شود. این داده‌ها حاوی پیام‌های شما نمی‌شوند.", + "Chat with %(brand)s Bot": "گفتگو با بات %(brand)s", + "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "برای گرفتن کمک در استفاده از %(brand)s، اینجا کلید کرده یا با استفاده از دکمه‌ی زیر اقدام به شروع گفتگو با بات ما نمائید.", + "For help with using %(brand)s, click here.": "برای گرفتن کمک در استفاده از %(brand)s، اینجا کلیک کنید.", + "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "با شرایط و ضوایط سرویس سرور هویت‌سنجی (%(serverName)s) موافقت کرده تا بتوانید از طریق آدرس ایمیل و شماره تلفن قابل یافته‌شدن باشید.", + "Spell check dictionaries": "دیکشنری برای چک کردن املاء", + "Appearance Settings only affect this %(brand)s session.": "تنظیمات ظاهری برنامه تنها همین نشست %(brand)s را تحت تاثیر قرار می‌دهد.", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "نام فونتی که بر روی سیستم‌تان نصب است را وارد کرده و %(brand)s سعی می‌کند از آن استفاده کند.", + "Use between %(min)s pt and %(max)s pt": "از عددی بین %(min)s pt و %(max)s pt استفاده کنید", + "Custom font size can only be between %(min)s pt and %(max)s pt": "اندازه فونت دلخواه تنها می‌تواند عددی بین %(min)s pt و %(max)s pt باشد", + "New version available. Update now.": "نسخه‌ی جدید موجود است. هم‌اکنون به‌روزرسانی کنید.", + "Use an Integration Manager (%(serverName)s) to manage bots, widgets, and sticker packs.": "از یک مدیر پکپارچه‌سازی (%(serverName)s) برای مدیریت بات‌ها، ویجت‌ها و پک‌های استیکر استفاده کنید.", + "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "استفاده از سرور هویت‌سنجی اختیاری است. اگر تصمیم بگیرید از سرور هویت‌سنجی استفاده نکنید، شما با استفاده از آدرس ایمیل و شماره تلفن قابل یافته‌شدن و دعوت‌شدن توسط سایر کاربران نخواهید بود.", + "Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "قطع ارتباط با سرور هویت‌سنجی به این معناست که شما از طریق ادرس ایمیل و شماره تلفن، بیش از این قابل یافته‌شدن و دعوت‌شدن توسط کاربران دیگر نیستید.", + "You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.": "در حال حاضر از سرور هویت‌سنجی استفاده نمی‌کنید. برای یافتن و یافته‌شدن توسط مخاطبان موجود که شما آن‌ها را می‌شناسید، یک مورد در پایین اضافه کنید.", + "Identity Server": "سرور هویت‌سنجی", + "If you don't want to use to discover and be discoverable by existing contacts you know, enter another identity server below.": "اگر تمایل به استفاده از برای یافتن و یافته‌شدن توسط مخاطبان خود را ندارید، سرور هویت‌سنجی دیگری را در پایین وارد کنید.", + "You are currently using to discover and be discoverable by existing contacts you know. You can change your identity server below.": "در حال حاضر شما از برای یافتن و یافته‌شدن توسط مخاطبانی که می‌شناسید، استفاده می‌کنید. می‌توانید سرور هویت‌سنجی خود را در زیر تغییر دهید.", + "Identity Server (%(server)s)": "سرور هویت‌سنجی (%(server)s)", + "We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.": "توصیه می‌کنیم آدرس‌های ایمیل و شماره تلفن‌های خود را پیش از قطع ارتباط با سرور هویت‌سنجی از روی آن پاک کنید.", + "You are still sharing your personal data on the identity server .": "شما هم‌چنان داده‌های شخصی خودتان را بر روی سرور هویت‌سنجی به اشتراک می‌گذارید.", + "Disconnect anyway": "در هر صورت قطع کن", + "wait and try again later": "صبر کرده و بعدا دوباره امتحان کنید", + "contact the administrators of identity server ": "با مدیران سرور هویت‌سنجی تماس بگیرید", + "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "پلاگین‌های مرورگر خود را بررسی کنید تا مبادا سرور هویت‌سنجی را بلاک کرده باشند (پلاگینی مانند Privacy Badger)", + "You should:": "شما باید:", + "You should remove your personal data from identity server before disconnecting. Unfortunately, identity server is currently offline or cannot be reached.": "شما باید قبل از قطع اتصال، داده‌های شخصی خود را از سرور هویت‌سنجی پاک کنید. متاسفانه سرور هویت‌سنجی هم‌اکنون آفلاین بوده و یا دسترسی به آن امکان‌پذیر نیست.", + "Disconnect": "قطع شو", + "Disconnect from the identity server ?": "از سرور هویت‌سنجی قطع می‌شوید؟", + "Disconnect identity server": "اتصال با سرور هویت‌سنجی را قطع کن", + "The identity server you have chosen does not have any terms of service.": "سرور هویت‌سنجی که انتخاب کرده‌اید شرایط و ضوابط سرویس ندارد.", + "Terms of service not accepted or the identity server is invalid.": "شرایط و ضوابط سرویس پذیرفته نشده و یا سرور هویت‌سنجی معتبر نیست.", + "Disconnect from the identity server and connect to instead?": "ارتباط با سرور هویت‌سنجی قطع شده و در عوض به متصل شوید؟", + "Change identity server": "تغییر سرور هویت‌سنجی", + "Checking server": "در حال بررسی سرور", + "Could not connect to Identity Server": "اتصال به سرور هیوت‌سنجی امکان پذیر نیست", + "Not a valid Identity Server (status code %(code)s)": "سرور هویت‌سنجی معتبر نیست (کد وضعیت %(code)s)", + "Identity Server URL must be HTTPS": "پروتکل آدرس سرور هویت‌سنجی باید HTTPS باشد", + "not ready": "آماده نیست", + "ready": "آماده", + "Secret storage:": "حافظه نهان:", + "in account data": "در داده‌های حساب کاربری", + "Secret storage public key:": "کلید عمومی حافظه نهان:", + "Backup key cached:": "کلید پشتیبان ذخیره شد:", + "not stored": "ذخیره نشد", + "Backup key stored:": "کلید پشتیبان ذخیره شد:", + "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.": "در صورت از دست رفتن دسترسی به نشست‌هایتان، از کلیدهای رمزنگاری و داده‌های حساب کاربری خود نسخه‌ی پشتیبان تهیه نمائید. کلیدهای شما توسط کلید منحضر به فرد امنیتی (Security Key) امن خواهند ماند.", + "unexpected type": "تایپ (نوع) غیرمنتظره", + "well formed": "خوش‌ساخت", + "Back up your keys before signing out to avoid losing them.": "پیش از خروج از حساب کاربری، از کلید‌های خود پشتیبان بگیرید تا آن‌ها را از دست ندهید.", + "Your keys are not being backed up from this session.": "کلید‌های شما از این نشست پشتیبان‌گیری نمی‌شود.", + "Algorithm:": "الگوریتم:", + "Backup version:": "نسخه‌ی پشتیبان:", + "This backup is trusted because it has been restored on this session": "این نسخه‌ی پشتیبان قابل اعتماد است چرا که بر روی این نشست بازیابی شد", + "Backup is not signed by any of your sessions": "نسخه پشتیبان توسط هیچ کدام از نشست‌های شما امضاء نشده‌است", + "Backup has an invalid signature from unverified session ": "نسخه پشتیبان دارای امضاء نامعتبر از نشست تائیدنشده‌ی می‌باشد", + "Backup has an invalid signature from verified session ": "نسخه‌ی پشتبان دارای امضاء نامعتبر از نشست تائیدشده‌ی می‌باشد", + "Backup has a valid signature from unverified session ": "نسخه پشتیبان دارای امضاء معتبر از نشست تائيد نشده‌ی می‌باشد", + "Backup has a valid signature from verified session ": "نسخه پشتیبان دارای امضاء معتبر از نشست تائیدشده‌ی می‌باشد", + "Backup has an invalid signature from this session": "نسخه پشتیبان دارای امضاء نامعتبر از طرف این نشست است", + "Backup has a valid signature from this session": "نسخه پشتیبان دارای امضاء معتبر از طرف این نشست است", + "Backup has a signature from unknown session with ID %(deviceId)s": "نسخه پشتیبان دارای امضاء از نشست ناشناس با شناسه‌ی %(deviceId)s است", + "Backup has a signature from unknown user with ID %(deviceId)s": "نسخه پشتیبان دارای امضاء از کاربر ناشناس با شناسه‌ی %(deviceId)s است", + "Backup has a invalid signature from this user": "نسخه پشتیبان دارای امضاء نامعتبر از این کاربر است", + "Backup has a valid signature from this user": "نسخه پشتیبان دارای امضاء معتبر از این کاربر است", + "All keys backed up": "از همه کلیدها نسخه‌ی پشتیبان گرفته شد", + "Backing up %(sessionsRemaining)s keys...": "در حال پیشیبان‌گیری کلید‌های %(sessionsRemaining)s ...", + "Connect this session to Key Backup": "این نشست را به کلید پشتیبان‌گیر متصل کن", + "Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "پیش از خروج از حساب کاربری، این نشست را به کلید پشتیبان‌گیر متصل نمائید. با این کار مانع از گم‌شدن کلیدهای که فقط بر روی این نشست وجود دارند می‌شوید.", + "This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.": "این نشست از کلیدهای شما پشتیبان‌گیری نمی‌کند، با این حال شما یک نسخه‌ی پشتیبان موجود دارید که می‌توانید آن را بازیابی کنید.", + "This session is backing up your keys. ": "این نشست در حال پشتیبان‌گیری از کلیدهای شماست. ", + "Restore from Backup": "بازیابی از نسخه‌ی پشتیبان", + "Unable to load key backup status": "امکان بارگیری و نمایش وضعیت کلید پشتیبان وجود ندارد", + "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "آیا اطمینان دارید؟ در صورتی که از کلیدهای شما به درستی پشتیبان‌گیری نشده باشد، تمام پیام‌های رمزشده‌ی خود را از دست خواهید داد.", + "Delete Backup": "پاک‌کردن نسخه پشتیبان (Backup)", + "Save": "ذخیره", + "Profile picture": "تصویر پروفایل", + "Display Name": "نام نمایشی", + "Profile": "پروفایل", + "Upgrade to your own domain": "به دامنه‌ی خودتان به روز‌رسانی کنید", + "The operation could not be completed": "امکان تکمیل عملیات وجود ندارد", + "Failed to save your profile": "ذخیره‌ی تنظیمات شما موفقیت‌آمیز نبود", + "Enable audible notifications for this session": "فعال‌سازی اعلان‌های صدادار برای این نشست", + "Show message in desktop notification": "پیام‌ها را در اعلان دسکتاپ نشان بده", + "Enable desktop notifications for this session": "فعال‌سازی اعلان‌های دسکتاپ برای این نشست", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "ممکن است شما آن‌ها را بر روی کلاینت دیگری به غیر از %(brand)s پیکربندی کرده باشید. شما نمی‌توانید آن موارد را بر روی %(brand)s تغییر دهید.", + "There are advanced notifications which are not shown here.": "اعلان‌های پیشرفته‌ای وجود دارد که در این‌جا نمایش داده نمی‌شود.", + "Add an email address to configure email notifications": "برای راه‌اندازی اعلان‌های ایمیلی یک آدرس ایمیل اضافه کنید", + "Clear notifications": "پاک‌کردن اعلان‌ها", + "The integration manager is offline or it cannot reach your homeserver.": "مدیر یکپارچه‌سازی‌ یا آفلاین است و یا نمی‌تواند به سرور شما متصل شود.", + "Cannot connect to integration manager": "امکان اتصال به مدیر یکپارچه‌سازی‌ها وجود ندارد", + "Connecting to integration manager...": "در حال اتصال به مدیر پکپارچه‌سازی...", + "Message search initialisation failed": "آغاز فرآیند جستجوی پیام‌ها با شکست همراه بود", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s نمی‌تواند پیام‌های رمزشده را به شکل امن و به صورت محلی در هنگامی که مرورگر در حال فعالیت است ذخیره کند. از %(brand)s نسخه‌ی دسکتاپ برای نمایش پیام‌های رمزشده در نتایج جستجو استفاده نمائید.", + "%(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 search components added.": "%(brand)s بعضی از مولفه‌های مورد نیاز برای ذخیره امن پیام‌های رمزشده به صورت محلی را ندارد. اگر تمایل به استفاده از این قابلیت دارید، یک نسخه‌ی دلخواه از %(brand)s با مولفه‌های مورد نظر بسازید.", + "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|other": "پیام‌های رمزشده را به صورتی محلی و امن ذخیره کرده تا در نتایج جستجو ظاهر شوند، با استفاده از %(size)s برای ذخیره‌ی پیام‌ها از اتاق‌های %(rooms)s.", + "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|one": "پیام‌های رمزشده را به صورتی محلی و امن ذخیره کرده تا در نتایج جستجو ظاهر شوند، با استفاده از %(size)s برای ذخیره‌ی پیام‌ها از اتاق %(rooms)s.", + "Securely cache encrypted messages locally for them to appear in search results.": "پیام‌های رمزشده را به صورتی محلی و امن ذخیره کرده تا در نتایج جستجو ظاهر شوند.", + "Manage": "مدیریت", + "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "به صورت جداگانه هر نشستی که با بقیه‌ی کاربران دارید را تائید کنید تا به عنوان نشست قابل اعتماد نشانه‌گذاری شود، با این کار می‌توانید به دستگاه‌های امضاء متقابل اعتماد نکنید.", + "Encryption": "رمزنگاری", + "Last seen": "آخرین بازدید", + "You'll need to authenticate with the server to confirm the upgrade.": "برای تائید ارتقاء، نیاز به احراز هویت نزد سرور خواهید داشت.", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)s دعوت خود را %(count)s مرتبه پس‌گرفتند", + "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "برای اینکه بتوانید بقیه‌ی نشست‌ها را تائید کرده و به آن‌ها امکان مشاهده‌ی پیام‌های رمزشده را بدهید، ابتدا باید این نشست را ارتقاء دهید. بعد از تائیدشدن، به عنوان نشست‌ّای تائید‌شده به سایر کاربران نمایش داده خواهند شد.", + "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s دعوت خود را رد کرد", + "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s دعوت خود را %(count)s مرتبه رد کرد", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s دعوت‌های خود را رد کردند", + "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s دعوت خود را %(count)s مرتبه رد کردند", + "Enter a security phrase only you know, as it’s used to safeguard your data. To be secure, you shouldn’t re-use your account password.": "یک عبارت امنیتی که فقط خودتان می‌دانید را وارد کنید؛ این عبارت از داده‌های شما محافظت می‌کند. برای حفظ امنیت، نباید از گذرواژه‌ی خود در اینجا استفاده کنید.", + "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "کلید امنیتی خود را در جایی امن ذخیره کنید، چرا که از آن به عنوان محافظ پیام‌های رمز‌شده‌ی شما استفاده می‌شود.", + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s خارج شد و مجددا عضو شد", + "Unable to query secret storage status": "امکان جستجو و کنکاش وضعیت حافظه‌ی مخفی میسر نیست", + "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)s %(count)s مرتبه خارج شد و مجددا عضو شد", + "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)s خارج شدند و مجددا عضو شدند", + "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "اگر الان لغو کنید، ممکن است پیام‌ها و داده‌های رمزشده‌ی خود را در صورت خارج‌شدن از حساب‌های کاربریتان، از دست دهید.", + "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s %(count)s مرتبه خارج شدند و مجددا عضو شدند", + "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s پیوست و خارج شد", + "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s %(count)s مرتبه عضو شده و خارج شدند", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s عضو شدند و خارج شدند", + "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s %(count)s مرتبه عضو شده و خارج شدند", + "%(oneUser)sleft %(count)s times|one": "%(oneUser)s خارج شد", + "%(oneUser)sleft %(count)s times|other": "%(oneUser)s %(count)s مرتبه خارج شده‌است", + "You can also set up Secure Backup & manage your keys in Settings.": "همچنین می‌توانید پشتیبان‌گیری امن را برپا کرده و کلید‌های خود را در تنظیمات مدیریت کنید.", + "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s خارج شدند", + "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)s %(count)s مرتبه خارج شدند", + "Upgrade your encryption": "رمزنگاری خود را ارتقا دهید", + "Set a Security Phrase": "یک عبارت امنیتی تنظیم کنید", + "Confirm Security Phrase": "عبارت امنیتی را تأیید کنید", + "%(oneUser)sjoined %(count)s times|one": "%(oneUser)s پیوست", + "%(oneUser)sjoined %(count)s times|other": "%(oneUser)s %(count)s مرتبه عضو شدند", + "Save your Security Key": "کلید امنیتی خود را ذخیره کنید", + "Unable to set up secret storage": "تنظیم حافظه‌ی پنهان امکان پذیر نیست", + "Passphrases must match": "عبارات‌های امنیتی باید مطابقت داشته باشند", + "Passphrase must not be empty": "عبارت امنیتی نمی‌تواند خالی باشد", + "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s%(count)s مرتبه عضو شده‌اند", + "Unknown error": "خطای ناشناخته", + "This room is not showing flair for any communities": "این اتاق برای هیچ اجتماعی استعداد نشان نمی دهد", + "Showing flair for these communities:": "نمایش استعداد برای این اجتماع‌ها:", + "'%(groupId)s' is not a valid community ID": "«%(groupId)s» یک شناسه معتبر اجتماع نیست", + "Invalid community ID": "شناسه انجمن نامعتبر است", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "در به روزرسانی وضعیت این اتاق خطایی روی داد. سرور ممکن است اجازه نداده باشد و یا خطایی موقت روی داده باشد.", + "Error updating flair": "خطا در به روزرسانی", + "Show more": "نمایش بیشتر", + "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "آدرس‌های این اتاق را تنظیم کنید تا کاربران بتوانند این اتاق را از طریق سرور شما پیدا کنند (%(localDomain)s)", + "Local Addresses": "آدرس‌های محلی", + "New published address (e.g. #alias:server)": "آدرس جدید منتشر شده (به عنوان مثال #alias:server)", + "No other published addresses yet, add one below": "آدرس دیگری منتشر نشده است، در زیر اضافه کنید", + "Other published addresses:": "دیگر آدرس‌های منتشر شده:", + "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "آدرس‌های منتشرشده را می توان در هر سرور برای پیوستن به اتاق شما استفاده کرد. برای انتشار آدرس، ابتدا باید آن را به عنوان آدرس محلی تنظیم کنید.", + "Published Addresses": "آدرس‌های منتشر شده", + "Local address": "آدرس محلی", + "This room has no local addresses": "این اتاق آدرس محلی ندارد", + "not specified": "مشخص نشده", + "Main address": "آدرس اصلی", + "Error removing address": "خطا در حذف آدرس", + "There was an error removing that address. It may no longer exist or a temporary error occurred.": "هنگام حذف آدرس خطایی روی داد. ممکن است دیگر وجود نداشته باشد یا خطایی موقت روی داده باشد.", + "You don't have permission to delete the address.": "شما اجازه حذف آدرس را ندارید.", + "There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "هنگام ایجاد آدرس خطایی روی داد. ممکن است سرور مجاز نباشد و یا اینکه خطایی موقت رخ داده باشد.", + "Error creating address": "خطا در ایجاد آدرس", + "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "در به روزرسانی آدرس های جایگزین اتاق خطایی روی داد. ممکن است سرور مجاز نباشد و یا اینکه خطایی موقت رخ داده باشد.", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "در به روزرسانی آدرس اصلی اتاق خطایی روی داد. ممکن است سرور مجاز نباشد و یا خطای موقتی رخ داده باشد.", + "Error updating main address": "خطا در به روزرسانی آدرس اصلی", + "Delete recording": "حذف پیام ضبط شده", + "Stop the recording": "توقف ضبط", + "Record a voice message": "ضبط پیام صوتی", + "We didn't find a microphone on your device. Please check your settings and try again.": "ما میکروفونی در دستگاه شما پیدا نکردیم. لطفاً تنظیمات خود را بررسی کنید و دوباره امتحان کنید.", + "No microphone found": "میکروفونی یافت نشد", + "We were unable to access your microphone. Please check your browser settings and try again.": "ما نتوانستیم به میکروفون شما دسترسی پیدا کنیم. لطفا تنظیمات مرورگر خود را بررسی کنید و دوباره سعی کنید.", + "Unable to access your microphone": "دسترسی به میکروفن شما امکان پذیر نیست", + "Mark all as read": "همه را به عنوان خوانده شده علامت بزن", + "Jump to first unread message.": "رفتن به اولین پیام خوانده نشده.", + "Invited by %(sender)s": "دعوت شده توسط %(sender)s", + "Revoke invite": "لغو دعوت", + "Admin Tools": "ابزارهای مدیریت", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "دعوت لغو نشد. ممکن است سرور با یک مشکل موقتی روبرو شده باشد و یا اینکه شما مجوز کافی برای لغو دعوت را نداشته باشید.", + "Failed to revoke invite": "دعوت لغو نشد", + "Show Stickers": "نمایش استیکرها", + "Hide Stickers": "پنهان کردن استیکر‌ها", + "Stickerpack": "استیکر", + "Add some now": "اکنون چندتایی اضافه کنید", + "You don't currently have any stickerpacks enabled": "شما در حال حاضر هیچ بسته برچسب فعالی ندارید", + "Failed to connect to integration manager": "اتصال به سیستم مدیریت ادغام انجام نشد", + "Only room administrators will see this warning": "فقط مدیران اتاق این هشدار را مشاهده خواهند کرد", + "This room is running room version , which this homeserver has marked as unstable.": "این اتاق از نسخه اتاق استفاده می کند، که این سرور آن را به عنوان ناپایدار علامت گذاری کرده است.", + "This room has already been upgraded.": "این اتاق قبلاً ارتقا یافته است.", + "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "با ارتقا این اتاق نسخه فعلی اتاق خاموش شده و یک اتاق ارتقا یافته به همین نام ایجاد می شود.", + "Unread messages.": "پیام های خوانده نشده.", + "%(count)s unread messages.|one": "۱ پیام خوانده نشده.", + "%(count)s unread messages.|other": "%(count)s پیام خوانده نشده.", + "%(count)s unread messages including mentions.|one": "۱ اشاره خوانده نشده.", + "%(count)s unread messages including mentions.|other": "%(count)s پیام‌های خوانده نشده از جمله اشاره‌ها.", + "Room options": "تنظیمات اتاق", + "Leave Room": "ترک اتاق", + "Invite People": "افراد را دعوت کنید", + "Favourited": "مورد علاقه", + "Forget Room": "اتاق را فراموش کن", + "Notification options": "تنظیمات اعلان", + "Mentions & Keywords": "اشاره‌ها و کلمات کلیدی", + "Use default": "استفاده از پیش‌فرض", + "Show less": "نمایش کمتر", + "Public Name": "نام عمومی", + "ID": "شناسه", + "Delete %(count)s sessions|one": "حذف %(count)s نشست", + "Delete %(count)s sessions|other": "حذف %(count)s نشست", + "Delete sessions|one": "حذف نشست", + "Delete sessions|other": "حذف نشست‌ها", + "Click the button below to confirm deleting these sessions.|one": "برای تائید حذف این نشست بر روی دکمه‌ی زیر کلیک کنید.", + "Click the button below to confirm deleting these sessions.|other": "برای تائید حذف این نشست‌ها بر روی دکمه‌ی زیر کلیک کنید.", + "Confirm deleting these sessions": "حذف این نشست‌ها را تائید کنید", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "حذف‌کردن این نشست را با استفاده از احراز هویت یکپارچه که هویت شما را ثابت می‌کند، تائید نمائید.", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "حذف‌کردن این نشست‌ها را با استفاده از احراز هویت یکپارچه که هویت شما را ثابت می‌کند، تائید نمائید.", + "Unable to load session list": "امکان بارگیری و نمایش لیست نشست‌ها ممکن نیست", + "Your homeserver does not support session management.": "سرور شما قابلیت مدیریت نشست‌ها را پشتیبانی نمی‌کند.", + "exists": "وجود دارد", + "Homeserver feature support:": "قابلیت‌های پشتیبانی‌شده سمت سرور:", + "User signing private key:": "کلید امضاء خصوصی کاربر:", + "Self signing private key:": "کلید خصوصی self-sign:", + "not found locally": "به صورت محلی یافت نشد", + "cached locally": "به صورت محلی کش شده‌است", + "Master private key:": "شاه‌کلید خصوصی:", + "not found in storage": "در حافظه یافت نشد", + "in secret storage": "بر روی حافظه نهان", + "Cross-signing private keys:": "کلیدهای خصوصی امضاء متقابل:", + "not found": "یافت نشد", + "in memory": "بر روی حافظه", + "Cross-signing public keys:": "کلیدهای عمومی امضاء متقابل:", + "Go back": "بازگشت", + "You can change this later": "می‌توانید بعدا این را تغییر دهید", + "Invite only, best for yourself or teams": "فقط با دعوتنامه، مناسب برای خودتان یا تیم‌ها یا جمع‌های خصوصی", + "Private": "خصوصی", + "Open space for anyone, best for communities": "محیط باز برای همه، مناسب برای جمع عمومی", + "Public": "عمومی", + "Spaces are a new way to group rooms and people. To join an existing space you'll need an invite.": "محیط‌ها یک روش جدید برای دسته‌بندی کاربران و اتاق‌ها هستند. برای پیوستن به یک محیط موجود، نیاز به یک دعوتنامه دارید.", + "Create a space": "ساختن یک محیط", + "Please enter a name for the space": "لطفا یک نام برای محیط وارد کنید", + "Description": "توضیحات", + "Name": "نام", + "Upload": "بارگذاری", + "Delete": "پاک‌کردن", + "Accept to continue:": "برای ادامه را بپذیرید:", + "Decline (%(counter)s)": "رد کردن (%(counter)s)", + "Your server isn't responding to some requests.": "سرور شما به بعضی درخواست‌ها پاسخ نمی‌دهد.", + "Pin": "سنجاق", + "Folder": "پوشه", + "Headphones": "هدفون", + "Anchor": "لنگر", + "Bell": "زنگ", + "Trumpet": "شیپور", + "Guitar": "گیتار", + "Ball": "توپ", + "Trophy": "کاپ", + "Rocket": "موشک", + "Aeroplane": "هواپیما", + "Bicycle": "دوچرخه", + "Train": "قطار", + "Flag": "پرچم", + "Telephone": "تلفن", + "Hammer": "چکش", + "Key": "کلید", + "Lock": "قفل", + "Scissors": "قیچی", + "Paperclip": "گیره کاغذ", + "Pencil": "مداد", + "Book": "کتاب", + "Light bulb": "لامپ روشن", + "Gift": "هدیه", + "Clock": "ساعت", + "Hourglass": "ساعت‌شنی", + "Umbrella": "چتر", + "Thumbs up": "موافق", + "Santa": "بابانوئل", + "Spanner": "آچار", + "Glasses": "عینک", + "Hat": "کلاه", + "Robot": "ربات", + "Smiley": "لبخند", + "Heart": "قلب", + "Cake": "کیک", + "Pizza": "پیتزا", + "Corn": "ذرت", + "Strawberry": "توت‌فرنگی", + "Apple": "سیب", + "Banana": "موز", + "Fire": "آتش", + "Cloud": "ابر", + "Moon": "ماه", + "Globe": "کره", + "Mushroom": "قارچ", + "Cactus": "کاکتوس", + "Tree": "درخت", + "Flower": "گل", + "Butterfly": "پروانه", + "Octopus": "اختاپوس", + "Fish": "ماهی", + "Turtle": "لاک‌پشت", + "Penguin": "پنگوئن", + "Rooster": "خروس", + "Panda": "پاندا", + "Rabbit": "خرگوش", + "Elephant": "فیل", + "Pig": "خوک", + "Unicorn": "اسب تک‌شاخ", + "Horse": "اسب", + "Lion": "شیر", + "Cat": "گربه", + "Dog": "سگ", + "To be secure, do this in person or use a trusted way to communicate.": "برای حفظ امنیت، خودتان این کار را انجام دهید و یا از یک روش ارتباطی قابل اعتماد استفاده نمائید.", + "They don't match": "مطابقت ندارند", + "They match": "مطابقت دارند", + "Cancelling…": "در حال لغو…", + "Waiting for %(displayName)s to verify…": "منتظر %(displayName)s برای تائید کردن…", + "Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": "منتظر نشست دیگر شما، %(deviceName)s (%(deviceId)s) برای تائید کردن…", + "Waiting for your other session to verify…": "منتظر نشست دیگر شما برای تائید‌کردن…", + "Unable to find a supported verification method.": "روش پشتیبانی‌شده‌ای برای تائید پیدا نشد.", + "Verify this user by confirming the following number appears on their screen.": "در صورتی که عدد بعدی بر روی صفحه‌ی کاربر نمایش داده می‌شود، او را تائید نمائید.", + "Verify this session by confirming the following number appears on its screen.": "در صورتی که شماره‌ی بعدی بر روی دستگاه نمایش داده می‌شود، این نشست را تائید نمائید.", + "Verify this user by confirming the following emoji appear on their screen.": "در صورتی که همه‌ی شکلک‌های موجود بر روی صفحه‌ی دستگاه کاربر ظاهر شده‌اند، او را تائید نمائید.", + "Confirm the emoji below are displayed on both sessions, in the same order:": "تائید کنید که شکلک‌های زیر بر روی هر دو دستگاه و به ترتیب نمایش داده می‌شوند:", + "Start": "شروع", + "Compare a unique set of emoji if you don't have a camera on either device": "اگر بر روی دستگاه خود دوربین ندارید، از تطابق شکلک‌های منحصر به فرد استفاده نمائید", + "Compare unique emoji": "شکلک‌های منحصر به فرد را مقایسه کنید", + "Scan this unique code": "این QR-code منحصر به فرد را اسکن کنید", + "or": "یا", + "Verify this session by completing one of the following:": "این نشست را با دنبال‌کردن یکی از فرآیندهای زیر تائید کنید:", + "Got It": "متوجه شدم", + "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "پیام‌های رد و بدل شده با این کاربر به صورت سرتاسر رمزشده و هیچ نفر سومی امکان مشاهده و خواندن آن‌ها را ندارد.", + "You've successfully verified this user.": "شما با موفقیت این کاربر را تائید کردید.", + "Verified!": "تائید شد!", + "The other party cancelled the verification.": "طرف مقابل فرآیند تائید را لغو کرد.", + "Play": "اجرا کردن", + "Pause": "متوقف‌کردن", + "Accept": "پذیرفتن", + "Decline": "رد کردن", + "Incoming call": "تماس ورودی", + "Incoming video call": "تماس تصویری ورودی", + "Incoming voice call": "تماس صوتی ورودی", + "Unknown caller": "تماس‌گیرنده‌ی ناشناس", + "Dial pad": "صفحه شماره‌گیری", + "There was an error looking up the phone number": "هنگام یافتن شماره تلفن خطایی رخ داد", + "Unable to look up phone number": "امکان یافتن شماره تلفن میسر نیست", + "%(name)s on hold": "%(name)s در حال تعلیق است", + "Return to call": "بازگشت به تماس", + "Fill Screen": "صفحه را پر کن", + "Voice Call": "تماس صوتی", + "Video Call": "تماس تصویری", + "Connecting": "در حال اتصال", + "%(peerName)s held the call": "%(peerName)s تماس را به حالت تعلیق درآورد", + "You held the call Resume": "شما تماس را به حالت تعلیق نگه داشته‌اید ادامه", + "You held the call Switch": "شما تماس را به حالت تعلیق نگه داشته‌اید تعویض", + "Consulting with %(transferTarget)s. Transfer to %(transferee)s": "با %(transferTarget)s مشورت کنید. انتقال به %(transferee)s", + "unknown person": "فرد ناشناس", + "sends confetti": "انیمیشن بارش کاغذ شادی را ارسال کن", + "sends snowfall": "انیمیشن بارش برف را ارسال کن", + "Sends the given message with snowfall": "این پیام را با انیمیشن بارش برف ارسال کن", + "sends fireworks": "انیمیشن آتش‌بازی را ارسال کن", + "Sends the given message with fireworks": "این پیام را با انیمیشن آتش‌بازی ارسال کن", + "Sends the given message with confetti": "این پیام را با انیمیشن بارش کاغد شادی ارسال کن", + "This is your list of users/servers you have blocked - don't leave the room!": "این لیست کاربران/اتاق‌هایی است که شما آن‌ها را بلاک کرده‌اید - اتاق را ترک نکنید!", + "My Ban List": "لیست تحریم‌های من", + "When rooms are upgraded": "زمانی که اتاق‌ها به‌روزرسانی می‌گردند", + "Encrypted messages in group chats": "پیام‌های رمزشده در اتاق‌ها", + "Encrypted messages in one-to-one chats": "پیام‌های رمزشده در گفتگو‌های خصوصی", + "Messages containing @room": "پیام‌های حاوی شناسه‌ی اتاق", + "Messages containing my username": "پیام‌های حاوی نام کاربری من", + "Downloading logs": "در حال دریافت لاگ‌ها", + "Uploading logs": "در حال بارگذاری لاگ‌ها", + "Show chat effects (animations when receiving e.g. confetti)": "نمایش قابلیت‌های بصری (انیمیشن‌هایی مثل بارش برف یا کاغذ شادی هنگام دریافت پیام)", + "IRC display name width": "عرض نمایش نام‌های IRC", + "Manually verify all remote sessions": "به صورت دستی همه‌ی نشست‌ها را تائید نمائید", + "How fast should messages be downloaded.": "پیام‌ها باید چقدر سریع بارگیری شوند.", + "Enable message search in encrypted rooms": "فعال‌سازی قابلیت جستجو در اتاق‌های رمزشده", + "Show previews/thumbnails for images": "پیش‌نمایش تصاویر را نشان بده", + "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "زمانی که سرور شما پیشنهادی ندارد، از سرور کمکی turn.hivaa.im برای برقراری تماس استفاده کنید (در این صورت آدرس IP شما برای سرور turn.hivaa.im آشکار خواهد شد)", + "Low bandwidth mode": "حالت پهنای باند کم", + "Show hidden events in timeline": "نمایش رخدادهای مخفی در گفتگو‌ها", + "Show shortcuts to recently viewed rooms above the room list": "نمایش میانبر در بالای لیست اتاق‌ها برای مشاهده‌ی اتاق‌هایی که اخیرا باز کرده‌اید", + "Show rooms with unread notifications first": "اتاق‌های با پیام‌های خوانده‌نشده را ابتدا نشان بده", + "Order rooms by name": "مرتب‌کردن اتاق‌ها بر اساس نام", + "Show developer tools": "نمایش ابزار توسعه‌دهندگان", + "Prompt before sending invites to potentially invalid matrix IDs": "قبل از ارسال دعوت‌نامه برای کاربری که شناسه‌ی او احتمالا معتبر نیست، هشدا بده", + "Enable widget screenshots on supported widgets": "فعال‌سازی امکان اسکرین‌شات برای ویجت‌های پشتیبانی‌شده", + "Room Colour": "رنگ اتاق", + "Enable URL previews by default for participants in this room": "امکان پیش‌نمایش URL را به صورت پیش‌فرض برای اعضای این اتاق فعال کن", + "Enable URL previews for this room (only affects you)": "فعال‌سازی پیش‌نمایش URL برای این اتاق (تنها شما را تحت تاثیر قرار می‌دهد)", + "Enable inline URL previews by default": "فعال‌سازی پیش‌نمایش URL به صورت پیش‌فرض", + "Never send encrypted messages to unverified sessions in this room from this session": "هرگز از این نشست، پیام‌های رمزشده برای به نشست‌های تائید نشده در این اتاق ارسال مکن", + "Never send encrypted messages to unverified sessions from this session": "هرگز از این نشست، پیام‌های رمزشده را به نشست‌های تائید نشده ارسال مکن", + "Send analytics data": "ارسال داده‌های تجزیه و تحلیلی", + "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "اجازه برقراری تماس‌های یک به یک را بده (با فعال‌شدن این قابلیت، ممکن است طرف مقابل بتواند آدرس IP شما را ببیند)", + "System font name": "نام فونت سیستمی", + "Use a system font": "استفاده از یک فونت موجود بر روی سیستم شما", + "Match system theme": "با پوسته‌ی سیستم تطبیق پیدا کن", + "Enable Community Filter Panel": "پنل پالایش فضای کاری را فعال کن", + "Mirror local video feed": "تصویر خودتان را هنگام تماس تصویری برعکس (مثل آینه) نمایش بده", + "Automatically replace plain text Emoji": "متن ساده را به صورت خودکار با شکلک جایگزین کن", + "Use Ctrl + Enter to send a message": "استفاده از Ctrl + Enter برای ارسال پیام", + "Use Command + Enter to send a message": "استفاده از Command + Enter برای ارسال پیام", + "Use Ctrl + F to search": "استفاده از Ctrl + F برای جستجو", + "Use Command + F to search": "استفاده از Command + F برای جستجو", + "Show typing notifications": "نمایش اعلان «در حال نوشتن»", + "Send typing notifications": "ارسال اعلان «در حال نوشتن»", + "Enable big emoji in chat": "نمایش شکلک‌های بزرگ در گفتگوها را فعال کن", + "Space used:": "فضای مصرفی:", + "Indexed messages:": "پیام‌های ایندکس‌شده:", + "Send %(eventType)s events as you in this room": "رویدادهای %(eventType)s هنگامی که داخل این اتاق هستید ارسال شود", + "Indexed rooms:": "اتاق‌های ایندکس‌شده:", + "%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s از %(totalRooms)s", + "Navigation": "پیمایش", + "Calls": "تماس‌ها", + "Room List": "لیست اتاق‌ها", + "Remain on your screen while running": "بر روی صفحه خود باقی بمانید", + "Autocomplete": "تکمیل خودکار", + "Alt": "Alt", + "Alt Gr": "Alt Gr", + "Shift": "Shift", + "Remain on your screen when viewing another room, when running": "هنگام مشاهده اتاق دیگر، روی صفحه خود باشید", + "Ctrl": "Ctrl", + "Toggle Bold": "بولد‌کردن", + "Toggle Quote": "نقل‌قول کردن", + "Toggle Italics": "ایتالیک‌کردن", + "New line": "خط جدید", + "Navigate recent messages to edit": "پیام‌های اخیر را برای ویرایش پیمایش کنید", + "Jump to start/end of the composer": "به ابتدا/انتهای سازنده پرش کن", + "Navigate composer history": "پیمایش در تاریخچه‌ی سازنده", + "Cancel replying to a message": "پاسخ به پیام را لغو کن", + "Toggle microphone mute": "میکروفون را قطع کنید", + "Toggle video on/off": "ویدئو را وصل/قطع کنید", + "Scroll up/down in the timeline": "تایم‌لاین پیام‌ها را به سمت بالا/پایین پیمایش کنید", + "Dismiss read marker and jump to bottom": "نشانه‌ی خوانده‌شده را بیخیال شو و به انتها پرش کن", + "Jump to oldest unread message": "به قدیمی‌ترین پیام خوانده نشده پرش کن", + "Upload a file": "فایل بارگذاری کنید", + "Search (must be enabled)": "جستجو (باید فعال باشد)", + "Jump to room search": "به قسمت جستجوی اتاق پرش کن", + "Navigate up/down in the room list": "در لیست اتاق‌ها به بالا/پایین بروید", + "Select room from the room list": "از لیست اتاق‌ها انتخاب کنید", + "Collapse room list section": "قسمت لیست اتاق‌ها را جمع کن", + "Expand room list section": "قسمت لیست اتاق‌ها را بسط بده", + "Clear room list filter field": "پاک‌کردن قسمت پالایش‌های لیست اتاق‌ها", + "Previous/next unread room or DM": "اتاق یا گفتگوی خوانده‌نشده قبلی/بعدی", + "Previous/next room or DM": "اتاق یا گفتگوی قبلی/بعدی", + "Toggle the top left menu": "منوی بالا سمت چپ را تغییر دهید", + "Activate selected button": "دکمه انتخاب شده را فعال کنید", + "Toggle right panel": "پانل سمت راست را تغییر دهید", + "Go to Home View": "برو به مشاهده خانه", + "Key request sent.": "درخواست کلید ارسال شد.", + "If your other sessions do not have the key for this message you will not be able to decrypt them.": "اگر بقیه‌ی نشست‌های شما نیز کلید این پیام را نداشته باشند، امکان رمزگشایی و مشاهده‌ی آن برای شما وجود نخواهد داشت.", + "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "درخواست‌های به اشتراک‌گذاری کلید برای بقیه‌ی نشست‌های شما به صورت خودکار ارسال می‌شود. اگر این درخواست‌ها را بر روی سایر نشست‌هایتان رد کرده‌اید، اینجا کلیک کنید تا درخواست به اشتراک‌گذاری کلیدها برای این نشست مجدد ارسال شود.", + "Your key share request has been sent - please check your other sessions for key share requests.": "درخواست به اشتراک‌گذاری کلید ارسال شد - لطفا بقیه‌ی نشست‌های خود را برای درخواست به اشتراک‌گذاری کلید بررسی کنید.", + "This event could not be displayed": "امکان نمایش این رخداد وجود ندارد", + "Edit message": "ویرایش پیام", + "Send as message": "ارسال به عنوان پیام", + "Show avatars in user and room mentions": "نمایش نمایه‌ها هنگام اشاره‌کردن به فرد یا اتاق", + "Jump to the bottom of the timeline when you send a message": "زمانی که پیام ارسال می‌کنید، به صورت خودکار به آخرین پیام پرش کن", + "Show line numbers in code blocks": "شماره‌ی خط‌ها را در بلاک‌های کد نمایش بده", + "Expand code blocks by default": "بلاک‌های کد را به صورت پیش‌فرض کامل نشان بده", + "Enable automatic language detection for syntax highlighting": "فعال‌سازی تشخیص خودکار زبان برای پررنگ‌سازی نحوی", + "Show timestamps in 12 hour format (e.g. 2:30pm)": "زمان را با فرمت ۱۲ ساعته نشان بده (مثلا ۲:۳۰ بعدازظهر)", + "Show read receipts sent by other users": "نشانه‌ی خوانده‌شدن پیام توسط دیگران را نشان بده", + "Show display name changes": "تغییرات نام کاربران را نشان بده", + "Show avatar changes": "تغییرات نمایه را نشان بده", + "Show join/leave messages (invites/kicks/bans unaffected)": "پیام‌های پیوستن/ترک‌کردن را نشان بده (دعوت‌ها، اخراج‌ها و تحریم‌ها بدون اثر خواهند ماند)", + "Show a placeholder for removed messages": "جای خالی پیام‌های پاک‌شده را نشان بده", + "Use a more compact ‘Modern’ layout": "از چیدمان فشرده‌تر و مدرن استفاده کن", + "Show stickers button": "نمایش دکمه‌ی استکیر", + "Enable Emoji suggestions while typing": "پیشنهاد دادن شکلک‌ها هنگام تایپ‌کردن را فعال کن", + "Use custom size": "از اندازه‌ی دلخواه استفاده کنید", + "Font size": "اندازه فونت", + "Show info about bridges in room settings": "اطلاعات پل‌های ارتباطی را در تنظیمات اتاق نمایش بده", + "Enable advanced debugging for the room list": "فعال‌سازی قابلیت رفع‌مشکل پیشرفته برای لیست اتاق‌ها", + "Offline encrypted messaging using dehydrated devices": "ارسال پیام رمزشده به شکل آفلاین با استفاده از دستگاه‌های خاص", + "Show message previews for reactions in all rooms": "پیش‌نمایش احساسات و شکلک‌ها را برای همه اتاق‌ها نشان بده", + "Show message previews for reactions in DMs": "پیش‌نمایش احساسات و شکلک‌ها را برای گفتگوهای خصوصی نشان بده", + "Support adding custom themes": "پشتیبانی از افزودن پوسته‌های ظاهری دلخواه", + "Try out new ways to ignore people (experimental)": "روش‌های جدید برای نادیده‌گرفتن افراد را امتحان کنید (آزمایشی)", + "Multiple integration managers": "چند مدیر پکپارچه‌سازی", + "Render simple counters in room header": "شمارنده‌های ساده‌ای در سرآیند اتاق نمایش بده", + "Group & filter rooms by custom tags (refresh to apply changes)": "دسته‌بندی و پالایش اتاق‌ها با استفاده از تگ‌های دلخواه (برای اعمال تغییرات صفحه را رفرش کنید)", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "تکرارهایی مانند \"abcabcabc\" تنها مقداری سخت‌تر از \"abc\" قابل حدس‌زدن هستند", + "Add another word or two. Uncommon words are better.": "یک یا دو کلمه دیگر اضافه کنید. کلمات غیرمعمول بهتر هستند.", + "Reversed words aren't much harder to guess": "حدس زدن کلمات معکوس خیلی سخت تر نیست", + "All-uppercase is almost as easy to guess as all-lowercase": "اگر همه‌ی موارد حروف بزرگ باشند، سختی حدس‌زدن آن‌ها با حالتی که فقط از حروف کوچک استفاده شود، تفاوتی نمی‌کند", + "Capitalization doesn't help very much": "استفاده از حروه بزرگ کمک چندانی نمی‌کند", + "Avoid dates and years that are associated with you": "از تاریخ و سالهایی که با شما در ارتباط هستند خودداری کنید", + "Avoid years that are associated with you": "از سالهایی که با شما در ارتباط هستند دوری کنید", + "Avoid recent years": "از سالهای اخیر خودداری کنید", + "Avoid sequences": "از موارد پشت سر هم اجتناب کنید", + "Avoid repeated words and characters": "از تکرار کلمات و کاراکترها خودداری نمائید", + "Use a longer keyboard pattern with more turns": "از الگوی طولانی‌ و پیچیده‌تر استفاده نمائید", + "No need for symbols, digits, or uppercase letters": "نیازی به علامت ، عدد یا حروف بزرگ نیست", + "Use a few words, avoid common phrases": "از چند کلمه استفاده کنید ، از عبارات معمول خودداری نمائید", + "Unknown server error": "خطای ناشناخته از سمت سرور", + "The user's homeserver does not support the version of the room.": "سرور کاربر از نسخه‌ی اتاق پشتیبانی نمی‌کند.", + "The user must be unbanned before they can be invited.": "برای اینکه کاربر بتواند دعوت شود، ابتدا باید رفع تحریم شود.", + "User %(user_id)s may or may not exist": "کاربر %(user_id)s ممکن است وجود داشته باشد یا نداشته باشد", + "User %(user_id)s does not exist": "کاربر %(user_id)s وجود ندارد", + "User %(userId)s is already in the room": "کاربر %(userId)s هم‌اکنون عضو این اتاق است", + "You do not have permission to invite people to this room.": "شما دسترسی دعوت افراد به این اتاق را ندارید.", + "Unrecognised address": "آدرس ناشناخته", + "Error leaving room": "خطا در ترک اتاق", + "This room is used for important messages from the Homeserver, so you cannot leave it.": "این اتاق برای نمایش پیام‌های مهم سرور استفاده می‌شود، لذا امکان ترک آن وجود ندارد.", + "Can't leave Server Notices room": "نمی توان از اتاق اعلامیه های سرور خارج شد", + "Unexpected server error trying to leave the room": "خطای غیرمنتظره روی سرور هنگام تلاش برای ترک اتاق", + "Authentication check failed: incorrect password?": "احراز هویت موفقیت‌آمیز نبود: گذرواژه نادرست است؟", + "Not a valid %(brand)s keyfile": "فایل کلید %(brand)s معتبر نیست", + "Your browser does not support the required cryptography extensions": "مرورگر شما از افزونه‌های رمزنگاری مورد نیاز پشتیبانی نمی‌کند", + "%(name)s (%(userId)s)": "%(name)s (%(userId)s)", + "%(num)s days from now": "%(num)s روز دیگر", + "about a day from now": "حدود یک روز دیگر", + "%(num)s hours from now": "%(num)s ساعت دیگر", + "about an hour from now": "حدود یک ساعت دیگر", + "%(num)s minutes from now": "%(num)s دقیقه دیگر", + "about a minute from now": "حدود یک دقیقه دیگر", + "a few seconds from now": "چند ثانیه دیگر", + "%(num)s days ago": "%(num)s روز قبل", + "about a day ago": "حدود یک روز قبل", + "%(num)s hours ago": "%(num)s ساعت قبل", + "about an hour ago": "حدود یک ساعت قبل", + "about a minute ago": "حدود یک دقیقه قبل", + "%(num)s minutes ago": "%(num)s دقیقه قبل", + "a few seconds ago": "چند ثانیه قبل", + "%(items)s and %(lastItem)s": "%(items)s و %(lastItem)s", + "%(items)s and %(count)s others|one": "%(items)s و یکی دیگر", + "%(items)s and %(count)s others|other": "%(items)s و %(count)s دیگر", + "Unable to connect to Homeserver. Retrying...": "اتصال به سرور میسر نشد. در حال تلاش دوباره...", + "Please contact your service administrator to continue using the service.": "لطفا برای ادامه‌ی استفاده از سرویس، با مدیر سرویس خود تماس بگیرید.", + "This homeserver has exceeded one of its resource limits.": "این سرور از یکی از محدودیت های منابع خود فراتر رفته است.", + "This homeserver has been blocked by its administrator.": "این سرور توسط مدیر آن مسدود شده‌است.", + "This homeserver has hit its Monthly Active User limit.": "این سرور به محدودیت بیشینه‌ی تعداد کاربران فعال ماهانه رسیده‌است.", + "Unexpected error resolving identity server configuration": "خطای غیر منتظره‌ای در حین بررسی پیکربندی سرور هویت‌سنجی رخ داد", + "Unexpected error resolving homeserver configuration": "خطای غیر منتظره‌ای در حین بررسی پیکربندی سرور رخ داد", + "No homeserver URL provided": "هیچ آدرس سروری وارد نشده‌است", + "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.": "شما می توانید وارد شوید ، اما برخی از ویژگی ها تا زمانی که سرور هویت‌سنجی آنلاین نشود ، در دسترس نخواهند بود. اگر مدام این هشدار را می بینید ، پیکربندی خود را بررسی کنید یا با مدیر سرور تماس بگیرید.", + "You can register, 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.": "شما می‌توانید حساب کاربری بسازید، اما برخی قابلیت‌ها تا زمان اتصال مجدد به سرور هویت‌سنجی در دسترس نخواهند بود. اگر شما مدام این هشدار را مشاهده می‌کنید، پیکربندی خود را بررسی کرده و یا با مدیر سرور تماس بگیرید.", + "Cannot reach identity server": "دسترسی به سرور هویت‌سنجی امکان پذیر نیست", + "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "از مدیر %(brand)s خود بخواهید تا پیکربندی شما را از جهت ورودی‌های نادرست یا تکراری بررسی کند.", + "Kick, ban, or invite people to this room, and make you leave": "کاربران را به این اتاق دعوت کنید، آن‌ها اخراج و یا تحریم کرده، و حتی به آن‌ها اجازه دهید شما را از اتاق بیرون بیاندازند", + "Kick, ban, or invite people to your active room, and make you leave": "کاربران را به اتاق فعال خود دعوت کنید، آن‌ها اخراج و یا تحریم کرده، و حتی به آن‌ها اجازه دهید شما را از آن بیرون بیاندازند", + "End": "End", + "Enter": "Enter", + "Page Down": "Page Down", + "Page Up": "Page Up", + "Cancel autocomplete": "غیرفعال کردن تکمیل‌کننده خودکار", + "Users": "کاربران", + "Clear personal data": "پاک‌کردن داده‌های شخصی", + "You're signed out": "شما خارج شدید", + "Sign in and regain access to your account.": "وارد شوید و به حساب کاربری خود دسترسی داشته باشید.", + "Forgotten your password?": "گذرواژه‌ی خود را فراموش کردید؟", + "Enter your password to sign in and regain access to your account.": "جهت ورود مجدد به حساب کاربری و دسترسی به منوی کاربری، گذرواژه‌ی خود را وارد نمائید.", + "Regain access to your account and recover encryption keys stored in this session. Without them, you won’t be able to read all of your secure messages in any session.": "مجددا وارد حساب کاربری خود شده و کلیدهای رمزنگاری ذخیره‌شده در این نشست را بازیابی کنید. بدون آن‌ها، قادر به خواندن پیام‌های رمزشده بر روی هیچ نشست دیگری نخواهید بود.", + "Failed to re-authenticate": "احراز هویت مجدد موفیت‌آمیز نبود", + "Incorrect password": "گذرواژه صحیح نیست", + "Without verifying, you won’t have access to all your messages and may appear as untrusted to others.": "بدون تائید نشست، به همه‌ی پیام‌هایتان دسترسی نداشته و ممکن است بقیه به شما اعتماد نکنند.", + "Your new session is now verified. Other users will see it as trusted.": "نشست جدید شما تائید شد. سایر کاربران آن را به عنوان یک نشست قابل اطمینان مشاهده می‌کنند.", + "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "نشست جدید شما تائید شد. اکنون به پیام‌های رمزشده‌ی شما دسترسی داشته و بقیه کاربران، آن را به عنوان یک نشست قابل اعتماد مشاهده می‌کنند.", + "Verify your identity to access encrypted messages and prove your identity to others.": "با تائید هویت خود به پیام‌های رمزشده دسترسی یافته و هویت خود را به دیگران ثابت می‌کنید.", + "Use Security Key": "استفاده از کلید امنیتی", + "Use Security Key or Phrase": "استفاده از کلید یا عبارت امنیتی", + "Decide where your account is hosted": "حساب کاربری شما بر روی کجا ساخته شود", + "Host account on": "ساختن حساب کاربری بر روی", + "Create account": "ساختن حساب کاربری", + "Registration Successful": "ثبت‌نام موفقیت‌آمیز بود", + "Already have an account? Sign in here": "حساب کاربری دارید؟ وارد شوید", + "Registration has been disabled on this homeserver.": "ثبت‌نام بر روی این سرور غیرفعال شده‌است.", + "New? Create account": "کاربر جدید هستید؟ حساب کاربری بسازید", + "Signing In...": "در حال ورود...", + "Syncing...": "در حال همگام‌سازی...", + "Set a new password": "تنظیم گذرواژه‌ی جدید", + "Return to login screen": "بازگشت به صفحه‌ی ورود", + "Your password has been reset.": "گذرواژه‌ی شما با موفقیت تغییر کرد.", + "Sign in instead": "به جای آن وارد شوید", + "Send Reset Email": "ارسال ایمیل تغییر", + "New Password": "گذرواژه جدید", + "New passwords must match each other.": "گذرواژه‌ی جدید باید مطابقت داشته باشند.", + "Please choose a strong password": "لطفا یک گذرواژه‌ی قوی انتخاب کنید", + "Session verified": "نشست تائید شد", + "Verify this login": "این ورود را تائید نمائید", + "Original event source": "منبع اصلی رخداد", + "Decrypted event source": "رمزگشایی منبع رخداد", + "Could not load user profile": "امکان نمایش پروفایل کاربر میسر نیست", + "Community and user menu": "فضای کاری و منوی کاربر", + "User menu": "منوی کاربر", + "Switch theme": "تعویض پوسته", + "Switch to dark mode": "انتخاب حالت تاریک", + "Switch to light mode": "انتخاب حالت روشن", + "User settings": "تنظیمات حساب کاربری", + "Community settings": "تنظیمات فضای کاری", + "All settings": "همه تنظیمات", + "Security & privacy": "امنیت و محرمانگی", + "Notification settings": "تنظیمات اعلان", + "Inviting...": "در حال دعوت...", + "Creating rooms...": "در حال ساختن اتاق...", + "Skip for now": "فعلا بیخیال", + "Room name": "نام اتاق", + "Support": "پشتیبانی", + "Random": "تصادفی", + "Welcome to ": "به خوش‌آمدید", + " invites you": " شما را دعوت کرد", + "Private space": "محیط خصوصی", + "Public space": "محیط عمومی", + "Spaces are a beta feature.": "فضای کاری یک قابلیت بتا است.", + "Create room": "ساختن اتاق", + "No results found": "نتیجه‌ای یافت نشد", + "Removing...": "در حال حذف...", + "You don't have permission": "شما دسترسی ندارید", + "Drop file here to upload": "برای بارگذاری فایل آن را کشیده و در این‌جا رها کنید", + "Failed to reject invite": "رد دعوتنامه با شکست همراه شد", + "Room": "اتاق", + "No more results": "نتایج بیشتری یافن نشد", + "Search failed": "جستجو موفیت‌آمیز نبود", + "You seem to be in a call, are you sure you want to quit?": "به نظر می‌رسد شما در میانه‌ی یک تماس هستید، آیا از خروج اطمینان دارید؟", + "You seem to be uploading files, are you sure you want to quit?": "به نظر می‌رسد شما در حال باگذاری فایل هستید، آیا از خروج اطمینان دارید؟", + "Connectivity to the server has been lost.": "اتصال به سرور از دست رفت.", + "Sending": "در حال ارسال", + "Retry all": "همه را دوباره امتحان کنید", + "Delete all": "حذف همه", + "Filter rooms and people": "پالایش اتاق‌ها و کاربران", + "Clear filter": "حذف پالایش", + "Filter all spaces": "پالایش همه محیط‌ها", + "Filter": "پالایش", + "Explore rooms in %(communityName)s": "جستجوی اتاق در فضای کاری %(communityName)s", + "Find a room… (e.g. %(exampleRoom)s)": "یافتن اتاق (برای مثال %(exampleRoom)s)", + "View": "مشاهده", + "Preview": "پیش‌نمایش", + "delete the address.": "آدرس را حذف کنید.", + "The homeserver may be unavailable or overloaded.": "احتمالا سرور در دسترس نباشد و یا بار زیادی روی آن قرار گرفته باشد.", + "You have no visible notifications.": "اعلان قابل مشاهده‌ای ندارید.", + "Communities are changing to Spaces": "فضای کاری به محیط تغییر پیدا کرد", + "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "برای دسته‌بندی اتاق‌ها و کاربران، فضای کاری بسازید!", + "Create a new community": "ساختن فضای کاری جدید", + "Your Communities": "فضاهای کاری شما", + "Logout": "خروج", + "Verification requested": "درخواست تائید", + "Old cryptography data detected": "داده‌های رمزنگاری قدیمی شناسایی شد", + "Review terms and conditions": "مرور شرایط و ضوابط", + "Terms and Conditions": "شرایط و ضوابط", + "Signed Out": "از حساب کاربری خارج شدید", + "Are you sure you want to leave the space '%(spaceName)s'?": "آیا از ترک فضای '%(spaceName)s' اطمینان دارید؟", + "This room is not public. You will not be able to rejoin without an invite.": "این اتاق عمومی نیست. پیوستن مجدد بدون دعوتنامه امکان‌پذیر نخواهد بود.", + "This space is not public. You will not be able to rejoin without an invite.": "این فضا عمومی نیست. امکان پیوستن مجدد بدون دعوتنامه امکان‌پذیر نخواهد بود.", + "You are the only person here. If you leave, no one will be able to join in the future, including you.": "شما در این‌جا تنها هستید. اگر اینجا را ترک کنید، دیگر هیچ‌کس حتی خودتان امکان پیوستن مجدد را نخواهید داشت.", + "You do not have permission to create rooms in this community.": "شما دسترسی کافی برای ساختن اتاق در این فضای کاری را ندارید.", + "Cannot create rooms in this community": "امکان ساختن اتاق در این اتاق میسر نیست", + "Failed to reject invitation": "رد دعوتنامه موفقیت‌آمیز نبود", + "Create a Group Chat": "ساختن یک گروه", + "Explore Public Rooms": "جستجوی اتاق‌های عمومی", + "Send a Direct Message": "ارسال یک پیام مستقیم", + "Liberate your communication": "ارتباطات خود را توسعه دهید", + "Welcome to %(appName)s": "به %(appName)s خوش‌آمدید", + "Now, let's help you get started": "همین الان شروع کنید", + "Welcome %(name)s": "%(name)s خوش‌آمدید", + "Add a photo so people know it's you.": "برای اینکه بقیه شما را بشناسند، یک تصویر اضافه کنید.", + "Great, that'll help people know it's you": "احسنت، با این کار شما به سایر افراد کمک می‌کنید که شما را بشناسند", + "Reset": "بازراه‌اندازی", + "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.": "سرور شما امضاء متقابل را پشتیبانی نمی‌کند.", + "Passwords don't match": "گذرواژه‌ها مطابقت ندارند", + "Do you want to set an email address?": "آیا تمایل به تنظیم یک ادرس ایمیل دارید؟", + "Export E2E room keys": "استخراج (Export) کلیدهای رمزنگاری اتاق‌ها", + "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "در حال حاضر تغییر گذرواژه منجر به بازنشانی کلید‌های رمزنگاری سرتاسر برای همه‌ی نشست‌ها می‌شود، در نتیجه تاریخچه‌ی پیام‌های رمزشده دیگر قابل مشاهده و خواندن نیستند. لذا حتما ابتدا کلید اتاق‌های خود را Export کرده و بعد از تغییر گذرواژه، مجددا آن‌ها را Import نمائید. این فرآیند در آینده بهبود خواهد یافت.", + "Warning!": "هشدار!", + "Passwords can't be empty": "گذرواژه‌ها نمی‌توانند خالی باشند", + "New passwords don't match": "گذرواژه‌های جدید مطابقت ندارند", + "No display name": "هیچ نامی برای نمایش وجود ندارد", + "Upload new:": "بارگذاری جدید:", + "Channel: ": "کانال:", + "Workspace: ": "فضای کار:", + "This bridge is managed by .": "این پل ارتباطی توسط مدیریت می‌شود.", + "This bridge was provisioned by .": "این پل ارتباطی توسط ارائه شده‌است.", + "Space options": "گزینه‌های انتخابی محیط", + "Manage & explore rooms": "مدیریت و جستجوی اتاق‌ها", + "Add existing room": "اضافه‌کردن اتاق موجود", + "Create": "ایجاد‌کردن", + "Create new room": "ایجاد اتاق جدید", + "Leave space": "ترک محیط", + "Settings": "تنظیمات", + "Invite with email or username": "دعوت با ایمیل یا نام‌کاربری", + "Invite people": "دعوت کاربران", + "Share invite link": "به اشتراک‌گذاری لینک دعوت", + "Failed to copy": "خطا در گرفتن رونوشت", + "Copied!": "رونوشت گرفته شد!", + "Click to copy": "برای گرفتن رونوشت کلیک کنید", + "All rooms": "همه اتاق‌ها", + "Collapse space panel": "جمع‌کردن پنل محیط", + "Expand space panel": "بسط‌دادن پنل محیط", + "Creating...": "در حال ساختن...", + "You can change these anytime.": "شما می‌توانید این را هر زمان که خواستید، تغییر دهید.", + "Add some details to help people recognise it.": "برای کمک به کاربران جهت شناخت محیط، مقداری جزئیات اضافه کنید.", + "Your private space": "محیط خصوصی شما", + "Your public space": "محیط عمومی شما", + "This homeserver does not support communities": "سرور شما از قابلیت فضای کاری پشتیبانی نمی‌کند", + "Upload avatar": "بارگذاری نمایه", + "Long Description (HTML)": "توضیح طولانی (امکان استفاده از تگ‌های HTML نیز میسر است)", + "Everyone": "همه", + "Who can join this community?": "چه کسانی بتوانند به این فضای کاری بپیوندند؟", + "You are a member of this community": "شما یک عضو این فضای کاری هستید", + "You are an administrator of this community": "شما یکی از مدیران این فضای کاری هستید", + "Leave this community": "ترک این فضای کاری", + "Join this community": "پیوستن به این فضای کاری", + "Featured Users:": "کاربران ویژه:", + "Featured Rooms:": "اتاق‌های ویژه:", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "این اتاق‌ها به اعضای فضای کاری در صفحه‌ی این فضا نمایش داده می‌شود. اعضا‌ی فضا می‌توانند با کلیک بر روی اتاق‌ها به آن‌ها بپیوندند.", + "Community Settings": "تنظیمات فضای کاری", + "Unable to leave community": "ترک فضای کاری ممکن نیست", + "Leave Community": "ترک فضای کاری", + "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "شما مدیر این فضای کاری هستید. امکان پیوستن مجدد شما به این فضای کاری بدون دعوت یک مدیر دیگر در این فضا امکان‌پذیر نخواهد بود.", + "Unable to join community": "پیوستن به فضای کاری ممکن نیست", + "Unable to accept invite": "تائید دعوت ممکن نیست", + "Failed to update community": "به‌روزرسانی فضای کاری با موفقیت همراه نبود", + "Failed to upload image": "بارگذاری تصویر با موفقیت همراه نبود", + "Add a User": "افزودن کاربر", + "Who would you like to add to this summary?": "تمایل دارید کدام کاربران را به این خلاصه اضافه کنید؟", + "Add users to the community summary": "افزودن کاربران به خلاصه‌ی فضای کاری", + "Add a Room": "افزودن اتاق", + "Add to summary": "افزودن به خلاصه", + "Which rooms would you like to add to this summary?": "تمایل دارید چه اتاق‌هایی را به این خلاصه اضافه کنید؟", + "Add rooms to the community summary": "افزودن اتاق به خلاصه‌ی فضای کاری", + "Create community": "ساختن فضای کاری", + "Communities": "فضاهای کاری", + "Attach files from chat or just drag and drop them anywhere in a room.": "فایل‌ها را از محیط چت ضمیمه کرده و یا آن‌ها را کشیده و در محیط اتاق رها کنید.", + "No files visible in this room": "هیچ فایلی در این اتاق قابل مشاهده نیست", + "You must join the room to see its files": "برای دیدن فایل‌های یک اتاق، باید عضو آن باشید", + "Couldn't load page": "نمایش صفحه امکان‌پذیر نبود", + "Sign in with SSO": "ورود با استفاده از احراز هویت یکپارچه", + "Add an email to be able to reset your password.": "برای داشتن امکان تغییر گذرواژه در صورت فراموش‌کردن آن، لطفا یک آدرس ایمیل وارد نمائید.", + "Register": "ایجاد حساب کاربری", + "Sign in": "ورود به حساب کاربری", + "Sign in with": "نحوه ورود", + "Forgot password?": "فراموشی گذرواژه", + "Phone": "شماره تلفن", + "Username": "نام کاربری", + "That phone number doesn't look quite right, please check and try again": "به نظر شماره تلفن صحیح نمی‌باشد، لطفا بررسی کرده و مجددا تلاش فرمائید", + "Enter phone number": "شماره تلفن را وارد کنید", + "Enter email address": "آدرس ایمیل را وارد کنید", + "Enter username": "نام کاربری را وارد کنید", + "Keep going...": "ادامه دهید...", + "Nice, strong password!": "احسنت، گذرواژه‌ی انتخابی قوی است!", + "Enter password": "گذرواژه را وارد کنید", + "Start authentication": "آغاز فرآیند احراز هویت", + "Something went wrong in confirming your identity. Cancel and try again.": "تائید هویت شما با مشکل مواجه شد. لطفا فرآیند را لغو کرده و مجددا اقدام نمائید.", + "Submit": "ارسال", + "Code": "کد", + "Password": "گذرواژه", + "User Status": "وضعیت کاربر", + "This room is public": "این اتاق عمومی است", + "Avatar": "نمایه", + "Join the beta": "اضافه‌شدن به نسخه‌ی بتا", + "Leave the beta": "ترک نسخه‌ی بتا", + "Beta": "بتا", + "Tap for more info": "برای اطلاعات بیشتر کلیک کنید", + "Spaces is a beta feature": "ساختن فضا یک قابلیت بتا است", + "Move right": "به سمت راست ببر", + "Move left": "به سمت چپ ببر", + "Revoke permissions": "دسترسی‌ها را لغو کنید", + "Remove for everyone": "حذف برای همه", + "Delete widget": "حذف ویجت", + "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "حذف یک ویجت، باعث حذف‌شدن آن برای همه‌ی کاربران این اتاق می‌شود. آیا از حذف این ویجت اطمینان دارید؟", + "Delete Widget": "حذف ویجت", + "Take a picture": "عکس بگیرید", + "Start audio stream": "آغاز جریان صدا", + "Failed to start livestream": "آغاز livestream با شکست همراه بود", + "Unable to start audio streaming.": "شروع پخش جریان صدا امکان‌پذیر نیست.", + "View Community": "مشاهده‌ی فضای کاری", + "Set a new status...": "تنظیم وضعیت جدید...", + "Set status": "تنظیم وضعیت", + "Update status": "به‌روزرسانی وضعیت", + "Clear status": "پاک‌کردن وضعیت", + "Report Content": "گزارش محتوا", + "Share Message": "به اشتراک‌گذاری پیام", + "Share Permalink": "اشتراک لینک پیام", + "Pin Message": "پین‌کردن پیام", + "Unable to reject invite": "رد کردن دعوت امکان‌پذیر نیست", + "Reject invitation": "ردکردن دعوت", + "Hold": "نگه‌داشتن", + "Resume": "ادامه", + "Appearance": "شکل و ظاهر", + "Share": "اشتراک‌گذاری", + "Revoke": "برگرداندن", + "Complete": "تکمیل", + "Verify the link in your inbox": "لینک موجود در صندوق دریافت خود را تائید کنید", + "Unable to verify email address.": "تائید آدرس ایمیل ممکن نیست.", + "Click the link in the email you received to verify and then click continue again.": "برای تائید ادرس ایمیل، بر روی لینکی که برای شما ایمیل شده‌است کلیک کرده و مجددا بر روی ادامه کلیک کنید.", + "Your email address hasn't been verified yet": "آدرس ایمیل شما هنوز تائید نشده‌است", + "Unable to share email address": "به اشتراک‌گذاری آدرس ایمیل ممکن نیست", + "Unable to revoke sharing for email address": "لغو اشتراک گذاری برای آدرس ایمیل ممکن نیست", + "Who can access this room?": "چه افرادی بتوانند به این اتاق دسترسی داشته باشند؟", + "Encrypted": "رمزشده", + "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)": "فقط اعضاء (از زمانی که این تنظیم اعمال می‌شود)", + "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "تغییر تنظیمات اینکه چه کاربرانی سابقه‌ی پیام‌ها را مشاهده کنند، تنها برای پیام‌های آتی اتاق اعمال میشود. پیام‌های قبلی متناسب با تنظیمات گذشته نمایش داده می‌شوند.", + "Only people who have been invited": "تنها کاربرانی که دعوت شده‌اند", + "Guests cannot join this room even if explicitly invited.": "کاربران مهمان حتی در صورتی که صراحتا به گروه دعوت شوند، امکان پیوستن به اتاق را نخواهند داشت.", + "Enable encryption?": "رمزنگاری را فعال می‌کنید؟", + "Select the roles required to change various parts of the room": "برای تغییر هر یک از بخش‌های اتاق، خداقل نقش مورد نیاز را انتخاب کنید", + "Permissions": "دسترسی‌ها", + "Roles & Permissions": "نقش‌ها و دسترسی‌ها", + "Muted Users": "کاربران بی‌صدا", + "Privileged Users": "کاربران ممتاز", + "No users have specific privileges in this room": "هیچ کاربری در این اتاق دسترسی خاصی ندارد", + "Notify everyone": "اعلان عمومی به همه", + "Remove messages sent by others": "پاک‌کردن پیام‌های دیگران", + "Ban users": "تحریم کاربران", + "Kick users": "اخراج کاربران", + "Change settings": "تغییر تنظیمات", + "Invite users": "دعوت کاربران", + "Send messages": "ارسال پیام‌ها", + "Default role": "نقش پیش‌فرض", + "An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "هنگام تغییر طرح دسترسی کاربر خطایی رخ داد. از داشتن سطح دسترسی کافی برای این کار اطمینان حاصل کرده و مجددا اقدام نمائید.", + "Error changing power level": "تغییر سطح دسترسی با خطا همراه بود", + "Unban": "رفع تحریم", + "Modify widgets": "تغییر ویجت‌ها", + "Enable room encryption": "فعال‌کردن رمزنگاری برای اتاق", + "Upgrade the room": "ارتقاء نسخه اتاق", + "Change topic": "تغییر عنوان", + "Change permissions": "تغییر دسترسی‌ها", + "Change history visibility": "تغییر مشاهده‌پذیری تاریخچه", + "Change main address for the room": "تغییر آدرس اصلی اتاق", + "Change room name": "تغییر نام اتاق", + "Change room avatar": "تغییر نمایه اتاق", + "Browse": "جستجو", + "Set a new custom sound": "تنظیم صدای دلخواه جدید", + "Notification sound": "صدای اعلان", + "Sounds": "صداها", + "Uploaded sound": "صدای بارگذاری‌شده", + "Room Addresses": "آدرس‌های اتاق", + "URL Previews": "پیش‌نمایش URL", + "Bridges": "پل‌ها", + "Open Devtools": "بازکردن ابزار توسعه", + "Developer options": "گزینه‌های توسعه‌دهنده", + "Room version:": "نسخه‌ی اتاق:", + "Room version": "نسخه‌ی اتاق", + "Internal room ID:": "شناسه‌ی داخلی اتاق:", + "Room information": "اطلاعات اتاق", + "this room": "این اتاق", + "Upgrade this room to the recommended room version": "نسخه‌ی این اتاق را به نسخه‌ی توصیه‌شده ارتقاء دهید", + "This room is not accessible by remote Matrix servers": "این اتاق توسط سرورهای ماتریکس در دسترس نیست", + "Voice & Video": "صدا و تصویر", + "Audio Output": "خروجی صدا", + "No Audio Outputs detected": "هیچ خروجی صدایی یافت نشد", + "Request media permissions": "درخواست دسترسی به رسانه", + "Missing media permissions, click the button below to request.": "دسترسی به رسانه از دست رفت، برای درخواست مجدد بر روی دکمه‌ی زیر کلیک نمائید.", + "A session's public name is visible to people you communicate with": "نام عمومی یک نشست برای افرادی که با آن‌ها ارتباط برقرار کرده‌اید، قابل مشاهده است", + "Where you’re logged in": "کجا وارد حساب کاربری خود شده‌اید", + "Learn more about how we use analytics.": "در مورد نحوه‌ی استفاده‌ی ما از داده‌ها بیشتر بدانید.", + "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "به دلیل اهمیت حریم خصوصی، ما هیچ‌گونه‌ داده‌ی شخصی‌ و قابل ردگیری را از شما جمع‌آوری نمی‌کنیم.", + "Privacy": "حریم خصوصی", + "Cross-signing": "امضاء متقابل", + "Message search": "جستجوی پیام‌ها", + "Secure Backup": "پشتیبان‌گیری امن", + "You have no ignored users.": "شما هیچ کاربری را نادیده نگرفته‌اید.", + "Session key:": "کلید نشست:", + "Session ID:": "شناسه‌ی نشست:", + "Import E2E room keys": "واردکردن کلیدهای رمزنگاری اتاق‌ها", + "": "<پشتیبانی نمی‌شود>", + "Unignore": "لغو نادیده‌گرفتن", + "Autocomplete delay (ms)": "تاخیر تکمیل خودکار به میلی ثانیه", + "Timeline": "سیر زمان گفتگو‌ها", + "Room list": "لیست اتاق‌ها", + "Preferences": "ترجیحات", + "Subscribed lists": "لیست‌هایی که در آن‌ها ثبت‌نام کرده‌اید", + "Ignore": "نادیده‌گرفتن", + "Server or user ID to ignore": "شناسه‌ی سرور یا کاربر مورد نظر برای نادیده‌گرفتن", + "Personal ban list": "لیست تحریم شخصی", + "Ignored users": "کاربران نادیده‌گرفته‌شده", + "View rules": "مشاهده قوانین", + "Unsubscribe": "لغو اشتراک", + "You are not subscribed to any lists": "شما در هیچ لیستی ثبت‌نام نکرده‌اید", + "You have not ignored anyone.": "شما هیچ‌کس را نادیده نگرفته‌اید.", + "User rules": "قوانین کاربر", + "Server rules": "قوانین سرور", + "None": "هیچ‌کدام", + "Please try again or view your console for hints.": "لطفا مجددا اقدام کرده و برای کسب اطلاعات بیشتر کنسول مرورگر خود را مشاهده نمائید.", + "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.": "مشکلی پیش آمد. لطفا مجددا تلاش کرده و در صورت نیاز، کنسول مرورگر خود را برای کسب اطلاعات بیشتر مشاهده نمائید.", + "Error adding ignored user/server": "افزودن کاربر/سرور به لیست نادیده‌گرفته‌ها با خطا همراه بود", + "Ignored/Blocked": "نادیده گرفته‌شده/بلاک‌شده", + "Labs": "قابلیت‌های بتا", + "Clear cache and reload": "پاک‌کردن حافظه‌ی کش و راه‌اندازی مجدد", + "Copy": "رونوشت", + "Your access token gives full access to your account. Do not share it with anyone.": "توکن دسترسی شما، دسترسی کامل به حساب کاربری شما را میسر می‌سازد. لطفا آن را در اختیار فرد دیگری قرار ندهید.", + "Access Token": "توکن دسترسی", + "Identity Server is": "سرور هویت‌سنجی شما عبارت است از", + "Homeserver is": "سرور ما عبارت است از", + "olm version:": "نسخه‌ی olm:", + "Versions": "نسخه‌ها", + "Keyboard Shortcuts": "کلیدهای میانبر", + "FAQ": "سوالات پرتکرار", + "Help & About": "کمک و درباره‌ی‌ ما", + "Submit debug logs": "ارسال لاگ مشکل", + "Bug reporting": "گزارش مشکل", + "Credits": "اعتبارها", + "Legal": "قانونی", + "General": "عمومی", + "Discovery": "کاوش", + "Deactivate account": "غیرفعال‌کردن حساب کاربری", + "Deactivating your account is a permanent action - be careful!": "غیرفعال‌سازی حساب کاربری یک عمل دائمی و غیرقابل بازگشت است - لطفا مراقب باشید!", + "Account management": "مدیریت حساب کاربری", + "You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "شما می‌توانید هر زمان که خواستید، در قسمت تنظیمات و یا با کلیک بر روی علامت بتا از محیط بتا خارج شوید.", + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "اگر ترک کنید، %(brand)s بعد از غیرفعال کردن قابلیت محیط بازراه‌اندازی خواهد شد. قابلیت‌های فضای کاری و تگ‌های دلخواه مجددا قابل مشاهده خواهند بود.", + "Custom user status messages": "پیام‌های وضعیت کاربر دلخواه", + "Message Pinning": "پین کردن پیام", + "New spinner design": "طرح اسپینر جدید", + "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "نسخه‌ی ۲ فضای کاری. نیاز به سرور سازگار دارد. به شدت ازمایشی و ناپایدار است - با احتباط استفاده کنید.", + "Render LaTeX maths in messages": "نمایش لاتکس ریاضیات در پیام‌ها", + "Send and receive voice messages": "ارسال و دریافت پیام‌های صوتی", + "Show options to enable 'Do not disturb' mode": "گزینه‌ها را برای فعال‌کردن حالت 'مزاحم نشوید' نشان بده", + "Your feedback will help make spaces better. The more detail you can go into, the better.": "بازخورد شما به بهبود قابلیت محیط کمک خواهد کرد. هر چقدر وارد جزئیات بیشتری شوید، بهتر خواهد بود.", + "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "نسخه‌ی بتا برای وب، دسکتاپ و اندروید در دسترس است. بعضی از قابلیت‌ها ممکن است بر روی سرور شما در دسترس نباشند.", + "%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "%(brand)s با فعال‌شدن قابلیت محیط‌ها بازراه‌اندازی خواهد شد. فضای کاری و تگ‌های دلخواه ناپدید خواهند شد.", + "Beta available for web, desktop and Android. Thank you for trying the beta.": "نسخه‌ی بتا برای کلاینت‌های وب، دسکتاپ و اندروید موجود است. از بابت امتحان‌کردن نسخه‌ی بتا سپاس‌گزاریم.", + "Spaces are a new way to group rooms and people.": "محیط‌ها روش جدیدی برای دسته‌بندی اتاق‌ها و کاربران است.", + "Spaces": "محیط‌ها", + "Spaces prototype. Incompatible with Communities, Communities v2 and Custom Tags. Requires compatible homeserver for some features.": "نمونه اولیه قابلیت محیط. با نسخه‌های ۱ و ۲ فضای کاری، و تگ‌های دلخواه سازگار نیست. برای برخی از قابلیت‌ها نیاز به سرور سازگار دارد.", + "Change notification settings": "تنظیمات اعلان را تغییر دهید", + "%(senderName)s: %(stickerName)s": "%(senderName)s:%(stickerName)s", + "%(senderName)s: %(reaction)s": "%(senderName)s:%(reaction)s", + "%(senderName)s: %(message)s": "%(senderName)s:%(message)s", + "* %(senderName)s %(emote)s": "* %(senderName)s.%(emote)s", + "%(senderName)s is calling": "%(senderName)s در حال تماس است", + "Waiting for answer": "منتظر پاسخ", + "%(senderName)s started a call": "%(senderName)s تماس را شروع کرد", + "You started a call": "شما یک تماس را شروع کردید", + "Call ended": "تماس پایان یافت", + "%(senderName)s ended the call": "%(senderName)s تماس را پایان داد", + "You ended the call": "شما تماس را پایان دادید", + "Call in progress": "تماس در جریان است", + "%(senderName)s joined the call": "%(senderName)s به تماس پیوست", + "You joined the call": "شما به تماس پیوستید", + "The person who invited you already left the room, or their server is offline.": "شخصی که شما را دعوت کرده است از اتاق خارج شده یا سرور وی در دسترس نیست.", + "The person who invited you already left the room.": "شخصی که شما را دعوت کرده از اتاق خارج شده است.", + "Please contact your homeserver administrator.": "لطفاً با مدیر سرور خود تماس بگیرید.", + "Sorry, your homeserver is too old to participate in this room.": "با عرض پوزش ، سرور شما برای شرکت در این اتاق بیش از حد قدیمی است.", + "There was an error joining the room": "هنگام پیوستن به اتاق خطایی رخ داد", + "New version of %(brand)s is available": "نسخه‌ی جدید %(brand)s وجود است", + "Update %(brand)s": "%(brand)s را به‌روزرسانی کنید", + "Check your devices": "دستگاه های خود را بررسی کنید", + "%(deviceId)s from %(ip)s": "%(deviceId)s از %(ip)s", + "New login. Was this you?": "ورود جدید. آیا شما بودید؟", + "Other users may not trust it": "ممکن است سایر کاربران به آن اعتماد نکنند", + "Safeguard against losing access to encrypted messages & data": "محافظ در برابر از دست‌دادن داده‌ها و پیام‌های رمزشده", + "Set up Secure Backup": "پشتیبان‌گیری امن را انجام دهید", + "Your homeserver has exceeded one of its resource limits.": "سرور شما از یکی از محدودیت‌های منابع خود فراتر رفته است.", + "This homeserver has been blocked by it's administrator.": "این سرور توسط مدیر آن مسدود شده است.", + "Your homeserver has exceeded its user limit.": "سرور شما از حد مجاز کاربر خود فراتر رفته است.", + "Use app": "از برنامه استفاده کنید", + "Element Web is experimental on mobile. For a better experience and the latest features, use our free native app.": "نسخه‌ی المنت وب برای گوشی به شکل آزمایشی است. برای داشتن تجربه‌ی بهتر و آخرین به‌روزرسانی‌ها، از برنامک موبایلی استفاده نمائید.", + "Use app for a better experience": "برای تجربه بهتر از برنامه استفاده کنید", + "Enable": "فعال کن", + "Enable desktop notifications": "فعال‌کردن اعلان‌های دسکتاپ", + "Don't miss a reply": "پاسخی را از دست ندهید", + "Review to ensure your account is safe": "برای کسب اطمینان از امن‌بودن حساب کاربری خود، لطفا بررسی فرمائید", + "You have unverified logins": "شما ورودهای تأیید نشده دارید", + "Yes": "بله", + "Help us improve %(brand)s": "به ما در بهبود %(brand)s کمک کنید", + "Unknown App": "برنامه ناشناخته", + "Share your public space": "محیط عمومی خود را به اشتراک بگذارید", + "Invite to %(spaceName)s": "دعوت به %(spaceName)s", + "A word by itself is easy to guess": "حدس زدن یک کلمه به خودی خود آسان است", + "This is similar to a commonly used password": "این مشابه یکی از گذرواژه‌‌هایی است که معمولاً استفاده می شود", + "This is a very common password": "این یک گذرواژه‌ی بسیار رایج است", + "This is a top-100 common password": "این‌ها ۱۰۰ گذرواژه‌ی پر استفاده هستند", + "This is a top-10 common password": "این‌ها ۱۰ گذرواژه‌ی پس استفاده هستند", + "Dates are often easy to guess": "حدس زدن تاریخ‌ها اغلب آسان است", + "Recent years are easy to guess": "حدس زدن سالهای اخیر آسان است", + "Sequences like abc or 6543 are easy to guess": "موارد متوالی نظیر abc یا 6543 برای حدس‌زدن راحت هستند", + "Language and region": "زبان و جغرافیا", + "Set a new account password...": "تنظیم گذرواژه جدید...", + "Phone numbers": "شماره تلفن", + "Email addresses": "آدرس ایمیل", + "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "گذرواژه‌ی شما با موفیت تغییر کرد. برای دریافت اعلان بر روی سایر نشست‌ها، لطفا مجددا وارد شوید", + "Success": "موفقیت", + "Flair": "فضای کاری", + "Customise your appearance": "ظاهر پیام‌رسان خود را سفارشی‌سازی کنید", + "Enable experimental, compact IRC style layout": "چیدمان IRC فشرده آزمایشی را فعال کنید", + "Show advanced": "نمایش بخش پیشرفته", + "Hide advanced": "پنهان‌کردن بخش پیشرفته", + "Theme": "پوسته", + "Add theme": "افزودن پوسته", + "Custom theme URL": "آدرس پوسته دلخواه", + "Error downloading theme information.": "بارگیری اطلاعات پوسته با خطا همراه بود.", + "Invalid theme schema.": "ساختار پوسته صحیح نیست.", + "Size must be a number": "سایز باید یک عدد باشد", + "Hey you. You're the best!": "سلام. حال شما خوبه؟", + "Check for update": "بررسی برای به‌روزرسانی جدید", + "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "مدیرهای یکپارچه‌سازی، داده‌های مربوط به پیکربندی را دریافت کرده و امکان تغییر ویجت‌ها، ارسال دعوتنامه برای اتاق و تنظیم سطح دسترسی از طرف شما را دارا هستند.", + "Manage integrations": "مدیریت پکپارچه‌سازی‌ها", + "Use an Integration Manager to manage bots, widgets, and sticker packs.": "از یک مدیر پکپارچه‌سازی برای مدیریت بات‌ها، ویجت‌ها و پک‌های استیکر مورد نظرتان استفاده نمائید.", + "Change": "تغییر بده", + "Enter a new identity server": "یک سرور هویت‌سنجی جدید وارد کنید", + "Do not use an identity server": "از سرور هویت‌سنجی استفاده نکن", + "If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated": "اگر این کار را انجام می‌دهید، لطفاً توجه داشته باشید که هیچ یک از پیام‌های شما حذف نمی‌شوند ، با این حال چون پیام‌ها مجددا ایندکس می‌شوند، ممکن است برای چند لحظه قابلیت جستجو با مشکل مواجه شود", + "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "حذف کلیدهای امضای متقابل دائمی است. هرکسی که او را تائید کرده‌باشید، هشدارهای امنیتی را مشاهده خواهد کرد. به احتمال زیاد نمی‌خواهید این کار را انجام دهید ، مگر هیچ دستگاهی برای امضاء متقابل از طریق آن نداشته باشید.", + "Enter your Security Phrase or to continue.": "برای ادامه، عبارت امنیتی خود را وارد کرده و یا .", + "Click the button below to confirm setting up encryption.": "برای تأیید و فعال‌سازی رمزگذاری ، روی دکمه زیر کلیک کنید.", + "Unable to access secret storage. Please verify that you entered the correct Security Phrase.": "دسترسی به حافظه نهان امکان‌پذیر نیست. لطفاً تأیید کنید که عبارت امنیتی صحیح را وارد کرده‌اید.", + "If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "اگر همه موارد را بازراه‌اندازی (reset) کنید، دیگر هیچ نشست تائید شده‌ای و هیچ کاربر تائيد‌ شده‌ای نخواهید داشت و ممکن است نتوانید پیام‌های گذشته‌ی خود را مشاهده نمائید.", + "Backup could not be decrypted with this Security Key: please verify that you entered the correct Security Key.": "نسخه پشتیبان با این کلید امنیتی رمزگشایی نمی شود: لطفاً بررسی کنید که کلید امنیتی درست را وارد کرده اید.", + "Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.": "نسخه پشتیبان با این عبارت امنیتی رمزگشایی نمی‌شود: لطفاً بررسی کنید که عبارت امنیتی درست را وارد کرده اید.", + "Warning: you should only set up key backup from a trusted computer.": "هشدا: پشتیبان گیری از کلید را فقط از یک رایانه مطمئن انجام دهید.", + "Access your secure message history and set up secure messaging by entering your Security Phrase.": "با وارد کردن عبارت امنیتی خود به سابقه پیام‌های رمز شدتان دسترسی پیدا کرده و پیام امن ارسال کنید.", + "Only do this if you have no other device to complete verification with.": "این کار را فقط درصورتی انجام دهید که دستگاه دیگری برای تکمیل فرآیند تأیید ندارید.", + "Forgotten or lost all recovery methods? Reset all": "همه روش‌های بازیابی را فراموش کرده یا از دست داده‌اید؟ بازراه‌اندازی (reset) همه", + "If you've forgotten your Security Phrase you can use your Security Key or set up new recovery options": "اگر عبارت امنیتی خود را فراموش کرده اید، می توانید از کلید امنیتی خود استفاده کنید یا تنظیمات پشتیانی‌گیری را مجددا انجام دهید", + "The widget will verify your user ID, but won't be able to perform actions for you:": "ابزارک شناسه‌ی کاربری شما را تائید خواهد کرد، اما نمی‌تواند این کارها را برای شما انجام دهد:", + "This looks like a valid Security Key!": "به نظر می رسد این یک کلید امنیتی معتبر است!", + "Warning: You should only set up key backup from a trusted computer.": "هشدار: پشتیان کلید تنها باید در یک رایانه‌ی مطمئن انجام شود.", + "Allow this widget to verify your identity": "به این ابزارک اجازه دهید هویت شما را تأیید کند", + "Approve": "تایید", + "Some files are too large to be uploaded. The file size limit is %(limit)s.": "برخی از فایل‌ها برای بارگذاری بیش از حد بزرگ هستند. محدودیت اندازه فایل %(limit)s است.", + "Access your secure message history and set up secure messaging by entering your Security Key.": "با وارد کردن کلید امنیتی خود به تاریخچه‌ی پیام‌‌های رمز شده خود دسترسی پیدا کرده و پیام امن ارسال کنید.", + "These files are too large to upload. The file size limit is %(limit)s.": "این فایل‌ها برای بارگذاری بیش از حد بزرگ هستند. محدودیت اندازه فایل %(limit)s است.", + "If you've forgotten your Security Key you can ": "اگر کلید امنیتی خود را فراموش کرده‌اید ، می توانید ", + "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "این فایل برای بارگذاری بسیار بزرگ است. محدودیت اندازه‌ی فایل برابر %(limit)s است اما حجم این فایل %(sizeOfThisFile)s.", + "Ask this user to verify their session, or manually verify it below.": "از این کاربر بخواهید نشست خود را تأیید کرده و یا آن را به صورت دستی تأیید کنید.", + "Away": "بعدا", + "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) وارد یک نشست جدید شد بدون اینکه آن را تائید کند:", + "This homeserver would like to make sure you are not a robot.": "این سرور می خواهد مطمئن شود که شما یک ربات نیستید.", + "Confirm your identity by entering your account password below.": "با وارد کردن رمز ورود حساب خود در زیر ، هویت خود را تأیید کنید.", + "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "کلید عمومی captcha در پیکربندی سرور خانگی وجود ندارد. لطفاً این را به ادمین سرور خود گزارش دهید.", + "Verify your other session using one of the options below.": "نست دیگر خود را با استفاده از یکی از راهکارهای زیر تأیید کنید.", + "You signed in to a new session without verifying it:": "شما وارد یک نشست جدید شده‌اید بدون اینکه آن را تائید کنید:", + "Please review and accept all of the homeserver's policies": "لطفاً کلیه خط مشی‌های سرور را مرور و قبول کنید", + "Please review and accept the policies of this homeserver:": "لطفاً خط مشی‌های این سرور را مرور و قبول کنید:", + "Next": "بعدی", + "A confirmation email has been sent to %(emailAddress)s": "یک ایمیل تأیید به %(emailAddress)s ارسال شد", + "Document": "سند", + "Summary": "خلاصه", + "Service": "سرویس", + "Open the link in the email to continue registration.": "برای ادامه ثبت نام ، پیوند موجود در ایمیل را باز کنید.", + "Token incorrect": "کد نامعتبر است", + "To continue you need to accept the terms of this service.": "برای ادامه باید شرایط این سرویس را بپذیرید.", + "Use bots, bridges, widgets and sticker packs": "از بات‌ها، پل‌ها ارتباطی، ابزارک‌ها و بسته‌های استیکر استفاده کنید", + "A text message has been sent to %(msisdn)s": "کد فعال‌سازی به %(msisdn)s ارسال شد", + "Your browser likely removed this data when running low on disk space.": "هنگام کمبود فضای دیسک ، مرورگر شما این داده ها را حذف می کند.", + "Use an email address to recover your account": "برای بازیابی حساب خود از آدرس ایمیل استفاده کنید", + "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "برخی از داده‌های نشست ، از جمله کلیدهای رمزنگاری پیام‌ها موجود نیست. برای برطرف کردن این مشکل از برنامه خارج شده و مجددا وارد شوید و از کلیدها را از نسخه‌ی پشتیبان بازیابی نمائيد.", + "Enter email address (required on this homeserver)": "آدرس ایمیل را وارد کنید (در این سرور اجباری است)", + "Other users can invite you to rooms using your contact details": "سایر کاربران می توانند شما را با استفاده از اطلاعات تماستان به اتاق ها دعوت کنند", + "Enter phone number (required on this homeserver)": "شماره تلفن را وارد کنید (در این سرور اجباری است)", + "Use lowercase letters, numbers, dashes and underscores only": "فقط از حروف کوچک، اعداد، خط تیره و زیر خط استفاده کنید", + "Use email to optionally be discoverable by existing contacts.": "از ایمیل استفاده کنید تا به طور اختیاری توسط مخاطبین موجود قابل کشف باشید.", + "Use email or phone to optionally be discoverable by existing contacts.": "از ایمیل یا تلفن استفاده کنید تا به طور اختیاری توسط مخاطبین موجود قابل کشف باشید.", + "To help us prevent this in future, please send us logs.": "برای کمک به ما در جلوگیری از این امر در آینده ، لطفا لاگ‌ها را برای ما ارسال کنید.", + "You must register to use this functionality": "برای استفاده از این قابلیت باید ثبت نام کنید", + "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even add images with Matrix URLs \n

    \n": "

    html مرتبط با اجتماع شما

    \n

    \n برای معرفی اجتماع به اعضای جدید، یا ذکر نکات مهم،\n از توضیحات مفصل استفاده کنیدلینک\n

    \n

    \n شما حتی می‌توانید تصاویر را با استفاده از url ماتریکس به این صفحه اضافه کنید \n

    \n", + "Saving...": "در حال ذخیره‌سازی...", + "Edit settings relating to your space.": "تنظیمات مربوط به فضای کاری خود را ویرایش کنید.", + "This will allow you to reset your password and receive notifications.": "با این کار می‌توانید گذرواژه خود را تغییر داده و اعلان‌ها را دریافت کنید.", + "Please check your email and click on the link it contains. Once this is done, click continue.": "لطفاً ایمیل خود را بررسی کرده و روی لینکی که برایتان ارسال شده، کلیک کنید. پس از انجام این کار، روی ادامه کلیک کنید.", + "Verification Pending": "در انتظار تائید", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "پاک کردن فضای ذخیره‌سازی مرورگر ممکن است این مشکل را برطرف کند ، اما شما را از برنامه خارج کرده و باعث می‌شود هرگونه سابقه گفتگوی رمزشده غیرقابل خواندن باشد.", + "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 استفاده کرده‌اید ، نشست شما ممکن است با این نسخه ناسازگار باشد. این پنجره را بسته و به نسخه جدیدتر برگردید.", + "We encountered an error trying to restore your previous session.": "هنگام تلاش برای بازیابی نشست قبلی شما، با خطایی روبرو شدیم.", + "Refresh": "رفرش", + "Failed to add the following rooms to the summary of %(groupId)s:": "افزدون اتاق‌های زیر به خلاصه %(groupId)s انجام نشد:", + "You most likely do not want to reset your event index store": "به احتمال زیاد نمی‌خواهید مخزن فهرست رویدادهای خود را حذف کنید", + "Failed to remove the room from the summary of %(groupId)s": "اتاق از خلاصه %(groupId)s حذف نشد", + "Use your preferred Matrix homeserver if you have one, or host your own.": "از یک سرور مبتنی بر پروتکل ماتریکس که ترجیح می‌دهید استفاده کرده، و یا از سرور شخصی خودتان استفاده کنید.", + "The room '%(roomName)s' could not be removed from the summary.": "اتاق «%(roomName)s» از خلاصه حذف نمی شود.", + "Failed to add the following users to the summary of %(groupId)s:": "افزودن کاربران زیر به خلاصه %(groupId)s انجام نشد:", + "We call the places where you can host your account ‘homeservers’.": "ما به زیرساختی که شما می‌توانید بر روی آن حساب کاربری ایجاد کنید، \"سرور\" می‌گوییم.", + "Failed to remove a user from the summary of %(groupId)s": "حذف کاربر از خلاصه %(groupId)s انجام نشد", + "The user '%(displayName)s' could not be removed from the summary.": "کاربر «%(displayName)s» را نمی توان از خلاصه حذف کرد.", + "Leave %(groupName)s?": "%(groupName)s را ترک می‌کنید؟", + "Want more than a community? Get your own server": "بیش از یک اجتماع می خواهید؟سرور خود را دریافت کنید", + "Matrix.org is the biggest public homeserver in the world, so it’s a good place for many.": "Matrix.org بزرگترین سرور عمومی در جهان است ، بنابراین مکان خوبی برای بسیاری از افراد جهت برقراری ارتباط به شمار می‌رود.", + "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "تغییراتی که در نام و آواتار در اجتماع شما ایجاد شده است ممکن است توسط کاربران دیگر حداکثر تا ۳۰ دقیقه دیده شود.", + "Recent changes that have not yet been received": "تغییرات اخیری که هنوز دریافت نشده‌اند", + "The server is not configured to indicate what the problem is (CORS).": "سرور طوری پیکربندی نشده تا نشان دهد مشکل چیست (CORS).", + "%(inviter)s has invited you to join this community": "%(inviter)s از شما برای پیوستن به این اجتماع دعوت کرده است", + "A connection error occurred while trying to contact the server.": "هنگام تلاش برای اتصال به سرور خطایی رخ داده است.", + "Your community hasn't got a Long Description, a HTML page to show to community members.
    Click here to open settings and give it one!": "اجتماع شما دارای توصیف طولانی (صفحه HTML برای نشان دادن به اعضای انجمن) نیست.
    برای باز کردن تنظیمات اینجا کلیک کنید و یک توصیف به آن اضافه کنید!", + "Your area is experiencing difficulties connecting to the internet.": "منطقه شما در اتصال به اینترنت با مشکل روبرو است.", + "A browser extension is preventing the request.": "پلاگینی در مرورگر مانع از ارسال درخواست می‌گردد.", + "Your firewall or anti-virus is blocking the request.": "دیوار آتش یا آنتی‌ویروس شما مانع از ارسال درخواست می‌شود.", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "برای ادامه استفاده از سرور %(homeserverDomain)s باید شرایط و ضوابط ما را بررسی کرده و موافقت کنید.", + "The server (%(serverName)s) took too long to respond.": "زمان پاسخگویی سرور (%(serverName)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 شناسایی شده است. این امر باعث اختلال در رمزنگاری سرتاسر در نسخه قدیمی شده است. پیام های رمزگذاری شده سرتاسر که اخیراً رد و بدل شده اند ممکن است با استفاده از نسخه قدیمی رمزگشایی نشوند. همچنین ممکن است پیام های رد و بدل شده با این نسخه با مشکل مواجه شود. اگر مشکلی رخ داد، از سیستم خارج شوید و مجددا وارد شوید. برای حفظ سابقه پیام، کلیدهای خود را خروجی گرفته و دوباره وارد کنید.", + "Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "سرور شما به برخی از درخواست‌ها پاسخ نمی‌دهد. در ادامه برخی از دلایل محتمل آن ذکر شده است.", + "You'll upgrade this room from to .": "این اتاق را از به ارتقا خواهید داد.", + "Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.": "به‌روزرسانی اتاق اقدامی پیشرفته بوده و معمولاً در صورتی توصیه می‌شود که اتاق به دلیل اشکالات، فقدان قابلیت‌ها یا آسیب پذیری‌های امنیتی، پایدار و قابل استفاده نباشد.", + "Did you know: you can use communities to filter your %(brand)s experience!": "آیا می دانید: برای فیلتر کردن تجربیات خود در %(brand)s می توانید از اجتماع‌ها استفاده کنید!", + "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "این معمولاً فقط بر نحوه پردازش اتاق در سرور تأثیر می‌گذارد. اگر با %(brand)s خود مشکلی دارید، لطفاً اشکال را گزارش کنید.", + "To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "برای تنظیم فیلتر، آواتار یک اجتماع را به صفحه فیلتر در سمت چپ صفحه بکشید. همواره می‌توانید با کلیک برر روی آواتار در صفحه فیلتر، فقط اتاق ها و افراد مرتبط با آن انجمن را مشاهده کنید.", + "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "این معمولاً فقط بر نحوه پردازش اتاق در سرور تأثیر می‌گذارد. اگر با %(brand)s خود مشکلی دارید ، لطفاً یک اشکال گزارش دهید.", + "Put a link back to the old room at the start of the new room so people can see old messages": "در ابتدای اتاق جدید پیوندی به اتاق قدیمی قرار دهید تا افراد بتوانند پیام‌های موجود در اتاق قدیمی را ببینند", + "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "از گفتگوی کاربران در نسخه قدیمی اتاق جلوگیری کرده و با ارسال پیامی به کاربران توصیه کنید به اتاق جدید منتقل شوند", + "Update any local room aliases to point to the new room": "برای اشاره به اتاق جدید، نام‌های مستعار (aliases) اتاق محلی را به‌روز کنید", + "Create a new room with the same name, description and avatar": "یک اتاق جدید با همان نام ، توضیحات و نمایه ایجاد کنید", + "Upgrading this room requires closing down the current instance of the room and creating a new room in its place. To give room members the best possible experience, we will:": "ارتقاء این اتاق نیازمند بستن نسخه‌ی فعلی و ساختن درجای یک اتاق جدید است. برای داشتن بهترین تجربه‌ی کاربری ممکن، ما:", + "The room upgrade could not be completed": "متاسفانه فرآیند ارتقاء اتاق به پایان نرسید", + "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "گزارش این پیام شناسه‌ی منحصر به فرد رخداد آن را برای مدیر سرور ارسال می‌کند. اگر پیام‌های این اتاق رمزشده باشند، مدیر سرور شما امکان خواندن متن آن پیام یا مشاهده‌ی عکس یا فایل‌های دیگر را نخواهد داشت.", + "Just a heads up, if you don't add an email and forget your password, you could permanently lose access to your account.": "حواستان را جمع کنید، اگر ایمیلی اضافه نکرده و گذرواژه‌ی خود را فراموش کنید ، ممکن است دسترسی به حساب کاربری خود را برای همیشه از دست دهید.", + "Doesn't look like a valid email address": "به نظر نمی‌رسد یک آدرس ایمیل معتبر باشد", + "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "%(brand)s نتوانست لیست پروتکل را از سرور میزبان دریافت کند. ممکن است سرور برای پشتیبانی از شبکه های شخص ثالث خیلی قدیمی باشد.", + "If they don't match, the security of your communication may be compromised.": "اگر آنها مطابقت نداشته‌باشند ، ممکن است امنیت ارتباطات شما به خطر افتاده باشد.", + "If you didn’t sign in to this session, your account may be compromised.": "اگر وارد این نشست نشده‌اید ، ممکن است حساب کاربری شما به خطر افتاد باشد.", + "%(brand)s failed to get the public room list.": "%(brand)s نتوانست لیست اتاق‌های عمومی را دریافت کند.", + "Use this session to verify your new one, granting it access to encrypted messages:": "از این نشست برای تائید نشست‌های جدید خود و اعطای دسترسی به پیام‌های رمزشده استفاده کنید:", + "Delete the room address %(alias)s and remove %(name)s from the directory?": "اتاق با آدرس %(alias)s حذف شده و نام %(name)s از فهرست اتاق‌ها نیز پاک شود؟", + "We recommend you change your password and Security Key in Settings immediately": "ما به شما توصیه می‌کنیم بلافاصله گذرواژه و کلید امنیتی خود را در تنظیمات تغییر دهید", + "The internet connection either session is using": "اتصال اینترنت و یا نشست در حال استفاده است", + "%(brand)s does not know how to join a room on this network": "%(brand)s نمی‌تواند به اتاقی در این شبکه بپیوندد", + "Data on this screen is shared with %(widgetDomain)s": "داده‌های این صفحه با %(widgetDomain)s به اشتراک گذاشته می‌شود", + "Your homeserver doesn't seem to support this feature.": "به نظر نمی‌رسد که سرور شما از این قابلیت پشتیبانی کند.", + "Unable to look up room ID from server": "جستجوی شناسه اتاق از سرور انجام نشد", + "Not currently indexing messages for any room.": "در حال حاضر ایندکس پیام ها برای هیچ اتاقی انجام نمی‌شود.", + "Session ID": "شناسه‌ی نشست", + "Confirm this user's session by comparing the following with their User Settings:": "این نشست کاربر را از طریق مقایسه‌ی این با تنظیمات کاربری تائيد کنید:", + "Confirm by comparing the following with the User Settings in your other session:": "از طریق مقایسه‌ی این با تنظیمات کاربری در نشست‌های دیگرتان، تائيد کنید:", + "Are you sure you want to sign out?": "آیا مطمئن هستید که می خواهید از برنامه خارج شوید؟", + "You'll lose access to your encrypted messages": "دسترسی به پیام‌های رمزشده‌ی خود را از دست خواهید داد", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "پیام‌های رمزشده با رمزنگاری سرتاسر ایمن می‌شوند. فقط شما و طرف گیرنده(ها) کلیدهای خواندن این پیام ها را در اختیار دارید.", + "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "هم‌اکنون %(brand)s از طریق بارگیری و نمایش اطلاعات کاربران تنها در زمان‌هایی که نیاز است، حدود ۳ تا ۵ مرتبه حافظه‌ی کمتری استفاده می‌کند. لطفا تا همگام‌سازی با سرور منتظر بمانید!", + "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 با قابلیت بارگیری تکه‌تکه‌ی فعال روی یکی و غیرفعال روی دیگری، باعث ایجاد مشکل می شود.", + "You've previously used %(brand)s on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, %(brand)s needs to resync your account.": "شما از %(brand)s بر روی %(host)s با قابلیت بارگیری اعضا به شکل تکه‌تکه استفاده می‌کنید. در این نسخه قابلیت بارگیری تکه‌تکه غیرفعال است. از آن‌جایی که حافظه‌ی کش مورد استفاده برای این دو پیکربندی با هم سازگار نیست، %(brand)s نیاز به همگام‌سازی مجدد حساب کاربری شما دارد.", + "%(brand)s encountered an error during upload of:": "%(brand)s در حین بارگذاری این دچار مشکل شد:", + "Transfer": "منتقل کردن", + "Invited people will be able to read old messages.": "افراد دعوت‌شده خواهند توانست پیام‌های قدیمی را بخوانند.", + "Invite someone using their name, username (like ) or share this room.": "با استفاده از نام یا نام کاربری (مانند ) از افراد دعوت کرده و یا این اتاق را به اشتراک بگذارید.", + "Invite someone using their name, email address, username (like ) or share this room.": "با استفاده از نام، آدرس ایمیل، نام کاربری (مانند ) از فردی دعوت کرده و یا این اتاق را به اشتراک بگذارید.", + "Invite someone using their name, email address, username (like ) or share this space.": "با استفاده از نام ، آدرس ایمیل ، نام کاربری (مانند ) کسی را دعوت کرده یا این فضای کاری را به اشتراک بگذارید.", + "Invite someone using their name, username (like ) or share this space.": "با استفاده از نام یا نام کاربری (مانند ) از افراد دعوت کرده و یا این فضای کاری را به اشتراک بگذارید.", + "Go": "برو", + "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "این کار آنها را به %(communityName)s دعوت نمی‌کند. برای دعوت افراد به %(communityName)s،اینجا کلیک کنید", + "Start a conversation with someone using their name or username (like ).": "با استفاده از نام یا نام کاربری (مانند )، گفتگوی جدیدی را با دیگران شروع کنید.", + "Start a conversation with someone using their name, email address or username (like ).": "با استفاده از نام، آدرس ایمیل و یا نام کاربری (مانند )، یک گفتگوی جدید را شروع کنید.", + "May include members not in %(communityName)s": "ممکن شامل اعضایی که در %(communityName)s نیستند نیز شود" } diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index 5452176cd9..23140846b3 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -2950,5 +2950,58 @@ "A new login is accessing your account: %(name)s (%(deviceID)s) at %(ip)s": "Uusi kirjautuminen tilillesi: %(name)s (%(deviceID)s) osoitteesta %(ip)s", "This homeserver has been blocked by its administrator.": "Tämä kotipalvelin on ylläpitäjänsä estämä.", "You're already in a call with this person.": "Olet jo puhelussa tämän henkilön kanssa.", - "Already in call": "Olet jo puhelussa" + "Already in call": "Olet jo puhelussa", + "Please choose a strong password": "Valitse vahva salasana", + "You can add more later too, including already existing ones.": "Voit lisätä niitä myöhemmin, mukaan lukien olemassa olevia.", + "Let's create a room for each of them.": "Tehdään huone jokaiselle.", + "What do you want to organise?": "Mitä haluat järjestää?", + "Random": "Satunnainen", + "Search names and descriptions": "Etsi nimistä ja kuvauksista", + "Failed to remove some rooms. Try again later": "Joitakin huoneita ei voitu poistaa. Yritä myöhemmin uudelleen.", + "Select a room below first": "Valitse ensin huone alta", + "You can select all or individual messages to retry or delete": "Voit valita kaikki tai yksittäisiä viestejä yritettäväksi uudelleen tai poistettavaksi", + "Sending": "Lähetetään", + "Retry all": "Yritä kaikkia uudelleen", + "Delete all": "Poista kaikki", + "Some of your messages have not been sent": "Osaa viesteistäsi ei ole lähetetty", + "You are the only person here. If you leave, no one will be able to join in the future, including you.": "Olet ainoa henkilö täällä. Jos lähdet, kukaan ei voi liittyä tulevaisuudessa, et myöskään sinä.", + "Beta": "Beeta", + "Tap for more info": "Lisää tietoa napauttamalla", + "The server is not configured to indicate what the problem is (CORS).": "Palvelinta ei ole säädetty ilmoittamaan, mikä ongelma on kyseessä (CORS).", + "Invited people will be able to read old messages.": "Kutsutut ihmiset voivat lukea vanhoja viestejä.", + "We couldn't create your DM.": "Yksityisviestiä ei voitu luoda.", + "Thank you for your feedback, we really appreciate it.": "Kiitos palautteesta, arvostamme sitä.", + "Beta feedback": "Palautetta beetaversiosta", + "Want to add a new room instead?": "Haluatko kuitenkin lisätä uuden huoneen?", + "Add existing rooms": "Lisää olemassa olevia huoneita", + "Adding rooms... (%(progress)s out of %(count)s)|one": "Lisätään huonetta...", + "Adding rooms... (%(progress)s out of %(count)s)|other": "Lisätään huoneita... (%(progress)s out of %(count)s)", + "Not all selected were added": "Kaikkia valittuja ei lisätty", + "You are not allowed to view this server's rooms list": "Sinulla ei ole oikeuksia nähdä tämän palvelimen huoneluetteloa", + "View message": "Näytä viesti", + "%(count)s people you know have already joined|one": "%(count)s tuntemasi henkilö on jo liittynyt", + "%(count)s people you know have already joined|other": "%(count)s tuntemaasi ihmistä on jo liittynyt", + "View all %(count)s members|one": "Näytä yksi jäsen", + "View all %(count)s members|other": "Näytä kaikki %(count)s jäsentä", + "Add reaction": "Lisää reaktio", + "Error processing voice message": "Virhe ääniviestin käsittelyssä", + "Delete recording": "Poista äänitys", + "Stop the recording": "Lopeta äänitys", + "Record a voice message": "Äänitä viesti", + "We were unable to access your microphone. Please check your browser settings and try again.": "Mikrofoniasi ei voitu käyttää. Tarkista selaimesi asetukset ja yritä uudelleen.", + "We didn't find a microphone on your device. Please check your settings and try again.": "Laitteestasi ei löytynyt mikrofonia. Tarkista asetuksesi ja yritä uudelleen.", + "No microphone found": "Mikrofonia ei löytynyt", + "Unable to access your microphone": "Mikrofonia ei voi käyttää", + "Quick actions": "Pikatoiminnot", + "%(seconds)ss left": "%(seconds)s s jäljellä", + "Failed to send": "Lähettäminen epäonnistui", + "You have no ignored users.": "Et ole sivuuttanut käyttäjiä.", + "Warn before quitting": "Varoita ennen lopettamista", + "Manage & explore rooms": "Hallitse ja selaa huoneita", + "Connecting": "Yhdistetään", + "unknown person": "tuntematon henkilö", + "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Salli vertaisyhteydet 1:1-puheluille (jos otat tämän käyttöön, toinen osapuoli saattaa nähdä IP-osoitteesi)", + "Send and receive voice messages": "Lähetä ja vastaanota ääniviestejä", + "Show options to enable 'Do not disturb' mode": "Näytä asetukset Älä häiritse -tilan ottamiseksi käyttöön", + "%(deviceId)s from %(ip)s": "%(deviceId)s osoitteesta %(ip)s" } diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index dc8b701e35..5a8208f50b 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -936,7 +936,7 @@ "Failed to load group members": "Échec du chargement des membres du groupe", "Failed to invite users to the room:": "Échec de l’invitation d'utilisateurs dans le salon :", "There was an error joining the room": "Une erreur est survenue en rejoignant le salon", - "You do not have permission to invite people to this room.": "Vous n’avez pas la permission d’envoyer des invitations dans ce salon.", + "You do not have permission to invite people to this room.": "Vous n’avez pas la permission d’inviter des personnes dans ce salon.", "User %(user_id)s does not exist": "L’utilisateur %(user_id)s n’existe pas", "Unknown server error": "Erreur de serveur inconnue", "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Afficher un rappel pour activer la récupération de messages sécurisée dans les salons chiffrés", @@ -3175,8 +3175,8 @@ "Delete": "Supprimer", "Jump to the bottom of the timeline when you send a message": "Sauter en bas du fil de discussion lorsque vous envoyez un message", "Spaces prototype. Incompatible with Communities, Communities v2 and Custom Tags. Requires compatible homeserver for some features.": "Prototype d’espaces. Incompatible avec les communautés, les communautés v2 et les étiquettes personnalisées. Nécessite un serveur d’accueil compatible pour certaines fonctionnalités.", - "This homeserver has been blocked by it's administrator.": "Ce serveur d’accueil a été banni par ses administrateurs.", - "This homeserver has been blocked by its administrator.": "Ce serveur d’accueil a été banni par ses administrateurs.", + "This homeserver has been blocked by it's administrator.": "Ce serveur d’accueil a été bloqué par son administrateur.", + "This homeserver has been blocked by its administrator.": "Ce serveur d’accueil a été bloqué par son administrateur.", "You're already in a call with this person.": "Vous êtes déjà en cours d’appel avec cette personne.", "Already in call": "Déjà en cours d’appel", "Space selection": "Sélection d’un espace", @@ -3344,5 +3344,13 @@ "To leave the beta, visit your settings.": "Pour quitter la bêta, consultez les paramètres.", "Your platform and username will be noted to help us use your feedback as much as we can.": "Votre plateforme et nom d’utilisateur seront consignés pour nous aider à tirer le maximum de vos retours.", "Add reaction": "Ajouter une réaction", - "Send and receive voice messages": "Envoyer et recevoir des messages vocaux" + "Send and receive voice messages": "Envoyer et recevoir des messages vocaux", + "See when people join, leave, or are invited to this room": "Voir quand une personne rejoint, quitte ou est invitée sur ce salon", + "Kick, ban, or invite people to this room, and make you leave": "Exclure, bannir ou inviter une personne dans ce salon et vous permettre de partir", + "Space Autocomplete": "Autocomplétion d’espace", + "Go to my space": "Aller à mon espace", + "sends space invaders": "Envoie les Space Invaders", + "Sends the given message with a space themed effect": "Envoyer le message avec un effet lié au thème de l’espace", + "See when people join, leave, or are invited to your active room": "Afficher quand des personnes rejoignent, partent, ou sont invités dans votre salon actif", + "Kick, ban, or invite people to your active room, and make you leave": "Expulser, bannir ou inviter des personnes dans votre salon actif et en partir" } diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json index 019929b081..12a2dcd8c3 100644 --- a/src/i18n/strings/gl.json +++ b/src/i18n/strings/gl.json @@ -3367,5 +3367,13 @@ "Send and receive voice messages": "Enviar e recibir mensaxes de voz", "Your feedback will help make spaces better. The more detail you can go into, the better.": "A túa opinión axudaranos a mellorar os espazos. Canto máis detallada sexa moito mellor para nós.", "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Se saes, %(brand)s volverá a cargar con Espazos desactivados. Comunidades e etiquetas personais serán visibles outra vez.", - "Message search initialisation failed": "Fallou a inicialización da busca de mensaxes" + "Message search initialisation failed": "Fallou a inicialización da busca de mensaxes", + "Space Autocomplete": "Autocompletado do espazo", + "Go to my space": "Ir ao meu espazo", + "sends space invaders": "enviar invasores espaciais", + "Sends the given message with a space themed effect": "Envía a mensaxe cun efecto de decorado espacial", + "See when people join, leave, or are invited to your active room": "Mira cando alguén se une, sae ou é convidada á túa sala activa", + "Kick, ban, or invite people to your active room, and make you leave": "Expulsa, veta ou convida a persoas á túa sala activa, e fai que saias", + "See when people join, leave, or are invited to this room": "Mira cando se une alguén, sae ou é convidada a esta sala", + "Kick, ban, or invite people to this room, and make you leave": "Expulsa, veta, ou convida persoas a esta sala, e fai que saias" } diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index bc38d20716..a6e9992866 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -3359,5 +3359,16 @@ "Send and receive voice messages": "Hangüzenet küldése, fogadása", "Your feedback will help make spaces better. The more detail you can go into, the better.": "A visszajelzése segítség a terek javításához. Minél részletesebb annál jobb.", "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Távozás után %(brand)s Terek nélkül lesz újra betöltve. A közösségek és egyedi címkék újra megjelennek.", - "Message search initialisation failed": "Üzenet keresés beállítása sikertelen" + "Message search initialisation failed": "Üzenet keresés beállítása sikertelen", + "Space Autocomplete": "Tér automatikus kiegészítése", + "Go to my space": "Irány a teréhez", + "Spaces are a beta feature.": "A terek béta állapotban van.", + "Search names and descriptions": "Nevek és leírások keresése", + "You may contact me if you have any follow up questions": "Ha további kérdés merülne fel, kapcsolatba léphetnek velem", + "sends space invaders": "space invaders küldése", + "Sends the given message with a space themed effect": "Üzenet küldése világűrös effekttel", + "See when people join, leave, or are invited to your active room": "Emberek belépésének, távozásának vagy meghívásának a megjelenítése az aktív szobájában", + "Kick, ban, or invite people to your active room, and make you leave": "Kirúgni, kitiltani vagy meghívni embereket az aktív szobába és, hogy ön elhagyja a szobát", + "See when people join, leave, or are invited to this room": "Emberek belépésének, távozásának vagy meghívásának a megjelenítése ebben a szobában", + "Kick, ban, or invite people to this room, and make you leave": "Kirúgni, kitiltani vagy meghívni embereket ebbe a szobába és, hogy ön elhagyja a szobát" } diff --git a/src/i18n/strings/is.json b/src/i18n/strings/is.json index 03fa871f29..35f5342b30 100644 --- a/src/i18n/strings/is.json +++ b/src/i18n/strings/is.json @@ -716,5 +716,9 @@ "%(duration)sm": "%(duration)sm", "%(duration)ss": "%(duration)ss", "Emoji picker": "Tjáningartáknmyndvalmynd", - "Show less": "Sýna minna" + "Show less": "Sýna minna", + "%(count)s messages deleted.|one": "%(count)s skilaboð eytt.", + "%(count)s messages deleted.|other": "%(count)s skilaboðum eytt.", + "Message deleted on %(date)s": "Skilaboð eytt á %(date)s", + "Message edits": "Skilaboðs breytingar" } diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index d109837bb1..585ee8ba3a 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -3367,5 +3367,13 @@ "Send and receive voice messages": "Invia e ricevi messaggi vocali", "Your feedback will help make spaces better. The more detail you can go into, the better.": "La tua opinione aiuterà a migliorare gli spazi. Più dettagli dai, meglio è.", "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Se esci, %(brand)s si ricaricherà con gli spazi disattivati. Le comunità e le etichette personalizzate saranno di nuovo visibili.", - "Message search initialisation failed": "Inizializzazione ricerca messaggi fallita" + "Message search initialisation failed": "Inizializzazione ricerca messaggi fallita", + "Space Autocomplete": "Autocompletamento spazio", + "Go to my space": "Vai nel mio spazio", + "sends space invaders": "invia space invaders", + "Sends the given message with a space themed effect": "Invia il messaggio con un effetto a tema spaziale", + "Kick, ban, or invite people to your active room, and make you leave": "Buttare fuori, bandire o invitare persone nella tua stanza attiva e farti uscire", + "See when people join, leave, or are invited to this room": "Vedere quando le persone entrano, escono o sono invitate in questa stanza", + "Kick, ban, or invite people to this room, and make you leave": "Buttare fuori, bandire o invitare persone in questa stanza e farti uscire", + "See when people join, leave, or are invited to your active room": "Vedere quando le persone entrano, escono o sono invitate nella tua stanza attiva" } diff --git a/src/i18n/strings/ja.json b/src/i18n/strings/ja.json index 4eb49e45e2..495e240051 100644 --- a/src/i18n/strings/ja.json +++ b/src/i18n/strings/ja.json @@ -351,7 +351,7 @@ "Mirror local video feed": "ローカルビデオ映像送信", "Send analytics data": "分析データを送信する", "Enable inline URL previews by default": "デフォルトでインライン URL プレビューを有効にする", - "Enable URL previews for this room (only affects you)": "この部屋の URL プレビューを有効にする (あなたにのみ影響する)", + "Enable URL previews for this room (only affects you)": "この部屋の URL プレビューを有効にする (あなたにのみ適用)", "Enable URL previews by default for participants in this room": "この部屋の参加者のためにデフォルトで URL プレビューを有効にする", "Room Colour": "部屋の色", "Enable widget screenshots on supported widgets": "サポートされているウィジェットでウィジェットのスクリーンショットを有効にする", @@ -502,10 +502,10 @@ "You have disabled URL previews by default.": "デフォルトで 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 プレビューが無効です。", - "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 プレビューはデフォルトで無効になっており、あなたのホームサーバー(プレビューを作成する場所)がこの部屋に表示されているリンクに関する情報を収集できないようにしています。", + "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": "URL プレビュー", "Historical": "履歴のある", - "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プレビューが表示され、タイトル、説明、ウェブサイトからの画像など、そのリンクに関する詳細情報が表示されます。", + "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 プレビューとして表示されます。", "Error decrypting audio": "オーディオの復号化エラー", "Error decrypting attachment": "添付ファイルの復号化エラー", "Decrypt %(text)s": "%(text)s を復号", @@ -753,8 +753,8 @@ "Community %(groupId)s not found": "コミュニティ %(groupId)s が見つかりません", "Failed to load %(groupId)s": "%(groupId)s をロードできませんでした", "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」から退出してよろしいですか?", + "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」から退出してよろしいですか?", "Failed to leave room": "部屋からの退出に失敗しました", "Can't leave Server Notices room": "サーバー通知部屋を離れることはできません", "This room is used for important messages from the Homeserver, so you cannot leave it.": "この部屋はホームサーバーからの重要なメッセージに使用されるため、そこを離れることはできません。", @@ -2406,7 +2406,7 @@ "Suggested Rooms": "おすすめの部屋", "Explore space rooms": "スペース内の部屋を探索します", "You do not have permissions to add rooms to this space": "このスペースに部屋を追加する権限がありません", - "Add existing room": "既存の部屋を追加します", + "Add existing room": "既存の部屋を追加", "You do not have permissions to create new rooms in this space": "このスペースに新しい部屋を作成する権限がありません", "Send message": "メッセージを送ります", "Invite to this space": "このスペースに招待します", @@ -2417,8 +2417,8 @@ "Space options": "スペースのオプション", "Space Home": "スペースのホーム", "New room": "新しい部屋", - "Leave space": "スペースを離れる", - "Invite people": "人々を招待する", + "Leave space": "スペースを退出", + "Invite people": "人々を招待", "Share your public space": "公開スペースを共有する", "Invite members": "参加者を招待する", "Invite by email or username": "メールまたはユーザー名で招待する", @@ -2469,7 +2469,7 @@ "Invite to just this room": "この部屋に招待", "Invite to %(spaceName)s": "%(spaceName)s に招待", "Quick actions": "クイックアクション", - "A private space for you and your teammates": "", + "A private space for you and your teammates": "あなたとチームメイトのプライベートスペース", "Me and my teammates": "自分とチームメイト", "Just me": "自分専用", "Make sure the right people have access to %(name)s": "必要な人が %(name)s にアクセスできるようにします", @@ -2477,5 +2477,30 @@ "Beta": "Beta", "Tap for more info": "タップして詳細を表示", "Spaces are a new way to group rooms and people. To join an existing space you'll need an invite.": "スペースは、部屋や人をグループ化する新しい方法です。既存のスペースに参加するには、招待が必要です。", - "Check your devices": "デバイスを確認" + "Check your devices": "デバイスを確認", + "Invite to %(roomName)s": "%(roomName)s へ招待", + "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta は、ウェブ、デスクトップ、Android で利用可能です。お使いのホームサーバーによっては一部機能が利用できない場合があります。", + "%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "%(brand)s はスペースが有効な状態で再読み込みされます。コミュニティとカスタムタグは非表示になります。", + "Communities are changing to Spaces": "コミュニティはスペースに生まれ変わります", + "Beta feedback": "Beta フィードバック", + "%(featureName)s beta feedback": "%(featureName)s Beta フィードバック", + "Send feedback": "フィードバックを送信", + "Manage & explore rooms": "部屋の管理および検索", + "Select a room below first": "以下から部屋を選択してください", + "A private space to organise your rooms": "部屋を整理するためのプライベートスペース", + "Private space": "プライベートスペース", + "Leave Space": "スペースを退出", + "Make this space private": "このスペースを非公開にする", + "Welcome %(name)s": "ようこそ、%(name)s", + "Are you sure you want to leave the space '%(spaceName)s'?": "このスペース「%(spaceName)s」から退出してよろしいですか?", + "This space is not public. You will not be able to rejoin without an invite.": "このスペースは公開されていません。再度参加するには、招待が必要です。", + "You are the only person here. If you leave, no one will be able to join in the future, including you.": "この部屋のメンバーはあなただけです。あなたが退出すると、今後あなたを含めて誰もこの部屋に参加できなくなります。", + "Adding rooms... (%(progress)s out of %(count)s)|one": "部屋を追加中...", + "Adding rooms... (%(progress)s out of %(count)s)|other": "部屋を追加中... (%(progress)s / %(count)s)", + "Skip for now": "スキップ", + "What do you want to organise?": "どれを追加しますか?", + "Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "部屋や会話を追加できます。これはあなた専用のスペースで、他の人からは見えません。後から部屋や会話を追加することもできます。", + "Support": "サポート", + "You can change these anytime.": "ここで入力した情報はいつでも編集できます。", + "Add some details to help people recognise it.": "情報を入力してください。" } diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 867478453f..16f74e7b2d 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -171,7 +171,7 @@ "Fill screen": "Scherm vullen", "Filter room members": "Gespreksleden filteren", "Forget room": "Gesprek vergeten", - "For security, this session has been signed out. Please sign in again.": "Wegens veiligheidsredenen is deze sessie afgemeld. Gelieve u opnieuw aan te melden.", + "For security, this session has been signed out. Please sign in again.": "Wegens veiligheidsredenen is deze sessie uitgelogd. Gelieve opnieuw inloggen.", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s van %(fromPowerLevel)s naar %(toPowerLevel)s", "Guests cannot join this room even if explicitly invited.": "Gasten - zelfs speficiek uitgenodigde - kunnen niet aan dit gesprek deelnemen.", "Hangup": "Ophangen", @@ -249,7 +249,7 @@ "%(senderName)s set a profile picture.": "%(senderName)s heeft een profielfoto ingesteld.", "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s heeft %(displayName)s als weergavenaam aangenomen.", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Tijd in 12-uursformaat tonen (bv. 2:30pm)", - "Signed Out": "Afgemeld", + "Signed Out": "Uitgelogd", "Sign in": "Inloggen", "Sign out": "Uitloggen", "%(count)s of your messages have not been sent.|other": "Enkele van uw berichten zijn niet verstuurd.", @@ -350,8 +350,8 @@ "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Weet u zeker dat u deze gebeurtenis wilt verwijderen? Besef wel dat het verwijderen van een van een gespreksnaams- of onderwerpswijziging die wijziging mogelijk teniet doet.", "Unknown error": "Onbekende fout", "Incorrect password": "Onjuist wachtwoord", - "Unable to restore session": "Sessieherstel lukt niet", - "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.": "Als u reeds een recentere versie van %(brand)s heeft gebruikt is uw sessie mogelijk onverenigbaar met deze versie. Sluit dit venster en ga terug naar die recentere versie.", + "Unable to restore session": "Herstellen van sessie mislukt", + "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.": "Als u een recentere versie van %(brand)s heeft gebruikt is uw sessie mogelijk niet geschikt voor deze versie. Sluit dit venster en ga terug naar die recentere versie.", "Unknown Address": "Onbekend adres", "ex. @bob:example.com": "bv. @jan:voorbeeld.com", "Add User": "Gebruiker toevoegen", @@ -802,7 +802,7 @@ "Send Logs": "Logs versturen", "Refresh": "Herladen", "We encountered an error trying to restore your previous session.": "Het herstel van uw vorige sessie is mislukt.", - "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Het legen van de opslag van uw browser zal het probleem misschien verhelpen, maar zal u ook uitloggen en uw gehele versleutelde gespreksgeschiedenis onleesbaar maken.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Het wissen van de browseropslag zal het probleem misschien verhelpen, maar zal u ook uitloggen en uw gehele versleutelde gespreksgeschiedenis onleesbaar maken.", "Collapse Reply Thread": "Reactieketting dichtvouwen", "Can't leave Server Notices room": "Kan servermeldingsgesprek niet verlaten", "This room is used for important messages from the Homeserver, so you cannot leave it.": "Dit gesprek is bedoeld voor belangrijke berichten van de homeserver, dus u kunt het niet verlaten.", @@ -1203,7 +1203,7 @@ "Please contact your service administrator to continue using this service.": "Gelieve contact op te nemen met uw dienstbeheerder om deze dienst te blijven gebruiken.", "Failed to perform homeserver discovery": "Ontdekken van homeserver is mislukt", "Sign in with single sign-on": "Inloggen met eenmalig inloggen", - "Create account": "Account aanmaken", + "Create account": "Registeren", "Registration has been disabled on this homeserver.": "Registratie is uitgeschakeld op deze homeserver.", "Unable to query for supported registration methods.": "Kan ondersteunde registratiemethoden niet opvragen.", "Create your account": "Maak uw account aan", @@ -1390,7 +1390,7 @@ "Failed to re-authenticate": "Opnieuw inloggen is mislukt", "Enter your password to sign in and regain access to your account.": "Voer uw wachtwoord in om u aan te melden en toegang tot uw account te herkrijgen.", "Forgotten your password?": "Wachtwoord vergeten?", - "You're signed out": "U bent afgemeld", + "You're signed out": "U bent uitgelogd", "Clear personal data": "Persoonlijke gegevens wissen", "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "Laat ons weten wat er verkeerd is gegaan, of nog beter, maak een foutrapport aan op GitHub, waarin u het probleem beschrijft.", "Identity Server": "Identiteitsserver", @@ -1750,7 +1750,7 @@ "exists": "aanwezig", "Sign In or Create Account": "Meld u aan of maak een account aan", "Use your account or create a new one to continue.": "Gebruik uw bestaande account of maak een nieuwe aan om verder te gaan.", - "Create Account": "Account aanmaken", + "Create Account": "Registeren", "Displays information about a user": "Geeft informatie weer over een gebruiker", "Order rooms by name": "Gesprekken sorteren op naam", "Show rooms with unread notifications first": "Gesprekken met ongelezen meldingen eerst tonen", @@ -2775,7 +2775,7 @@ "Attach files from chat or just drag and drop them anywhere in a room.": "Voeg bestanden toe vanuit het gesprek of sleep ze in een gesprek.", "No files visible in this room": "Geen bestanden zichtbaar in dit gesprek", "Sign in with SSO": "Inloggen met SSO", - "Use email to optionally be discoverable by existing contacts.": "Gebruik e-mail ook om optioneel ontdekt te worden door bestaande contacten.", + "Use email to optionally be discoverable by existing contacts.": "Optioneel kunt u uw e-mail ook gebruiken om ontdekt te worden door al bestaande contacten.", "Use email or phone to optionally be discoverable by existing contacts.": "Gebruik e-mail of telefoon om optioneel ontdekt te kunnen worden door bestaande contacten.", "Add an email to be able to reset your password.": "Voeg een e-mail toe om uw wachtwoord te kunnen resetten.", "Forgot password?": "Wachtwoord vergeten?", @@ -3211,7 +3211,7 @@ "To view %(spaceName)s, turn on the Spaces beta": "Om %(spaceName)s te bekijken moet u de Spaces beta inschakelen", "Select a room below first": "Start met selecteren van een gesprek hieronder", "Communities are changing to Spaces": "Gemeenschappen worden vervangen door Spaces", - "Join the beta": "Aan beta deelnemen", + "Join the beta": "Beta inschakelen", "Leave the beta": "Beta verlaten", "Beta": "Beta", "Tap for more info": "Klik voor meer info", @@ -3235,10 +3235,10 @@ "Please enter a name for the space": "Vul een naam in voor deze space", "Connecting": "Verbinden", "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Peer-to-peer voor 1op1 oproepen toestaan (als u dit inschakelt kunnen andere personen mogelijk uw ipadres zien)", - "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta beschikbaar voor web, desktop en Android. Sommige functies zijn nog niet beschikbaar op uw homeserver.", + "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "De beta is beschikbaar voor web, desktop en Android. Sommige functies zijn nog niet beschikbaar op uw homeserver.", "You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "U kunt de beta elk moment verlaten via instellingen of door op de beta badge hierboven te klikken.", "%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "%(brand)s zal herladen met Spaces ingeschakeld. Gemeenschappen en labels worden verborgen.", - "Beta available for web, desktop and Android. Thank you for trying the beta.": "Beta beschikbaar voor web, desktop en Android. Bedankt dat u de beta wilt proberen.", + "Beta available for web, desktop and Android. Thank you for trying the beta.": "De beta is beschikbaar voor web, desktop en Android. Bedankt dat u de beta wilt proberen.", "%(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "%(brand)s zal herladen met Spaces uitgeschakeld. Gemeenschappen en labels zullen weer zichtbaar worden.", "Spaces are a new way to group rooms and people.": "Spaces zijn de nieuwe manier om gesprekken en personen te groeperen.", "Message search initialisation failed": "Zoeken in berichten opstarten is mislukt", @@ -3253,5 +3253,13 @@ "Add reaction": "Reactie toevoegen", "Send and receive voice messages": "Stuur en ontvang spraakberichten", "Your feedback will help make spaces better. The more detail you can go into, the better.": "Uw feedback maakt spaces beter. Hoe meer details u kan geven, des te beter.", - "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Als u de pagina nu verlaat zal %(brand)s herladen met Spaces uitgeschakeld. Gemeenschappen en labels zullen weer zichtbaar worden." + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Als u de pagina nu verlaat zal %(brand)s herladen met Spaces uitgeschakeld. Gemeenschappen en labels zullen weer zichtbaar worden.", + "Space Autocomplete": "Space Autocomplete", + "Go to my space": "Ga naar mijn space", + "sends space invaders": "verstuur space invaders", + "Sends the given message with a space themed effect": "Verstuur het bericht met een space-thema-effect", + "See when people join, leave, or are invited to your active room": "Zie wanneer personen deelnemen, vertrekken of worden uitgenodigd in uw actieve gesprek", + "Kick, ban, or invite people to your active room, and make you leave": "Verwijder, verban of nodig personen uit voor uw actieve gesprek en uzelf laten vertrekken", + "See when people join, leave, or are invited to this room": "Zie wanneer personen deelnemen, vertrekken of worden uitgenodigd voor dit gesprek", + "Kick, ban, or invite people to this room, and make you leave": "Verwijder, verban of verwijder personen uit dit gesprek en uzelf laten vertrekken" } diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 8935b5e348..bd294093f9 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -3356,5 +3356,10 @@ "Beta available for web, desktop and Android. Thank you for trying the beta.": "Beta e gatshme për web, desktop dhe Android. Faleminderit që provoni beta-n.", "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Nëse ikni, %(brand)s-i do të ringarkohet me Hapësira të çaktivizuara. Bashkësitë dhe etiketat vetjake do të jenë sërish të dukshme.", "Spaces are a new way to group rooms and people.": "Hapësirat janë një rrugë e re për të grupuar dhoma dhe njerëz.", - "Message search initialisation failed": "Dështoi gatitje kërkimi mesazhesh" + "Message search initialisation failed": "Dështoi gatitje kërkimi mesazhesh", + "Go to my space": "Kalo te hapësira ime", + "sends space invaders": "dërgon pushtues hapësire", + "Sends the given message with a space themed effect": "E dërgon mesazhin e dhënë me një efekt teme hapësinore", + "See when people join, leave, or are invited to your active room": "Shihni kur persona vijnë, ikin ose janë ftuar në dhomën tuaj aktive", + "See when people join, leave, or are invited to this room": "Shihni kur persona vijnë, ikin ose janë ftuar në këtë dhomë" } diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index 1337dc47b7..a50c039e9e 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -3297,5 +3297,13 @@ "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Om du lämnar så kommer %(brand)s att ladda om med utrymmen inaktiverade. Gemenskaper och anpassade taggar kommer att synas igen.", "Spaces are a new way to group rooms and people.": "Utrymmen är nya sätt att gruppera rum och personer.", "This is an experimental feature. For now, new users receiving an invite will have to open the invite on to actually join.": "Det här är en experimentell funktion. För tillfället så behöver nya inbjudna användare öppna inbjudan på för att faktiskt gå med.", - "To join %(spaceName)s, turn on the Spaces beta": "För att gå med i %(spaceName)s, aktivera utrymmesbetan" + "To join %(spaceName)s, turn on the Spaces beta": "För att gå med i %(spaceName)s, aktivera utrymmesbetan", + "Space Autocomplete": "Utrymmesautokomplettering", + "Go to my space": "Gå till mitt utrymme", + "sends space invaders": "skickar Space Invaders", + "Sends the given message with a space themed effect": "Skickar det givna meddelandet med en effekt med rymdtema", + "See when people join, leave, or are invited to your active room": "Se när folk går med, lämnar eller bjuds in till ditt aktiva rum", + "Kick, ban, or invite people to your active room, and make you leave": "Kicka, banna eller bjuda in folk till ditt aktiva rum, och tvinga dig att lämna", + "See when people join, leave, or are invited to this room": "Se när folk går med, lämnar eller bjuds in till det här rummet", + "Kick, ban, or invite people to this room, and make you leave": "Kicka, banna eller bjuda in folk till det här rummet, och tvinga dig att lämna" } diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json index 6afe74dbee..af02a40587 100644 --- a/src/i18n/strings/zh_Hans.json +++ b/src/i18n/strings/zh_Hans.json @@ -51,7 +51,7 @@ "Invalid Email Address": "邮箱地址格式错误", "Invalid file%(extra)s": "无效文件%(extra)s", "Return to login screen": "返回登录页面", - "%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s 没有通知发送权限 - 请检查您的浏览器设置", + "%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s 没有通知发送权限 - 请检查你的浏览器设置", "%(brand)s was not given permission to send notifications - please try again": "%(brand)s 没有通知发送权限 - 请重试", "%(brand)s version:": "%(brand)s 版本:", "Room %(roomId)s not visible": "聊天室 %(roomId)s 已隐藏", @@ -65,7 +65,7 @@ "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s 向 %(targetDisplayName)s 发了加入聊天室的邀请。", "Server error": "服务器错误", "Server may be unavailable, overloaded, or search timed out :(": "服务器可能不可用、超载,或者搜索超时 :(", - "Server may be unavailable, overloaded, or you hit a bug.": "当前服务器可能处于不可用或过载状态,或者您遇到了一个 bug。", + "Server may be unavailable, overloaded, or you hit a bug.": "当前服务器可能处于不可用或过载状态,或者你遇到了一个 bug。", "Server unavailable, overloaded, or something else went wrong.": "服务器可能不可用、超载,或者其他东西出错了.", "Session ID": "会话 ID", "%(senderName)s set a profile picture.": "%(senderName)s 设置了头像。", @@ -272,7 +272,7 @@ "Upload file": "上传文件", "Usage": "用法", "Who can read history?": "谁可以阅读历史消息?", - "You are not in this room.": "您不在此聊天室中。", + "You are not in this room.": "你不在此聊天室中。", "You have no visible notifications": "没有可见的通知", "Not a valid %(brand)s keyfile": "不是有效的 %(brand)s 密钥文件", "%(targetName)s accepted an invitation.": "%(targetName)s 已接受邀请。", @@ -310,11 +310,11 @@ "(no answer)": "(无回复)", "Who can access this room?": "谁有权访问此聊天室?", "You are already in a call.": "您正在通话。", - "You do not have permission to do that in this room.": "您没有进行此操作的权限。", + "You do not have permission to do that in this room.": "你没有进行此操作的权限。", "You cannot place VoIP calls in this browser.": "无法在此浏览器中发起 VoIP 通话。", - "You do not have permission to post to this room": "您没有在此聊天室发送消息的权限", - "You seem to be in a call, are you sure you want to quit?": "您似乎正在进行通话,确定要退出吗?", - "You seem to be uploading files, are you sure you want to quit?": "您似乎正在上传文件,确定要退出吗?", + "You do not have permission to post to this room": "你没有在此聊天室发送消息的权限", + "You seem to be in a call, are you sure you want to quit?": "你似乎正在进行通话,确定要退出吗?", + "You seem to be uploading files, are you sure you want to quit?": "你似乎正在上传文件,确定要退出吗?", "Upload an avatar:": "上传头像:", "An error occurred: %(error_string)s": "发生了一个错误: %(error_string)s", "There are no visible files in this room": "此聊天室中没有可见的文件", @@ -327,13 +327,13 @@ "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s 移除了聊天室头像。", "Something went wrong!": "出了点问题!", "If you already have a Matrix account you can log in instead.": "若您已经拥有 Matrix 帐号,您也可以 登录。", - "Do you want to set an email address?": "您想要设置一个邮箱地址吗?", + "Do you want to set an email address?": "你想要设置一个邮箱地址吗?", "Upload new:": "上传新的:", "Username invalid: %(errMessage)s": "用户名无效: %(errMessage)s", "Verification Pending": "验证等待中", "(unknown failure: %(reason)s)": "(未知错误:%(reason)s)", "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s 收回了 %(targetName)s 的邀请。", - "You cannot place a call with yourself.": "您无法向自己发起通话。", + "You cannot place a call with yourself.": "你无法向自己发起通话。", "You have disabled URL previews by default.": "你已经默认禁用链接预览。", "You have enabled URL previews by default.": "你已经默认启用链接预览。", "Set a display name:": "设置昵称:", @@ -385,10 +385,10 @@ "%(widgetName)s widget removed by %(senderName)s": "%(senderName)s 移除了 %(widgetName)s 挂件", "%(widgetName)s widget modified by %(senderName)s": "%(senderName)s 修改了 %(widgetName)s 挂件", "Unpin Message": "取消置顶消息", - "Add rooms to this community": "添加聊天室到此社区", + "Add rooms to this community": "添加聊天室到此社群", "Call Failed": "呼叫失败", - "Invite new community members": "邀请新社区成员", - "Invite to Community": "邀请到社区", + "Invite new community members": "邀请新社群成员", + "Invite to Community": "邀请到社群", "Ignored user": "已忽略的用户", "You are now ignoring %(userId)s": "你忽略了 %(userId)s", "Unignored user": "未忽略的用户", @@ -450,28 +450,28 @@ "collapse": "折叠", "expand": "展开", "email address": "邮箱地址", - "You have entered an invalid address.": "您输入了无效的地址。", + "You have entered an invalid address.": "你输入了无效的地址。", "Leave": "退出", "Description": "描述", "Warning": "警告", "Room Notification": "聊天室通知", - "The platform you're on": "您使用的平台是", + "The platform you're on": "你使用的平台是", "The version of %(brand)s": "%(brand)s 版本", - "Your language of choice": "您选择的语言是", - "Whether or not you're using the Richtext mode of the Rich Text Editor": "您是否正在使用富文本编辑器的富文本模式", - "Your homeserver's URL": "您的主服务器的链接", + "Your language of choice": "你选择的语言是", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "你是否正在使用富文本编辑器的富文本模式", + "Your homeserver's URL": "你的主服务器的链接", "The information being sent to us to help make %(brand)s better includes:": "正在给我们发送信息以帮助 %(brand)s:", - "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "此页面中含有可用于识别您身份的信息,比如聊天室、用户或群组 ID,这些数据会在发送到服务器前被移除。", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "此页面中含有可用于识别你身份的信息,比如聊天室、用户或群组 ID,这些数据会在发送到服务器前被移除。", "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(monthName)s %(day)s %(time)s, %(weekDayName)s", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(fullYear)s %(monthName)s %(day)s, %(weekDayName)s", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(fullYear)s %(monthName)s %(day)s %(time)s, %(weekDayName)s", - "Who would you like to add to this community?": "您想把谁添加至此社区中?", - "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "警告:您添加的一切用户都将会对一切知道此社区的 ID 的人公开", - "Which rooms would you like to add to this community?": "您想把哪个聊天室添加至此社区中?", - "Add rooms to the community": "添加聊天室到社区", - "Add to community": "添加到社区", - "Failed to invite users to community": "邀请用户到社区失败", + "Who would you like to add to this community?": "你想把谁添加至此社群中?", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "警告:你添加的一切用户都将会对一切知道此社群的 ID 的人公开", + "Which rooms would you like to add to this community?": "你想把哪个聊天室添加至此社群中?", + "Add rooms to the community": "添加聊天室到社群", + "Add to community": "添加到社群", + "Failed to invite users to community": "邀请用户到社群失败", "Enable inline URL previews by default": "默认启用链接预览", "Disinvite this user?": "是否不再邀请此用户?", "Kick this user?": "是否移除此用户?", @@ -485,24 +485,24 @@ "Members only (since the point in time of selecting this option)": "仅成员(从选中此选项时开始)", "Members only (since they were invited)": "只有成员(从他们被邀请开始)", "Members only (since they joined)": "只有成员(从他们加入开始)", - "Invalid community ID": "无效的社区 ID", - "Create Community": "创建社区", - "Community Name": "社区名称", - "Community ID": "社区 ID", + "Invalid community ID": "无效的社群 ID", + "Create Community": "创建社群", + "Community Name": "社群名称", + "Community ID": "社群 ID", "example": "示例", "Add a Room": "添加聊天室", "Add a User": "添加用户", "Unable to accept invite": "无法接受邀请", "Unable to reject invite": "无法拒绝邀请", - "Leave Community": "退出社区", - "Community Settings": "社区设置", - "Community %(groupId)s not found": "找不到社区 %(groupId)s", - "Your Communities": "我的社区", + "Leave Community": "退出社群", + "Community Settings": "社群设置", + "Community %(groupId)s not found": "找不到社群 %(groupId)s", + "Your Communities": "我的社群", "Failed to set direct chat tag": "无法设定私聊标签", "Failed to remove tag %(tagName)s from room": "移除聊天室标签 %(tagName)s 失败", "Failed to add tag %(tagName)s to room": "无法为聊天室新增标签 %(tagName)s", "Submit debug logs": "提交调试日志", - "Show these rooms to non-members on the community page and room list?": "在社区页面与聊天室列表上对非社区成员显示这些聊天室?", + "Show these rooms to non-members on the community page and room list?": "在社群页面与聊天室列表上对非社群成员显示这些聊天室?", "Failed to invite users to %(groupId)s": "邀请用户到 %(groupId)s 失败", "Failed to invite the following users to %(groupId)s:": "邀请下列用户到 %(groupId)s 失败:", "Failed to add the following rooms to %(groupId)s:": "添加以下聊天室到 %(groupId)s 失败:", @@ -511,10 +511,10 @@ "To use it, just wait for autocomplete results to load and tab through them.": "若要使用自动补全,只要等待自动补全结果加载完成,按 Tab 键切换即可。", "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s 将他们的昵称修改成了 %(displayName)s 。", "Stickerpack": "贴图集", - "You don't currently have any stickerpacks enabled": "您目前没有启用任何贴图集", + "You don't currently have any stickerpacks enabled": "你目前没有启用任何贴图集", "Key request sent.": "已发送密钥共享请求。", - "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "如果您是房间中最后一位有权限的用户,在您降低自己的权限等级后将无法撤回此修改,因为你将无法重新获得权限。", - "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "您将无法撤回此修改,因为您正在将此用户的滥权等级提升至与你相同。", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "如果你是房间中最后一位有权限的用户,在你降低自己的权限等级后将无法撤回此修改,因为你将无法重新获得权限。", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "你将无法撤回此修改,因为你正在将此用户的滥权等级提升至与你相同。", "Unmute": "取消静音", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s(滥权等级 %(powerLevelNumber)s)", "Hide Stickers": "隐藏贴图", @@ -528,23 +528,23 @@ "Offline for %(duration)s": "已离线 %(duration)s", "Unknown for %(duration)s": "未知状态已持续 %(duration)s", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "%(displayName)s (%(userName)s) 在 %(dateTime)s 看到这里", - "'%(groupId)s' is not a valid community ID": "“%(groupId)s” 不是有效的社区 ID", + "'%(groupId)s' is not a valid community ID": "“%(groupId)s” 不是有效的社群 ID", "Flair": "个性徽章", "Code": "代码", - "Remove from community": "从社区中移除", - "Disinvite this user from community?": "是否不再邀请此用户加入本社区?", - "Remove this user from community?": "是否要从社区中移除此用户?", + "Remove from community": "从社群中移除", + "Disinvite this user from community?": "是否不再邀请此用户加入本社群?", + "Remove this user from community?": "是否要从社群中移除此用户?", "Failed to withdraw invitation": "撤回邀请失败", "Failed to remove user from community": "移除用户失败", - "Filter community members": "过滤社区成员", + "Filter community members": "过滤社群成员", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "你确定要从 %(groupId)s 中移除 %(roomName)s 吗?", - "Removing a room from the community will also remove it from the community page.": "从社区中移除房间时,同时也会将其从社区页面中移除。", - "Failed to remove room from community": "从社区中移除聊天室失败", + "Removing a room from the community will also remove it from the community page.": "从社群中移除房间时,同时也会将其从社群页面中移除。", + "Failed to remove room from community": "从社群中移除聊天室失败", "Failed to remove '%(roomName)s' from %(groupId)s": "从 %(groupId)s 中移除 “%(roomName)s” 失败", - "Only visible to community members": "仅对社区成员可见", - "Filter community rooms": "过滤社区聊天室", - "You're not currently a member of any communities.": "您目前不是任何一个社区的成员。", - "Communities": "社区", + "Only visible to community members": "仅对社群成员可见", + "Filter community rooms": "过滤社群聊天室", + "You're not currently a member of any communities.": "你目前不是任何一个社群的成员。", + "Communities": "社群", "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s 已加入 %(count)s 次", "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)s 已加入", @@ -571,13 +571,13 @@ "%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)s 撤回了他们的邀请共 %(count)s 次", "%(oneUser)shad their invitation withdrawn %(count)s times|one": "%(oneUser)s 撤回了他们的邀请", "In reply to ": "回复给 ", - "Community IDs cannot be empty.": "社区 ID 不能为空。", - "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "社区 ID 只能包含 a-z、0-9 或 “=_-./” 等字符", - "Something went wrong whilst creating your community": "创建社区时出现问题", - "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,则您的会话可能与当前版本不兼容。请关闭此窗口并使用最新版本。", - "Showing flair for these communities:": "显示这些社区的个性徽章:", - "This room is not showing flair for any communities": "此聊天室没有显示任何社区的个性徽章", - "New community ID (e.g. +foo:%(localDomain)s)": "新社区 ID(例子:+foo:%(localDomain)s)", + "Community IDs cannot be empty.": "社群 ID 不能为空。", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "社群 ID 只能包含 a-z、0-9 或 “=_-./” 等字符", + "Something went wrong whilst creating your community": "创建社群时出现问题", + "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,则你的会话可能与当前版本不兼容。请关闭此窗口并使用最新版本。", + "Showing flair for these communities:": "显示这些社群的个性徽章:", + "This room is not showing flair for any communities": "此聊天室没有显示任何社群的个性徽章", + "New community ID (e.g. +foo:%(localDomain)s)": "新社群 ID(例子:+foo:%(localDomain)s)", "URL previews are enabled by default for participants in this room.": "此聊天室默认启用链接预览。", "URL previews are disabled by default for participants in this room.": "此聊天室默认禁用链接预览。", "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s 将聊天室的头像更改为 ", @@ -585,56 +585,56 @@ "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix 聊天室 ID", "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n": "", - "Add rooms to the community summary": "将聊天室添加到社区简介中", - "Which rooms would you like to add to this summary?": "您想要将哪个聊天室添加到社区简介?", + "Add rooms to the community summary": "将聊天室添加到社群简介中", + "Which rooms would you like to add to this summary?": "你想要将哪个聊天室添加到社群简介?", "Add to summary": "添加到简介", "Failed to add the following rooms to the summary of %(groupId)s:": "添加以下聊天室到 %(groupId)s 的简介中时失败:", "Failed to remove the room from the summary of %(groupId)s": "从 %(groupId)s 的简介中移除此聊天室时失败", - "The room '%(roomName)s' could not be removed from the summary.": "聊天室 “%(roomName)s” 无法从社区简介中移除。", - "Failed to update community": "更新社区简介失败", - "Unable to leave community": "无法退出社区", + "The room '%(roomName)s' could not be removed from the summary.": "聊天室 “%(roomName)s” 无法从社群简介中移除。", + "Failed to update community": "更新社群简介失败", + "Unable to leave community": "无法退出社群", "Leave %(groupName)s?": "退出 %(groupName)s?", "Featured Rooms:": "核心聊天室:", "Featured Users:": "核心用户:", - "Join this community": "加入此社区", - "%(inviter)s has invited you to join this community": "%(inviter)s 邀请您加入此社区", + "Join this community": "加入此社群", + "%(inviter)s has invited you to join this community": "%(inviter)s 邀请你加入此社群", "Failed to add the following users to the summary of %(groupId)s:": "将下列用户添加至 %(groupId)s 的简介中时失败:", "Failed to remove a user from the summary of %(groupId)s": "从 %(groupId)s 的简介中移除用户时失败", - "You are an administrator of this community": "你是此社区的管理员", - "You are a member of this community": "你是此社区的成员", - "Who can join this community?": "谁可以加入此社区?", + "You are an administrator of this community": "你是此社群的管理员", + "You are a member of this community": "你是此社群的成员", + "Who can join this community?": "谁可以加入此社群?", "Everyone": "所有人", - "Leave this community": "退出此社区", + "Leave this community": "退出此社群", "Long Description (HTML)": "长描述(HTML)", "Old cryptography data detected": "检测到旧的加密数据", - "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的数据,这将导致端到端加密在旧版本中发生故障。在此版本中,使用旧版本交换的端对端加密消息可能无法解密。这也可能导致与此版本交换的消息失败。如果您遇到问题,请退出并重新登录。要保留历史消息,请先导出并在重新登录后导入您的密钥。", - "Did you know: you can use communities to filter your %(brand)s experience!": "你知道吗:你可以将社区用作过滤器以增强你的 %(brand)s 使用体验!", - "Create a new community": "创建新社区", - "Error whilst fetching joined communities": "获取已加入社区列表时出现错误", - "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "创建社区,将用户与聊天室整合在一起!搭建自定义社区主页以在 Matrix 宇宙之中标出您的私人空间。", + "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的数据,这将导致端到端加密在旧版本中发生故障。在此版本中,使用旧版本交换的端对端加密消息可能无法解密。这也可能导致与此版本交换的消息失败。如果你遇到问题,请退出并重新登录。要保留历史消息,请先导出并在重新登录后导入你的密钥。", + "Did you know: you can use communities to filter your %(brand)s experience!": "你知道吗:你可以将社群用作过滤器以增强你的 %(brand)s 使用体验!", + "Create a new community": "创建新社群", + "Error whilst fetching joined communities": "获取已加入社群列表时出现错误", + "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "创建社群,将用户与聊天室整合在一起!搭建自定义社群主页以在 Matrix 宇宙之中标出你的私人空间。", "%(count)s of your messages have not been sent.|one": "您的消息尚未发送。", "Uploading %(filename)s and %(count)s others|other": "正在上传 %(filename)s 与其他 %(count)s 个文件", "Uploading %(filename)s and %(count)s others|zero": "正在上传 %(filename)s", "Uploading %(filename)s and %(count)s others|one": "正在上传 %(filename)s 与其他 %(count)s 个文件", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "隐私对我们而言重要至极,所以我们不会在分析统计服务中收集任何个人信息或者可用于识别身份的数据。", "Learn more about how we use analytics.": "进一步了解我们如何使用分析统计服务。", - "Please note you are logging into the %(hs)s server, not matrix.org.": "请注意,您正在登录 %(hs)s,而非 matrix.org。", + "Please note you are logging into the %(hs)s server, not matrix.org.": "请注意,你正在登录 %(hs)s,而非 matrix.org。", "This homeserver doesn't offer any login flows which are supported by this client.": "此主服务器不兼容本客户端支持的任何登录方式。", "Opens the Developer Tools dialog": "打开开发者工具窗口", "Notify the whole room": "通知聊天室全体成员", - "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 客户端,以便让别的客户端在未收到密钥的情况下解密这些消息。", - "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "导出的文件将允许任何可以读取它的人解密任何他们可以看到的加密消息,因此,您应该小心对待,以确保其安全。为解决此问题,您应当在下面输入密语以加密导出的数据。只有输入相同的密语才能导入数据。", + "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 客户端,以便让别的客户端在未收到密钥的情况下解密这些消息。", + "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "导出的文件将允许任何可以读取它的人解密任何他们可以看到的加密消息,因此,你应此小心对待,以确保其安全。为解决此问题,你应当在下面输入密语以加密导出的数据。只有输入相同的密语才能导入数据。", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "导出文件受密语保护。必须输入密语以解密此文件。", - "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 客户端中导出的加密密钥文件。导入完成后,您将能够解密那个客户端可以解密的加密消息。", + "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 客户端中导出的加密密钥文件。导入完成后,你将能够解密那个客户端可以解密的加密消息。", "Ignores a user, hiding their messages from you": "忽略用户,隐藏他们发送的消息", "Stops ignoring a user, showing their messages going forward": "解除忽略用户,显示他们的消息", - "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "如果你在 GitHub 提交了一个 bug,调试日志可以帮助我们追踪这个问题。 调试日志包含应用程序使用数据,也就包括您的用户名、您访问的房间或社区的 ID 或别名,以及其他用户的用户名,但不包括聊天记录。", + "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "如果你在 GitHub 提交了一个 bug,调试日志可以帮助我们追踪这个问题。 调试日志包含应用程序使用数据,也就包括你的用户名、你访问的房间或社群的 ID 或别名,以及其他用户的用户名,但不包括聊天记录。", "Tried to load a specific point in this room's timeline, but was unable to find it.": "尝试加载此聊天室的时间线的特定时间点,但是无法找到。", "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "现在 重新发送消息取消发送 。", "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "現在 重新发送消息取消发送 。你也可以单独选择消息以重新发送或取消。", "Visibility in Room List": "是否在聊天室目录中可见", - "Something went wrong when trying to get your communities.": "获取你加入的社区时发生错误。", - "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "删除挂件时将为聊天室中的所有成员删除。您确定要删除此挂件吗?", + "Something went wrong when trying to get your communities.": "获取你加入的社群时发生错误。", + "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "删除挂件时将为聊天室中的所有成员删除。你确定要删除此挂件吗?", "Fetching third party location failed": "获取第三方位置失败", "Send Account Data": "发送账号数据", "All notifications are currently disabled for all targets.": "目前所有通知都已禁用。", @@ -647,7 +647,7 @@ "Update": "更新", "What's New": "更新内容", "On": "打开", - "Changelog": "变更日志", + "Changelog": "更改日志", "Waiting for response from server": "正在等待服务器响应", "Send Custom Event": "发送自定义事件", "Advanced notification settings": "通知高级设置", @@ -679,7 +679,7 @@ "Collecting app version information": "正在收集应用版本信息", "Keywords": "关键词", "Enable notifications for this account": "对此账号启用通知", - "Invite to this community": "邀请加入此社区", + "Invite to this community": "邀请加入此社群", "Messages containing keywords": "包含 关键词 的消息", "Room not found": "找不到聊天室", "Tuesday": "星期二", @@ -730,7 +730,7 @@ "Back": "返回", "Reply": "回复", "Show message in desktop notification": "在桌面通知中显示信息", - "Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "调试日志包含使用数据(包括您的用户名、您访问过的聊天室/群组的 ID 或别名,以及其他用户的用户名),不含聊天消息。", + "Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "调试日志包含使用数据(包括你的用户名、你访问过的聊天室/群组的 ID 或别名,以及其他用户的用户名),不含聊天消息。", "Unhide Preview": "取消隐藏预览", "Unable to join network": "无法加入网络", "Sorry, your browser is not able to run %(brand)s.": "抱歉,您的浏览器 无法 运行 %(brand)s.", @@ -749,8 +749,8 @@ "Event Type": "事件类型", "Download this file": "下载该文件", "Pin Message": "置顶消息", - "Failed to change settings": "变更设置失败", - "View Community": "查看社区", + "Failed to change settings": "更改设置失败", + "View Community": "查看社群", "Event sent!": "事件已发送!", "View Source": "查看源码", "Event Content": "事件内容", @@ -761,13 +761,13 @@ "You need to be able to invite users to do that.": "你需要有邀请用户的权限才能进行此操作。", "Missing roomId.": "找不到此聊天室 ID 所对应的聊天室。", "e.g. ": "例如:", - "Your device resolution": "您设备的分辨率", + "Your device resolution": "你的设备分辨率", "Always show encryption icons": "总是显示加密标志", - "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 提供的集成。您希望继续吗?", - "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "无法更新聊天室 %(roomName)s 在社区 “%(groupId)s” 中的可见性。", + "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 提供的集成。你希望继续吗?", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "无法更新聊天室 %(roomName)s 在社群 “%(groupId)s” 中的可见性。", "Minimize apps": "最小化应用程序", "Popout widget": "在弹出式窗口中打开挂件", - "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "无法加载被回复的事件,它可能不存在,也可能是您没有权限查看它。", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "无法加载被回复的事件,它可能不存在,也可能是你没有权限查看它。", "And %(count)s more...|other": "和 %(count)s 个其他…", "Try using one of the following valid address types: %(validTypesList)s.": "请尝试使用以下的有效邮箱地址格式中的一种:%(validTypesList)s", "e.g. %(exampleValue)s": "例如:%(exampleValue)s", @@ -775,11 +775,11 @@ "A call is already in progress!": "您已在通话中!", "Send analytics data": "发送统计数据", "Enable widget screenshots on supported widgets": "对支持的挂件启用挂件截图", - "Demote yourself?": "是否降低您自己的权限?", + "Demote yourself?": "是否降低你自己的权限?", "Demote": "降权", "A call is currently being placed!": "正在发起通话!", "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": "你没有在此聊天室发起通话会议的权限", "This event could not be displayed": "无法显示此事件", "Share Link to User": "分享链接给其他用户", "Share room": "分享聊天室", @@ -790,53 +790,53 @@ "The email field must not be blank.": "必须输入电子邮箱。", "The phone number field must not be blank.": "必须输入电话号码。", "The password field must not be blank.": "必须输入密码。", - "Display your community flair in rooms configured to show it.": "在启用“显示徽章”的聊天室中显示本社区的个性徽章。", + "Display your community flair in rooms configured to show it.": "在启用“显示徽章”的聊天室中显示本社群的个性徽章。", "Failed to remove widget": "移除小挂件失败", "An error ocurred whilst trying to remove the widget from the room": "尝试从聊天室中移除小部件时发生了错误", - "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "您确定要移除(删除)此事件吗?注意,如果删除了聊天室名称或话题的修改事件,就会撤销此更改。", - "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "这将使您的账号永远不再可用。您将不能登录,或使用相同的用户 ID 重新注册。您的账号将退出所有已加入的聊天室,身份服务器上的账号信息也会被删除。此操作是不可逆的。", - "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "默认情况下,停用您的账号不会忘记您发送的消息 。如果您希望我们忘记您发送的消息,请勾选下面的选择框。", - "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Matrix 中的(历史)信息可见性类似于电子邮件。我们忘记您的消息意味着您发送的消息将不会被发至新注册或未注册的用户,但是已收到您的消息的注册用户依旧可以看到他们的副本。", + "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "你确定要移除(删除)此事件吗?注意,如果删除了聊天室名称或话题的修改事件,就会撤销此更改。", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "这将使你的账号永远不再可用。你将不能登录,或使用相同的用户 ID 重新注册。你的账号将退出所有已加入的聊天室,身份服务器上的账号信息也会被删除。此操作是不可逆的。", + "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "默认情况下,停用你的账号不会忘记你发送的消息 。如果你希望我们忘记你发送的消息,请勾选下面的选择框。", + "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Matrix 中的(历史)信息可见性类似于电子邮件。我们忘记你的消息意味着你发送的消息将不会被发至新注册或未注册的用户,但是已收到你的消息的注册用户依旧可以看到他们的副本。", "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "请在停用我的账号的同时忘记我发送的所有消息(警告:这将导致未来的用户看到的对话记录不完整)", - "To continue, please enter your password:": "请输入您的密码以继续:", + "To continue, please enter your password:": "请输入你的密码以继续:", "Clear Storage and Sign Out": "清除数据并退出登录", "Send Logs": "发送日志", "Refresh": "刷新", - "Unable to join community": "无法加入社区", + "Unable to join community": "无法加入社群", "The user '%(displayName)s' could not be removed from the summary.": "无法将用户“%(displayName)s”从简介中移除。", - "Who would you like to add to this summary?": "您想将谁添加到简介中?", - "Add users to the community summary": "添加用户至社区简介", + "Who would you like to add to this summary?": "你想将谁添加到简介中?", + "Add users to the community summary": "添加用户至社群简介", "Collapse Reply Thread": "收起回复", "Share Message": "分享消息", "COPY": "复制", "Share Room Message": "分享聊天室消息", - "Share Community": "分享社区", + "Share Community": "分享社群", "Share User": "分享用户", "Share Room": "分享聊天室", - "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "清除本页储存在您浏览器上的数据或许能修复此问题,但也会导致您退出登录并无法读取任何已加密的聊天记录。", - "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.": "清除本页储存在你浏览器上的数据或许能修复此问题,但也会导致你退出登录并无法读取任何已加密的聊天记录。", + "We encountered an error trying to restore your previous session.": "我们在尝试恢复你先前的会话时遇到了错误。", "Link to most recent message": "最新消息的链接", "Link to selected message": "选中消息的链接", - "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "至多半个小时内,其他用户可能看不到您社区的 名称头像 的变化。", - "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "这些聊天室对社区成员可见。社区成员可通过点击来加入它们。", - "Your community hasn't got a Long Description, a HTML page to show to community members.
    Click here to open settings and give it one!": "你的社区没有一个很长的描述,一个HTML页面可以展示给社区成员。
    点击这里即可打开设置添加详细介绍!", + "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "至多半个小时内,其他用户可能看不到你社群的 名称头像 的变化。", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "这些聊天室对社群成员可见。社群成员可通过点击来加入它们。", + "Your community hasn't got a Long Description, a HTML page to show to community members.
    Click here to open settings and give it one!": "你的社群没有一个很长的描述,一个HTML页面可以展示给社群成员。
    点击这里即可打开设置添加详细介绍!", "Failed to load %(groupId)s": "%(groupId)s 加载失败", - "This room is not public. You will not be able to rejoin without an invite.": "此聊天室不是公开聊天室。如果没有成员邀请,您将无法重新加入。", + "This room is not public. You will not be able to rejoin without an invite.": "此聊天室不是公开聊天室。如果没有成员邀请,你将无法重新加入。", "Can't leave Server Notices room": "无法退出服务器公告聊天室", - "This room is used for important messages from the Homeserver, so you cannot leave it.": "此聊天室是用于发布来自主服务器的重要讯息的,所以您不能退出它。", + "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,您必须浏览并同意我们的条款与要求。", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "若要继续使用主服务器 %(homeserverDomain)s,你必须浏览并同意我们的条款与要求。", "Review terms and conditions": "浏览条款与要求", - "To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "若要设置社区过滤器,请将社区头像拖到屏幕最左侧的社区过滤器面板上。单击社区过滤器面板中的社区头像即可过滤出与该社区相关联的房间和人员。", - "You can't send any messages until you review and agree to our terms and conditions.": "在您查看并同意 我们的条款与要求 之前,您不能发送任何消息。", + "To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "若要设置社群过滤器,请将社群头像拖到屏幕最左侧的社群过滤器面板上。单击社群过滤器面板中的社群头像即可过滤出与此社群相关联的房间和人员。", + "You can't send any messages until you review and agree to our terms and conditions.": "在你查看并同意 我们的条款与要求 之前,你不能发送任何消息。", "Clear filter": "清除过滤器", - "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.": "尝试加载此聊天室时间轴上的某处,但你没有查看相关消息的权限。", "No Audio Outputs detected": "未检测到可用的音频输出方式", "Audio Output": "音频输出", "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "已向 %(emailAddress)s 发送了一封电子邮件。点开邮件中的链接后,请点击下面。", "Forces the current outbound group session in an encrypted room to be discarded": "强制丢弃加密聊天室中的当前出站群组会话", "Unable to connect to Homeserver. Retrying...": "无法连接至主服务器。正在重试…", - "Sorry, your homeserver is too old to participate in this room.": "抱歉,因您的主服务器的程序版本过旧,无法加入此聊天室。", + "Sorry, your homeserver is too old to participate in this room.": "抱歉,因你的主服务器的程序版本过旧,无法加入此聊天室。", "Mirror local video feed": "镜像翻转本地视频源", "This room has been replaced and is no longer active.": "此聊天室已被取代,且不再活跃。", "The conversation continues here.": "对话在这里继续。", @@ -854,14 +854,14 @@ "Legal": "法律信息", "This homeserver has hit its Monthly Active User limit.": "此主服务器已达到其每月活跃用户限制。", "This homeserver has exceeded one of its resource limits.": "本服务器已达到其使用量限制之一。", - "Please contact your service administrator to continue using this service.": "请 联系您的服务管理员 以继续使用本服务。", - "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "您的消息未被发送,因为本主服务器已达到其使用量限制之一。请 联系您的服务管理员 以继续使用本服务。", - "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "您的消息未被发送,因为本主服务器已达到其每月活跃用户限制。请 联系您的服务管理员 以继续使用本服务。", - "Please contact your service administrator to continue using the service.": "请 联系您的服务管理员 以继续使用本服务。", - "Please contact your homeserver administrator.": "请 联系您的主服务器管理员。", - "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s 将此聊天室的主地址设为了 %(address)s。", - "%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主地址。", - "Unable to load! Check your network connectivity and try again.": "无法加载!请检查您的网络连接并重试。", + "Please contact your service administrator to continue using this service.": "请 联系你的服务管理员 以继续使用本服务。", + "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "你的消息未被发送,因为本主服务器已达到其使用量限制之一。请 联系你的服务管理员 以继续使用本服务。", + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "你的消息未被发送,因为本主服务器已达到其每月活跃用户限制。请 联系你的服务管理员 以继续使用本服务。", + "Please contact your service administrator to continue using the service.": "请 联系你的服务管理员 以继续使用本服务。", + "Please contact your homeserver administrator.": "请 联系你的主服务器管理员。", + "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s 将此聊天室的主要地址设为了 %(address)s。", + "%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主要地址。", + "Unable to load! Check your network connectivity and try again.": "无法加载!请检查你的网络连接并重试。", "User %(user_id)s does not exist": "用户 %(user_id)s 不存在", "There was an error joining the room": "加入聊天室时发生错误", "Custom user status messages": "自定义用户状态信息", @@ -887,7 +887,7 @@ "Download": "下载", "Retry": "重试", "Go to Settings": "打开设置", - "You do not have permission to invite people to this room.": "您没有权限将其他用户邀请至本聊天室。", + "You do not have permission to invite people to this room.": "你没有权限将其他用户邀请至本聊天室。", "Unknown server error": "未知服务器错误", "Failed to invite users to the room:": "邀请失败:", "No need for symbols, digits, or uppercase letters": "不一定要有符号、数字或大写字母", @@ -895,12 +895,12 @@ "Avoid repeated words and characters": "避免重复词语与字符", "Avoid sequences": "避免递增或递减的序列", "Avoid recent years": "避免年份", - "Avoid years that are associated with you": "避免与您相关联的年份", - "Avoid dates and years that are associated with you": "避免与您相关联的日期与年份", + "Avoid years that are associated with you": "避免与你相关联的年份", + "Avoid dates and years that are associated with you": "避免与你相关联的日期与年份", "Capitalization doesn't help very much": "大写字母并没有很大的作用", "All-uppercase is almost as easy to guess as all-lowercase": "全大写的密码通常比全小写的更容易猜测", "Reversed words aren't much harder to guess": "把单词倒过来不会比原来的难猜很多", - "Whether or not you're logged in (we don't record your username)": "您是否已经登入(我们不会记录您的用户名)", + "Whether or not you're logged in (we don't record your username)": "你是否已经登入(我们不会记录你的用户名)", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "文件 %(fileName)s 超过主服务器的文件大小限制", "Upgrades a room to a new version": "将聊天室升级到新版本", "Gets or sets the room topic": "获取或设置聊天室话题", @@ -952,7 +952,7 @@ "Show avatars in user and room mentions": "在用户和聊天室提及中显示头像", "Enable big emoji in chat": "在聊天中启用大型表情符号", "Send typing notifications": "发送正在输入通知", - "Enable Community Filter Panel": "启用社区筛选器面板", + "Enable Community Filter Panel": "启用社群筛选器面板", "Allow Peer-to-Peer for 1:1 calls": "允许一对一通话使用 P2P", "Prompt before sending invites to potentially invalid matrix IDs": "在发送邀请之前提示可能无效的 Matrix ID", "Messages containing my username": "包含我的用户名的消息", @@ -960,7 +960,7 @@ "Encrypted messages in group chats": "群聊中的加密消息", "The other party cancelled the verification.": "另一方取消了验证。", "Verified!": "已验证!", - "You've successfully verified this user.": "您已成功验证此用户。", + "You've successfully verified this user.": "你已成功验证此用户。", "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 emoji appear on their screen.": "通过在其屏幕上显示以下表情符号来验证此用户。", @@ -1031,10 +1031,10 @@ "Pin": "别针", "Yes": "是", "No": "拒绝", - "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "我们已向您发送了一封电子邮件,以验证您的地址。 请按照里面的说明操作,然后单击下面的按钮。", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "我们已向你发送了一封电子邮件,以验证你的地址。 请按照里面的说明操作,然后单击下面的按钮。", "Email Address": "电子邮箱地址", - "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "您确定吗?如果密钥没有正确地备份您将失去您的加密消息。", - "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "加密消息已使用端对端加密保护。只有您和拥有密钥的收件人可以阅读这些消息。", + "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "你确定吗?如果密钥没有正确地备份你将失去你的加密消息。", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "加密消息已使用端对端加密保护。只有你和拥有密钥的收件人可以阅读这些消息。", "Unable to load key backup status": "无法载入密钥备份状态", "Restore from Backup": "从备份恢复", "Back up your keys before signing out to avoid losing them.": "在登出账号之前请备份密钥以免丢失。", @@ -1053,7 +1053,7 @@ "Language and region": "语言与区域", "Theme": "主题", "Account management": "账号管理", - "Deactivating your account is a permanent action - be careful!": "停用您的账号是一项永久性操作 - 请小心!", + "Deactivating your account is a permanent action - be careful!": "停用你的账号是一项永久性操作 - 请小心!", "General": "通用", "Credits": "感谢", "For help with using %(brand)s, click here.": "对使用 %(brand)s 的说明,请点击 这里。", @@ -1082,7 +1082,7 @@ "Developer options": "开发者选项", "Room Addresses": "聊天室地址", "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.": "历史记录阅读权限的变更只会应用到此聊天室中将来的消息。既有历史记录的可见性将不会变更。", + "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "历史记录阅读权限的更改只会应用到此聊天室中将来的消息。既有历史记录的可见性将不会更改。", "Encryption": "加密", "Once enabled, encryption cannot be disabled.": "加密一经启用,便无法禁用。", "Encrypted": "已加密", @@ -1092,32 +1092,32 @@ "Not now": "现在不要", "Don't ask me again": "不再询问", "Add some now": "立即添加", - "Error updating main address": "更新主地址时发生错误", - "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "更新聊天室的主地址时发生错误。可能是该服务器不允许,也可能是出现了一个临时错误。", - "Main address": "主地址", + "Error updating main address": "更新主要地址时发生错误", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "更新聊天室的主要地址时发生错误。可能是此服务器不允许,也可能是出现了一个临时错误。", + "Main address": "主要地址", "Error updating flair": "更新个性徽章时发生错误", - "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "更新此聊天室的个性徽章时发生错误。可能时该服务器不允许,也可能是发生了一个临时错误。", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "更新此聊天室的个性徽章时发生错误。可能时此服务器不允许,也可能是发生了一个临时错误。", "Room avatar": "聊天室头像", "Room Name": "聊天室名称", "Room Topic": "聊天室话题", "Join": "加入", "That doesn't look like a valid email address": "这看起来不像是有效的电子邮箱地址", "The following users may not exist": "以下用户可能不存在", - "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "找不到下列 Matrix ID 的用户资料,您还是要邀请吗?", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "找不到下列 Matrix ID 的用户资料,你还是要邀请吗?", "Invite anyway and never warn me again": "还是邀请,不用再提醒我", "Invite anyway": "还是邀请", - "Before submitting logs, you must create a GitHub issue to describe your problem.": "在提交日志之前,您必须创建一个GitHub issue 来描述您的问题。", + "Before submitting logs, you must create a GitHub issue to describe your problem.": "在提交日志之前,你必须创建一个GitHub issue 来描述你的问题。", "Unable to load commit detail: %(msg)s": "无法加载提交详情:%(msg)s", - "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 才能执行此操作", - "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "验证此用户并将其标记为已信任。在收发端到端加密消息时,信任用户可让您更加放心。", + "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 才能执行此操作", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "验证此用户并将其标记为已信任。在收发端到端加密消息时,信任用户可让你更加放心。", "Waiting for partner to confirm...": "等待对方确认中...", "Incoming Verification Request": "收到验证请求", - "You've previously used %(brand)s on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, %(brand)s needs to resync your account.": "您之前在 %(host)s 上开启了 %(brand)s 的成员列表延迟加载设置。目前版本中延迟加载功能已被停用。因为本地缓存在这两个设置项上不相容,%(brand)s 需要重新同步您的账号。", + "You've previously used %(brand)s on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, %(brand)s needs to resync your account.": "你之前在 %(host)s 上开启了 %(brand)s 的成员列表延迟加载设置。目前版本中延迟加载功能已被停用。因为本地缓存在这两个设置项上不相容,%(brand)s 需要重新同步你的账号。", "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "通过仅在需要时加载其他用户的信息,%(brand)s 现在使用的内存减少到了原来的三分之一至五分之一。 请等待与服务器重新同步!", "I don't want my encrypted messages": "我不想要我的加密消息", "Manually export keys": "手动导出密钥", - "You'll lose access to your encrypted messages": "您将失去您的加密消息的访问权", - "Are you sure you want to sign out?": "您确定要登出账号吗?", + "You'll lose access to your encrypted messages": "你将失去你的加密消息的访问权", + "Are you sure you want to sign out?": "你确定要登出账号吗?", "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "如果您碰到任何错误或者希望分享您的反馈,请在 Github 上联系我们。", "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "要帮助避免提交重复的 issue,请您先 查阅是否为已存在的 issue (如有则添加一个 +1 ) ,或者如果找不到则 新建一个 issue 。", "Report bugs & give feedback": "上报错误及提供反馈", @@ -1125,7 +1125,7 @@ "Room Settings - %(roomName)s": "聊天室设置 - %(roomName)s", "A username can only contain lower case letters, numbers and '=_-./'": "用户名只能包含小写字母、数字和 '=_-./'", "Failed to decrypt %(failedCount)s sessions!": "%(failedCount)s 个会话解密失败!", - "Warning: you should only set up key backup from a trusted computer.": "警告:您应该只在受信任的电脑上设置密钥备份。", + "Warning: you should only set up key backup from a trusted computer.": "警告:你应此只在受信任的电脑上设置密钥备份。", "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "通过输入恢复密码来访问您的安全消息历史记录和设置安全通信。", "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "如果忘记了恢复密码,您可以 使用恢复密钥 或者 设置新的恢复选项", "This looks like a valid recovery key!": "看起来是有效的恢复密钥!", @@ -1137,8 +1137,8 @@ "Set status": "设置状态", "Set a new status...": "设置新状态...", "Hide": "隐藏", - "This homeserver would like to make sure you are not a robot.": "此主服务器想要确认您不是机器人。", - "Please review and accept all of the homeserver's policies": "请阅读并接受该主服务器的所有政策", + "This homeserver would like to make sure you are not a robot.": "此主服务器想要确认你不是机器人。", + "Please review and accept all of the homeserver's policies": "请阅读并接受此主服务器的所有政策", "Please review and accept the policies of this homeserver:": "请阅读并接受此主服务器的政策:", "Your Modular server": "您的模组服务器", "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "输入您的模组主服务器的位置。它可能使用的是您自己的域名或者 modular.im 的子域名。", @@ -1162,14 +1162,14 @@ "Other": "其他", "Find other public servers or use a custom server": "寻找其他公共服务器或使用自定义服务器", "Couldn't load page": "无法加载页面", - "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "您是此社区的管理员。 没有其他管理员的邀请,您将无法重新加入。", - "This homeserver does not support communities": "此主服务器不支持社区功能", + "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "你是此社群的管理员。 没有其他管理员的邀请,你将无法重新加入。", + "This homeserver does not support communities": "此主服务器不支持社群功能", "Guest": "游客", "Could not load user profile": "无法加载用户资料", "Your Matrix account on %(serverName)s": "您在 %(serverName)s 上的 Matrix 账号", - "A verification email will be sent to your inbox to confirm setting your new password.": "一封验证电子邮件将发送到您的邮箱以确认您设置了新密码。", + "A verification email will be sent to your inbox to confirm setting your new password.": "一封验证电子邮件将发送到你的邮箱以确认你设置了新密码。", "Sign in instead": "登入", - "Your password has been reset.": "您的密码已重置。", + "Your password has been reset.": "你的密码已重置。", "Set a new password": "设置新密码", "Invalid homeserver discovery response": "无效的主服务器搜索响应", "Invalid identity server discovery response": "无效的身份服务器搜索响应", @@ -1182,14 +1182,14 @@ "Unable to query for supported registration methods.": "无法查询支持的注册方法。", "Create your account": "创建您的账号", "Keep going...": "请继续...", - "For maximum security, this should be different from your account password.": "为确保最大的安全性,它应该与您的账号密码不同。", + "For maximum security, this should be different from your account password.": "为确保最大的安全性,它应该与你的账号密码不同。", "That matches!": "匹配成功!", "That doesn't match.": "不匹配。", "Go back to set it again.": "返回重新设置。", "Print it and store it somewhere safe": "打印 并存放在安全的地方", "Save it on a USB key or backup drive": "保存 在 U 盘或备份磁盘中", - "Copy it to your personal cloud storage": "复制 到您的个人云端存储", - "Your keys are being backed up (the first backup could take a few minutes).": "正在备份您的密钥(第一次备份可能会花费几分钟时间)。", + "Copy it to your personal cloud storage": "复制 到你的个人云端存储", + "Your keys are being backed up (the first backup could take a few minutes).": "正在备份你的密钥(第一次备份可能会花费几分钟时间)。", "Set up Secure Message Recovery": "设置安全消息恢复", "Starting backup...": "开始备份...", "Success!": "成功!", @@ -1198,18 +1198,18 @@ "If you don't want to set this up now, you can later in Settings.": "如果您现在不想设置,您可以稍后在设置中操作。", "New Recovery Method": "新恢复方式", "A new recovery passphrase and key for Secure Messages have been detected.": "检测到安全消息的一个新恢复密码和密钥。", - "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "如果您没有设置新恢复方式,可能有攻击者正试图侵入您的账号。请立即更改您的账号密码并在设置中设定一个新恢复方式。", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "如果你没有设置新恢复方式,可能有攻击者正试图侵入你的账号。请立即更改你的账号密码并在设置中设定一个新恢复方式。", "Set up Secure Messages": "设置安全消息", "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.": "如果您没有移除该恢复方式,可能有攻击者正试图侵入您的账号。请立即更改您的账号密码并在设置中设定一个新的恢复方式。", + "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.": "如果你没有移除此恢复方式,可能有攻击者正试图侵入你的账号。请立即更改你的账号密码并在设置中设定一个新的恢复方式。", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "在纯文本消息开头添加 ¯\\_(ツ)_/¯", "User %(userId)s is already in the room": "用户 %(userId)s 已在聊天室中", "The user must be unbanned before they can be invited.": "用户必须先解封才能被邀请。", - "Upgrade to your own domain": "升级 到您自己的域名", + "Upgrade to your own domain": "升级 到你自己的域名", "Accept all %(invitedRooms)s invites": "接受所有 %(invitedRooms)s 邀请", "Change room avatar": "更改聊天室头像", "Change room name": "更改聊天室名称", - "Change main address for the room": "更改聊天室主地址", + "Change main address for the room": "更改聊天室主要地址", "Change history visibility": "更改历史记录可见性", "Change permissions": "更改权限", "Change topic": "更改话题", @@ -1227,18 +1227,18 @@ "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. Learn more about encryption.": "聊天室加密一经启用,便无法禁用。在加密聊天室中,发送的消息无法被服务器看到,只能被聊天室的参与者看到。启用加密可能会使许多机器人和桥接无法正常运作。 详细了解加密。", "Power level": "权限级别", - "Want more than a community? Get your own server": "想要的不只是社区? 架设您自己的服务器", + "Want more than a community? Get your own server": "想要的不只是社群? 架设你自己的服务器", "Please install Chrome, Firefox, or Safari for the best experience.": "请安装 ChromeFirefox,或 Safari 以获得最佳体验。", - "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. 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.": "警告:升级聊天室 不会自动将聊天室成员转移到新版聊天室中。 我们将会在旧版聊天室中发布一个新版聊天室的链接 - 聊天室成员必须点击该链接以加入新聊天室。", + "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. 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.": "警告:升级聊天室 不会自动将聊天室成员转移到新版聊天室中。 我们将会在旧版聊天室中发布一个新版聊天室的链接 - 聊天室成员必须点击此链接以加入新聊天室。", "Adds a custom widget by URL to the room": "通过链接为聊天室添加自定义挂件", "Please supply a https:// or http:// widget URL": "请提供一个 https:// 或 http:// 形式的插件", - "You cannot modify widgets in this room.": "您无法修改此聊天室的插件。", + "You cannot modify widgets in this room.": "你无法修改此聊天室的插件。", "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s 撤销了对 %(targetDisplayName)s 加入聊天室的邀请。", "Upgrade this room to the recommended room version": "升级此聊天室至推荐版本", - "This room is running room version , which this homeserver has marked as unstable.": "此聊天室运行的聊天室版本是 ,该版本已被主服务器标记为 不稳定 。", + "This room is running room version , which this homeserver has marked as unstable.": "此聊天室运行的聊天室版本是 ,此版本已被主服务器标记为 不稳定 。", "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": "撤销邀请失败", - "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "无法撤销邀请。该服务器可能出现了临时错误,或者您没有足够的权限来撤销邀请。", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "无法撤销邀请。此服务器可能出现了临时错误,或者你没有足够的权限来撤销邀请。", "Revoke invite": "撤销邀请", "Invited by %(sender)s": "被 %(sender)s 邀请", "Maximize apps": "最大化应用程序", @@ -1246,32 +1246,32 @@ "A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.": "位于 %(widgetUrl)s 的小部件想要验证您的身份。在您允许后,小部件就可以验证您的用户 ID,但不能代您执行操作。", "Remember my selection for this widget": "记住我对此挂件的选择", "Deny": "拒绝", - "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "%(brand)s 无法从主服务器处获取协议列表。该主服务器上的软件可能过旧,不支持第三方网络。", + "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "%(brand)s 无法从主服务器处获取协议列表。此主服务器上的软件可能过旧,不支持第三方网络。", "%(brand)s failed to get the public room list.": "%(brand)s 无法获取公开聊天室列表。", "The homeserver may be unavailable or overloaded.": "主服务器似乎不可用或过载。", - "You have %(count)s unread notifications in a prior version of this room.|other": "您在此聊天室的先前版本中有 %(count)s 条未读通知。", - "You have %(count)s unread notifications in a prior version of this room.|one": "您在此聊天室的先前版本中有 %(count)s 条未读通知。", + "You have %(count)s unread notifications in a prior version of this room.|other": "你在此聊天室的先前版本中有 %(count)s 条未读通知。", + "You have %(count)s unread notifications in a prior version of this room.|one": "你在此聊天室的先前版本中有 %(count)s 条未读通知。", "Add Email Address": "添加 Email 地址", "Add Phone Number": "添加电话号码", "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "是否使用“面包屑”功能(最近访问的房间的图标在房间列表上方显示)", "Call failed due to misconfigured server": "因为服务器配置错误通话失败", - "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "请联系您主服务器(%(homeserverDomain)s)的管理员设置 TURN 服务器来确保通话运作稳定。", - "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "您也可以尝试使用turn.matrix.org公共服务器,但通话质量稍差,并且其将会得知您的 IP。您可以在设置中更改此选项。", + "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "请联系你主服务器(%(homeserverDomain)s)的管理员设置 TURN 服务器来确保通话运作稳定。", + "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "你也可以尝试使用turn.matrix.org公共服务器,但通话质量稍差,并且其将会得知你的 IP。你可以在设置中更改此选项。", "Try using turn.matrix.org": "尝试使用 turn.matrix.org", - "Your %(brand)s is misconfigured": "您的 %(brand)s 配置有错误", + "Your %(brand)s is misconfigured": "你的 %(brand)s 配置有错误", "Use Single Sign On to continue": "使用单点登录继续", - "Confirm adding this email address by using Single Sign On to prove your identity.": "通过使用单点登录来证明您的身份,并确认添加此邮件地址。", + "Confirm adding this email address by using Single Sign On to prove your identity.": "通过使用单点登录来证明你的身份,并确认添加此邮件地址。", "Single Sign On": "单点登录", "Confirm adding email": "确认使用邮件", "Click the button below to confirm adding this email address.": "点击下面的按钮以确认添加此邮箱地址。", - "Confirm adding this phone number by using Single Sign On to prove your identity.": "通过单点登录以证明您的身份,并确认添加此电话号码。", + "Confirm adding this phone number by using Single Sign On to prove your identity.": "通过单点登录以证明你的身份,并确认添加此电话号码。", "Confirm adding phone number": "确认添加电话号码", "Click the button below to confirm adding this phone number.": "点击下面的按钮以确认添加此电话号码。", "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "是否在触屏设备上使用 %(brand)s", - "Whether you're using %(brand)s as an installed Progressive Web App": "您是否已将 %(brand)s 作为渐进式 Web 应用(PWA)安装", - "Your user agent": "您的用户代理(user agent)", + "Whether you're using %(brand)s as an installed Progressive Web App": "你是否已将 %(brand)s 作为渐进式 Web 应用(PWA)安装", + "Your user agent": "你的用户代理(user agent)", "Replying With Files": "回复文件", - "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "当前无法在回复中附加文件。您想要仅上传此文件而不回复吗?", + "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "当前无法在回复中附加文件。你想要仅上传此文件而不回复吗?", "The file '%(fileName)s' failed to upload.": "上传文件 ‘%(fileName)s’ 失败。", "The server does not support the room version specified.": "服务器不支持指定的聊天室版本。", "If you cancel now, you won't complete verifying the other user.": "如果现在取消,您将无法完成验证其他用户。", @@ -1283,11 +1283,11 @@ "Encryption upgrade available": "提供加密升级", "Set up encryption": "设置加密", "Review where you’re logged in": "查看您的登录位置", - "New login. Was this you?": "现在登录。请问是您本人吗?", + "New login. Was this you?": "现在登录。请问是你本人吗?", "Name or Matrix ID": "姓名或 Matrix ID", "Identity server has no terms of service": "身份服务器无服务条款", "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.": "此操作需要访问默认的身份服务器 以验证邮箱地址或电话号码,但是此服务器无任何服务条款。", - "Only continue if you trust the owner of the server.": "只有您信任服务器所有者才能继续。", + "Only continue if you trust the owner of the server.": "只有你信任服务器所有者才能继续。", "Trust": "信任", "%(name)s is requesting verification": "%(name)s 正在请求验证", "Sign In or Create Account": "登录或创建账号", @@ -1299,12 +1299,12 @@ "Actions": "动作", "Sends a message as plain text, without interpreting it as markdown": "以纯文本形式发送消息,不将其作为 markdown 处理", "Sends a message as html, without interpreting it as markdown": "以 html 格式发送消息,不将其作为 markdown 处理", - "You do not have the required permissions to use this command.": "您没有权限使用此命令。", + "You do not have the required permissions to use this command.": "你没有权限使用此命令。", "Error upgrading room": "升级聊天室时发生错误", - "Double check that your server supports the room version chosen and try again.": "请再次检查您的服务器是否支持所选聊天室版本,然后再试一次。", + "Double check that your server supports the room version chosen and try again.": "请再次检查你的服务器是否支持所选聊天室版本,然后再试一次。", "Changes the avatar of the current room": "更改当前聊天室头像", - "Changes your avatar in this current room only": "仅改变您在当前聊天室的头像", - "Changes your avatar in all rooms": "改变您在所有聊天室的头像", + "Changes your avatar in this current room only": "仅改变你在当前聊天室的头像", + "Changes your avatar in all rooms": "改变你在所有聊天室的头像", "Failed to set topic": "话题设置失败", "Use an identity server": "使用身份服务器", "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "使用身份服务器以通过电子邮件邀请其他用户。单击继续以使用默认身份服务器(%(defaultIdentityServerName)s),或在设置中进行管理。", @@ -1317,23 +1317,23 @@ "Unknown (user, session) pair:": "未知(用户、会话)对:", "Session already verified!": "会话已验证!", "WARNING: Session already verified, but keys do NOT MATCH!": "警告:会话已验证,但密钥不匹配!", - "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!": "警告:密钥验证失败!%(userId)s 的会话 %(deviceId)s 的签名密钥为 %(fprint)s,与提供的密钥 %(fingerprint)s 不符。这可能表示您的通讯已被截获!", - "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "您提供的签名密钥与您从 %(userId)s 的会话 %(deviceId)s 获取的一致。该会话被标为已验证。", - "Sends the given message coloured as a rainbow": "以彩虹色发送给定消息", + "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!": "警告:密钥验证失败!%(userId)s 的会话 %(deviceId)s 的签名密钥为 %(fprint)s,与提供的密钥 %(fingerprint)s 不符。这可能表示你的通讯已被截获!", + "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "你提供的签名密钥与你从 %(userId)s 的会话 %(deviceId)s 获取的一致。此会话被标为已验证。", + "Sends the given message coloured as a rainbow": "此消息以彩虹色进行渲染", "Sends the given emote coloured as a rainbow": "以彩虹色发送给定表情符号", "Displays list of commands with usages and descriptions": "显示指令清单与其描述和用法", "Displays information about a user": "显示关于用户的信息", "Send a bug report with logs": "发送带日志的错误报告", "Opens chat with the given user": "与指定用户发起聊天", "Sends a message to the given user": "向指定用户发消息", - "%(senderName)s made no change.": "%(senderName)s 未做出变更。", + "%(senderName)s made no change.": "%(senderName)s 未做出更改。", "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": "%(senderDisplayName)s 将聊天室名称从 %(oldRoomName)s 改为 %(newRoomName)s。", "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": "%(senderName)s 为此聊天室添加备用地址 %(addresses)s。", "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": "%(senderName)s 为此聊天室添加了备用地址 %(addresses)s。", "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "%(senderName)s 为此聊天室移除了备用地址 %(addresses)s。", "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s 为此聊天室移除了备用地址 %(addresses)s。", "%(senderName)s changed the alternative addresses for this room.": "%(senderName)s 更改了此聊天室的备用地址。", - "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s 更改了此聊天室的主地址与备用地址。", + "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s 更改了此聊天室的主要地址与备用地址。", "%(senderName)s changed the addresses for this room.": "%(senderName)s 更改了此聊天室的地址。", "%(senderName)s placed a voice call.": "%(senderName)s 发起了语音通话。", "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s 发起了语音通话。(此浏览器不支持)", @@ -1356,25 +1356,25 @@ "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s更改了一个由于%(reason)s而禁止聊天室%(oldGlob)s跟%(newGlob)s匹配的规则", "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s 更新了一个由于%(reason)s而禁止服务器%(oldGlob)s跟%(newGlob)s匹配的规则", "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s 更新了一个由于%(reason)s而禁止%(oldGlob)s跟%(newGlob)s匹配的规则", - "You signed in to a new session without verifying it:": "您登录了未经过验证的新会话:", - "Verify your other session using one of the options below.": "使用以下选项之一验证您的其他会话。", + "You signed in to a new session without verifying it:": "你登录了未经过验证的新会话:", + "Verify your other session using one of the options below.": "使用以下选项之一验证你的其他会话。", "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s(%(userId)s)登录到未验证的新会话:", - "Ask this user to verify their session, or manually verify it below.": "要求该用户验证其会话,或在下面手动进行验证。", + "Ask this user to verify their session, or manually verify it below.": "要求此用户验证其会话,或在下面手动进行验证。", "Not Trusted": "不可信任", "Manually Verify by Text": "手动验证文字", "Interactively verify by Emoji": "通过表情符号进行交互式验证", "Done": "完成", "Cannot reach homeserver": "不可连接到主服务器", - "Ensure you have a stable internet connection, or get in touch with the server admin": "确保您的网络连接稳定,或与服务器管理员联系", - "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "跟您的%(brand)s管理员确认您的配置不正确或重复的条目。", + "Ensure you have a stable internet connection, or get in touch with the server admin": "确保你的网络连接稳定,或与服务器管理员联系", + "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "跟你的%(brand)s管理员确认你的配置不正确或重复的条目。", "Cannot reach identity server": "不可连接到身份服务器", "Room name or address": "房间名称或地址", "Joins room with given address": "使用给定地址加入房间", "Verify this login": "验证此登录名", "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "通过从其他会话之一验证此登录名并授予其访问加密信息的权限来确认您的身份。", - "Which officially provided instance you are using, if any": "如果您在使用官方实例,是哪一个", - "Every page you use in the app": "您在应用中使用的每个页面", - "Are you sure you want to cancel entering passphrase?": "您确定要取消输入密语吗?", + "Which officially provided instance you are using, if any": "如果有的话,你正在使用官方所提供的哪个实例", + "Every page you use in the app": "你在应用中使用的每个页面", + "Are you sure you want to cancel entering passphrase?": "你确定要取消输入密语吗?", "Go Back": "后退", "Use your account to sign in to the latest version": "使用您的帐户登录到最新版本", "We’re excited to announce Riot is now Element": "我们很高兴地宣布Riot现在更名为Element", @@ -1382,9 +1382,9 @@ "Unrecognised room address:": "无法识别的聊天室地址:", "Light": "浅色", "Dark": "深色", - "You can register, 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 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.": "您可以登录,但部分功能在身份服务器重新上线之前不可用。如果持续看到此警告,请检查配置或联系服务器管理员。", + "You can register, 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 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.": "你可以登录,但部分功能在身份服务器重新上线之前不可用。如果持续看到此警告,请检查配置或联系服务器管理员。", "No homeserver URL provided": "未输入主服务器链接", "Unexpected error resolving homeserver configuration": "解析主服务器配置时发生未知错误", "Unexpected error resolving identity server configuration": "解析身份服务器配置时发生未知错误", @@ -1404,17 +1404,17 @@ "about a day from now": "从现在开始约一天", "%(num)s days from now": "从现在开始%(num)s天", "%(name)s (%(userId)s)": "%(name)s%(userId)s", - "Your browser does not support the required cryptography extensions": "您的浏览器不支持所需的密码学扩展", - "The user's homeserver does not support the version of the room.": "用户的主服务器不支持该聊天室版本。", + "Your browser does not support the required cryptography extensions": "你的浏览器不支持所需的密码学扩展", + "The user's homeserver does not support the version of the room.": "用户的主服务器不支持此聊天室版本。", "Help us improve %(brand)s": "请协助我们改进%(brand)s", "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "发送匿名使用情况数据,以协助我们改进%(brand)s。这将使用cookie。", "I want to help": "我乐意协助", "Verify all your sessions to ensure your account & messages are safe": "验证您的所有会话,以确保账号和消息安全", "Review": "开始验证", "Later": "稍后再说", - "Your homeserver has exceeded its user limit.": "您的主服务器已超过用户限制。", - "Your homeserver has exceeded one of its resource limits.": "您的主服务器已超过某项资源限制。", - "Contact your server admin.": "请联系您的服务器管理员。", + "Your homeserver has exceeded its user limit.": "你的主服务器已超过用户限制。", + "Your homeserver has exceeded one of its resource limits.": "你的主服务器已超过某项资源限制。", + "Contact your server admin.": "请联系你的服务器管理员。", "Ok": "确定", "Set password": "设置密码", "To return to your account in future you need to set a password": "要在之后取回您的帐户,您需要设置密码", @@ -1426,13 +1426,13 @@ "Restart": "重启应用", "Upgrade your %(brand)s": "升级您的%(brand)s", "A new version of %(brand)s is available!": "发现%(brand)s的新版本!", - "You joined the call": "您加入通话", + "You joined the call": "你加入通话", "%(senderName)s joined the call": "%(senderName)s加入通话", "Call in progress": "通话中", "You left the call": "您离开了通话", "%(senderName)s left the call": "%(senderName)s离开了通话", "Call ended": "通话结束", - "You started a call": "您开始了通话", + "You started a call": "你开始了通话", "%(senderName)s started a call": "%(senderName)s开始了通话", "Waiting for answer": "等待接听", "%(senderName)s is calling": "%(senderName)s正在通话", @@ -1461,35 +1461,35 @@ "or": "或者", "Start": "开始", "Confirm the emoji below are displayed on both sessions, in the same order:": "确认两个会话上都以同样顺序显示了下面的emoji:", - "The person who invited you already left the room.": "邀请您的人已经离开了聊天室。", - "The person who invited you already left the room, or their server is offline.": "邀请您的人已经离开了聊天室,或者其服务器为离线状态。", + "The person who invited you already left the room.": "邀请你的人已经离开了聊天室。", + "The person who invited you already left the room, or their server is offline.": "邀请你的人已经离开了聊天室,或者其服务器为离线状态。", "Change notification settings": "修改通知设置", "Manually verify all remote sessions": "手动验证所有远程会话", "My Ban List": "我的封禁列表", - "This is your list of users/servers you have blocked - don't leave the room!": "这是您屏蔽的用户和服务器的列表——请不要离开此聊天室!", + "This is your list of users/servers you have blocked - don't leave the room!": "这是你屏蔽的用户和服务器的列表——请不要离开此聊天室!", "Unknown caller": "未知来电人", "Incoming voice call": "语音来电", "Incoming video call": "视频来电", "Incoming call": "来电", - "Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": "等待您的另一个会话 %(deviceName)s (%(deviceId)s) 进行验证…", - "Waiting for your other session to verify…": "等待您的另一个会话进行验证…", + "Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": "等待你的另一个会话 %(deviceName)s (%(deviceId)s) 进行验证…", + "Waiting for your other session to verify…": "等待你的另一个会话进行验证…", "Waiting for %(displayName)s to verify…": "等待 %(displayName)s 进行验证…", "Cancelling…": "正在取消…", "They match": "它们匹配", "They don't match": "它们不匹配", "To be secure, do this in person or use a trusted way to communicate.": "为了安全,请当面完成或使用信任的方法交流。", "Lock": "锁", - "Your server isn't responding to some requests.": "您的服务器没有响应一些请求。", + "Your server isn't responding to some requests.": "你的服务器没有响应一些请求。", "From %(deviceName)s (%(deviceId)s)": "来自 %(deviceName)s (%(deviceId)s)", "Decline (%(counter)s)": "拒绝 (%(counter)s)", "Accept to continue:": "接受 以继续:", "Upload": "上传", "Show less": "显示更少", "Show more": "显示更多", - "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "修改密码会重置所有会话上的端对端加密的密钥,使加密聊天记录不可读,除非您先导出您的聊天室密钥,之后再重新导入。在未来会有所改进。", - "Your homeserver does not support cross-signing.": "您的主服务器不支持交叉签名。", + "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "修改密码会重置所有会话上的端对端加密的密钥,使加密聊天记录不可读,除非你先导出你的聊天室密钥,之后再重新导入。在未来会有所改进。", + "Your homeserver does not support cross-signing.": "你的主服务器不支持交叉签名。", "Cross-signing and secret storage are enabled.": "交叉签名和秘密存储已启用。", - "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "您的账号在秘密存储中有交叉签名身份,但并没有被此会话信任。", + "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "你的账号在秘密存储中有交叉签名身份,但并没有被此会话信任。", "Cross-signing and secret storage are not yet set up.": "交叉签名和秘密存储尚未设置。", "Reset cross-signing and secret storage": "重置交叉签名和秘密存储", "Bootstrap cross-signing and secret storage": "自举交叉签名和秘密存储", @@ -1505,7 +1505,7 @@ "Secret storage public key:": "秘密存储公钥:", "in account data": "在账号数据中", "exists": "存在", - "Your homeserver does not support session management.": "您的主服务器不支持会话管理。", + "Your homeserver does not support session management.": "你的主服务器不支持会话管理。", "Unable to load session list": "无法加载会话列表", "Confirm deleting these sessions": "确认删除这些会话", "Click the button below to confirm deleting these sessions.|other": "点击下方按钮以确认删除这些会话。", @@ -1518,9 +1518,9 @@ "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "逐一验证用户的每一个会话以将其标记为已信任,而不信任交叉签名的设备。", "Manage": "管理", "Enable": "启用", - "%(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 search components added.": "%(brand)s 缺少安全地在本地缓存加密信息所必须的部件。如果您想实验此功能,请构建一个自定义的带有搜索部件的 %(brand)s 桌面版。", + "%(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 search components added.": "%(brand)s 缺少安全地在本地缓存加密信息所必须的部件。如果你想实验此功能,请构建一个自定义的带有搜索部件的 %(brand)s 桌面版。", "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s 在浏览器中运行时不能安全地在本地缓存加密信息。请使用%(brand)s 桌面版以使加密信息出现在搜索结果中。", - "This session is backing up your keys. ": "此会话正在备份您的密钥。 ", + "This session is backing up your keys. ": "此会话正在备份你的密钥。 ", "Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "在登出前连接此会话到密钥备份以避免丢失可能仅在此会话上的密钥。", "Connect this session to Key Backup": "将此会话连接到密钥备份", "Backup has a valid signature from this user": "备份有来自此用户的有效签名", @@ -1533,13 +1533,13 @@ "Backup has a valid signature from unverified session ": "备份有一个有效的签名,它来自未验证的会话", "Backup has an invalid signature from verified session ": "备份有一个无效的签名,它来自已验证的会话", "Backup has an invalid signature from unverified session ": "备份有一个无效的签名,它来自未验证的会话", - "Backup is not signed by any of your sessions": "备份没有被您的任何一个会话签名", + "Backup is not signed by any of your sessions": "备份没有被你的任何一个会话签名", "This backup is trusted because it has been restored on this session": "此备份是受信任的因为它被恢复到了此会话上", "Backup key stored: ": "存储的备份密钥: ", - "Your keys are not being backed up from this session.": "您的密钥没有被此会话备份。", + "Your keys are not being backed up from this session.": "你的密钥没有被此会话备份。", "Clear notifications": "清除通知", "There are advanced notifications which are not shown here.": "有高级通知没有显示在此处。", - "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "您可能在非 %(brand)s 的客户端里配置了它们。您在 %(brand)s 里无法修改它们,但它们仍然适用。", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "你可能在非 %(brand)s 的客户端里配置了它们。你在 %(brand)s 里无法修改它们,但它们仍然适用。", "Enable desktop notifications for this session": "为此会话启用桌面通知", "Enable audible notifications for this session": "为此会话启用声音通知", "Identity Server URL must be HTTPS": "身份服务器连接必须是 HTTPS", @@ -1549,29 +1549,29 @@ "Change identity server": "更改身份服务器", "Disconnect from the identity server and connect to instead?": "从 身份服务器断开连接并连接到 吗?", "Terms of service not accepted or the identity server is invalid.": "服务协议未同意或身份服务器无效。", - "The identity server you have chosen does not have any terms of service.": "您选择的身份服务器没有服务协议。", + "The identity server you have chosen does not have any terms of service.": "你选择的身份服务器没有服务协议。", "Disconnect identity server": "断开身份服务器连接", "Disconnect from the identity server ?": "从身份服务器 断开连接吗?", "Disconnect": "断开连接", "You should remove your personal data from identity server before disconnecting. Unfortunately, identity server is currently offline or cannot be reached.": "断开连接前,你应当删除你的个人信息从身份服务器。不幸的是,身份服务器当前处于离线状态或无法访问。", - "You should:": "您应该:", + "You should:": "你应该:", "contact the administrators of identity server ": "联系身份服务器 的管理员", "wait and try again later": "等待并稍后重试", "Disconnect anyway": "仍然断开连接", - "You are still sharing your personal data on the identity server .": "您仍然在分享您的个人信息在身份服务器上。", - "We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.": "我们推荐您在断开连接前从身份服务器上删除您的邮箱地址和电话号码。", + "You are still sharing your personal data on the identity server .": "你仍然在分享你的个人信息在身份服务器上。", + "We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.": "我们推荐你在断开连接前从身份服务器上删除你的邮箱地址和电话号码。", "Identity Server (%(server)s)": "身份服务器(%(server)s)", "not stored": "未存储", - "You are currently using to discover and be discoverable by existing contacts you know. You can change your identity server below.": "您正在使用 以发现您认识的现存联系人并被其发现。您可以在下方更改您的身份服务器。", - "If you don't want to use to discover and be discoverable by existing contacts you know, enter another identity server below.": "如果您不想使用 以发现您认识的现存联系人并被其发现,请在下方输入另一个身份服务器。", + "You are currently using to discover and be discoverable by existing contacts you know. You can change your identity server below.": "你正在使用 以发现你认识的现存联系人并被其发现。你可以在下方更改你的身份服务器。", + "If you don't want to use to discover and be discoverable by existing contacts you know, enter another identity server below.": "如果你不想使用 以发现你认识的现存联系人并被其发现,请在下方输入另一个身份服务器。", "Identity Server": "身份服务器", - "You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.": "您现在没有使用身份服务器。若想发现您认识的现存联系人并被其发现,请在下方添加一个身份服务器。", - "Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "从您的身份服务器断开连接意味着您将不可被别的用户发现,同时您也将不能用邮箱或电话邀请别人。", - "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "使用身份服务器是可选的。如果您选择不使用身份服务器,您将不能被别的用户发现,也不能用邮箱或电话邀请别人。", + "You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.": "你现在没有使用身份服务器。若想发现你认识的现存联系人并被其发现,请在下方添加一个身份服务器。", + "Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "从你的身份服务器断开连接意味着你将不可被别的用户发现,同时你也将不能用邮箱或电话邀请别人。", + "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "使用身份服务器是可选的。如果你选择不使用身份服务器,你将不能被别的用户发现,也不能用邮箱或电话邀请别人。", "Do not use an identity server": "不使用身份服务器", "Enter a new identity server": "输入一个新的身份服务器", "New version available. Update now.": "新版本可用。现在更新。", - "Hey you. You're the best!": "嘿呀。您就是最棒的!", + "Hey you. You're the best!": "嘿呀。你就是最棒的!", "Size must be a number": "大小必须是数字", "Custom font size can only be between %(min)s pt and %(max)s pt": "自定义字体大小只能介于 %(min)s pt 和 %(max)s pt 之间", "Error downloading theme information.": "下载主题信息时发生错误。", @@ -1581,10 +1581,10 @@ "Message layout": "信息布局", "Compact": "紧凑", "Modern": "现代", - "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "设置一个安装在您的系统上的字体名称,%(brand)s 会尝试使用它。", - "Customise your appearance": "自定义您的外观", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "设置一个安装在你的系统上的字体名称,%(brand)s 会尝试使用它。", + "Customise your appearance": "自定义你的外观", "Appearance Settings only affect this %(brand)s session.": "外观设置仅会影响此 %(brand)s 会话。", - "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "您的密码已成功更改。在您重新登录别的会话之前,您将不会在那里收到推送通知", + "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "你的密码已成功更改。在你重新登录别的会话之前,你将不会在那里收到推送通知", "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "同意身份服务器(%(serverName)s)的服务协议以允许自己被通过邮件地址或电话号码发现。", "Discovery": "发现", "Clear cache and reload": "清除缓存重新加载", @@ -1600,22 +1600,22 @@ "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": "您没有订阅任何列表", + "You have not ignored anyone.": "你没有忽略任何人。", + "You are currently ignoring:": "你正在忽略:", + "You are not subscribed to any lists": "你没有订阅任何列表", "Unsubscribe": "取消订阅", "View rules": "查看规则", - "You are currently subscribed to:": "您正在订阅:", + "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, @bot:* would ignore all users that have the name 'bot' on any server.": "在此处添加您想忽略的用户和服务器。使用星号以使 %(brand)s 匹配任何字符。例如,@bot:* 会忽略在任何服务器上以「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.": "忽略人是通过含有封禁规则的封禁列表来完成的。订阅一个封禁列表意味着被该列表阻止的用户/服务器将会对您隐藏。", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "在此处添加你想忽略的用户和服务器。使用星号以使 %(brand)s 匹配任何字符。例如,@bot:* 会忽略在任何服务器上以「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": "个人封禁列表", - "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 'My Ban List' - stay in this room to keep the ban list in effect.": "您的个人封禁列表包含所有您不想看见信息的用户/服务器。您第一次忽略用户/服务器。后,一个名叫「我的封禁列表」的新聊天室将会显示在您的聊天室列表中——留在该聊天室以保持该封禁列表生效。", + "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 'My Ban List' - stay in this room to keep the ban list in effect.": "你的个人封禁列表包含所有你不想看见信息的用户/服务器。你第一次忽略用户/服务器。后,一个名叫「我的封禁列表」的新聊天室将会显示在你的聊天室列表中——留在此聊天室以保持此封禁列表生效。", "Server or user ID to ignore": "要忽略的服务器或用户 ID", "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.": "如果这不是您想要的,请使用别的的工具来忽略用户。", + "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.": "如果这不是你想要的,请使用别的的工具来忽略用户。", "Room ID or address of ban list": "封禁列表的聊天室 ID 或地址", "Subscribe": "订阅", "Always show the window menu bar": "总是显示窗口菜单栏", @@ -1624,8 +1624,8 @@ "Session key:": "会话密钥:", "Message search": "信息搜索", "Cross-signing": "交叉签名", - "Where you’re logged in": "您在何处登录", - "A session's public name is visible to people you communicate with": "会话的公共名称会对和您交流的人显示", + "Where you’re logged in": "你在何处登录", + "A session's public name is visible to people you communicate with": "会话的公共名称会对和你交流的人显示", "this room": "此聊天室", "View older messages in %(roomName)s.": "查看 %(roomName)s 里更旧的信息。", "Uploaded sound": "已上传的声音", @@ -1637,26 +1637,26 @@ "Upgrade the room": "更新聊天室", "Enable room encryption": "启用聊天室加密", "Error changing power level requirement": "更改权限级别需求时出错", - "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "更改此聊天室的权限级别需求时出错。请确保您有足够的权限后重试。", + "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "更改此聊天室的权限级别需求时出错。请确保你有足够的权限后重试。", "Error changing power level": "更改权限级别时出错", - "An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "更改此用户的权限级别时出错。请确保您有足够权限后重试。", + "An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "更改此用户的权限级别时出错。请确保你有足够权限后重试。", "To link to this room, please add an address.": "要链接至此聊天室,请添加一个地址。", "Unable to share email address": "无法共享邮件地址", - "Your email address hasn't been verified yet": "您的邮件地址尚未被验证", - "Click the link in the email you received to verify and then click continue again.": "请点击您收到的邮件中的链接后再点击继续。", - "Verify the link in your inbox": "验证您的收件箱中的链接", + "Your email address hasn't been verified yet": "你的邮件地址尚未被验证", + "Click the link in the email you received to verify and then click continue again.": "请点击你收到的邮件中的链接后再点击继续。", + "Verify the link in your inbox": "验证你的收件箱中的链接", "Complete": "完成", "Share": "共享", - "Discovery options will appear once you have added an email above.": "您在上方添加邮箱后发现选项将会出现。", + "Discovery options will appear once you have added an email above.": "你在上方添加邮箱后发现选项将会出现。", "Unable to share phone number": "无法共享电话号码", "Please enter verification code sent via text.": "请输入短信中发送的验证码。", - "Discovery options will appear once you have added a phone number above.": "您添加电话号码后发现选项将会出现。", + "Discovery options will appear once you have added a phone number above.": "你添加电话号码后发现选项将会出现。", "Remove %(email)s?": "删除 %(email)s 吗?", "Remove %(phone)s?": "删除 %(phone)s 吗?", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "一封短信已发送至 +%(msisdn)s。请输入其中包含的验证码。", "This user has not verified all of their sessions.": "此用户没有验证其全部会话。", - "You have not verified this user.": "您没有验证此用户。", - "You have verified this user. This user has verified all of their sessions.": "您验证了此用户。此用户已验证了其全部会话。", + "You have not verified this user.": "你没有验证此用户。", + "You have verified this user. This user has verified all of their sessions.": "你验证了此用户。此用户已验证了其全部会话。", "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", @@ -1670,33 +1670,33 @@ "Show shortcuts to recently viewed rooms above the room list": "在聊天室列表上方显示最近浏览过的聊天室的快捷方式", "Show hidden events in timeline": "显示时间线中的隐藏事件", "Low bandwidth mode": "低带宽模式", - "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "当您的主服务器没有提供通话辅助服务器时使用备用的 turn.matrix.org 服务器(您的IP地址会在通话期间被共享)", + "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "当你的主服务器没有提供通话辅助服务器时使用备用的 turn.matrix.org 服务器(你的IP地址会在通话期间被共享)", "Send read receipts for messages (requires compatible homeserver to disable)": "为消息发送已读回执(需要兼容的主服务器方可禁用)", "Scan this unique code": "扫描此唯一代码", "Compare unique emoji": "比较唯一表情符号", - "Compare a unique set of emoji if you don't have a camera on either device": "若您在两个设备上都没有相机,比较唯一一组表情符号", + "Compare a unique set of emoji if you don't have a camera on either device": "若你在两个设备上都没有相机,比较唯一一组表情符号", "Verify this session by confirming the following number appears on its screen.": "确认下方数字显示在屏幕上以验证此会话。", "This bridge is managed by .": "此桥接由 管理。", "Homeserver feature support:": "主服务器功能支持:", - "Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "通过单点登录证明您的身份并确认删除这些会话。", - "Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "通过单点登录证明您的身份并确认删除此会话。", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "通过单点登录证明你的身份并确认删除这些会话。", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "通过单点登录证明你的身份并确认删除此会话。", "Public Name": "公开名称", "Securely cache encrypted messages locally for them to appear in search results.": "在本地安全地缓存加密消息以使其出现在搜索结果中。", "Connecting to integration manager...": "正在连接至集成管理器...", "Cannot connect to integration manager": "不能连接到集成管理器", - "The integration manager is offline or it cannot reach your homeserver.": "此集成管理器为离线状态或者其不能访问您的主服务器。", - "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "检查您的浏览器是否安装有可能屏蔽身份服务器的插件(例如 Privacy Badger)", + "The integration manager is offline or it cannot reach your homeserver.": "此集成管理器为离线状态或者其不能访问你的主服务器。", + "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "检查你的浏览器是否安装有可能屏蔽身份服务器的插件(例如 Privacy Badger)", "Use an Integration Manager (%(serverName)s) to manage bots, widgets, and sticker packs.": "使用集成管理器 (%(serverName)s) 以管理机器人、挂件和贴图集。", "Use an Integration Manager to manage bots, widgets, and sticker packs.": "使用集成管理器以管理机器人、挂件和贴图集。", "Manage integrations": "管理集成", - "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "集成管理器接收配置数据,并可以以您的名义修改挂件、发送聊天室邀请及设置权限级别。", + "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "集成管理器接收配置数据,并可以以你的名义修改挂件、发送聊天室邀请及设置权限级别。", "Use between %(min)s pt and %(max)s pt": "请使用介于 %(min)s pt 和 %(max)s pt 之间的大小", "Deactivate account": "停用账号", "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "要报告 Matrix 相关的安全问题,请阅读 Matrix.org 的安全公开策略。", - "Something went wrong. Please try again or view your console for hints.": "出现问题。请重试或查看您的终端以获得提示。", - "Please try again or view your console for hints.": "请重试或查看您的终端以获得提示。", - "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "您的服务器管理员未在私人聊天室和私聊中默认启用端对端加密。", - "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "在下方管理会话名称,登出您的会话或在您的用户资料中验证它们。", + "Something went wrong. Please try again or view your console for hints.": "出现问题。请重试或查看你的终端以获得提示。", + "Please try again or view your console for hints.": "请重试或查看你的终端以获得提示。", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "你的服务器管理员未在私人聊天室和私聊中默认启用端对端加密。", + "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "在下方管理会话名称,登出你的会话或在你的用户资料中验证它们。", "This room is bridging messages to the following platforms. Learn more.": "此聊天室正将消息桥接到以下平台。了解更多。", "This room isn’t bridging messages to any platforms. Learn more.": "此聊天室未将消息桥接到任何平台。了解更多。", "Bridges": "桥接", @@ -1704,10 +1704,10 @@ "This room is end-to-end encrypted": "此聊天室是端对端加密的", "Everyone in this room is verified": "聊天室中所有人都已被验证", "Edit message": "编辑消息", - "Your key share request has been sent - please check your other sessions for key share requests.": "您的密钥共享请求已发送——请检查您别的会话。", - "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "密钥共享请求会自动发送至您别的会话。如果您拒绝或忽略了您别的会话上的密钥共享请求,请点击此处重新为此会话请求密钥。", - "If your other sessions do not have the key for this message you will not be able to decrypt them.": "如果您别的会话没有此消息的密钥您将不能解密它们。", - "Re-request encryption keys from your other sessions.": "从您别的会话重新请求加密密钥。", + "Your key share request has been sent - please check your other sessions for key share requests.": "你的密钥共享请求已发送——请检查你别的会话。", + "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "密钥共享请求会自动发送至你别的会话。如果你拒绝或忽略了你别的会话上的密钥共享请求,请点击此处重新为此会话请求密钥。", + "If your other sessions do not have the key for this message you will not be able to decrypt them.": "如果你别的会话没有此消息的密钥你将不能解密它们。", + "Re-request encryption keys from your other sessions.": "从你别的会话重新请求加密密钥。", "This message cannot be decrypted": "此消息无法被解密", "Encrypted by an unverified session": "由未验证的会话加密", "Unencrypted": "未加密", @@ -1715,7 +1715,7 @@ "The authenticity of this encrypted message can't be guaranteed on this device.": "此加密消息的权威性不能在此设备上被保证。", "Scroll to most recent messages": "滚动到最近的消息", "Close preview": "关闭预览", - "Emoji picker": "表情符号选择器", + "Emoji picker": "Emoji 选择器", "Send a reply…": "发送回复…", "Send a message…": "发送消息…", "Bold": "粗体", @@ -1733,32 +1733,32 @@ "Join the conversation with an account": "使用一个账号加入对话", "Sign Up": "注册", "Loading room preview": "正在加载聊天室预览", - "You were kicked from %(roomName)s by %(memberName)s": "您被 %(memberName)s 踢出了 %(roomName)s", + "You were kicked from %(roomName)s by %(memberName)s": "你被 %(memberName)s 踢出了 %(roomName)s", "Reason: %(reason)s": "原因:%(reason)s", "Forget this room": "忘记此聊天室", "Re-join": "重新加入", - "You were banned from %(roomName)s by %(memberName)s": "您被 %(memberName)s 从 %(roomName)s 封禁了", - "Something went wrong with your invite to %(roomName)s": "您到 %(roomName)s 的邀请出错", - "An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to a room admin.": "尝试验证您的邀请时返回错误(%(errcode)s)。您可以将此信息转告给聊天室管理员。", + "You were banned from %(roomName)s by %(memberName)s": "你被 %(memberName)s 从 %(roomName)s 封禁了", + "Something went wrong with your invite to %(roomName)s": "你到 %(roomName)s 的邀请出错", + "An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to a room admin.": "尝试验证你的邀请时返回错误(%(errcode)s)。你可以将此信息转告给聊天室管理员。", "Try to join anyway": "仍然尝试加入", - "You can still join it because this is a public room.": "您仍然能加入,因为这是一个公共聊天室。", + "You can still join it because this is a public room.": "你仍然能加入,因为这是一个公共聊天室。", "Join the discussion": "加入讨论", - "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "这个到 %(roomName)s 的邀请是发送给 %(email)s 的,而此邮箱没有关联您的账号", - "Link this email with your account in Settings to receive invites directly in %(brand)s.": "要在 %(brand)s 中直接接收邀请,请在设置中将您的账号连接到此邮箱。", + "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "这个到 %(roomName)s 的邀请是发送给 %(email)s 的,而此邮箱没有关联你的账号", + "Link this email with your account in Settings to receive invites directly in %(brand)s.": "要在 %(brand)s 中直接接收邀请,请在设置中将你的账号连接到此邮箱。", "This invite to %(roomName)s was sent to %(email)s": "这个到 %(roomName)s 的邀请是发送给 %(email)s 的", "Use an identity server in Settings to receive invites directly in %(brand)s.": "要直接在 %(brand)s 中接收邀请,请在设置中使用一个身份服务器。", "Share this email in Settings to receive invites directly in %(brand)s.": "要在 %(brand)s 中直接接收邀请,请在设置中共享此邮箱。", - "Do you want to chat with %(user)s?": "您想和 %(user)s 聊天吗?", + "Do you want to chat with %(user)s?": "你想和 %(user)s 聊天吗?", " wants to chat": " 想聊天", "Start chatting": "开始聊天", - "Do you want to join %(roomName)s?": "您想加入 %(roomName)s 吗?", - " invited you": " 邀请了您", + "Do you want to join %(roomName)s?": "你想加入 %(roomName)s 吗?", + " invited you": " 邀请了你", "Reject & Ignore user": "拒绝并忽略用户", - "You're previewing %(roomName)s. Want to join it?": "您正在预览 %(roomName)s。想加入吗?", - "%(roomName)s can't be previewed. Do you want to join it?": "%(roomName)s 不能被预览。您想加入吗?", - "This room doesn't exist. Are you sure you're at the right place?": "此聊天室不存在。您确定您在正确的地方吗?", - "Try again later, or ask a room admin to check if you have access.": "请稍后重试,或询问聊天室管理员以检查您是否有权限。", - "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.": "尝试访问该房间是返回了 %(errcode)s。如果您认为您看到此消息是个错误,请提交一个错误报告。", + "You're previewing %(roomName)s. Want to join it?": "你正在预览 %(roomName)s。想加入吗?", + "%(roomName)s can't be previewed. Do you want to join it?": "%(roomName)s 不能被预览。你想加入吗?", + "This room doesn't exist. Are you sure you're at the right place?": "此聊天室不存在。你确定你在正确的地方吗?", + "Try again later, or ask a room admin to check if you have access.": "请稍后重试,或询问聊天室管理员以检查你是否有权限。", + "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.": "尝试访问该房间是返回了 %(errcode)s。如果你认为你看到此消息是个错误,请提交一个错误报告。", "Appearance": "外观", "Show rooms with unread messages first": "优先显示有未读消息的聊天室", "Show previews of messages": "显示消息预览", @@ -1788,41 +1788,41 @@ "This room has already been upgraded.": "此聊天室已经被升级。", "Unknown Command": "未知命令", "Unrecognised command: %(commandText)s": "未识别的命令:%(commandText)s", - "You can use /help to list available commands. Did you mean to send this as a message?": "您可以使用 /help 列出可用命令。您是否要将其作为消息发送?", - "Hint: Begin your message with // to start it with a slash.": "提示:以 // 开始您的消息来使其以一个斜杠开始。", + "You can use /help to list available commands. Did you mean to send this as a message?": "你可以使用 /help 列出可用命令。你是否要将其作为消息发送?", + "Hint: Begin your message with // to start it with a slash.": "提示:以 // 开始你的消息来使其以一个斜杠开始。", "Send as message": "作为消息发送", "Failed to connect to integration manager": "连接至集成管理器失败", "Mark all as read": "标记所有为已读", "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "更新此聊天室的备用地址时出现错误。可能是服务器不允许,也可能是出现了一个暂时的错误。", "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.": "您没有权限删除此地址。", + "You don't have permission to delete the address.": "你没有权限删除此地址。", "There was an error removing that address. It may no longer exist or a temporary error occurred.": "删除那个地址时出现错误。可能它已不存在,也可能出现了一个暂时的错误。", "Error removing address": "删除地址时出现错误", "Local address": "本地地址", "Published Addresses": "发布的地址", - "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "发布的地址可以被任何服务器上的任何人用来加入您的聊天室。要发布一个地址,它必须先被设为一个本地地址。", + "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "发布的地址可以被任何服务器上的任何人用来加入你的聊天室。要发布一个地址,它必须先被设为一个本地地址。", "Other published addresses:": "其它发布的地址:", "No other published addresses yet, add one below": "还没有别的发布的地址,可在下方添加", "New published address (e.g. #alias:server)": "新的发布的地址(例如 #alias:server)", "Local Addresses": "本地地址", - "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "为此聊天室设置地址以便用户通过您的主服务器(%(localDomain)s)找到此聊天室", + "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "为此聊天室设置地址以便用户通过你的主服务器(%(localDomain)s)找到此聊天室", "Waiting for you to accept on your other session…": "等待您在您别的会话上接受…", "Waiting for %(displayName)s to accept…": "等待 %(displayName)s 接受…", "Accepting…": "正在接受…", "Start Verification": "开始验证", "Messages in this room are end-to-end encrypted.": "此聊天室内的消息是端对端加密的。", - "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "您的消息是安全的,只有您和收件人有解开它们的唯一密钥。", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "你的消息是安全的,只有你和收件人有解开它们的唯一密钥。", "Messages in this room are not end-to-end encrypted.": "此聊天室内的消息未端对端加密。", - "In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "在加密聊天室中,您的消息是安全的,只有您和收件人有解开它们的唯一密钥。", + "In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "在加密聊天室中,你的消息是安全的,只有你和收件人有解开它们的唯一密钥。", "Verify User": "验证用户", - "For extra security, verify this user by checking a one-time code on both of your devices.": "为了更加安全,通过在您二者的设备上检查一次性代码来验证此用户。", - "Your messages are not secure": "您的消息不安全", + "For extra security, verify this user by checking a one-time code on both of your devices.": "为了更加安全,通过在你二者的设备上检查一次性代码来验证此用户。", + "Your messages are not secure": "你的消息不安全", "One of the following may be compromised:": "以下之一可能被损害:", - "Your homeserver": "您的主服务器", - "The homeserver the user you’re verifying is connected to": "您在验证的用户连接到的主服务器", - "Yours, or the other users’ internet connection": "您的或另一位用户的网络连接", - "Yours, or the other users’ session": "您的或另一位用户的会话", + "Your homeserver": "你的主服务器", + "The homeserver the user you’re verifying is connected to": "你在验证的用户连接到的主服务器", + "Yours, or the other users’ internet connection": "你的或另一位用户的网络连接", + "Yours, or the other users’ session": "你的或另一位用户的会话", "Trusted": "受信任的", "Not trusted": "不受信任的", "%(count)s verified sessions|other": "%(count)s 个已验证的会话", @@ -1835,39 +1835,39 @@ "No recent messages by %(user)s found": "没有找到 %(user)s 最近发送的消息", "Try scrolling up in the timeline to see if there are any earlier ones.": "请尝试在时间线中向上滚动以查看是否有更早的。", "Remove recent messages by %(user)s": "删除 %(user)s 最近发送的消息", - "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|other": "您将删除 %(user)s 发送的 %(count)s 条消息。此操作不能撤销。您想继续吗?", - "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|one": "您将删除 %(user)s 发送的 1 条消息。此操作不能撤销。您想继续吗?", - "For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.": "对于大量消息,可能会消耗一段时间。在此期间请不要刷新您的客户端。", + "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|other": "你将删除 %(user)s 发送的 %(count)s 条消息。此操作不能撤销。你想继续吗?", + "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|one": "你将删除 %(user)s 发送的 1 条消息。此操作不能撤销。你想继续吗?", + "For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.": "对于大量消息,可能会消耗一段时间。在此期间请不要刷新你的客户端。", "Remove %(count)s messages|other": "删除 %(count)s 条消息", "Remove %(count)s messages|one": "删除 1 条消息", "Remove recent messages": "删除最近消息", "%(role)s in %(roomName)s": "%(roomName)s 中的 %(role)s", "Deactivate user?": "停用用户吗?", - "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "停用此用户将会使其登出并阻止其再次登入。而且此用户也会离开其所在的所有聊天室。此操作不可逆。您确定要停用此用户吗?", + "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "停用此用户将会使其登出并阻止其再次登入。而且此用户也会离开其所在的所有聊天室。此操作不可逆。你确定要停用此用户吗?", "Deactivate user": "停用用户", "Failed to deactivate user": "停用用户失败", "This client does not support end-to-end encryption.": "此客户端不支持端对端加密。", "Security": "安全", "Verify by scanning": "扫码验证", - "Ask %(displayName)s to scan your code:": "请 %(displayName)s 扫描您的代码:", - "If you can't scan the code above, verify by comparing unique emoji.": "如果您不能扫描以上代码,请通过比较唯一的表情符号来验证。", + "Ask %(displayName)s to scan your code:": "请 %(displayName)s 扫描你的代码:", + "If you can't scan the code above, verify by comparing unique emoji.": "如果你不能扫描以上代码,请通过比较唯一的表情符号来验证。", "Verify by comparing unique emoji.": "通过比较唯一的表情符号来验证。", "Verify by emoji": "通过表情符号验证", - "Almost there! Is your other session showing the same shield?": "快完成了!您的另一个会话显示了同样的盾牌吗?", + "Almost there! Is your other session showing the same shield?": "快完成了!你的另一个会话显示了同样的盾牌吗?", "Almost there! Is %(displayName)s showing the same shield?": "快完成了!%(displayName)s 显示了同样的盾牌吗?", "Verify all users in a room to ensure it's secure.": "验证聊天室中所有用户以确保其安全。", "In encrypted rooms, verify all users to ensure it’s secure.": "在加密聊天室中,验证所有用户以确保其安全。", - "You've successfully verified your device!": "您成功验证了您的设备!", - "You've successfully verified %(deviceName)s (%(deviceId)s)!": "您成功验证了 %(deviceName)s (%(deviceId)s)!", - "You've successfully verified %(displayName)s!": "您成功验证了 %(displayName)s!", + "You've successfully verified your device!": "你成功验证了你的设备!", + "You've successfully verified %(deviceName)s (%(deviceId)s)!": "你成功验证了 %(deviceName)s (%(deviceId)s)!", + "You've successfully verified %(displayName)s!": "你成功验证了 %(displayName)s!", "Verified": "已验证", "Got it": "知道了", "Start verification again from the notification.": "请从提示重新开始验证。", "Start verification again from their profile.": "请从对方资料重新开始验证。", "Verification timed out.": "雅正超时。", - "You cancelled verification on your other session.": "您在您别的会话上取消了验证。", + "You cancelled verification on your other session.": "你在你别的会话上取消了验证。", "%(displayName)s cancelled verification.": "%(displayName)s 取消了验证。", - "You cancelled verification.": "您取消了验证。", + "You cancelled verification.": "你取消了验证。", "Verification cancelled": "验证已取消", "Compare emoji": "比较表情符号", "Encryption enabled": "已启用加密", @@ -1877,20 +1877,20 @@ "React": "回应", "Message Actions": "消息操作", "Show image": "显示图像", - "You have ignored this user, so their message is hidden. Show anyways.": "您已忽略该用户,所以其消息已被隐藏。仍然显示。", - "You verified %(name)s": "您验证了 %(name)s", - "You cancelled verifying %(name)s": "您取消了 %(name)s 的验证", + "You have ignored this user, so their message is hidden. Show anyways.": "你已忽略此用户,所以其消息已被隐藏。仍然显示。", + "You verified %(name)s": "你验证了 %(name)s", + "You cancelled verifying %(name)s": "你取消了 %(name)s 的验证", "%(name)s cancelled verifying": "%(name)s 取消了验证", - "You accepted": "您接受了", + "You accepted": "你接受了", "%(name)s accepted": "%(name)s 接受了", - "You declined": "您拒绝了", - "You cancelled": "您取消了", + "You declined": "你拒绝了", + "You cancelled": "你取消了", "%(name)s declined": "%(name)s 拒绝了", "%(name)s cancelled": "%(name)s 取消了", "Accepting …": "正在接受…", "Declining …": "正在拒绝…", "%(name)s wants to verify": "%(name)s 想要验证", - "You sent a verification request": "您发送了一个验证请求", + "You sent a verification request": "你发送了一个验证请求", "Show all": "显示全部", "Reactions": "回应", " reacted with %(content)s": " 回应了 %(content)s", @@ -1917,14 +1917,14 @@ "Quick Reactions": "快速回应", "Cancel search": "取消搜索", "Any of the following data may be shared:": "以下数据之一可能被分享:", - "Your display name": "您的显示名称", - "Your avatar URL": "您的头像链接", - "Your user ID": "您的用户 ID", - "Your theme": "您的主题", + "Your display name": "你的显示名称", + "Your avatar URL": "你的头像链接", + "Your user ID": "你的用户 ID", + "Your theme": "你的主题", "%(brand)s URL": "%(brand)s 的链接", "Room ID": "聊天室 ID", "Widget ID": "挂件 ID", - "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "使用此挂件可能会和 %(widgetDomain)s 及您的集成管理器共享数据 。", + "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "使用此挂件可能会和 %(widgetDomain)s 及你的集成管理器共享数据 。", "Using this widget may share data with %(widgetDomain)s.": "使用此挂件可能会和 %(widgetDomain)s 共享数据 。", "Widgets do not use message encryption.": "挂件不适用消息加密。", "This widget may use cookies.": "此挂件可能使用 cookie。", @@ -1945,12 +1945,12 @@ "Looks good": "看着不错", "Can't find this server or its room list": "找不到此服务器或其聊天室列表", "All rooms": "所有聊天室", - "Your server": "您的服务器", - "Are you sure you want to remove %(serverName)s": "您确定要移除 %(serverName)s 吗", + "Your server": "你的服务器", + "Are you sure you want to remove %(serverName)s": "你确定要移除 %(serverName)s 吗", "Remove server": "移除服务器", "Matrix": "Matrix", "Add a new server": "添加新服务器", - "Enter the name of a new server you want to explore.": "输入您想探索的新服务器的服务器名。", + "Enter the name of a new server you want to explore.": "输入你想探索的新服务器的服务器名。", "Server name": "服务器名", "Add a new server...": "添加新服务器…", "%(networkName)s rooms": "%(networkName)s 的聊天室", @@ -1958,14 +1958,14 @@ "Use an identity server to invite by email. Use the default (%(defaultIdentityServerName)s) or manage in Settings.": "使用一个身份服务器以通过邮箱邀请。使用默认(%(defaultIdentityServerName)s)或在设置中管理。", "Use an identity server to invite by email. Manage in Settings.": "使用一个身份服务器以通过邮箱邀请。在设置中管理。", "Close dialog": "关闭对话框", - "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "请告诉我们哪里出错了,或最好创建一个 GitHub issue 来描述该问题。", - "Reminder: Your browser is unsupported, so your experience may be unpredictable.": "提醒:您的浏览器不被支持,所以您的体验可能不可预料。", + "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "请告诉我们哪里出错了,或最好创建一个 GitHub issue 来描述此问题。", + "Reminder: Your browser is unsupported, so your experience may be unpredictable.": "提醒:你的浏览器不被支持,所以你的体验可能不可预料。", "GitHub issue": "GitHub 上的 issue", "Notes": "提示", - "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "如果有额外的上下文可以帮助我们分析问题,比如您当时在做什么、房间 ID、用户 ID 等等,请将其列于此处。", + "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "如果有额外的上下文可以帮助我们分析问题,比如你当时在做什么、房间 ID、用户 ID 等等,请将其列于此处。", "Removing…": "正在移除…", "Destroy cross-signing keys?": "销毁交叉签名密钥?", - "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "删除交叉签名密钥是永久的。所有您验证过的人都会看到安全警报。除非您丢失了所有可以交叉签名的设备,否则几乎可以确定您不想这么做。", + "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "删除交叉签名密钥是永久的。所有你验证过的人都会看到安全警报。除非你丢失了所有可以交叉签名的设备,否则几乎可以确定你不想这么做。", "Clear cross-signing keys": "清楚交叉签名密钥", "Clear all data in this session?": "是否清除此会话中的所有数据?", "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "清除此会话中的所有数据是永久的。加密消息会丢失,除非其密钥已被备份。", @@ -1973,7 +1973,7 @@ "Please enter a name for the room": "请输入聊天室名称", "Set a room address to easily share your room with other people.": "设置一个聊天室地址以轻松地和别人共享您的聊天室。", "This room is private, and can only be joined by invitation.": "此聊天室是私人的,只能通过邀请加入。", - "You can’t disable this later. Bridges & most bots won’t work yet.": "您之后不能禁用此项。桥接和大部分机器人还不能正常工作。", + "You can’t disable this later. Bridges & most bots won’t work yet.": "你之后不能禁用此项。桥接和大部分机器人还不能正常工作。", "Enable end-to-end encryption": "启用端对端加密", "Create a public room": "创建一个公共聊天室", "Create a private room": "创建一个私人聊天室", @@ -1982,28 +1982,28 @@ "Hide advanced": "隐藏高级", "Show advanced": "显示高级", "Block users on other matrix homeservers from joining this room (This setting cannot be changed later!)": "阻止别的 matrix 主服务器上的用户加入此聊天室(此设置之后不能更改!)", - "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "您曾在此会话中使用了一个更新版本的 %(brand)s。要再使用此版本并使用端对端加密,您需要登出再重新登录。", - "Confirm your account deactivation by using Single Sign On to prove your identity.": "通过单点登录证明您的身份并确认停用您的账号。", - "Are you sure you want to deactivate your account? This is irreversible.": "您确定要停用您的账号吗?此操作不可逆。", + "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "你曾在此会话中使用了一个更新版本的 %(brand)s。要再使用此版本并使用端对端加密,你需要登出再重新登录。", + "Confirm your account deactivation by using Single Sign On to prove your identity.": "通过单点登录证明你的身份并确认停用你的账号。", + "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.": "联系服务器时出现问题。请重试。", "Server did not require any authentication": "服务器不要求任何认证", "Server did not return valid authentication information.": "服务器未返回有效认证信息。", "View Servers in Room": "查看聊天室中的服务器", "Verification Requests": "验证请求", - "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "验证此用户会将其会话标记为已信任,与此同时,您的会话也会被此用户标记为已信任。", - "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "验证此设备以将其标记为已信任。在收发端对端加密消息时,信任设备可让您与其他用户更加放心。", - "Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "验证此设备会将其标记为已信任,与此同时,其他验证了您的用户也会信任此设备。", + "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "验证此用户会将其会话标记为已信任,与此同时,你的会话也会被此用户标记为已信任。", + "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "验证此设备以将其标记为已信任。在收发端对端加密消息时,信任设备可让你与其他用户更加放心。", + "Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "验证此设备会将其标记为已信任,与此同时,其他验证了你的用户也会信任此设备。", "Integrations are disabled": "集成已禁用", "Enable 'Manage Integrations' in Settings to do this.": "在设置中启用「管理集成」以执行此操作。", "Integrations not allowed": "集成未被允许", - "Your %(brand)s doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "您的 %(brand)s 不允许您使用集成管理器来完成此操作。请联系管理员。", - "To continue, use Single Sign On to prove your identity.": "要继续,请使用单点登录证明您的身份。", + "Your %(brand)s doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "你的 %(brand)s 不允许你使用集成管理器来完成此操作。请联系管理员。", + "To continue, use Single Sign On to prove your identity.": "要继续,请使用单点登录证明你的身份。", "Confirm to continue": "确认以继续", - "Click the button below to confirm your identity.": "点击下方按钮确认您的身份。", + "Click the button below to confirm your identity.": "点击下方按钮确认你的身份。", "Failed to invite the following users to chat: %(csvUsers)s": "邀请以下用户加入聊天失败:%(csvUsers)s", "Something went wrong trying to invite the users.": "尝试邀请用户时出错。", - "We couldn't invite those users. Please check the users you want to invite and try again.": "我们不能邀请这些用户。请检查您想邀请的用户并重试。", + "We couldn't invite those users. Please check the users you want to invite and try again.": "我们不能邀请这些用户。请检查你想邀请的用户并重试。", "Failed to find the following users": "寻找以下用户失败", "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "下列用户可能不存在或无效,因此不能被邀请:%(csvNames)s", "Recent Conversations": "最近对话", @@ -2023,48 +2023,48 @@ "Signature upload success": "签名上传成功", "Signature upload failed": "签名上传失败", "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 会导致问题。", - "Confirm by comparing the following with the User Settings in your other session:": "通过比较下方内容和您别的会话中的用户设置来确认:", + "Confirm by comparing the following with the User Settings in your other session:": "通过比较下方内容和你别的会话中的用户设置来确认:", "Confirm this user's session by comparing the following with their User Settings:": "通过比较下方内容和对方用户设置来确认此用户会话:", "Session name": "会话名称", "Session key": "会话密钥", - "If they don't match, the security of your communication may be compromised.": "如果它们不匹配,您通讯的安全性可能已受损。", + "If they don't match, the security of your communication may be compromised.": "如果它们不匹配,你通讯的安全性可能已受损。", "Verify session": "验证会话", - "Your homeserver doesn't seem to support this feature.": "您的主服务器似乎不支持此功能。", + "Your homeserver doesn't seem to support this feature.": "你的主服务器似乎不支持此功能。", "Message edits": "消息编辑历史", - "Your account is not secure": "您的账号不安全", - "Your password": "您的密码", + "Your account is not secure": "你的账号不安全", + "Your password": "你的密码", "This session, or the other session": "此会话,或别的会话", - "The internet connection either session is using": "您会话使用的网络连接", + "The internet connection either session is using": "你会话使用的网络连接", "We recommend you change your password and recovery key in Settings immediately": "我们推荐您立刻在设置中更改您的密码和恢复密钥", "New session": "新会话", - "Use this session to verify your new one, granting it access to encrypted messages:": "使用此会话以验证您的新会话,并允许其访问加密信息:", - "If you didn’t sign in to this session, your account may be compromised.": "如果您没有登录进此会话,您的账号可能已受损。", + "Use this session to verify your new one, granting it access to encrypted messages:": "使用此会话以验证你的新会话,并允许其访问加密信息:", + "If you didn’t sign in to this session, your account may be compromised.": "如果你没有登录进此会话,你的账号可能已受损。", "This wasn't me": "这不是我", "Use your account to sign in to the latest version of the app at ": "使用您的账户在 登录此应用的最新版", "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "您已经登录且一切已就绪,但您也可以在 element.io/get-started 获取此应用在全平台上的最新版。", "Go to Element": "前往 Element", "We’re excited to announce Riot is now Element!": "我们很兴奋地宣布 Riot 现在是 Element 了!", "Learn more at element.io/previously-riot": "访问 element.io/previously-riot 了解更多", - "Please fill why you're reporting.": "请填写您为何做此报告。", - "Report Content to Your Homeserver Administrator": "向您的主服务器管理员举报内容", - "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "举报此消息会将其唯一的「事件 ID」发送给您的主服务器的管理员。如果此聊天室中的消息被加密,您的主服务器管理员将不能阅读消息文本,也不能查看任何文件或图片。", + "Please fill why you're reporting.": "请填写你为何做此报告。", + "Report Content to Your Homeserver Administrator": "向你的主服务器管理员举报内容", + "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "举报此消息会将其唯一的「事件 ID」发送给你的主服务器的管理员。如果此聊天室中的消息被加密,你的主服务器管理员将不能阅读消息文本,也不能查看任何文件或图片。", "Send report": "发送报告", "Upgrading this room requires closing down the current instance of the room and creating a new room in its place. To give room members the best possible experience, we will:": "更新此聊天室需要关闭此聊天室的当前实力并创建一个新的聊天室代替它。为了给聊天室成员最好的体验,我们会:", "Automatically invite users": "自动邀请用户", "Upgrade private room": "更新私人聊天室", "Upgrade public room": "更新公共聊天室", "Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.": "更新聊天室是高级操作,通常建议在聊天室由于错误、缺失功能或安全漏洞而不稳定时使用。", - "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "通常这只影响聊天室在服务器上的处理方式。如果您对您的 %(brand)s 有问题,请报告一个错误。", - "You'll upgrade this room from to .": "您将把此聊天室从 升级至 。", + "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "通常这只影响聊天室在服务器上的处理方式。如果你对你的 %(brand)s 有问题,请报告一个错误。", + "You'll upgrade this room from to .": "你将把此聊天室从 升级至 。", "You're all caught up.": "全数阅毕。", "Server isn't responding": "服务器未响应", - "Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "您的服务器未响应您的一些请求。下方是一些最可能的原因。", + "Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "你的服务器未响应你的一些请求。下方是一些最可能的原因。", "The server (%(serverName)s) took too long to respond.": "服务器(%(serverName)s)花了太长时间响应。", - "Your firewall or anti-virus is blocking the request.": "您的防火墙或防病毒软件阻止了该请求。", - "A browser extension is preventing the request.": "一个浏览器扩展阻止了该请求。", - "The server is offline.": "该服务器为离线状态。", - "The server has denied your request.": "该服务器拒绝了您的请求。", - "Your area is experiencing difficulties connecting to the internet.": "您的区域难以连接上互联网。", + "Your firewall or anti-virus is blocking the request.": "你的防火墙或防病毒软件阻止了此请求。", + "A browser extension is preventing the request.": "一个浏览器扩展阻止了此请求。", + "The server is offline.": "此服务器为离线状态。", + "The server has denied your request.": "此服务器拒绝了你的请求。", + "Your area is experiencing difficulties connecting to the internet.": "你的区域难以连接上互联网。", "A connection error occurred while trying to contact the server.": "尝试联系服务器时出现连接错误。", "Recent changes that have not yet been received": "尚未被接受的最近更改", "Sign out and remove encryption keys?": "登出并删除加密密钥?", @@ -2073,13 +2073,13 @@ "To help us prevent this in future, please send us logs.": "要帮助我们防止其以后发生,请给我们发送日志。", "Missing session data": "缺失会话数据", "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "一些会话数据,包括加密消息密钥,已缺失。要修复此问题,登出并重新登录,然后从备份恢复密钥。", - "Your browser likely removed this data when running low on disk space.": "您的浏览器可能在磁盘空间不足时删除了此数据。", + "Your browser likely removed this data when running low on disk space.": "你的浏览器可能在磁盘空间不足时删除了此数据。", "Integration Manager": "集成管理器", "Find others by phone or email": "通过电话或邮箱寻找别人", "Be found by phone or email": "通过电话或邮箱被寻找", "Use bots, bridges, widgets and sticker packs": "使用机器人、桥接、挂件和贴图集", "Terms of Service": "服务协议", - "To continue you need to accept the terms of this service.": "要继续,您需要接受此服务协议。", + "To continue you need to accept the terms of this service.": "要继续,你需要接受此服务协议。", "Service": "服务", "Summary": "总结", "Document": "文档", @@ -2101,9 +2101,9 @@ "Invalid Recovery Key": "无效的恢复密钥", "Security Phrase": "安全密码", "Unable to access secret storage. Please verify that you entered the correct recovery passphrase.": "无法访问秘密存储。请确认您输入了正确的恢复密码。", - "Enter your Security Phrase or to continue.": "输入您的安全密码或以继续。", + "Enter your Security Phrase or to continue.": "输入你的安全密码或以继续。", "Security Key": "安全密钥", - "Use your Security Key to continue.": "使用您的安全密钥以继续。", + "Use your Security Key to continue.": "使用你的安全密钥以继续。", "Restoring keys from backup": "从备份恢复密钥", "Fetching keys from server...": "正在从服务器获取密钥...", "%(completed)s of %(total)s keys restored": "%(total)s 个密钥中之 %(completed)s 个已恢复", @@ -2115,7 +2115,7 @@ "Successfully restored %(sessionCount)s keys": "成功恢复了 %(sessionCount)s 个密钥", "Enter recovery passphrase": "输入恢复密码", "Enter recovery key": "输入恢复密钥", - "Warning: You should only set up key backup from a trusted computer.": "警告:您应该只从信任的计算机设置密钥备份。", + "Warning: You should only set up key backup from a trusted computer.": "警告:你应此只从信任的计算机设置密钥备份。", "If you've forgotten your recovery key you can ": "如果您忘记了恢复密钥,您可以", "Address (optional)": "地址(可选)", "Resend edit": "重新发送编辑", @@ -2130,19 +2130,19 @@ "Remove for me": "为我删除", "User Status": "用户状态", "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "您可以使用自定义服务器选项以使用不同的主服务器链接登录至别的 Matrix 服务器。这允许您通过不同的主服务器上的现存 Matrix 账户使用 %(brand)s。", - "Confirm your identity by entering your account password below.": "在下方输入账号密码以确认您的身份。", - "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "在主服务器配置中缺少验证码公钥。请将此报告给您的主服务器管理员。", + "Confirm your identity by entering your account password below.": "在下方输入账号密码以确认你的身份。", + "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "在主服务器配置中缺少验证码公钥。请将此报告给你的主服务器管理员。", "Unable to validate homeserver/identity server": "无法验证主服务器/身份服务器", "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "输入您的 Element Matrix Services 主服务器的地址。它可能使用您自己的域名,也可能是 element.io 的子域名。", "Enter password": "输入密码", "Nice, strong password!": "不错,是个强密码!", "Password is allowed, but unsafe": "密码允许但不安全", "No identity server is configured so you cannot add an email address in order to reset your password in the future.": "没有配置身份服务器因此您不能添加邮件地址以在将来重置您的密码。", - "Use an email address to recover your account": "使用邮件地址恢复您的账号", + "Use an email address to recover your account": "使用邮件地址恢复你的账号", "Enter email address (required on this homeserver)": "输入邮件地址(此主服务器上必须)", "Doesn't look like a valid email address": "看起来不像有效的邮件地址", "Passwords don't match": "密码不匹配", - "Other users can invite you to rooms using your contact details": "别的用户可以使用您的联系人信息邀请您加入聊天室", + "Other users can invite you to rooms using your contact details": "别的用户可以使用你的联系人信息邀请你加入聊天室", "Enter phone number (required on this homeserver)": "输入电话号码(此主服务器上必须)", "Doesn't look like a valid phone number": "看着不像一个有效的电话号码", "Use lowercase letters, numbers, dashes and underscores only": "仅使用小写字母,数字,横杠和下划线", @@ -2156,7 +2156,7 @@ "Sign in with SSO": "使用单点登录", "No files visible in this room": "此聊天室中没有可见文件", "Welcome to %(appName)s": "欢迎来到 %(appName)s", - "Liberate your communication": "解放您的交流", + "Liberate your communication": "解放你的交流", "Send a Direct Message": "发送私聊", "Explore Public Rooms": "探索公共聊天室", "Create a Group Chat": "创建一个群聊", @@ -2171,7 +2171,7 @@ "View": "查看", "Find a room…": "寻找聊天室…", "Find a room… (e.g. %(exampleRoom)s)": "寻找聊天室... (例如 %(exampleRoom)s)", - "If you can't find the room you're looking for, ask for an invite or Create a new room.": "如果您不能找到您所寻找的聊天室,请索要一个邀请或创建新聊天室。", + "If you can't find the room you're looking for, ask for an invite or Create a new room.": "如果你不能找到你所寻找的聊天室,请索要一个邀请或创建新聊天室。", "Search rooms": "搜索聊天室", "Switch to light mode": "切换到浅色模式", "Switch to dark mode": "切换到深色模式", @@ -2183,7 +2183,7 @@ "Session verified": "会话已验证", "Your Matrix account on ": "您在 上的 Matrix 账户", "No identity server is configured: add one in server settings to reset your password.": "没有配置身份服务器:在服务器设置中添加一个以重设您的密码。", - "You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "您已经登出了所有会话,并将不会收到推送通知。要重新启用通知,请在每个设备上重新登录。", + "You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "你已经登出了所有会话,并将不会收到推送通知。要重新启用通知,请在每个设备上重新登录。", "Failed to get autodiscovery configuration from server": "从服务器获取自动发现配置时失败", "Invalid base_url for m.homeserver": "m.homeserver 的 base_url 无效", "Homeserver URL does not appear to be a valid Matrix homeserver": "主服务器链接不像是有效的 Matrix 主服务器", @@ -2192,11 +2192,11 @@ "This account has been deactivated.": "此账号已被停用。", "Syncing...": "正在同步...", "Signing In...": "正在登录...", - "If you've joined lots of rooms, this might take a while": "如果您加入了很多聊天室,可能会消耗一些时间", - "Your new account (%(newAccountId)s) is registered, but you're already logged into a different account (%(loggedInUserId)s).": "您的新账号(%(newAccountId)s)已注册,但您已经登录了一个不同的账号(%(loggedInUserId)s)。", + "If you've joined lots of rooms, this might take a while": "如果你加入了很多聊天室,可能会消耗一些时间", + "Your new account (%(newAccountId)s) is registered, but you're already logged into a different account (%(loggedInUserId)s).": "你的新账号(%(newAccountId)s)已注册,但你已经登录了一个不同的账号(%(loggedInUserId)s)。", "Continue with previous account": "用之前的账号继续", - "Log in to your new account.": "登录到您的新账号。", - "You can now close this window or log in to your new account.": "您现在可以关闭此窗口或登录到您的新账号。", + "Log in to your new account.": "登录到你的新账号。", + "You can now close this window or log in to your new account.": "你现在可以关闭此窗口或登录到你的新账号。", "Registration Successful": "注册成功", "Use Recovery Key or Passphrase": "使用恢复密钥或密码", "Use Recovery Key": "使用恢复密钥", @@ -2206,21 +2206,21 @@ "%(brand)s iOS": "%(brand)s iOS", "%(brand)s X for Android": "%(brand)s X for Android", "or another cross-signing capable Matrix client": "或者别的可以交叉签名的 Matrix 客户端", - "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "您的新会话现已被验证。它可以访问您的加密消息,别的用户也会视其为受信任的。", - "Your new session is now verified. Other users will see it as trusted.": "您的新会话现已被验证。别的用户会视其为受信任的。", + "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "你的新会话现已被验证。它可以访问你的加密消息,别的用户也会视其为受信任的。", + "Your new session is now verified. Other users will see it as trusted.": "你的新会话现已被验证。别的用户会视其为受信任的。", "Without completing security on this session, it won’t have access to encrypted messages.": "若不在此会话中完成安全验证,它便不能访问加密消息。", "Failed to re-authenticate due to a homeserver problem": "由于主服务器的问题,重新认证失败", "Failed to re-authenticate": "重新认证失败", - "Regain access to your account and recover encryption keys stored in this session. Without them, you won’t be able to read all of your secure messages in any session.": "重新获得访问您账号的权限,并恢复存储在此会话中的加密密钥。没有这些密钥,您将不能在任何会话中阅读您的所有安全消息。", - "Enter your password to sign in and regain access to your account.": "输入您的密码以登录并重新获取访问您账号的权限。", - "Forgotten your password?": "忘记您的密码了吗?", - "Sign in and regain access to your account.": "请登录以重新获取访问您账号的权限。", - "You cannot sign in to your account. Please contact your homeserver admin for more information.": "您不能登录进您的账号。请联系您的主服务器管理员以获取更多信息。", - "You're signed out": "您已登出", + "Regain access to your account and recover encryption keys stored in this session. Without them, you won’t be able to read all of your secure messages in any session.": "重新获得访问你账号的权限,并恢复存储在此会话中的加密密钥。没有这些密钥,你将不能在任何会话中阅读你的所有安全消息。", + "Enter your password to sign in and regain access to your account.": "输入你的密码以登录并重新获取访问你账号的权限。", + "Forgotten your password?": "忘记你的密码了吗?", + "Sign in and regain access to your account.": "请登录以重新获取访问你账号的权限。", + "You cannot sign in to your account. Please contact your homeserver admin for more information.": "你不能登录进你的账号。请联系你的主服务器管理员以获取更多信息。", + "You're signed out": "你已登出", "Clear personal data": "清除个人信息", - "Warning: Your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.": "警告:您的个人信息(包括加密密钥)仍存储于此会话中。如果您不用再使用此会话或想登录进另一个账号,请清除它。", + "Warning: Your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.": "警告:你的个人信息(包括加密密钥)仍存储于此会话中。如果你不用再使用此会话或想登录进另一个账号,请清除它。", "Command Autocomplete": "命令自动补全", - "Community Autocomplete": "社区自动补全", + "Community Autocomplete": "社群自动补全", "DuckDuckGo Results": "DuckDuckGo 结果", "Emoji Autocomplete": "表情符号自动补全", "Notification Autocomplete": "通知自动补全", @@ -2228,32 +2228,32 @@ "User Autocomplete": "用户自动补全", "Confirm encryption setup": "确认加密设置", "Click the button below to confirm setting up encryption.": "点击下方按钮以确认设置加密。", - "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "通过在您的服务器上备份加密密钥来防止丢失您对加密消息和数据的访问权。", + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "通过在你的服务器上备份加密密钥来防止丢失你对加密消息和数据的访问权。", "Generate a Security Key": "生成一个安全密钥", - "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "我们会生成一个安全密钥以便让您存储在安全的地方,比如密码管理器或保险箱里。", + "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "我们会生成一个安全密钥以便让你存储在安全的地方,比如密码管理器或保险箱里。", "Enter a Security Phrase": "输入一个安全密码", - "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "使用一个只有您知道的密码,您也可以保存安全密钥以供备份使用。", - "Enter your account password to confirm the upgrade:": "输入您的账号密码以确认更新:", - "Restore your key backup to upgrade your encryption": "恢复您的密钥备份以更新您的加密方式", + "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "使用一个只有你知道的密码,你也可以保存安全密钥以供备份使用。", + "Enter your account password to confirm the upgrade:": "输入你的账号密码以确认更新:", + "Restore your key backup to upgrade your encryption": "恢复你的密钥备份以更新你的加密方式", "Restore": "恢复", - "You'll need to authenticate with the server to confirm the upgrade.": "您需要和服务器进行认证以确认更新。", + "You'll need to authenticate with the server to confirm the upgrade.": "你需要和服务器进行认证以确认更新。", "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "更新此会话以允许其验证其他会话、允许其他会话访问加密消息,并将它们对别的用户标记为已信任。", - "Enter a security phrase only you know, as it’s used to safeguard your data. To be secure, you shouldn’t re-use your account password.": "输入一个只有您知道的安全密码,它将被用来保护您的数据。为了安全,您不应该复用您的账号密码。", + "Enter a security phrase only you know, as it’s used to safeguard your data. To be secure, you shouldn’t re-use your account password.": "输入一个只有你知道的安全密码,它将被用来保护你的数据。为了安全,你不应该复用你的账号密码。", "Enter a recovery passphrase": "输入一个恢复密码", "Great! This recovery passphrase looks strong enough.": "棒!这个恢复密码看着够强。", "Use a different passphrase?": "使用不同的密语?", "Enter your recovery passphrase a second time to confirm it.": "再次输入您的恢复密语以确认。", "Confirm your recovery passphrase": "确认您的恢复密语", - "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "将您的安全密钥存储在安全的地方,像是密码管理器或保险箱里,它将被用来保护您的加密数据。", + "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "将你的安全密钥存储在安全的地方,像是密码管理器或保险箱里,它将被用来保护你的加密数据。", "Copy": "复制", "Unable to query secret storage status": "无法查询秘密存储状态", - "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "如果您现在取消,您可能会丢失加密的消息和数据,如果您丢失了登录信息的话。", - "You can also set up Secure Backup & manage your keys in Settings.": "您也可以在设置中设置安全备份并管理您的密钥。", + "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "如果你现在取消,你可能会丢失加密的消息和数据,如果你丢失了登录信息的话。", + "You can also set up Secure Backup & manage your keys in Settings.": "你也可以在设置中设置安全备份并管理你的密钥。", "Set up Secure backup": "设置安全备份", - "Upgrade your encryption": "更新您的加密方法", + "Upgrade your encryption": "更新你的加密方法", "Set a Security Phrase": "设置一个安全密码", "Confirm Security Phrase": "确认安全密码", - "Save your Security Key": "保存您的安全密钥", + "Save your Security Key": "保存你的安全密钥", "Unable to set up secret storage": "无法设置秘密存储", "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "我们会在服务器上存储一份您的密钥的加密副本。用恢复密码来保护您的备份。", "Set up with a recovery key": "用恢复密钥设置", @@ -2264,13 +2264,13 @@ "Your recovery key": "您的恢复密钥", "Your recovery key has been copied to your clipboard, paste it to:": "您的恢复密钥已被复制到您的剪贴板,将其粘贴至:", "Your recovery key is in your Downloads folder.": "您的恢复密钥在您的下载文件夹里。", - "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.": "若不设置安全消息恢复,您如果登出或使用另一个会话,则将不能恢复您的加密消息历史。", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.": "若不设置安全消息恢复,你如果登出或使用另一个会话,则将不能恢复你的加密消息历史。", "Secure your backup with a recovery passphrase": "用恢复密码保护您的备份", "Make a copy of your recovery key": "制作一份您的恢复密钥的副本", "Create key backup": "创建密钥备份", "This session is encrypting history using the new recovery method.": "此会话正在使用新的恢复方法加密历史。", "This session has detected that your recovery passphrase and key for Secure Messages have been removed.": "此会话检测到您的恢复密码和安全消息的密钥已被移除。", - "If you did this accidentally, you can setup Secure Messages on this session which will re-encrypt this session's message history with a new recovery method.": "如果您出于意外这样做了,您可以在此会话上设置安全消息,以使用新的加密方式重新加密此会话的消息历史。", + "If you did this accidentally, you can setup Secure Messages on this session which will re-encrypt this session's message history with a new recovery method.": "如果你出于意外这样做了,你可以在此会话上设置安全消息,以使用新的加密方式重新加密此会话的消息历史。", "If disabled, messages from encrypted rooms won't appear in search results.": "如果被禁用,加密聊天室内的消息不会显示在搜索结果中。", "Disable": "禁用", "Not currently indexing messages for any room.": "现在没有为任何聊天室索引消息。", @@ -2329,7 +2329,7 @@ "Securely cache encrypted messages locally for them to appear in search results, using ": "在本地安全缓存已加密消息以使其出现在搜索结果中,使用 ", " to store messages from ": " 存储来自 ", "rooms.": "聊天室的消息。", - "This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.": "此会话未备份您的密钥,但您已有备份,您可以继续并从中恢复和向其添加。", + "This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.": "此会话未备份你的密钥,但如果你已有现存备份,你可以继续并从中恢复和向其添加。", "Invalid theme schema.": "无效主题方案。", "Read Marker lifetime (ms)": "已读标记生存期 (ms)", "Read Marker off-screen lifetime (ms)": "已读标记屏幕外生存期 (ms)", @@ -2338,11 +2338,11 @@ "Unable to revoke sharing for phone number": "无法撤销电话号码共享", "Mod": "管理员", "Explore public rooms": "探索公共聊天室", - "Can't see what you’re looking for?": "看不到您要找的吗?", + "Can't see what you’re looking for?": "看不到你要找的吗?", "Explore all public rooms": "探索所有公共聊天室", "%(count)s results|other": "%(count)s 个结果", - "You can only join it with a working invite.": "您只能通过有效邀请加入。", - "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "您尝试验证的会话不支持 %(brand)s 支持的扫描二维码或表情符号验证。尝试使用其他客户端。", + "You can only join it with a working invite.": "你只能通过有效邀请加入。", + "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "你尝试验证的会话不支持 %(brand)s 支持的扫描二维码或表情符号验证。尝试使用其他客户端。", "Language Dropdown": "语言下拉菜单", "%(severalUsers)smade no changes %(count)s times|other": "%(severalUsers)s 未做更改 %(count)s 次", "%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)s 未做更改", @@ -2380,7 +2380,7 @@ "Group call started by %(senderName)s": "%(senderName)s 发起的群通话", "Group call ended by %(senderName)s": "%(senderName)s 结束了群通话", "Unknown App": "未知应用", - "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "社区 v2 原型。需要兼容的主服务器。高度实验性 - 谨慎使用。", + "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "社群 v2 原型。需要兼容的主服务器。高度实验性 - 谨慎使用。", "Cross-signing is ready for use.": "交叉签名已可用。", "Cross-signing is not set up.": "未设置交叉签名。", "Backup version:": "备份版本:", @@ -2396,7 +2396,7 @@ "not ready": "尚未就绪", "Secure Backup": "安全备份", "Privacy": "隐私", - "Explore community rooms": "探索社区聊天室", + "Explore community rooms": "探索社群聊天室", "%(count)s results|one": "%(count)s 个结果", "Room Info": "聊天室信息", "No other application is using the webcam": "没有其他应用程序正在使用摄像头", @@ -2406,7 +2406,7 @@ "Unable to access webcam / microphone": "无法访问摄像头/麦克风", "Call failed because no microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "呼叫失败,因为无法访问任何麦克风。 检查是否已插入麦克风并正确设置。", "Unable to access microphone": "无法使用麦克风", - "The call was answered on another device.": "在另一台设备上应答了该通话。", + "The call was answered on another device.": "在另一台设备上应答了此通话。", "The call could not be established": "无法建立通话", "The other party declined the call.": "对方拒绝了通话。", "Call Declined": "通话被拒绝", @@ -2471,18 +2471,18 @@ "Afghanistan": "阿富汗", "United States": "美国", "United Kingdom": "英国", - "Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.": "您的主服务器已拒绝您的登入尝试。请重试。如果此情况持续发生,请联系您的主服务器管理员。", - "Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.": "无法访问您的主服务器,因而无法登入。请重试。如果此情况持续发生,请联系您的主服务器管理员。", + "Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.": "你的主服务器已拒绝你的登入尝试。请重试。如果此情况持续发生,请联系你的主服务器管理员。", + "Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.": "无法访问你的主服务器,因而无法登入。请重试。如果此情况持续发生,请联系你的主服务器管理员。", "Try again": "重试", - "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.": "我们已要求浏览器记住您使用的主服务器,但不幸的是您的浏览器已忘记。请前往登录页面重试。", - "We couldn't log you in": "我们无法使您登入", + "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.": "我们已要求浏览器记住你使用的主服务器,但不幸的是你的浏览器已忘记。请前往登录页面重试。", + "We couldn't log you in": "我们无法使你登入", "This will end the conference for everyone. Continue?": "这将结束所有人的会议。是否继续?", "End conference": "结束会议", - "You've reached the maximum number of simultaneous calls.": "您已达到并行呼叫最大数量。", + "You've reached the maximum number of simultaneous calls.": "你已达到并行呼叫最大数量。", "Too Many Calls": "太多呼叫", "Call failed because webcam or microphone could not be accessed. Check that:": "通话失败,因为无法访问网络摄像头或麦克风。请检查:", "Call failed because microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "呼叫失败,因为无法访问任何麦克风。 检查是否已插入麦克风并正确设置。", - "Answered Elsewhere": "在其他地方已回答", + "Answered Elsewhere": "已在其他地方回答", "Use the + to make a new room or explore existing ones below": "使用 + 创建新的聊天室或通过下面列出的方式探索已有聊天室", "Start a new chat": "开始新会话", "Room settings": "聊天室设置", @@ -2497,10 +2497,10 @@ "Creating...": "创建中……", "You can change these at any point.": "您可随时更改这些。", "Give it a photo, name and description to help you identify it.": "为它添加一张照片、姓名与描述来帮助您辨认它。", - "Your private space": "您的私有空间", - "Your public space": "您的公共空间", - "You can change this later": "您可稍后更改此项", - "Invite only, best for yourself or teams": "仅邀请,适合您自己或团队", + "Your private space": "你的私有空间", + "Your public space": "你的公共空间", + "You can change this later": "你可稍后更改此项", + "Invite only, best for yourself or teams": "仅邀请,适合你自己或团队", "Private": "私有", "Public": "公共", "Delete": "删除", @@ -2511,8 +2511,8 @@ "Voice Call": "语音通话", "Video Call": "视频通话", "%(peerName)s held the call": "%(peerName)s 挂起了通话", - "You held the call Resume": "您挂起了通话 恢复", - "You held the call Switch": "您挂起了通话 切换", + "You held the call Resume": "你挂起了通话 恢复", + "You held the call Switch": "你挂起了通话 切换", "Takes the call in the current room off hold": "解除挂起当前聊天室的通话", "Places the call in the current room on hold": "挂起当前聊天室的通话", "Show chat effects (animations when receiving e.g. confetti)": "显示聊天特效(如收到五彩纸屑时的动画效果)", @@ -2526,7 +2526,7 @@ "Show stickers button": "显示贴纸按钮", "Render LaTeX maths in messages": "在信息中渲染 LaTeX 数学", "%(senderName)s ended the call": "%(senderName)s 结束了通话", - "You ended the call": "您结束了通话", + "You ended the call": "你结束了通话", "This homeserver has been blocked by it's administrator.": "此 homeserver 已被其管理员屏蔽。", "Use app": "使用 app", "Element Web is experimental on mobile. For a better experience and the latest features, use our free native app.": "Element 网页版在移动设备上仍处于试验阶段。使用免费的原生 app 以获得更好的体验与最新的功能。", @@ -2534,7 +2534,7 @@ "Enable desktop notifications": "开启桌面通知", "Don't miss a reply": "不要错过任何回复", "This homeserver has been blocked by its administrator.": "此 homeserver 已被其管理员屏蔽。", - "Send stickers to this room as you": "以您的身份发送贴纸到此聊天室", + "Send stickers to this room as you": "以你的身份发送贴纸到此聊天室", "Change the avatar of your active room": "更改活跃聊天室的头像", "Change the avatar of this room": "更改当前聊天室的头像", "Change the name of your active room": "更改活跃聊天室的名称", @@ -2543,10 +2543,10 @@ "Change the topic of this room": "更改当前聊天室的话题", "Change which room, message, or user you're viewing": "更改当前正在查看哪个聊天室、消息或用户", "Change which room you're viewing": "更改当前正在查看哪个聊天室", - "Send stickers into your active room": "发送贴纸到您的活跃聊天室", + "Send stickers into your active room": "发送贴纸到你的活跃聊天室", "Send stickers into this room": "发送贴纸到此聊天室", - "Remain on your screen while running": "运行时始终保留在您的屏幕上", - "Remain on your screen when viewing another room, when running": "运行时始终保留在您的屏幕上,即使您在浏览其它聊天室", + "Remain on your screen while running": "运行时始终保留在你的屏幕上", + "Remain on your screen when viewing another room, when running": "运行时始终保留在你的屏幕上,即使你在浏览其它聊天室", "%(senderName)s declined the call.": "%(senderName)s 拒绝了通话。", "(an error occurred)": "(发生了一个错误)", "(their device couldn't start the camera / microphone)": "(对方的设备无法开启摄像头/麦克风)", @@ -2554,12 +2554,12 @@ "Converts the DM to a room": "将此私聊会话转化为聊天室会话", "Prepends ┬──┬ ノ( ゜-゜ノ) to a plain-text message": "在纯文本消息开头添加 ┬──┬ ノ( ゜-゜ノ)", "Prepends (╯°□°)╯︵ ┻━┻ to a plain-text message": "在纯文本消息开头添加 (╯°□°)╯︵ ┻━┻", - "You're already in a call with this person.": "您与此人已处在通话中。", + "You're already in a call with this person.": "你正在与其通话中。", "Already in call": "已在通话中", "Navigate composer history": "浏览编辑区历史", "Go to Home View": "转到主视图", "Search (must be enabled)": "搜索(必须启用)", - "Your Security Key": "您的安全密钥", + "Your Security Key": "你的安全密钥", "Use Security Key": "使用安全密钥", "%(ssoButtons)s Or %(usernamePassword)s": "%(ssoButtons)s 或 %(usernamePassword)s", "User settings": "用户设置", @@ -2575,7 +2575,7 @@ "Remove from Space": "从空间中移除", "Undo": "撤销", "Welcome %(name)s": "欢迎 %(name)s", - "Create community": "创建社区", + "Create community": "创建社群", "Forgot password?": "忘记密码?", "Enter Security Key": "输入安全密钥", "Invalid Security Key": "安全密钥无效", @@ -2603,7 +2603,7 @@ "Value": "值", "Setting ID": "设置 ID", "Enter name": "输入名称", - "Community ID: +:%(domain)s": "社区 ID:+:%(domain)s", + "Community ID: +:%(domain)s": "社群 ID:+:%(domain)s", "Reason (optional)": "理由(可选)", "Show": "显示", "Apply": "应用", @@ -2634,7 +2634,7 @@ "Send message": "发送消息", "Invite to this space": "邀请至此空间", "Your message was sent": "消息已发送", - "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.": "请使用您的账号数据备份加密密钥,以免您无法访问您的会话。密钥将通过一个唯一的安全密钥进行保护。", + "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.": "请使用你的账号数据备份加密密钥,以免你无法访问你的会话。密钥将通过一个唯一的安全密钥进行保护。", "Spell check dictionaries": "拼写检查字典", "Failed to save your profile": "个人资料保存失败", "The operation could not be completed": "操作无法完成", @@ -2654,11 +2654,11 @@ "Sends the given message with fireworks": "附加烟火发送", "sends fireworks": "发送烟火", "Offline encrypted messaging using dehydrated devices": "需要离线设备(dehydrated devices)的加密消息离线传递", - "Spaces prototype. Incompatible with Communities, Communities v2 and Custom Tags. Requires compatible homeserver for some features.": "正在开发的空间功能的原型。与社区、社区 V2 和自定义标签功能不兼容。需要主服务器兼容才能使用某些功能。", + "Spaces prototype. Incompatible with Communities, Communities v2 and Custom Tags. Requires compatible homeserver for some features.": "正在开发的空间功能的原型。与社群、社群 V2 和自定义标签功能不兼容。需要主服务器兼容才能使用某些功能。", "The %(capability)s capability": "%(capability)s 容量", "%(senderName)s has updated the widget layout": "%(senderName)s 已更新挂件布局", "Support": "支持", - "Your server does not support showing space hierarchies.": "您的服务器不支持显示空间层次结构。", + "Your server does not support showing space hierarchies.": "你的服务器不支持显示空间层次结构。", "This version of %(brand)s does not support searching encrypted messages": "当前版本的 %(brand)s 不支持搜索加密消息", "This version of %(brand)s does not support viewing some encrypted files": "当前版本的 %(brand)s 不支持查看某些加密文件", "Effects": "效果", @@ -2760,7 +2760,7 @@ "Explore rooms in %(communityName)s": "在 %(communityName)s 中探索聊天室", "%(count)s messages deleted.|one": "已删除 %(count)s 条消息。", "%(count)s messages deleted.|other": "已删除 %(count)s 条消息。", - "Cannot create rooms in this community": "无法在此社区中创建聊天室", + "Cannot create rooms in this community": "无法在此社群中创建聊天室", "Upgrade to %(hostSignupBrand)s": "升级至 %(hostSignupBrand)s", "Enter phone number": "输入电话号码", "Enter email address": "输入邮箱地址", @@ -2769,13 +2769,13 @@ "Revoke permissions": "撤销权限", "Take a picture": "拍照", "Enter Security Phrase": "输入安全密语", - "Allow this widget to verify your identity": "允许此挂件验证您的身份", + "Allow this widget to verify your identity": "允许此挂件验证你的身份", "Decline All": "全部拒绝", "Approve": "批准", "This widget would like to:": "此挂件想要:", "Approve widget permissions": "批准挂件权限", "Failed to save space settings.": "空间设置保存失败。", - "Sign into your homeserver": "登录您的主服务器", + "Sign into your homeserver": "登录你的主服务器", "Unable to validate homeserver": "无法验证主服务器", "Invalid URL": "URL 无效", "Modal Widget": "模态框挂件(Modal Widget)", @@ -2793,24 +2793,24 @@ "Widgets": "挂件", "This is the start of .": "这里是 的开始。", "Add a photo, so people can easily spot your room.": "添加图片,让人们一眼就能看到你的聊天室。", - "You can change these anytime.": "您随时可以更改它们。", - "Add some details to help people recognise it.": "添加一些细节,以便人们辨识你的社区。", - "Open space for anyone, best for communities": "适合每一个人的开放空间,社区的理想选择", + "You can change these anytime.": "你随时可以更改它们。", + "Add some details to help people recognise it.": "添加一些细节,以便人们辨识你的社群。", + "Open space for anyone, best for communities": "适合每一个人的开放空间,社群的理想选择", "Spaces are new ways to group rooms and people. To join an existing space you'll need an invite.": "空间是为房间和人员分组的新方法。要加入现有的空间,您需要被邀请。", "From %(deviceName)s (%(deviceId)s) at %(ip)s": "来自 %(deviceName)s(%(deviceId)s)于 %(ip)s", "New version of %(brand)s is available": "%(brand)s 有新版本可用", - "You have unverified logins": "您有未验证的登录", + "You have unverified logins": "你有未验证的登录", "You should know": "你应当知道", "Learn more in our , and .": "请通过我们的了解更多信息。", - "Failed to connect to your homeserver. Please close this dialog and try again.": "无法连接至您的主服务器。请关闭此对话框并再试一次。", - "Are you sure you wish to abort creation of the host? The process cannot be continued.": "您确定要放弃创建主机吗?被放弃的创建流程将无法再继续。", + "Failed to connect to your homeserver. Please close this dialog and try again.": "无法连接至你的主服务器。请关闭此对话框并再试一次。", + "Are you sure you wish to abort creation of the host? The process cannot be continued.": "你确定要放弃创建主机吗?被放弃的创建流程将无法再继续。", "Confirm abort of host creation": "确定放弃创建主机", "Please view existing bugs on Github first. No match? Start a new one.": "请先查找一下 Github 上已有的问题,以免重复。找不到重复问题?发起一个吧。", - "PRO TIP: If you start a bug, please submit debug logs to help us track down the problem.": "专业建议:如果您要发起新问题,请一并提交调试日志,以便我们找出问题根源。", + "PRO TIP: If you start a bug, please submit debug logs to help us track down the problem.": "专业建议:如果你要发起新问题,请一并提交调试日志,以便我们找出问题根源。", "There are two ways you can provide feedback and help us improve %(brand)s.": "有两种方式可以提供反馈,并帮助我们改进 %(brand)s。", "Please go into as much detail as you like, so we can track down the problem.": "请按照你的意愿,尽可能详细地描述问题,以便我们找出问题根源。", - "Tell us below how you feel about %(brand)s so far.": "请在下面告诉我们直到目前为止您使用 %(brand)s 的感受。", - "There was an error updating your community. The server is unable to process your request.": "更新你的社区时出现错误。服务器无法处理你的请求。", + "Tell us below how you feel about %(brand)s so far.": "请在下面告诉我们直到目前为止你使用 %(brand)s 的感受。", + "There was an error updating your community. The server is unable to process your request.": "更新你的社群时出现错误。服务器无法处理你的请求。", "Values at explicit levels": "各层级的值", "Values at explicit levels:": "各层级的值:", "Values at explicit levels in this room": "此聊天室中各层级的值", @@ -2824,12 +2824,12 @@ "Value in this room": "此聊天室中的值", "Settings Explorer": "设置浏览器", "with state key %(stateKey)s": "附带有状态键(state key)%(stateKey)s", - "Your server requires encryption to be enabled in private rooms.": "您的服务器要求私人房间启用加密。", - "An image will help people identify your community.": "图片可以让人们辨识您的社区。", - "What's the name of your community or team?": "你的社区或者团队的名称是什么?", - "You can change this later if needed.": "如果需要,您可以稍后更改。", - "Use this when referencing your community to others. The community ID cannot be changed.": "在将您的社区推荐给其他人时使用此 ID,社区 ID 不能更改。", - "There was an error creating your community. The name may be taken or the server is unable to process your request.": "创建社区时发生错误。名称可能已被使用,或者服务器无法处理您的请求。", + "Your server requires encryption to be enabled in private rooms.": "你的服务器要求私人房间启用加密。", + "An image will help people identify your community.": "图片可以让人们辨识你的社群。", + "What's the name of your community or team?": "你的社群或者团队的名称是什么?", + "You can change this later if needed.": "如果需要,你可以稍后更改。", + "Use this when referencing your community to others. The community ID cannot be changed.": "在将你的社群推荐给其他人时使用此 ID,社群 ID 不能更改。", + "There was an error creating your community. The name may be taken or the server is unable to process your request.": "创建社群时发生错误。名称可能已被使用,或者服务器无法处理你的请求。", "Invite people to join %(communityName)s": "邀请人们加入 %(communityName)s", "Send %(count)s invites|one": "发送 %(count)s 个邀请", "Send %(count)s invites|other": "发送 %(count)s 个邀请", @@ -2864,7 +2864,7 @@ "Add comment": "添加备注", "Rate %(brand)s": "评价 %(brand)s", "Feedback sent": "反馈已发送", - "Update community": "更新社区", + "Update community": "更新社群", "Failed to save settings": "设置保存失败", "Create a room in %(communityName)s": "在 %(communityName)s 中创建聊天室", "Add image (optional)": "添加图片(可选)", @@ -2879,7 +2879,7 @@ "Invite with email or username": "使用邮箱或者用户名邀请", "Invite people": "邀请人们", "Update %(brand)s": "更新 %(brand)s", - "Check your devices": "检查您的设备", + "Check your devices": "检查你的设备", "Zimbabwe": "津巴布韦", "Zambia": "赞比亚", "Western Sahara": "西撒哈拉", @@ -2960,16 +2960,16 @@ "Ignored attempt to disable encryption": "已忽略禁用加密的尝试", "Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "此聊天室中的消息已被端对端加密。当人们加入,你可以点击他们的头像,在他们的资料中验证他们。", "Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "此处的消息已被端对端加密。请点击对方头像,在其资料中验证 %(displayName)s。", - "Secure your backup with a Security Phrase": "使用安全密语保护您的备份", - "Confirm your Security Phrase": "确认您的安全密语", + "Secure your backup with a Security Phrase": "使用安全密语保护你的备份", + "Confirm your Security Phrase": "确认你的安全密语", "Verify with another session": "使用另一个会话验证", "Use Security Key or Phrase": "使用安全密钥或密语", "Continue with %(ssoButtons)s": "使用 %(ssoButtons)s 继续", "There was a problem communicating with the homeserver, please try again later.": "与主服务器通讯时出现问题,请稍后再试。", "Decrypted event source": "解密事件源码", "Original event source": "原始事件源码", - "Community and user menu": "社区与用户菜单", - "Community settings": "社区设置", + "Community and user menu": "社群与用户菜单", + "Community settings": "社群设置", "Invite by username": "按照用户名邀请", "Inviting...": "正在邀请…", "Welcome to ": "欢迎来到 ", @@ -3013,5 +3013,266 @@ "Guyana": "圭亚那", "Guinea-Bissau": "几内亚比绍", "Guinea": "几内亚", - "Guernsey": "根西岛" + "Guernsey": "根西岛", + "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "你可以启用此选项如果此聊天室将仅用于你的主服务器上的内部团队协作。此选项之后无法更改。", + "Unable to access secret storage. Please verify that you entered the correct Security Phrase.": "无法访问秘密存储。请确认你输入了正确的恢复密码。", + "Backup could not be decrypted with this Security Key: please verify that you entered the correct Security Key.": "无法使用此安全密钥解密备份:请检查你输入的安全密钥是否正确。", + "sends space invaders": "发送空间入侵者", + "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.": "检测到新的安全短语和安全信息密钥。", + "Make a copy of your Security Key": "复制你的安全密钥", + "Your Security Key is in your Downloads folder.": "你的安全密钥在你的下载文件夹中。", + "Your Security Key has been copied to your clipboard, paste it to:": "你的安全密钥已 复制到你的粘贴板,将其粘贴至:", + "Your Security Key is a safety net - you can use it to restore access to your encrypted messages if you forget your Security Phrase.": "你的安全密钥是一张安全网——如果你忘记了你的安全短语的话,你可以用它来恢复你对已加密消息的访问权。", + "Repeat your Security Phrase...": "重复你的安全短语……", + "Enter your Security Phrase a second time to confirm it.": "再次输入你的安全短语进行确认。", + "Set up with a Security Key": "设置安全密钥", + "Great! This Security Phrase looks strong enough.": "棒!这个安全短语看着够强。", + "We'll store an encrypted copy of your keys on our server. Secure your backup with a Security Phrase.": "我们会将你的密钥的加密副本保存在我们的服务器上。使用安全短语来保证你的备份。", + "Space Autocomplete": "空间自动完成", + "Without verifying, you won’t have access to all your messages and may appear as untrusted to others.": "未经验证,你将无法获取你的所有信息,且可能不被他人所信任。", + "Verify your identity to access encrypted messages and prove your identity to others.": "验证你的身份来获取已加密的消息并向其他人证明你的身份。", + "Use another login": "使用其他账号登录", + "Decide where your account is hosted": "决定账号托管位置", + "Host account on": "账号托管于", + "Already have an account? Sign in here": "已有账号?在此登录", + "That username already exists, please try another.": "用户名已存在,请试试别的。", + "New? Create account": "新来的?创建账号", + "Please choose a strong password": "请选择强密码", + "New here? Create an account": "新来的?创建账号", + "Got an account? Sign in": "有账号了?登录", + "Failed to find the general chat for this community": "找不到此社群的一般性聊天记录", + "We'll create rooms for each of them. You can add more later too, including already existing ones.": "我们将会为每个主题创建一个聊天室。你也可以稍后再进行添加,包括现有聊天室。", + "What projects are you working on?": "你正在从事哪些项目?", + "You can add more later too, including already existing ones.": "稍后你可以添加更多聊天室,包括现有的。", + "Let's create a room for each of them.": "让我们未每个主题都创建一个聊天室吧。", + "What are some things you want to discuss in %(spaceName)s?": "你想在 %(spaceName)s 中讨论什么?", + "This is an experimental feature. For now, new users receiving an invite will have to open the invite on to actually join.": "这是实验性功能。当前收到邀请的新用户必须在上开启邀请才能真正加入。", + "Make sure the right people have access. You can invite more later.": "确保对的人可以访问。稍后你可以邀请更多人。", + "Invite your teammates": "邀请你的伙伴", + "Failed to invite the following users to your space: %(csvUsers)s": "邀请以下用户加入你的空间失败:%(csvUsers)s", + "A private space for you and your teammates": "供你和你的伙伴使用的私有空间", + "Me and my teammates": "我和我的伙伴", + "A private space to organise your rooms": "用于整理你聊天室的私有空间", + "Just me": "仅有我", + "Make sure the right people have access to %(name)s": "确保对的人有权访问 %(name)s", + "Who are you working with?": "你与谁一同工作?", + "Go to my space": "前往我的空间", + "Go to my first room": "前往我的第一个聊天室", + "It's just you at the moment, it will be even better with others.": "当前仅有你一人,与人同道而行会更好。", + "Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "选择要添加的聊天室或对话。这是专属于你的空间,不会有人被通知。你稍后可以再增加更多。", + "Select a room below first": "首先选择一个聊天室", + "%(count)s rooms and %(numSpaces)s spaces|other": "%(count)s 个聊天室和 %(numSpaces)s 个空间", + "This room is suggested as a good one to join": "此聊天室很适合加入", + "You can select all or individual messages to retry or delete": "你可以选择全部或单独的消息来重试或删除", + "Sending": "正在发送", + "Delete all": "删除全部", + "Some of your messages have not been sent": "你的部分消息未被发送", + "Your message wasn't sent because this homeserver has been blocked by it's administrator. Please contact your service administrator to continue using the service.": "你的消息未被发送,因为此主服务器已被其管理员封禁。请联络你的服务管理员已继续使用服务。", + "Filter all spaces": "过滤所有空间", + "You have no visible notifications.": "你没有可见的通知。", + "Communities are changing to Spaces": "社群正在转变为空间", + "%(creator)s created this DM.": "%(creator)s 创建了此私聊。", + "Verification requested": "已请求验证", + "Security Key mismatch": "安全密钥不符", + "Unable to set up keys": "无法设置密钥", + "If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "如果你全部重置,你将会在没有受信任的会话重新开始、没有受信任的用户,且可能会看不到过去的消息。", + "Only do this if you have no other device to complete verification with.": "当你没有其他设备可以用于完成验证时,方可执行此操作。", + "Reset everything": "全部重置", + "Forgotten or lost all recovery methods? Reset all": "忘记或丢失了所有恢复方式?全部重置", + "Remember this": "记住", + "The widget will verify your user ID, but won't be able to perform actions for you:": "挂件将会验证你的用户 ID,但将无法为你执行动作:", + "Verify other login": "验证其他登录", + "Make this space private": "将此空间设为私有", + "Edit settings relating to your space.": "编辑关于你的空间的设置。", + "Reset event store": "重置活动存储", + "If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated": "如果这样做,请注意你的信息并不会被删除,但在重新建立索引是,搜索体验可能会退步一些", + "You most likely do not want to reset your event index store": "你大概率不想重置你的活动缩影存储", + "Reset event store?": "重置活动存储?", + "Use your preferred Matrix homeserver if you have one, or host your own.": "如果你可以使用自己所偏好的 Matrix 主服务器,或是自己搭建一个。", + "We call the places where you can host your account ‘homeservers’.": "我们将你可以托管账号的地方称为「主服务器」。", + "Matrix.org is the biggest public homeserver in the world, so it’s a good place for many.": "Matrix.org 是世界上最大的公开主服务器,因此对于许多人而言是个好地方。", + "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "这通常仅影响服务器如何处理聊天室。如果你的 %(brand)s 遇到问题,请回报错误。", + "Just a heads up, if you don't add an email and forget your password, you could permanently lose access to your account.": "请注意,如果你不添加电子邮箱并且忘记密码,你将永远失去对你账号的访问权。", + "Continuing without email": "不使用电子邮箱并继续", + "We recommend you change your password and Security Key in Settings immediately": "我们建议你立即在设置中更改你的密码和安全密钥", + "Data on this screen is shared with %(widgetDomain)s": "在此画面上的资料会与 %(widgetDomain)s 分享", + "Consult first": "先询问", + "Invited people will be able to read old messages.": "被邀请的人将能够阅读过去的消息。", + "Invite someone using their name, username (like ) or share this room.": "使用某人的名字、用户名(如 )或分享此聊天室来邀请他们。", + "Invite someone using their name, email address, username (like ) or share this room.": "使用某人的名字、电子邮箱地址或用户名来与他们开始对话(如 )或分享此聊天室。", + "Invite someone using their name, username (like ) or share this space.": "使用某人的名字、用户名(如 )邀请他们,或分享此空间。", + "Invite someone using their name, email address, username (like ) or share this space.": "使用某人的名字、电子邮箱地址或用户名(如 )邀请他们,或分享此空间。", + "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "这不会邀请他们加入 %(communityName)s。要邀请某人加入 %(communityName)s,请点击这里", + "Start a conversation with someone using their name or username (like ).": "使用某人的名字或用户名开始与其进行对话(如 )。", + "Start a conversation with someone using their name, email address or username (like ).": "使用某人的名称、电子邮箱地址或用户名来与其开始对话(如 )。", + "May include members not in %(communityName)s": "可能不包括 %(communityName)s 中的成员", + "A call can only be transferred to a single user.": "通话只能转移到单个用户。", + "We couldn't create your DM.": "我们无法创建你的私聊。", + "Continuing temporarily allows the %(hostSignupBrand)s setup process to access your account to fetch verified email addresses. This data is not stored.": "继续暂时允许让 %(hostSignupBrand)s 安装过程可以访问你的账号以获取已验证电子邮箱地址。此数据不保存。", + "Block anyone not part of %(serverName)s from ever joining this room.": "阻住任何不属于 %(serverName)s 的人加入此聊天室。", + "You might disable this if the room will be used for collaborating with external teams who have their own homeserver. This cannot be changed later.": "如果聊天室用于与自己的主服务器外的团队进行协助的话,可以停用此功能。这将无法在稍后进行更改。", + "What do you want to organise?": "你想要组织什么?", + "Skip for now": "暂时跳过", + "Failed to create initial space rooms": "创建初始空间聊天室失败", + "To join %(spaceName)s, turn on the Spaces beta": "加入 %(spaceName)s 前,请开启空间测试版", + "To view %(spaceName)s, turn on the Spaces beta": "查看 %(spaceName)s 前,请开启空间测试版", + "Private space": "私有空间", + "Public space": "公开空间", + "Spaces are a beta feature.": "空间为测试版功能。", + "If you can't find the room you're looking for, ask for an invite or create a new room.": "如果你找不到正在寻找的聊天室,请请求邀请或创建一个新的聊天室。", + "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "私人聊天室仅能通过邀请找到与加入。公开聊天室则能够被所有人找到并加入。", + "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "私人聊天室仅能通过邀请找到与加入。公开聊天室则能够被所有在此社群的人找到并加入。", + "Search names and descriptions": "搜索名称和描述", + "You may want to try a different search or check for typos.": "你可能要尝试其他搜索或检查是否有错别字。", + "You may contact me if you have any follow up questions": "如果你有任何后续问题,可以联系我", + "To leave the beta, visit your settings.": "要退出测试版,请访问你的设置。", + "Your platform and username will be noted to help us use your feedback as much as we can.": "我们将会记录你的平台及用户名,以帮助我们尽我们所能地使用你的反馈。", + "%(featureName)s beta feedback": "%(featureName)s 测试版反馈", + "Thank you for your feedback, we really appreciate it.": "感谢你的反馈,我们衷心地感谢。", + "Beta feedback": "测试版反馈", + "Want to add a new room instead?": "想要添加一个新的聊天室吗?", + "Add existing rooms": "添加现有聊天室", + "You can add existing spaces to a space.": "你可以添加现有空间到另一空间中。", + "Feeling experimental?": "想要来点实验吗?", + "Adding rooms... (%(progress)s out of %(count)s)|one": "正在新增聊天室……", + "Adding rooms... (%(progress)s out of %(count)s)|other": "正在新增聊天室……(%(count)s 中的第 %(progress)s 个)", + "Not all selected were added": "并非所有选中的都被添加", + "You are not allowed to view this server's rooms list": "你不被允许查看此服务器的聊天室列表", + "Sends the given message with a space themed effect": "此消息带有空间主题化效果", + "Kick, ban, or invite people to your active room, and make you leave": "移除、封禁或邀请人们到你所活跃的聊天室,并让你离开", + "Sends the given message as a spoiler": "此消息包含剧透", + "Retry all": "全部重试", + "View message": "查看消息", + "Zoom in": "放大", + "Zoom out": "缩小", + "%(count)s people you know have already joined|one": "已有你所认识的 %(count)s 个人加入", + "%(count)s people you know have already joined|other": "已有你所认识的 %(count)s 个人加入", + "%(count)s members including %(commaSeparatedMembers)s|one": "%(commaSeparatedMembers)s", + "%(count)s members including %(commaSeparatedMembers)s|other": "%(count)s 位成员中包括 %(commaSeparatedMembers)s", + "Including %(commaSeparatedMembers)s": "包括 %(commaSeparatedMembers)s", + "View all %(count)s members|one": "查看 1 位成员", + "View all %(count)s members|other": "查看全部 %(count)s 位成员", + "Use the Desktop app to search encrypted messages": "使用桌面端英语来搜索加密消息", + "Use the Desktop app to see all encrypted files": "使用桌面端应用来查看所有加密文件", + "Add reaction": "添加回应", + "Error processing voice message": "处理语音消息时发生错误", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the space it will be impossible to regain privileges.": "当你将自己降级后,你将无法撤销此更改。如果你是此空间的最后一名拥有权限的用户,则无法重新获得权限。", + "Unpin a widget to view it in this panel": "取消固定挂件以在此面板中查看", + "You can only pin up to %(count)s widgets|other": "你仅能固定 %(count)s 个挂件", + "Accept on your other login…": "接受你的其他登录……", + "Delete recording": "删除录制", + "Stop the recording": "停止录制", + "Record a voice message": "录制语音消息", + "We didn't find a microphone on your device. Please check your settings and try again.": "我们没能在你的设备上找到麦克风。请检查设置并重试。", + "No microphone found": "无法发现麦克风", + "We were unable to access your microphone. Please check your browser settings and try again.": "我们无法访问你的麦克风。 请检查浏览器设置并重试。", + "Unable to access your microphone": "无法访问你的麦克风", + "%(count)s results in all spaces|one": "在所有空间中有 %(count)s 个结果", + "%(count)s results in all spaces|other": "在所有空间中有 %(count)s 个结果", + "Quick actions": "快捷操作", + "You do not have permissions to add rooms to this space": "你没有权限添加聊天室至此空间", + "You do not have permissions to create new rooms in this space": "你没有权限在此空间内创建新的聊天室", + "Invite to just this room": "仅邀请至此聊天室", + "This is the beginning of your direct message history with .": "这是你与 间进行私聊的历史记录的开始。", + "Only the two of you are in this conversation, unless either of you invites anyone to join.": "除非你们其中一个邀请了别人加入,否则将仅有你们两个人在此对话中。", + "%(seconds)ss left": "剩余 %(seconds)s 秒", + "Failed to send": "发送失败", + "Change server ACLs": "更改服务器访问控制列表", + "You have no ignored users.": "你没有设置忽略用户。", + "Warn before quitting": "退出前警告", + "Feeling experimental? Labs are the best way to get things early, test out new features and help shape them before they actually launch. Learn more.": "想要来点实验?实验室是提前体验、测试新功能并在它们正式发布前帮助它们定型的最佳方式。了解更多。", + "Your access token gives full access to your account. Do not share it with anyone.": "你的访问令牌可以完全访问你的帐户。不要将其与任何人分享。", + "Access Token": "访问令牌", + "Message search initialisation failed": "消息搜索初始化失败", + "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|one": "使用 %(size)s 来存储来自 %(rooms)s 聊天室的消息。在本地安全地缓存已加密的消息以使其出现在搜索结果中。", + "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|other": "使用 %(size)s 来存储来自 %(rooms)s 聊天室的消息。在本地安全地缓存已加密的消息以使其出现在搜索结果中。", + "Manage & explore rooms": "管理并探索聊天室", + "Spaces are a new way to group rooms and people. To join an existing space you'll need an invite.": "空间是一种将聊天室和人们进行分组的新方法。你需要得到邀请方可加入现有空间。", + "Please enter a name for the space": "请输入空间名称", + "Play": "播放", + "Pause": "暂停", + "%(name)s on hold": "保留 %(name)s", + "Connecting": "连接中", + "Consulting with %(transferTarget)s. Transfer to %(transferee)s": "与 %(transferTarget)s 进行协商。转让至 %(transferee)s", + "unknown person": "陌生人", + "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "允许在一对一通话中使用点对点通讯(如果你启用此功能,对方可能会看到你的 IP 地址)", + "Send and receive voice messages": "发送并接收语音消息", + "Show options to enable 'Do not disturb' mode": "显示启用「请勿打扰」模式的选项", + "Your feedback will help make spaces better. The more detail you can go into, the better.": "你的反馈将帮助空间变得更好。你能讲得越仔细越好。", + "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "测试版适用于网页端、桌面端以及安卓端。但在你的主服务器上有些特性可能不可用。", + "You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "你随时可以在设置中退出测试版,或轻点如上所示的测试版徽章。", + "%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "%(brand)s 将在空间启用时重载。社群和自定义标签将被隐藏。", + "Beta available for web, desktop and Android. Thank you for trying the beta.": "测试版适用于网页端、桌面端以及安卓端。感谢你试用测试版。", + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "如果你离开,%(brand)s 将会在空间禁用时重载。社群和自定义标记将再次可见。", + "Spaces are a new way to group rooms and people.": "空间是一种将聊天室与人们进行分组的新方式。", + "%(deviceId)s from %(ip)s": "来自 %(ip)s 的 %(deviceId)s", + "Review to ensure your account is safe": "检查以确保你的账号是安全的", + "See %(msgtype)s messages posted to your active room": "查看发布到你所活跃的聊天室的 %(msgtype)s 消息", + "See %(msgtype)s messages posted to this room": "查看发布到此聊天室的 %(msgtype)s 消息", + "Send %(msgtype)s messages as you in your active room": "在你所活跃的聊天室以你的身份发送 %(msgtype)s 消息", + "Send %(msgtype)s messages as you in this room": "在此聊天室以你的身份发送 %(msgtype)s 消息", + "See general files posted to your active room": "查看发布到你所活跃的聊天室的一般性文件", + "See general files posted to this room": "查看发布到此聊天室的一般性文件", + "Send general files as you in your active room": "在你所活跃的聊天室以你的身份发送一般性文件", + "Are you sure you want to leave the space '%(spaceName)s'?": "你确定要离开空间「%(spaceName)s」吗?", + "This space is not public. You will not be able to rejoin without an invite.": "此空间并不公开。在没有得到邀请的情况下,你将无法重新加入。", + "You are the only person here. If you leave, no one will be able to join in the future, including you.": "你是这里唯一的人。如果你离开了,以后包括你以在内任何人都将无法加入。", + "You do not have permission to create rooms in this community.": "你没有在此社群中建立聊天室的权限。", + "Now, let's help you get started": "现在,让我们协助你开始", + "Add a photo so people know it's you.": "添加照片,让人们知道这是你。", + "Great, that'll help people know it's you": "很好,这样大家就知道是你了", + "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even add images with Matrix URLs \n

    \n": "

    社群页面的 HTML

    \n

    \n 使用详细秒速向社群介绍新成员,或分发\n 一些重要链接\n

    \n

    \n 你甚至可以使用 Matrix 链接 新增图片\n

    \n", + "Use email to optionally be discoverable by existing contacts.": "使用电子邮箱以选择性地被现有联系人搜索。", + "Use email or phone to optionally be discoverable by existing contacts.": "使用电子邮箱或电话以选择性地被现有联系人搜索。", + "Add an email to be able to reset your password.": "添加电子邮箱以重置你的密码。", + "That phone number doesn't look quite right, please check and try again": "电话号码看起来不太对,请检查并重试", + "Something went wrong in confirming your identity. Cancel and try again.": "确认你的身份时出了一点问题。取消并重试。", + "Open the link in the email to continue registration.": "打开电子邮件中的链接以继续注册。", + "A confirmation email has been sent to %(emailAddress)s": "确认电子邮件以发送至 %(emailAddress)s", + "Avatar": "头像", + "Join the beta": "加入测试版", + "Leave the beta": "退出测试版", + "Beta": "测试版", + "Tap for more info": "点击以获取更多信息", + "Spaces is a beta feature": "空间为测试功能", + "Start audio stream": "开始音频流", + "Failed to start livestream": "开始流直播失败", + "Unable to start audio streaming.": "无法开始音频流媒体。", + "Hold": "挂起", + "Resume": "恢复", + "If you've forgotten your Security Key you can ": "如果你忘记了你的安全密钥,你可以", + "Access your secure message history and set up secure messaging by entering your Security Key.": "通过输入你的安全密钥来访问你的安全消息历史记录并设置安全通信。", + "Not a valid Security Key": "安全密钥无效", + "This looks like a valid Security Key!": "看起来是有效的安全密钥!", + "If you've forgotten your Security Phrase you can use your Security Key or set up new recovery options": "如果你忘记了你的安全短语,你可以使用你的安全密钥设置新的恢复选项", + "Access your secure message history and set up secure messaging by entering your Security Phrase.": "无法通过你的安全短语访问你的安全消息历史记录并设置安全通信。", + "Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.": "无法使用此安全短语解密备份:请确认你是否输入了正确的安全短语。", + "Incorrect Security Phrase": "安全短语错误", + "Send general files as you in this room": "查看发布到此聊天室的一般性文件", + "See videos posted to your active room": "查看发布到你所活跃的聊天室的视频", + "See videos posted to this room": "查看发布到此聊天室的视频", + "Send videos as you in your active room": "查看发布到你所活跃的聊天室的视频", + "Send videos as you in this room": "查看发布到此聊天室的视频", + "See images posted to your active room": "查看发布到你所活跃的聊天室的图片", + "See images posted to this room": "查看发布到此聊天室的图片", + "Send images as you in your active room": "在你所活跃的聊天室以你的身份发送图片", + "Send images as you in this room": "在此聊天室以你的身份发送图片", + "See emotes posted to your active room": "查看发布到你所活跃的聊天室的表情", + "See emotes posted to this room": "查看发布到此聊天室的表情", + "Send emotes as you in your active room": "在你所活跃的聊天室以你的身份发送表情", + "Send emotes as you in this room": "在此聊天室以你的身份发送表情", + "See text messages posted to your active room": "查看发布到你所活跃的聊天室的文本消息", + "See text messages posted to this room": "查看发布到此聊天室的文本消息", + "Send text messages as you in your active room": "在你所活跃的聊天室以你的身份发送文本消息", + "Send text messages as you in this room": "在此聊天室以你的身份发送文本消息", + "See messages posted to your active room": "查看发布到你所活跃的聊天室的消息", + "See messages posted to this room": "查看发布到此聊天室的消息", + "Send messages as you in your active room": "在你所活跃的聊天室以你的身份发送消息", + "Send messages as you in this room": "在此聊天室以你的身份发送消息", + "See when anyone posts a sticker to your active room": "查看何时有人发送贴纸到你所活跃的聊天室", + "Send stickers to your active room as you": "发送贴纸到你所活跃的聊天室", + "See when people join, leave, or are invited to your active room": "查看人们何时加入、离开或被邀请到你所活跃的聊天室", + "See when people join, leave, or are invited to this room": "查看人们何时加入、离开或被邀请到这个房间", + "Kick, ban, or invite people to this room, and make you leave": "移除、封禁或邀请用户到此聊天室,并让你离开" } diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 1ab5a59911..5c27fb3878 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -169,9 +169,9 @@ "No Webcams detected": "未偵測到網路攝影機", "No media permissions": "沒有媒體權限", "You may need to manually permit %(brand)s to access your microphone/webcam": "您可能需要手動允許 %(brand)s 存取您的麥克風/網路攝影機", - "Are you sure you want to leave the room '%(roomName)s'?": "您確定您要想要離開房間 '%(roomName)s' 嗎?", + "Are you sure you want to leave the room '%(roomName)s'?": "你確定你要想要離開房間 '%(roomName)s' 嗎?", "Bans user with given id": "阻擋指定 ID 的使用者", - "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "無法連線到家伺服器 - 請檢查您的連線,確保您的家伺服器的 SSL 憑證可被信任,而瀏覽器擴充套件也沒有阻擋請求。", + "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "無法連線到家伺服器 - 請檢查你的連線,確保你的家伺服器的 SSL 憑證可被信任,而瀏覽器擴充套件也沒有阻擋請求。", "%(senderName)s changed their profile picture.": "%(senderName)s 已經變更了他的基本資料圖片。", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s 變更了 %(powerLevelDiffText)s 權限等級。", "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s 將聊天室名稱變更為 %(roomName)s。", @@ -838,7 +838,7 @@ "An error ocurred whilst trying to remove the widget from the room": "嘗試從聊天室移除小工具時發生錯誤", "System Alerts": "系統警告", "Only room administrators will see this warning": "僅聊天室管理員會看到此警告", - "Please contact your service administrator to continue using the service.": "請聯絡您的服務管理員以繼續使用服務。", + "Please contact your service administrator to continue using the service.": "請聯絡你的服務管理員以繼續使用服務。", "This homeserver has hit its Monthly Active User limit.": "這個主伺服器已經到達其每月活躍使用者限制。", "This homeserver has exceeded one of its resource limits.": "此主伺服器已經超過其中一項資源限制。", "Upgrade Room Version": "更新聊天室版本", @@ -1160,7 +1160,7 @@ "Change": "變更", "Couldn't load page": "無法載入頁面", "This homeserver does not support communities": "此家伺服器不支援社群", - "A verification email will be sent to your inbox to confirm setting your new password.": "一封驗證用的電子郵件已經傳送到您的收件匣以確認您設定了新密碼。", + "A verification email will be sent to your inbox to confirm setting your new password.": "一封驗證用的電子郵件已經傳送到你的收件匣以確認你設定了新密碼。", "Your password has been reset.": "您的密碼已重設。", "This homeserver does not support login using email address.": "此家伺服器不支援使用電子郵件地址登入。", "Registration has been disabled on this homeserver.": "註冊已在此家伺服器上停用。", @@ -1973,8 +1973,8 @@ "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": "%(senderName)s 為此聊天室新增了替代位置 %(addresses)s。", "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "%(senderName)s 為此聊天室移除了替代位置 %(addresses)s。", "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s 為此聊天室移除了替代位置 %(addresses)s。", - "%(senderName)s changed the alternative addresses for this room.": "%(senderName)s 為此聊天是變更了替代位置。", - "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s 為此聊天是變更了主要及替代位置。", + "%(senderName)s changed the alternative addresses for this room.": "%(senderName)s 為此聊天室變更了替代位置。", + "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s 為此聊天室變更了主要及替代位置。", "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "更新聊天室的替代位置時發生錯誤。伺服器可能不允許這麼做,或是昱到了暫時性的故障。", "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": "%(senderDisplayName)s 將聊天室名稱從 %(oldRoomName)s 變更為 %(newRoomName)s。", "%(senderName)s changed the addresses for this room.": "%(senderName)s 變更了此聊天室的位置。", @@ -2889,7 +2889,7 @@ "Send messages as you in this room": "在此聊天室以您的身份傳送訊息", "The %(capability)s capability": "%(capability)s 能力", "See %(eventType)s events posted to your active room": "檢視發佈到您的活躍聊天室的 %(eventType)s 活動", - "Send %(eventType)s events as you in your active room": "以您的身份在您的活躍聊天是傳送 %(eventType)s 活動", + "Send %(eventType)s events as you in your active room": "以您的身份在您的活躍聊天室傳送 %(eventType)s 活動", "See %(eventType)s events posted to this room": "檢視發佈到此聊天室的 %(eventType)s 活動", "Send %(eventType)s events as you in this room": "以您的身份在此聊天室傳送 %(eventType)s 活動", "with state key %(stateKey)s": "帶有狀態金鑰 %(stateKey)s", @@ -2898,17 +2898,17 @@ "Send stickers to your active room as you": "以您的身份傳送貼圖到您活躍的聊天室", "See when a sticker is posted in this room": "檢視貼圖在此聊天室中何時貼出", "Send stickers to this room as you": "以您的身份傳送貼圖到此聊天室", - "See when the avatar changes in your active room": "檢視您活躍聊天是的大頭照何時變更", - "Change the avatar of your active room": "變更您活躍聊天是的大頭照", - "See when the avatar changes in this room": "檢視此聊天是的大頭照何時變更", + "See when the avatar changes in your active room": "檢視您活躍聊天室的大頭照何時變更", + "Change the avatar of your active room": "變更您活躍聊天室的大頭照", + "See when the avatar changes in this room": "檢視此聊天室的大頭照何時變更", "Change the avatar of this room": "變更此聊天室的大頭照", "See when the name changes in your active room": "檢視您活躍聊天室的名稱何時變更", "Change the name of your active room": "變更您活躍聊天室的名稱", - "See when the name changes in this room": "檢視此聊天是的名稱何時變更", + "See when the name changes in this room": "檢視此聊天室的名稱何時變更", "Change the name of this room": "變更此聊天室的名稱", - "See when the topic changes in your active room": "檢視您活躍的聊天是的主題何時變更", - "Change the topic of your active room": "變更您活躍聊天是的主題", - "See when the topic changes in this room": "檢視此聊天是的主題何時變更", + "See when the topic changes in your active room": "檢視您活躍的聊天室的主題何時變更", + "Change the topic of your active room": "變更您活躍聊天室的主題", + "See when the topic changes in this room": "檢視此聊天室的主題何時變更", "Change the topic of this room": "變更此聊天室的主題", "Change which room you're viewing": "變更您正在檢視的聊天室", "Send stickers into your active room": "傳送貼圖到您活躍的聊天室", @@ -3226,7 +3226,7 @@ "Mark as suggested": "標記為建議", "Mark as not suggested": "標記為不建議", "Removing...": "正在移除……", - "Failed to remove some rooms. Try again later": "移除部份聊天是失敗。稍後再試", + "Failed to remove some rooms. Try again later": "移除部份聊天室失敗。稍後再試", "%(count)s rooms and 1 space|one": "%(count)s 個聊天室與 1 個空間", "%(count)s rooms and 1 space|other": "%(count)s 個聊天室與 1 個空間", "%(count)s rooms and %(numSpaces)s spaces|one": "%(count)s 個聊天室與 %(numSpaces)s 個空間", @@ -3240,7 +3240,7 @@ "Open": "開啟", "%(count)s messages deleted.|one": "已刪除 %(count)s 則訊息。", "%(count)s messages deleted.|other": "已刪除 %(count)s 則訊息。", - "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "這通常只影響伺服器如何處理聊天是。如果您的 %(brand)s 遇到問題,請回報臭蟲。", + "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "這通常只影響伺服器如何處理聊天室。如果您的 %(brand)s 遇到問題,請回報臭蟲。", "Invite to %(roomName)s": "邀請至 %(roomName)s", "Edit devices": "編輯裝置", "Invite People": "邀請夥伴", @@ -3370,5 +3370,13 @@ "Add reaction": "新增反應", "Send and receive voice messages": "傳送與接收語音訊息", "Your feedback will help make spaces better. The more detail you can go into, the better.": "您的回饋意見將會讓空間變得更好。您可以輸入愈多細節愈好。", - "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "若您離開,%(brand)s 將在停用空間的情況下重新載入。社群與自訂標籤將再次可見。" + "If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "若您離開,%(brand)s 將在停用空間的情況下重新載入。社群與自訂標籤將再次可見。", + "Space Autocomplete": "空間自動完成", + "Go to my space": "到我的空間", + "sends space invaders": "傳送太空侵略者", + "Sends the given message with a space themed effect": "與太空主題效果一起傳送指定的訊息", + "See when people join, leave, or are invited to your active room": "檢視人們何時加入、離開或被邀請至您活躍的聊天室", + "Kick, ban, or invite people to your active room, and make you leave": "踢除、封鎖或邀請人們到您作用中的聊天室,然後讓您離開", + "See when people join, leave, or are invited to this room": "檢視人們何時加入、離開或被邀請至此聊天室", + "Kick, ban, or invite people to this room, and make you leave": "踢除、封鎖或邀請人們到此聊天室,然後讓您離開" } diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 26c89afec6..16950dc008 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -105,12 +105,14 @@ function safeCounterpartTranslate(text: string, options?: object) { return translated; } +type SubstitutionValue = number | string | React.ReactNode | ((sub: string) => React.ReactNode); + export interface IVariables { count?: number; - [key: string]: number | string; + [key: string]: SubstitutionValue; } -type Tags = Record React.ReactNode>; +type Tags = Record; export type TranslatedString = string | React.ReactNode; @@ -247,7 +249,7 @@ export function replaceByRegexes(text: string, mapping: IVariables | Tags): stri let replaced; // If substitution is a function, call it if (mapping[regexpString] instanceof Function) { - replaced = (mapping as Tags)[regexpString].apply(null, capturedGroups); + replaced = ((mapping as Tags)[regexpString] as Function)(...capturedGroups); } else { replaced = mapping[regexpString]; } diff --git a/src/settings/SettingsStore.ts b/src/settings/SettingsStore.ts index c32bbe731d..e1e300e185 100644 --- a/src/settings/SettingsStore.ts +++ b/src/settings/SettingsStore.ts @@ -26,7 +26,7 @@ import { _t } from '../languageHandler'; import dis from '../dispatcher/dispatcher'; import { ISetting, SETTINGS } from "./Settings"; import LocalEchoWrapper from "./handlers/LocalEchoWrapper"; -import { WatchManager } from "./WatchManager"; +import { WatchManager, CallbackFn as WatchCallbackFn } from "./WatchManager"; import { SettingLevel } from "./SettingLevel"; import SettingsHandler from "./handlers/SettingsHandler"; @@ -117,8 +117,8 @@ export default class SettingsStore { // We also maintain a list of monitors which are special watchers: they cause dispatches // when the setting changes. We track which rooms we're monitoring though to ensure we // don't duplicate updates on the bus. - private static watchers = {}; // { callbackRef => { callbackFn } } - private static monitors = {}; // { settingName => { roomId => callbackRef } } + private static watchers = new Map(); + private static monitors = new Map>(); // { settingName => { roomId => callbackRef } } // Counter used for generation of watcher IDs private static watcherCount = 1; @@ -163,7 +163,7 @@ export default class SettingsStore { callbackFn(originalSettingName, changedInRoomId, atLevel, newValAtLevel, newValue); }; - SettingsStore.watchers[watcherId] = localizedCallback; + SettingsStore.watchers.set(watcherId, localizedCallback); defaultWatchManager.watchSetting(settingName, roomId, localizedCallback); return watcherId; @@ -176,13 +176,13 @@ export default class SettingsStore { * to cancel. */ public static unwatchSetting(watcherReference: string) { - if (!SettingsStore.watchers[watcherReference]) { + if (!SettingsStore.watchers.has(watcherReference)) { console.warn(`Ending non-existent watcher ID ${watcherReference}`); return; } - defaultWatchManager.unwatchSetting(SettingsStore.watchers[watcherReference]); - delete SettingsStore.watchers[watcherReference]; + defaultWatchManager.unwatchSetting(SettingsStore.watchers.get(watcherReference)); + SettingsStore.watchers.delete(watcherReference); } /** @@ -196,10 +196,10 @@ export default class SettingsStore { public static monitorSetting(settingName: string, roomId: string) { roomId = roomId || null; // the thing wants null specifically to work, so appease it. - if (!this.monitors[settingName]) this.monitors[settingName] = {}; + if (!this.monitors.has(settingName)) this.monitors.set(settingName, new Map()); const registerWatcher = () => { - this.monitors[settingName][roomId] = SettingsStore.watchSetting( + this.monitors.get(settingName).set(roomId, SettingsStore.watchSetting( settingName, roomId, (settingName, inRoomId, level, newValueAtLevel, newValue) => { dis.dispatch({ action: 'setting_updated', @@ -210,19 +210,20 @@ export default class SettingsStore { newValue, }); }, - ); + )); }; - const hasRoom = Object.keys(this.monitors[settingName]).find((r) => r === roomId || r === null); + const rooms = Array.from(this.monitors.get(settingName).keys()); + const hasRoom = rooms.find((r) => r === roomId || r === null); if (!hasRoom) { registerWatcher(); } else { if (roomId === null) { // Unregister all existing watchers and register the new one - for (const roomId of Object.keys(this.monitors[settingName])) { - SettingsStore.unwatchSetting(this.monitors[settingName][roomId]); - } - this.monitors[settingName] = {}; + rooms.forEach(roomId => { + SettingsStore.unwatchSetting(this.monitors.get(settingName).get(roomId)); + }); + this.monitors.get(settingName).clear(); registerWatcher(); } // else a watcher is already registered for the room, so don't bother registering it again } diff --git a/src/settings/WatchManager.ts b/src/settings/WatchManager.ts index ea2f158ef6..56f911f180 100644 --- a/src/settings/WatchManager.ts +++ b/src/settings/WatchManager.ts @@ -18,11 +18,7 @@ import { SettingLevel } from "./SettingLevel"; export type CallbackFn = (changedInRoomId: string, atLevel: SettingLevel, newValAtLevel: any) => void; -const IRRELEVANT_ROOM: string = null; - -interface RoomWatcherMap { - [roomId: string]: CallbackFn[]; -} +const IRRELEVANT_ROOM = Symbol("irrelevant-room"); /** * Generalized management class for dealing with watchers on a per-handler (per-level) @@ -30,25 +26,25 @@ interface RoomWatcherMap { * class, which are then proxied outwards to any applicable watchers. */ export class WatchManager { - private watchers: {[settingName: string]: RoomWatcherMap} = {}; + private watchers = new Map>(); // settingName -> roomId -> CallbackFn[] // Proxy for handlers to delegate changes to this manager public watchSetting(settingName: string, roomId: string | null, cb: CallbackFn) { - if (!this.watchers[settingName]) this.watchers[settingName] = {}; - if (!this.watchers[settingName][roomId]) this.watchers[settingName][roomId] = []; - this.watchers[settingName][roomId].push(cb); + if (!this.watchers.has(settingName)) this.watchers.set(settingName, new Map()); + if (!this.watchers.get(settingName).has(roomId)) this.watchers.get(settingName).set(roomId, []); + this.watchers.get(settingName).get(roomId).push(cb); } // Proxy for handlers to delegate changes to this manager public unwatchSetting(cb: CallbackFn) { - for (const settingName of Object.keys(this.watchers)) { - for (const roomId of Object.keys(this.watchers[settingName])) { + this.watchers.forEach((map) => { + map.forEach((callbacks) => { let idx; - while ((idx = this.watchers[settingName][roomId].indexOf(cb)) !== -1) { - this.watchers[settingName][roomId].splice(idx, 1); + while ((idx = callbacks.indexOf(cb)) !== -1) { + callbacks.splice(idx, 1); } - } - } + }); + }); } public notifyUpdate(settingName: string, inRoomId: string | null, atLevel: SettingLevel, newValueAtLevel: any) { @@ -56,21 +52,21 @@ export class WatchManager { // we also don't have a reliable way to get the old value of a setting. Instead, we'll just // let it fall through regardless and let the receiver dedupe if they want to. - if (!this.watchers[settingName]) return; + if (!this.watchers.has(settingName)) return; - const roomWatchers = this.watchers[settingName]; + const roomWatchers = this.watchers.get(settingName); const callbacks = []; - if (inRoomId !== null && roomWatchers[inRoomId]) { - callbacks.push(...roomWatchers[inRoomId]); + if (inRoomId !== null && roomWatchers.has(inRoomId)) { + callbacks.push(...roomWatchers.get(inRoomId)); } if (!inRoomId) { - // Fire updates to all the individual room watchers too, as they probably - // care about the change higher up. - callbacks.push(...Object.values(roomWatchers).flat(1)); - } else if (roomWatchers[IRRELEVANT_ROOM]) { - callbacks.push(...roomWatchers[IRRELEVANT_ROOM]); + // Fire updates to all the individual room watchers too, as they probably care about the change higher up. + const callbacks = Array.from(roomWatchers.values()).flat(1); + callbacks.push(...callbacks); + } else if (roomWatchers.has(IRRELEVANT_ROOM)) { + callbacks.push(...roomWatchers.get(IRRELEVANT_ROOM)); } for (const callback of callbacks) { diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 37162c8ae7..8da565f603 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -17,17 +17,18 @@ limitations under the License. */ import React from "react"; -import {Store} from 'flux/utils'; -import {MatrixError} from "matrix-js-sdk/src/http-api"; +import { Store } from 'flux/utils'; +import { MatrixError } from "matrix-js-sdk/src/http-api"; import dis from '../dispatcher/dispatcher'; -import {MatrixClientPeg} from '../MatrixClientPeg'; +import { MatrixClientPeg } from '../MatrixClientPeg'; import * as sdk from '../index'; import Modal from '../Modal'; import { _t } from '../languageHandler'; import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache'; -import {ActionPayload} from "../dispatcher/payloads"; -import {retry} from "../utils/promise"; +import { ActionPayload } from "../dispatcher/payloads"; +import { Action } from "../dispatcher/actions"; +import { retry } from "../utils/promise"; import CountlyAnalytics from "../CountlyAnalytics"; const NUM_JOIN_RETRY = 5; @@ -134,13 +135,13 @@ class RoomViewStore extends Store { break; // join_room: // - opts: options for joinRoom - case 'join_room': + case Action.JoinRoom: this.joinRoom(payload); break; - case 'join_room_error': + case Action.JoinRoomError: this.joinRoomError(payload); break; - case 'join_room_ready': + case Action.JoinRoomReady: this.setState({ shouldPeek: false }); break; case 'on_client_not_viable': @@ -201,7 +202,11 @@ class RoomViewStore extends Store { this.setState(newState); if (payload.auto_join) { - this.joinRoom(payload); + dis.dispatch({ + ...payload, + action: Action.JoinRoom, + roomId: payload.room_id, + }); } } else if (payload.room_alias) { // Try the room alias to room ID navigation cache first to avoid @@ -282,41 +287,16 @@ class RoomViewStore extends Store { // We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not // have come down the sync stream yet, and that's the point at which we'd consider the user joined to the // room. - dis.dispatch({ action: 'join_room_ready' }); + dis.dispatch({ + action: Action.JoinRoomReady, + roomId: this.state.roomId, + }); } catch (err) { dis.dispatch({ - action: 'join_room_error', + action: Action.JoinRoomError, + roomId: this.state.roomId, err: err, }); - - let msg = err.message ? err.message : JSON.stringify(err); - console.log("Failed to join room:", msg); - - if (err.name === "ConnectionError") { - msg = _t("There was an error joining the room"); - } else if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') { - msg =
    - {_t("Sorry, your homeserver is too old to participate in this room.")}
    - {_t("Please contact your homeserver administrator.")} -
    ; - } else if (err.httpStatus === 404) { - const invitingUserId = this.getInvitingUserId(this.state.roomId); - // only provide a better error message for invites - if (invitingUserId) { - // if the inviting user is on the same HS, there can only be one cause: they left. - if (invitingUserId.endsWith(`:${MatrixClientPeg.get().getDomain()}`)) { - msg = _t("The person who invited you already left the room."); - } else { - msg = _t("The person who invited you already left the room, or their server is offline."); - } - } - } - - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { - title: _t("Failed to join room"), - description: msg, - }); } } @@ -335,6 +315,35 @@ class RoomViewStore extends Store { joining: false, joinError: payload.err, }); + const err = payload.err; + let msg = err.message ? err.message : JSON.stringify(err); + console.log("Failed to join room:", msg); + + if (err.name === "ConnectionError") { + msg = _t("There was an error joining the room"); + } else if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') { + msg =
    + {_t("Sorry, your homeserver is too old to participate in this room.")}
    + {_t("Please contact your homeserver administrator.")} +
    ; + } else if (err.httpStatus === 404) { + const invitingUserId = this.getInvitingUserId(this.state.roomId); + // only provide a better error message for invites + if (invitingUserId) { + // if the inviting user is on the same HS, there can only be one cause: they left. + if (invitingUserId.endsWith(`:${MatrixClientPeg.get().getDomain()}`)) { + msg = _t("The person who invited you already left the room."); + } else { + msg = _t("The person who invited you already left the room, or their server is offline."); + } + } + } + + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { + title: _t("Failed to join room"), + description: msg, + }); } public reset() { diff --git a/src/stores/UIStore.ts b/src/stores/UIStore.ts new file mode 100644 index 0000000000..7511527eb0 --- /dev/null +++ b/src/stores/UIStore.ts @@ -0,0 +1,112 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import EventEmitter from "events"; +import ResizeObserver from 'resize-observer-polyfill'; +import ResizeObserverEntry from 'resize-observer-polyfill/src/ResizeObserverEntry'; + +export enum UI_EVENTS { + Resize = "resize" +} + +export type ResizeObserverCallbackFunction = (entries: ResizeObserverEntry[]) => void; + +export default class UIStore extends EventEmitter { + private static _instance: UIStore = null; + + private resizeObserver: ResizeObserver; + + private uiElementDimensions = new Map(); + private trackedUiElements = new Map(); + + public windowWidth: number; + public windowHeight: number; + + constructor() { + super(); + + // eslint-disable-next-line no-restricted-properties + this.windowWidth = window.innerWidth; + // eslint-disable-next-line no-restricted-properties + this.windowHeight = window.innerHeight; + + this.resizeObserver = new ResizeObserver(this.resizeObserverCallback); + this.resizeObserver.observe(document.body); + } + + public static get instance(): UIStore { + if (!UIStore._instance) { + UIStore._instance = new UIStore(); + } + return UIStore._instance; + } + + public static destroy(): void { + if (UIStore._instance) { + UIStore._instance.resizeObserver.disconnect(); + UIStore._instance.removeAllListeners(); + UIStore._instance = null; + } + } + + public getElementDimensions(name: string): DOMRectReadOnly { + return this.uiElementDimensions.get(name); + } + + public trackElementDimensions(name: string, element: Element): void { + this.trackedUiElements.set(element, name); + this.resizeObserver.observe(element); + } + + public stopTrackingElementDimensions(name: string): void { + let trackedElement: Element; + this.trackedUiElements.forEach((trackedElementName, element) => { + if (trackedElementName === name) { + trackedElement = element; + } + }); + if (trackedElement) { + this.resizeObserver.unobserve(trackedElement); + this.uiElementDimensions.delete(name); + this.trackedUiElements.delete(trackedElement); + } + } + + public isTrackingElementDimensions(name: string): boolean { + return this.uiElementDimensions.has(name); + } + + private resizeObserverCallback = (entries: ResizeObserverEntry[]) => { + const windowEntry = entries.find(entry => entry.target === document.body); + + if (windowEntry) { + this.windowWidth = windowEntry.contentRect.width; + this.windowHeight = windowEntry.contentRect.height; + } + + entries.forEach(entry => { + const trackedElementName = this.trackedUiElements.get(entry.target); + if (trackedElementName) { + this.uiElementDimensions.set(trackedElementName, entry.contentRect); + this.emit(trackedElementName, UI_EVENTS.Resize, entry); + } + }); + + this.emit(UI_EVENTS.Resize, entries); + } +} + +window.mxUIStore = UIStore.instance; diff --git a/src/stores/room-list/MessagePreviewStore.ts b/src/stores/room-list/MessagePreviewStore.ts index 10e5cf554e..f5b9d9bc6a 100644 --- a/src/stores/room-list/MessagePreviewStore.ts +++ b/src/stores/room-list/MessagePreviewStore.ts @@ -176,7 +176,8 @@ export class MessagePreviewStore extends AsyncStoreWithClient { if (payload.action === 'MatrixActions.Room.timeline' || payload.action === 'MatrixActions.Event.decrypted') { const event = payload.event; // TODO: Type out the dispatcher - if (!this.previews.has(event.getRoomId())) return; // not important + const isHistoricalEvent = payload.hasOwnProperty("isLiveEvent") && !payload.isLiveEvent + if (!this.previews.has(event.getRoomId()) || isHistoricalEvent) return; // not important await this.generatePreview(this.matrixClient.getRoom(event.getRoomId()), TAG_ANY); } } diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts index a23401e4c9..b5961f1ac3 100644 --- a/src/stores/room-list/RoomListStore.ts +++ b/src/stores/room-list/RoomListStore.ts @@ -426,8 +426,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient { return; // don't do anything on rooms that aren't visible } - if (cause === RoomUpdateCause.NewRoom && !this.prefilterConditions.every(c => c.isVisible(room))) { - return; // don't do anything on new rooms which ought not to be shown + if ((cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.PossibleTagChange) && + !this.prefilterConditions.every(c => c.isVisible(room)) + ) { + return; // don't do anything on new/moved rooms which ought not to be shown } const shouldUpdate = await this.algorithm.handleRoomUpdate(room, cause); diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js index fd12a454f6..4d46d10f6c 100644 --- a/src/utils/ResizeNotifier.js +++ b/src/utils/ResizeNotifier.js @@ -74,12 +74,6 @@ export default class ResizeNotifier extends EventEmitter { // can be called in quick succession notifyWindowResized() { - // no need to throttle this one, - // also it could make scrollbars appear for - // a split second when the room list manual layout is now - // taller than the available space - this.emit("leftPanelResized"); - this._updateMiddlePanel(); } } diff --git a/src/utils/promise.ts b/src/utils/promise.ts index f828ddfdaf..4ebbb27141 100644 --- a/src/utils/promise.ts +++ b/src/utils/promise.ts @@ -51,24 +51,6 @@ export function defer(): IDeferred { return {resolve, reject, promise}; } -// Promise.allSettled polyfill until browser support is stable in Firefox -export function allSettled(promises: Promise[]): Promise | ISettledRejected>> { - if (Promise.allSettled) { - return Promise.allSettled(promises); - } - - // @ts-ignore - typescript isn't smart enough to see the disjoint here - return Promise.all(promises.map((promise) => { - return promise.then(value => ({ - status: "fulfilled", - value, - })).catch(reason => ({ - status: "rejected", - reason, - })); - })); -} - // Helper method to retry a Promise a given number of times or until a predicate fails export async function retry(fn: () => Promise, num: number, predicate?: (e: E) => boolean) { let lastErr: E; diff --git a/test/components/structures/auth/Login-test.js b/test/components/structures/auth/Login-test.js index 9b73137936..f39802464f 100644 --- a/test/components/structures/auth/Login-test.js +++ b/test/components/structures/auth/Login-test.js @@ -133,7 +133,7 @@ describe('Login', function() { root.setState({ flows: [{ "type": "m.login.sso", - "org.matrix.msc2858.identity_providers": [{ + "identity_providers": [{ id: "a", name: "Provider 1", }, { diff --git a/yarn.lock b/yarn.lock index 19c0646d32..0ff235a660 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1325,6 +1325,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz": + version "3.2.3" + resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz#cc332fdd25c08ef0e40f4d33fc3f822a0f98b6f4" + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents": version "2.1.8-no-fsevents" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz#da7c3996b8e6e19ebd14d82eaced2313e7769f9b" @@ -5670,8 +5674,8 @@ mathml-tag-names@^2.1.3: integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== "matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "11.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/52a893a8116d60bb76f1b015d3161a15404b3628" + version "11.1.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/acb9bc8cc5234326a7583514a8e120a4ac42eedc" dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" @@ -6144,10 +6148,6 @@ object.values@^1.1.1, object.values@^1.1.2: es-abstract "^1.18.0-next.1" has "^1.0.3" -"olm@https://packages.matrix.org/npm/olm/olm-3.2.1.tgz": - version "3.2.1" - resolved "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz#d623d76f99c3518dde68be8c86618d68bc7b004a" - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -8438,9 +8438,9 @@ write@1.0.3: mkdirp "^0.5.1" ws@^7.2.3: - version "7.4.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd" - integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA== + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== xml-name-validator@^3.0.0: version "3.0.0"