{ children }
{ title }
diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx
index 147d68f5ff..705474f8d0 100644
--- a/src/autocomplete/EmojiProvider.tsx
+++ b/src/autocomplete/EmojiProvider.tsx
@@ -23,8 +23,7 @@ import AutocompleteProvider from './AutocompleteProvider';
import QueryMatcher from './QueryMatcher';
import {PillCompletion} from './Components';
import {ICompletion, ISelectionRange} from './Autocompleter';
-import _uniq from 'lodash/uniq';
-import _sortBy from 'lodash/sortBy';
+import {uniq, sortBy} from 'lodash';
import SettingsStore from "../settings/SettingsStore";
import { shortcodeToUnicode } from '../HtmlUtils';
import { EMOJI, IEmoji } from '../emoji';
@@ -115,7 +114,7 @@ export default class EmojiProvider extends AutocompleteProvider {
}
// Finally, sort by original ordering
sorters.push((c) => c._orderBy);
- completions = _sortBy(_uniq(completions), sorters);
+ completions = sortBy(uniq(completions), sorters);
completions = completions.map(({shortname}) => {
const unicode = shortcodeToUnicode(shortname);
@@ -139,7 +138,11 @@ export default class EmojiProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return (
-
+
{ completions }
);
diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts
index 9c91414556..a07ed29c7e 100644
--- a/src/autocomplete/QueryMatcher.ts
+++ b/src/autocomplete/QueryMatcher.ts
@@ -16,8 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import _at from 'lodash/at';
-import _uniq from 'lodash/uniq';
+import {at, uniq} from 'lodash';
import {removeHiddenChars} from "matrix-js-sdk/src/utils";
interface IOptions {
@@ -73,7 +72,7 @@ export default class QueryMatcher {
// type for their values. We assume that those values who's keys have
// been specified will be string. Also, we cannot infer all the
// types of the keys of the objects at compile.
- const keyValues = _at(object, this._options.keys);
+ const keyValues = at(object, this._options.keys);
if (this._options.funcs) {
for (const f of this._options.funcs) {
@@ -137,7 +136,7 @@ export default class QueryMatcher {
});
// Now map the keys to the result objects. Also remove any duplicates.
- return _uniq(matches.map((match) => match.object));
+ return uniq(matches.map((match) => match.object));
}
private processQuery(query: string): string {
diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx
index b18b2d132c..74deacf61f 100644
--- a/src/autocomplete/RoomProvider.tsx
+++ b/src/autocomplete/RoomProvider.tsx
@@ -27,7 +27,7 @@ import {PillCompletion} from './Components';
import * as sdk from '../index';
import {makeRoomPermalink} from "../utils/permalinks/Permalinks";
import {ICompletion, ISelectionRange} from "./Autocompleter";
-import { uniqBy, sortBy } from 'lodash';
+import {uniqBy, sortBy} from "lodash";
const ROOM_REGEX = /\B#\S*/g;
@@ -110,9 +110,7 @@ export default class RoomProvider extends AutocompleteProvider {
),
range,
};
- })
- .filter((completion) => !!completion.completion && completion.completion.length > 0)
- .slice(0, 4);
+ }).filter((completion) => !!completion.completion && completion.completion.length > 0).slice(0, 4);
}
return completions;
}
diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx
index c957b5e597..32eea55b0b 100644
--- a/src/autocomplete/UserProvider.tsx
+++ b/src/autocomplete/UserProvider.tsx
@@ -23,7 +23,7 @@ import AutocompleteProvider from './AutocompleteProvider';
import {PillCompletion} from './Components';
import * as sdk from '../index';
import QueryMatcher from './QueryMatcher';
-import _sortBy from 'lodash/sortBy';
+import {sortBy} from 'lodash';
import {MatrixClientPeg} from '../MatrixClientPeg';
import MatrixEvent from "matrix-js-sdk/src/models/event";
@@ -71,8 +71,13 @@ export default class UserProvider extends AutocompleteProvider {
}
}
- private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: boolean, removed: boolean,
- data: IRoomTimelineData) => {
+ private onRoomTimeline = (
+ ev: MatrixEvent,
+ room: Room,
+ toStartOfTimeline: boolean,
+ removed: boolean,
+ data: IRoomTimelineData,
+ ) => {
if (!room) return;
if (removed) return;
if (room.roomId !== this.room.roomId) return;
@@ -151,7 +156,7 @@ export default class UserProvider extends AutocompleteProvider {
const currentUserId = MatrixClientPeg.get().credentials.userId;
this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId);
- this.users = _sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
+ this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20);
this.matcher.setObjects(this.users);
}
@@ -171,7 +176,11 @@ export default class UserProvider extends AutocompleteProvider {
renderCompletions(completions: React.ReactNode[]): React.ReactNode {
return (
-
+
{ completions }
);
diff --git a/src/components/structures/CompatibilityPage.js b/src/components/structures/CompatibilityPage.js
deleted file mode 100644
index 1fa6068675..0000000000
--- a/src/components/structures/CompatibilityPage.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-Copyright 2015, 2016 OpenMarket Ltd
-Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
-Copyright 2019, 2020 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 React from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
-import { _t } from '../../languageHandler';
-import SdkConfig from '../../SdkConfig';
-
-export default createReactClass({
- displayName: 'CompatibilityPage',
- propTypes: {
- onAccept: PropTypes.func,
- },
-
- getDefaultProps: function() {
- return {
- onAccept: function() {}, // NOP
- };
- },
-
- onAccept: function() {
- this.props.onAccept();
- },
-
- render: function() {
- const brand = SdkConfig.get().brand;
-
- return (
-
-
-
{_t(
- "Sorry, your browser is not able to run %(brand)s.",
- {
- brand,
- },
- {
- 'b': (sub) => {sub},
- })
- }
-
- { _t(
- "%(brand)s uses many advanced browser features, some of which are not available " +
- "or experimental in your current browser.",
- { brand },
- ) }
-
- { _t(
- "With your current browser, the look and feel of the application may be " +
- "completely incorrect, and some or all features may not function. " +
- "If you want to try it anyway you can continue, but you are on your own in terms " +
- "of any issues you may encounter!",
- ) }
-
-
-
-
- );
- },
-});
diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx
index 587ae2cb6b..884f77aba5 100644
--- a/src/components/structures/ContextMenu.tsx
+++ b/src/components/structures/ContextMenu.tsx
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React, {CSSProperties, useRef, useState} from "react";
+import React, {CSSProperties, RefObject, useRef, useState} from "react";
import ReactDOM from "react-dom";
import classNames from "classnames";
@@ -233,8 +233,7 @@ export class ContextMenu extends React.PureComponent {
switch (ev.key) {
case Key.TAB:
case Key.ESCAPE:
- // close on left and right arrows too for when it is a context menu on a
- case Key.ARROW_LEFT:
+ case Key.ARROW_LEFT: // close on left and right arrows too for when it is a context menu on a
case Key.ARROW_RIGHT:
this.props.onFinished();
break;
@@ -417,8 +416,8 @@ export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None
return menuOptions;
};
-export const useContextMenu = () => {
- const button = useRef(null);
+export const useContextMenu = (): [boolean, RefObject, () => void, () => void, (val: boolean) => void] => {
+ const button = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const open = () => {
setIsOpen(true);
diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js
index 49ba3d1227..cbfeff7582 100644
--- a/src/components/structures/EmbeddedPage.js
+++ b/src/components/structures/EmbeddedPage.js
@@ -43,8 +43,8 @@ export default class EmbeddedPage extends React.PureComponent {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this._dispatcherRef = null;
diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js
index d873dd4094..6d618d0b9d 100644
--- a/src/components/structures/FilePanel.js
+++ b/src/components/structures/FilePanel.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import {Filter} from 'matrix-js-sdk';
@@ -24,27 +23,27 @@ import * as sdk from '../../index';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import EventIndexPeg from "../../indexing/EventIndexPeg";
import { _t } from '../../languageHandler';
+import BaseCard from "../views/right_panel/BaseCard";
+import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
/*
* Component which shows the filtered file using a TimelinePanel
*/
-const FilePanel = createReactClass({
- displayName: 'FilePanel',
+class FilePanel extends React.Component {
+ static propTypes = {
+ roomId: PropTypes.string.isRequired,
+ onClose: PropTypes.func.isRequired,
+ };
+
// This is used to track if a decrypted event was a live event and should be
// added to the timeline.
- decryptingEvents: new Set(),
+ decryptingEvents = new Set();
- propTypes: {
- roomId: PropTypes.string.isRequired,
- },
+ state = {
+ timelineSet: null,
+ };
- getInitialState: function() {
- return {
- timelineSet: null,
- };
- },
-
- onRoomTimeline(ev, room, toStartOfTimeline, removed, data) {
+ onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => {
if (room.roomId !== this.props.roomId) return;
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
@@ -53,9 +52,9 @@ const FilePanel = createReactClass({
} else {
this.addEncryptedLiveEvent(ev);
}
- },
+ };
- onEventDecrypted(ev, err) {
+ onEventDecrypted = (ev, err) => {
if (ev.getRoomId() !== this.props.roomId) return;
const eventId = ev.getId();
@@ -63,7 +62,7 @@ const FilePanel = createReactClass({
if (err) return;
this.addEncryptedLiveEvent(ev);
- },
+ };
addEncryptedLiveEvent(ev, toStartOfTimeline) {
if (!this.state.timelineSet) return;
@@ -77,7 +76,7 @@ const FilePanel = createReactClass({
if (!this.state.timelineSet.eventIdToTimeline(ev.getId())) {
this.state.timelineSet.addEventToTimeline(ev, timeline, false);
}
- },
+ }
async componentDidMount() {
const client = MatrixClientPeg.get();
@@ -98,7 +97,7 @@ const FilePanel = createReactClass({
client.on('Room.timeline', this.onRoomTimeline);
client.on('Event.decrypted', this.onEventDecrypted);
}
- },
+ }
componentWillUnmount() {
const client = MatrixClientPeg.get();
@@ -110,7 +109,7 @@ const FilePanel = createReactClass({
client.removeListener('Room.timeline', this.onRoomTimeline);
client.removeListener('Event.decrypted', this.onEventDecrypted);
}
- },
+ }
async fetchFileEventsServer(room) {
const client = MatrixClientPeg.get();
@@ -134,9 +133,9 @@ const FilePanel = createReactClass({
const timelineSet = room.getOrCreateFilteredTimelineSet(filter);
return timelineSet;
- },
+ }
- onPaginationRequest(timelineWindow, direction, limit) {
+ onPaginationRequest = (timelineWindow, direction, limit) => {
const client = MatrixClientPeg.get();
const eventIndex = EventIndexPeg.get();
const roomId = this.props.roomId;
@@ -152,7 +151,7 @@ const FilePanel = createReactClass({
} else {
return timelineWindow.paginate(direction, limit);
}
- },
+ };
async updateTimelineSet(roomId: string) {
const client = MatrixClientPeg.get();
@@ -188,22 +187,30 @@ const FilePanel = createReactClass({
} else {
console.error("Failed to add filtered timelineSet for FilePanel as no room!");
}
- },
+ }
- render: function() {
+ render() {
if (MatrixClientPeg.get().isGuest()) {
- return
+ return
{ _t("You must register to use this functionality",
{},
{ 'a': (sub) => { sub } })
}
- );
+ content = ;
}
- },
-});
+
+ return
+ { content }
+ ;
+ }
+}
export default NotificationPanel;
diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js
index a4e3254e4c..6c6d8700a5 100644
--- a/src/components/structures/RightPanel.js
+++ b/src/components/structures/RightPanel.js
@@ -21,6 +21,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
+import {Room} from "matrix-js-sdk/src/models/room";
+
import * as sdk from '../../index';
import dis from '../../dispatcher/dispatcher';
import RateLimitedFunc from '../../ratelimitedfunc';
@@ -30,11 +32,14 @@ import {RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS} from "../../stores/RightPa
import RightPanelStore from "../../stores/RightPanelStore";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import {Action} from "../../dispatcher/actions";
+import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
+import WidgetCard from "../views/right_panel/WidgetCard";
+import defaultDispatcher from "../../dispatcher/dispatcher";
export default class RightPanel extends React.Component {
static get propTypes() {
return {
- roomId: PropTypes.string, // if showing panels for a given room, this is set
+ room: PropTypes.instanceOf(Room), // if showing panels for a given room, this is set
groupId: PropTypes.string, // if showing panels for a given group, this is set
user: PropTypes.object, // used if we know the user ahead of opening the panel
};
@@ -42,13 +47,13 @@ export default class RightPanel extends React.Component {
static contextType = MatrixClientContext;
- constructor(props) {
- super(props);
+ constructor(props, context) {
+ super(props, context);
this.state = {
+ ...RightPanelStore.getSharedInstance().roomPanelPhaseParams,
phase: this._getPhaseFromProps(),
isUserPrivilegedInGroup: null,
member: this._getUserForPanel(),
- verificationRequest: RightPanelStore.getSharedInstance().roomPanelPhaseParams.verificationRequest,
};
this.onAction = this.onAction.bind(this);
this.onRoomStateMember = this.onRoomStateMember.bind(this);
@@ -100,10 +105,6 @@ export default class RightPanel extends React.Component {
}
return RightPanelPhases.RoomMemberInfo;
} else {
- if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.roomPanelPhase)) {
- dis.dispatch({action: Action.SetRightPanelPhase, phase: RightPanelPhases.RoomMemberList});
- return RightPanelPhases.RoomMemberList;
- }
return rps.roomPanelPhase;
}
}
@@ -161,13 +162,13 @@ export default class RightPanel extends React.Component {
}
onRoomStateMember(ev, state, member) {
- if (member.roomId !== this.props.roomId) {
+ if (member.roomId !== this.props.room.roomId) {
return;
}
// redraw the badge on the membership list
- if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.roomId) {
+ if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.room.roomId) {
this._delayedUpdate();
- } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.roomId &&
+ } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.room.roomId &&
member.userId === this.state.member.userId) {
// refresh the member info (e.g. new power level)
this._delayedUpdate();
@@ -184,6 +185,7 @@ export default class RightPanel extends React.Component {
event: payload.event,
verificationRequest: payload.verificationRequest,
verificationRequestPromise: payload.verificationRequestPromise,
+ widgetId: payload.widgetId,
});
}
}
@@ -211,6 +213,14 @@ export default class RightPanel extends React.Component {
}
};
+ onClose = () => {
+ // the RightPanelStore has no way of knowing which mode room/group it is in, so we handle closing here
+ defaultDispatcher.dispatch({
+ action: Action.ToggleRightPanel,
+ type: this.props.groupId ? "group" : "room",
+ });
+ };
+
render() {
const MemberList = sdk.getComponent('rooms.MemberList');
const UserInfo = sdk.getComponent('right_panel.UserInfo');
@@ -223,36 +233,42 @@ export default class RightPanel extends React.Component {
const GroupRoomInfo = sdk.getComponent('groups.GroupRoomInfo');
let panel = ;
+ const roomId = this.props.room ? this.props.room.roomId : undefined;
switch (this.state.phase) {
case RightPanelPhases.RoomMemberList:
- if (this.props.roomId) {
- panel = ;
+ if (roomId) {
+ panel = ;
}
break;
+
case RightPanelPhases.GroupMemberList:
if (this.props.groupId) {
panel = ;
}
break;
+
case RightPanelPhases.GroupRoomList:
panel = ;
break;
+
case RightPanelPhases.RoomMemberInfo:
case RightPanelPhases.EncryptionPanel:
panel = ;
break;
+
case RightPanelPhases.Room3pidMemberInfo:
- panel = ;
+ panel = ;
break;
+
case RightPanelPhases.GroupMemberInfo:
panel = ;
break;
+
case RightPanelPhases.GroupRoomInfo:
panel = ;
break;
+
case RightPanelPhases.NotificationPanel:
- panel = ;
+ panel = ;
break;
+
case RightPanelPhases.FilePanel:
- panel = ;
+ panel = ;
+ break;
+
+ case RightPanelPhases.RoomSummary:
+ panel = ;
+ break;
+
+ case RightPanelPhases.Widget:
+ panel = ;
break;
}
diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js
index 5b12dae7df..55c6527f06 100644
--- a/src/components/structures/RoomDirectory.js
+++ b/src/components/structures/RoomDirectory.js
@@ -17,7 +17,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index";
import dis from "../../dispatcher/dispatcher";
@@ -30,6 +29,10 @@ import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/Di
import Analytics from '../../Analytics';
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
import {ALL_ROOMS} from "../views/directory/NetworkDropdown";
+import SettingsStore from "../../settings/SettingsStore";
+import TagOrderStore from "../../stores/TagOrderStore";
+import GroupStore from "../../stores/GroupStore";
+import FlairStore from "../../stores/FlairStore";
const MAX_NAME_LENGTH = 80;
const MAX_TOPIC_LENGTH = 160;
@@ -38,15 +41,16 @@ function track(action) {
Analytics.trackEvent('RoomDirectory', action);
}
-export default createReactClass({
- displayName: 'RoomDirectory',
-
- propTypes: {
+export default class RoomDirectory extends React.Component {
+ static propTypes = {
onFinished: PropTypes.func.isRequired,
- },
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ const selectedCommunityId = TagOrderStore.getSelectedTags()[0];
+ this.state = {
publicRooms: [],
loading: true,
protocolsLoading: true,
@@ -54,66 +58,108 @@ export default createReactClass({
instanceId: undefined,
roomServer: MatrixClientPeg.getHomeserverName(),
filterString: null,
+ selectedCommunityId: SettingsStore.getValue("feature_communities_v2_prototypes")
+ ? selectedCommunityId
+ : null,
+ communityName: null,
};
- },
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
this._unmounted = false;
this.nextBatch = null;
this.filterTimeout = null;
this.scrollPanel = null;
this.protocols = null;
- this.setState({protocolsLoading: true});
+ this.state.protocolsLoading = true;
if (!MatrixClientPeg.get()) {
// We may not have a client yet when invoked from welcome page
- this.setState({protocolsLoading: false});
+ this.state.protocolsLoading = false;
return;
}
- MatrixClientPeg.get().getThirdpartyProtocols().then((response) => {
- this.protocols = response;
- this.setState({protocolsLoading: false});
- }, (err) => {
- console.warn(`error loading third party protocols: ${err}`);
- this.setState({protocolsLoading: false});
- if (MatrixClientPeg.get().isGuest()) {
- // Guests currently aren't allowed to use this API, so
- // ignore this as otherwise this error is literally the
- // thing you see when loading the client!
- return;
- }
- track('Failed to get protocol list from homeserver');
- const brand = SdkConfig.get().brand;
- this.setState({
- error: _t(
- '%(brand)s failed to get the protocol list from the homeserver. ' +
- 'The homeserver may be too old to support third party networks.',
- { brand },
- ),
+
+ if (!this.state.selectedCommunityId) {
+ MatrixClientPeg.get().getThirdpartyProtocols().then((response) => {
+ this.protocols = response;
+ this.setState({protocolsLoading: false});
+ }, (err) => {
+ console.warn(`error loading third party protocols: ${err}`);
+ this.setState({protocolsLoading: false});
+ if (MatrixClientPeg.get().isGuest()) {
+ // Guests currently aren't allowed to use this API, so
+ // ignore this as otherwise this error is literally the
+ // thing you see when loading the client!
+ return;
+ }
+ track('Failed to get protocol list from homeserver');
+ const brand = SdkConfig.get().brand;
+ this.setState({
+ error: _t(
+ '%(brand)s failed to get the protocol list from the homeserver. ' +
+ 'The homeserver may be too old to support third party networks.',
+ {brand},
+ ),
+ });
});
- });
+ } else {
+ // We don't use the protocols in the communities v2 prototype experience
+ this.state.protocolsLoading = false;
+ // Grab the profile info async
+ FlairStore.getGroupProfileCached(MatrixClientPeg.get(), this.state.selectedCommunityId).then(profile => {
+ this.setState({communityName: profile.name});
+ });
+ }
+ }
+
+ componentDidMount() {
this.refreshRoomList();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
this._unmounted = true;
- },
+ }
+
+ refreshRoomList = () => {
+ if (this.state.selectedCommunityId) {
+ this.setState({
+ publicRooms: GroupStore.getGroupRooms(this.state.selectedCommunityId).map(r => {
+ return {
+ // Translate all the group properties to the directory format
+ room_id: r.roomId,
+ name: r.name,
+ topic: r.topic,
+ canonical_alias: r.canonicalAlias,
+ num_joined_members: r.numJoinedMembers,
+ avatarUrl: r.avatarUrl,
+ world_readable: r.worldReadable,
+ guest_can_join: r.guestsCanJoin,
+ };
+ }).filter(r => {
+ const filterString = this.state.filterString;
+ if (filterString) {
+ const containedIn = (s: string) => (s || "").toLowerCase().includes(filterString.toLowerCase());
+ return containedIn(r.name) || containedIn(r.topic) || containedIn(r.canonical_alias);
+ }
+ return true;
+ }),
+ loading: false,
+ });
+ return;
+ }
- refreshRoomList: function() {
this.nextBatch = null;
this.setState({
publicRooms: [],
loading: true,
});
this.getMoreRooms();
- },
+ };
- getMoreRooms: function() {
+ getMoreRooms() {
+ if (this.state.selectedCommunityId) return Promise.resolve(); // no more rooms
if (!MatrixClientPeg.get()) return Promise.resolve();
this.setState({
@@ -185,7 +231,7 @@ export default createReactClass({
),
});
});
- },
+ }
/**
* A limited interface for removing rooms from the directory.
@@ -194,7 +240,7 @@ export default createReactClass({
* HS admins to do this through the RoomSettings interface, but
* this needs SPEC-417.
*/
- removeFromDirectory: function(room) {
+ removeFromDirectory(room) {
const alias = get_display_alias_for_room(room);
const name = room.name || alias || _t('Unnamed room');
@@ -236,18 +282,18 @@ export default createReactClass({
});
},
});
- },
+ }
- onRoomClicked: function(room, ev) {
- if (ev.shiftKey) {
+ onRoomClicked = (room, ev) => {
+ if (ev.shiftKey && !this.state.selectedCommunityId) {
ev.preventDefault();
this.removeFromDirectory(room);
} else {
this.showRoom(room);
}
- },
+ };
- onOptionChange: function(server, instanceId) {
+ onOptionChange = (server, instanceId) => {
// clear next batch so we don't try to load more rooms
this.nextBatch = null;
this.setState({
@@ -265,15 +311,15 @@ export default createReactClass({
// find the five gitter ones, at which point we do not want
// to render all those rooms when switching back to 'all networks'.
// Easiest to just blow away the state & re-fetch.
- },
+ };
- onFillRequest: function(backwards) {
+ onFillRequest = (backwards) => {
if (backwards || !this.nextBatch) return Promise.resolve(false);
return this.getMoreRooms();
- },
+ };
- onFilterChange: function(alias) {
+ onFilterChange = (alias) => {
this.setState({
filterString: alias || null,
});
@@ -289,9 +335,9 @@ export default createReactClass({
this.filterTimeout = null;
this.refreshRoomList();
}, 700);
- },
+ };
- onFilterClear: function() {
+ onFilterClear = () => {
// update immediately
this.setState({
filterString: null,
@@ -300,9 +346,9 @@ export default createReactClass({
if (this.filterTimeout) {
clearTimeout(this.filterTimeout);
}
- },
+ };
- onJoinFromSearchClick: function(alias) {
+ onJoinFromSearchClick = (alias) => {
// If we don't have a particular instance id selected, just show that rooms alias
if (!this.state.instanceId || this.state.instanceId === ALL_ROOMS) {
// If the user specified an alias without a domain, add on whichever server is selected
@@ -343,50 +389,41 @@ export default createReactClass({
});
});
}
- },
+ };
- onPreviewClick: function(ev, room) {
- this.props.onFinished();
- dis.dispatch({
- action: 'view_room',
- room_id: room.room_id,
- should_peek: true,
- });
+ onPreviewClick = (ev, room) => {
+ this.showRoom(room, null, false, true);
ev.stopPropagation();
- },
+ };
- onViewClick: function(ev, room) {
- this.props.onFinished();
- dis.dispatch({
- action: 'view_room',
- room_id: room.room_id,
- should_peek: false,
- });
+ onViewClick = (ev, room) => {
+ this.showRoom(room);
ev.stopPropagation();
- },
+ };
- onJoinClick: function(ev, room) {
+ onJoinClick = (ev, room) => {
this.showRoom(room, null, true);
ev.stopPropagation();
- },
+ };
- onCreateRoomClick: function(room) {
+ onCreateRoomClick = room => {
this.props.onFinished();
dis.dispatch({
action: 'view_create_room',
public: true,
});
- },
+ };
- showRoomAlias: function(alias, autoJoin=false) {
+ showRoomAlias(alias, autoJoin=false) {
this.showRoom(null, alias, autoJoin);
- },
+ }
- showRoom: function(room, room_alias, autoJoin=false) {
+ showRoom(room, room_alias, autoJoin = false, shouldPeek = false) {
this.props.onFinished();
const payload = {
action: 'view_room',
auto_join: autoJoin,
+ should_peek: shouldPeek,
};
if (room) {
// Don't let the user view a room they won't be able to either
@@ -411,6 +448,7 @@ export default createReactClass({
};
if (this.state.roomServer) {
+ payload.via_servers = [this.state.roomServer];
payload.opts = {
viaServers: [this.state.roomServer],
};
@@ -426,7 +464,7 @@ export default createReactClass({
payload.room_id = room.room_id;
}
dis.dispatch(payload);
- },
+ }
getRow(room) {
const client = MatrixClientPeg.get();
@@ -492,22 +530,22 @@ export default createReactClass({
{joinOrViewButton}
);
- },
+ }
- collectScrollPanel: function(element) {
+ collectScrollPanel = (element) => {
this.scrollPanel = element;
- },
+ };
- _stringLooksLikeId: function(s, field_type) {
+ _stringLooksLikeId(s, field_type) {
let pat = /^#[^\s]+:[^\s]/;
if (field_type && field_type.regexp) {
pat = new RegExp(field_type.regexp);
}
return pat.test(s);
- },
+ }
- _getFieldsForThirdPartyLocation: function(userInput, protocol, instance) {
+ _getFieldsForThirdPartyLocation(userInput, protocol, instance) {
// make an object with the fields specified by that protocol. We
// require that the values of all but the last field come from the
// instance. The last is the user input.
@@ -521,20 +559,20 @@ export default createReactClass({
}
fields[requiredFields[requiredFields.length - 1]] = userInput;
return fields;
- },
+ }
/**
* called by the parent component when PageUp/Down/etc is pressed.
*
* We pass it down to the scroll panel.
*/
- handleScrollKey: function(ev) {
+ handleScrollKey = ev => {
if (this.scrollPanel) {
this.scrollPanel.handleScrollKey(ev);
}
- },
+ };
- render: function() {
+ render() {
const Loader = sdk.getComponent("elements.Spinner");
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -610,6 +648,18 @@ export default createReactClass({
}
}
+ let dropdown = (
+
+ );
+ if (this.state.selectedCommunityId) {
+ dropdown = null;
+ }
+
listHeader =
);
- },
-});
+ }
+}
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.tsx
similarity index 74%
rename from src/components/structures/RoomView.js
rename to src/components/structures/RoomView.tsx
index a79e5b0aa8..4c418e9994 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.tsx
@@ -21,28 +21,27 @@ limitations under the License.
// - Search results component
// - Drag and drop
-import shouldHideEvent from '../../shouldHideEvent';
-
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
-import PropTypes from 'prop-types';
import classNames from 'classnames';
-import { _t } from '../../languageHandler';
-import {RoomPermalinkCreator} from '../../utils/permalinks/Permalinks';
+import {Room} from "matrix-js-sdk/src/models/room";
+import {MatrixEvent} from "matrix-js-sdk/src/models/event";
+import {EventSubscription} from "fbemitter";
+import shouldHideEvent from '../../shouldHideEvent';
+import {_t} from '../../languageHandler';
+import {RoomPermalinkCreator} from '../../utils/permalinks/Permalinks';
+import ResizeNotifier from '../../utils/ResizeNotifier';
import ContentMessages from '../../ContentMessages';
import Modal from '../../Modal';
import * as sdk from '../../index';
import CallHandler from '../../CallHandler';
import dis from '../../dispatcher/dispatcher';
import Tinter from '../../Tinter';
-import rate_limited_func from '../../ratelimitedfunc';
+import rateLimitedFunc from '../../ratelimitedfunc';
import * as ObjectUtils from '../../ObjectUtils';
import * as Rooms from '../../Rooms';
import eventSearch, {searchPagination} from '../../Searching';
-
import {isOnlyCtrlOrCmdIgnoreShiftKeyEvent, isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard';
-
import MainSplit from './MainSplit';
import RightPanel from './RightPanel';
import RoomViewStore from '../../stores/RoomViewStore';
@@ -54,12 +53,28 @@ import RightPanelStore from "../../stores/RightPanelStore";
import {haveTileForEvent} from "../views/rooms/EventTile";
import RoomContext from "../../contexts/RoomContext";
import MatrixClientContext from "../../contexts/MatrixClientContext";
-import { shieldStatusForRoom } from '../../utils/ShieldUtils';
+import {E2EStatus, shieldStatusForRoom} from '../../utils/ShieldUtils';
import {Action} from "../../dispatcher/actions";
import {SettingLevel} from "../../settings/SettingLevel";
+import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
+import {IMatrixClientCreds} from "../../MatrixClientPeg";
+import ScrollPanel from "./ScrollPanel";
+import TimelinePanel from "./TimelinePanel";
+import ErrorBoundary from "../views/elements/ErrorBoundary";
+import RoomPreviewBar from "../views/rooms/RoomPreviewBar";
+import ForwardMessage from "../views/rooms/ForwardMessage";
+import SearchBar from "../views/rooms/SearchBar";
+import RoomUpgradeWarningBar from "../views/rooms/RoomUpgradeWarningBar";
+import PinnedEventsPanel from "../views/rooms/PinnedEventsPanel";
+import AuxPanel from "../views/rooms/AuxPanel";
+import RoomHeader from "../views/rooms/RoomHeader";
+import TintableSvg from "../views/elements/TintableSvg";
+import type * as ConferenceHandler from '../../VectorConferenceHandler';
+import {XOR} from "../../@types/common";
+import { IThreepidInvite } from "../../stores/ThreepidInviteStore";
const DEBUG = false;
-let debuglog = function() {};
+let debuglog = function(msg: string) {};
const BROWSER_SUPPORTS_SANDBOX = 'sandbox' in document.createElement('iframe');
@@ -68,64 +83,136 @@ if (DEBUG) {
debuglog = console.log.bind(console);
}
-export default createReactClass({
- displayName: 'RoomView',
- propTypes: {
- ConferenceHandler: PropTypes.any,
+interface IProps {
+ ConferenceHandler?: ConferenceHandler;
- // Called with the credentials of a registered user (if they were a ROU that
- // transitioned to PWLU)
- onRegistered: PropTypes.func,
+ threepidInvite: IThreepidInvite,
- // An object representing a third party invite to join this room
- // Fields:
- // * inviteSignUrl (string) The URL used to join this room from an email invite
- // (given as part of the link in the invite email)
- // * invitedEmail (string) The email address that was invited to this room
- thirdPartyInvite: PropTypes.object,
+ // Any data about the room that would normally come from the homeserver
+ // but has been passed out-of-band, eg. the room name and avatar URL
+ // from an email invite (a workaround for the fact that we can't
+ // get this information from the HS using an email invite).
+ // Fields:
+ // * name (string) The room's name
+ // * avatarUrl (string) The mxc:// avatar URL for the room
+ // * inviterName (string) The display name of the person who
+ // * invited us to the room
+ oobData?: {
+ name?: string;
+ avatarUrl?: string;
+ inviterName?: string;
+ };
- // Any data about the room that would normally come from the homeserver
- // but has been passed out-of-band, eg. the room name and avatar URL
- // from an email invite (a workaround for the fact that we can't
- // get this information from the HS using an email invite).
- // Fields:
- // * name (string) The room's name
- // * avatarUrl (string) The mxc:// avatar URL for the room
- // * inviterName (string) The display name of the person who
- // * invited us to the room
- oobData: PropTypes.object,
+ // Servers the RoomView can use to try and assist joins
+ viaServers?: string[];
- // Servers the RoomView can use to try and assist joins
- viaServers: PropTypes.arrayOf(PropTypes.string),
- },
+ autoJoin?: boolean;
+ disabled?: boolean;
+ resizeNotifier: ResizeNotifier;
- statics: {
- contextType: MatrixClientContext,
- },
+ // Called with the credentials of a registered user (if they were a ROU that transitioned to PWLU)
+ onRegistered?(credentials: IMatrixClientCreds): void;
+}
+
+export interface IState {
+ room?: Room;
+ roomId?: string;
+ roomAlias?: string;
+ roomLoading: boolean;
+ peekLoading: boolean;
+ shouldPeek: boolean;
+ // used to trigger a rerender in TimelinePanel once the members are loaded,
+ // so RR are rendered again (now with the members available), ...
+ membersLoaded: boolean;
+ // The event to be scrolled to initially
+ initialEventId?: string;
+ // The offset in pixels from the event with which to scroll vertically
+ initialEventPixelOffset?: number;
+ // Whether to highlight the event scrolled to
+ isInitialEventHighlighted?: boolean;
+ forwardingEvent?: MatrixEvent;
+ numUnreadMessages: number;
+ draggingFile: boolean;
+ searching: boolean;
+ searchTerm?: string;
+ searchScope?: "All" | "Room";
+ searchResults?: XOR<{}, {
+ count: number;
+ highlights: string[];
+ results: MatrixEvent[];
+ next_batch: string; // eslint-disable-line camelcase
+ }>;
+ searchHighlights?: string[];
+ searchInProgress?: boolean;
+ callState?: string;
+ guestsCanJoin: boolean;
+ canPeek: boolean;
+ showApps: boolean;
+ isAlone: boolean;
+ isPeeking: boolean;
+ showingPinned: boolean;
+ showReadReceipts: boolean;
+ showRightPanel: boolean;
+ // error object, as from the matrix client/server API
+ // If we failed to load information about the room,
+ // store the error here.
+ roomLoadError?: Error;
+ // Have we sent a request to join the room that we're waiting to complete?
+ joining: boolean;
+ // this is true if we are fully scrolled-down, and are looking at
+ // the end of the live timeline. It has the effect of hiding the
+ // 'scroll to bottom' knob, among a couple of other things.
+ atEndOfLiveTimeline: boolean;
+ // used by componentDidUpdate to avoid unnecessary checks
+ atEndOfLiveTimelineInit: boolean;
+ showTopUnreadMessagesBar: boolean;
+ auxPanelMaxHeight?: number;
+ statusBarVisible: boolean;
+ // We load this later by asking the js-sdk to suggest a version for us.
+ // This object is the result of Room#getRecommendedVersion()
+ upgradeRecommendation?: {
+ version: string;
+ needsUpgrade: boolean;
+ urgent: boolean;
+ };
+ canReact: boolean;
+ canReply: boolean;
+ useIRCLayout: boolean;
+ matrixClientIsReady: boolean;
+ showUrlPreview?: boolean;
+ e2eStatus?: E2EStatus;
+ displayConfCallNotification?: boolean;
+ rejecting?: boolean;
+ rejectError?: Error;
+}
+
+export default class RoomView extends React.Component {
+ private readonly dispatcherRef: string;
+ private readonly roomStoreToken: EventSubscription;
+ private readonly rightPanelStoreToken: EventSubscription;
+ private readonly showReadReceiptsWatchRef: string;
+ private readonly layoutWatcherRef: string;
+
+ private unmounted = false;
+ private permalinkCreators: Record = {};
+ private searchId: number;
+
+ private roomView = createRef();
+ private searchResultsPanel = createRef();
+ private messagePanel: TimelinePanel;
+
+ static contextType = MatrixClientContext;
+
+ constructor(props, context) {
+ super(props, context);
- getInitialState: function() {
const llMembers = this.context.hasLazyLoadMembersEnabled();
- return {
- room: null,
+ this.state = {
roomId: null,
roomLoading: true,
peekLoading: false,
shouldPeek: true,
-
- // Media limits for uploading.
- mediaConfig: undefined,
-
- // used to trigger a rerender in TimelinePanel once the members are loaded,
- // so RR are rendered again (now with the members available), ...
membersLoaded: !llMembers,
- // The event to be scrolled to initially
- initialEventId: null,
- // The offset in pixels from the event with which to scroll vertically
- initialEventPixelOffset: null,
- // Whether to highlight the event scrolled to
- isInitialEventHighlighted: null,
-
- forwardingEvent: null,
numUnreadMessages: 0,
draggingFile: false,
searching: false,
@@ -139,42 +226,17 @@ export default createReactClass({
showingPinned: false,
showReadReceipts: true,
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
-
- // error object, as from the matrix client/server API
- // If we failed to load information about the room,
- // store the error here.
- roomLoadError: null,
-
- // Have we sent a request to join the room that we're waiting to complete?
joining: false,
-
- // this is true if we are fully scrolled-down, and are looking at
- // the end of the live timeline. It has the effect of hiding the
- // 'scroll to bottom' knob, among a couple of other things.
atEndOfLiveTimeline: true,
- atEndOfLiveTimelineInit: false, // used by componentDidUpdate to avoid unnecessary checks
-
+ atEndOfLiveTimelineInit: false,
showTopUnreadMessagesBar: false,
-
- auxPanelMaxHeight: undefined,
-
statusBarVisible: false,
-
- // We load this later by asking the js-sdk to suggest a version for us.
- // This object is the result of Room#getRecommendedVersion()
- upgradeRecommendation: null,
-
canReact: false,
canReply: false,
-
useIRCLayout: SettingsStore.getValue("useIRCLayout"),
-
matrixClientIsReady: this.context && this.context.isInitialSyncComplete(),
};
- },
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this.dispatcherRef = dis.register(this.onAction);
this.context.on("Room", this.onRoom);
this.context.on("Room.timeline", this.onRoomTimeline);
@@ -189,27 +251,28 @@ export default createReactClass({
this.context.on("userTrustStatusChanged", this.onUserVerificationChanged);
this.context.on("crossSigning.keysChanged", this.onCrossSigningKeysChanged);
// Start listening for RoomViewStore updates
- this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
- this._rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this._onRightPanelStoreUpdate);
- this._onRoomViewStoreUpdate(true);
+ this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
+ this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate);
- WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate);
- this._showReadReceiptsWatchRef = SettingsStore.watchSetting("showReadReceipts", null,
- this._onReadReceiptsChange);
+ WidgetEchoStore.on('update', this.onWidgetEchoStoreUpdate);
+ this.showReadReceiptsWatchRef = SettingsStore.watchSetting("showReadReceipts", null,
+ this.onReadReceiptsChange);
+ this.layoutWatcherRef = SettingsStore.watchSetting("useIRCLayout", null, this.onLayoutChange);
+ }
- this._roomView = createRef();
- this._searchResultsPanel = createRef();
+ // TODO: [REACT-WARNING] Move into constructor
+ // eslint-disable-next-line camelcase
+ UNSAFE_componentWillMount() {
+ this.onRoomViewStoreUpdate(true);
+ }
- this._layoutWatcherRef = SettingsStore.watchSetting("useIRCLayout", null, this.onLayoutChange);
- },
-
- _onReadReceiptsChange: function() {
+ private onReadReceiptsChange = () => {
this.setState({
showReadReceipts: SettingsStore.getValue("showReadReceipts", this.state.roomId),
});
- },
+ };
- _onRoomViewStoreUpdate: function(initial) {
+ private onRoomViewStoreUpdate = (initial?: boolean) => {
if (this.unmounted) {
return;
}
@@ -231,7 +294,7 @@ export default createReactClass({
const roomId = RoomViewStore.getRoomId();
- const newState = {
+ const newState: Pick = {
roomId,
roomAlias: RoomViewStore.getRoomAlias(),
roomLoading: RoomViewStore.isRoomLoading(),
@@ -267,8 +330,8 @@ export default createReactClass({
if (initial) {
newState.room = this.context.getRoom(newState.roomId);
if (newState.room) {
- newState.showApps = this._shouldShowApps(newState.room);
- this._onRoomLoaded(newState.room);
+ newState.showApps = this.shouldShowApps(newState.room);
+ this.onRoomLoaded(newState.room);
}
}
@@ -301,48 +364,47 @@ export default createReactClass({
// callback because this would prevent the setStates from being batched,
// ie. cause it to render RoomView twice rather than the once that is necessary.
if (initial) {
- this._setupRoom(newState.room, newState.roomId, newState.joining, newState.shouldPeek);
+ this.setupRoom(newState.room, newState.roomId, newState.joining, newState.shouldPeek);
}
- },
+ };
- _getRoomId() {
- // According to `_onRoomViewStoreUpdate`, `state.roomId` can be null
+ private getRoomId = () => {
+ // According to `onRoomViewStoreUpdate`, `state.roomId` can be null
// if we have a room alias we haven't resolved yet. To work around this,
// first we'll try the room object if it's there, and then fallback to
// the bare room ID. (We may want to update `state.roomId` after
// resolving aliases, so we could always trust it.)
return this.state.room ? this.state.room.roomId : this.state.roomId;
- },
+ };
- _getPermalinkCreatorForRoom: function(room) {
- if (!this._permalinkCreators) this._permalinkCreators = {};
- if (this._permalinkCreators[room.roomId]) return this._permalinkCreators[room.roomId];
+ private getPermalinkCreatorForRoom(room: Room) {
+ if (this.permalinkCreators[room.roomId]) return this.permalinkCreators[room.roomId];
- this._permalinkCreators[room.roomId] = new RoomPermalinkCreator(room);
+ this.permalinkCreators[room.roomId] = new RoomPermalinkCreator(room);
if (this.state.room && room.roomId === this.state.room.roomId) {
// We want to watch for changes in the creator for the primary room in the view, but
// don't need to do so for search results.
- this._permalinkCreators[room.roomId].start();
+ this.permalinkCreators[room.roomId].start();
} else {
- this._permalinkCreators[room.roomId].load();
+ this.permalinkCreators[room.roomId].load();
}
- return this._permalinkCreators[room.roomId];
- },
+ return this.permalinkCreators[room.roomId];
+ }
- _stopAllPermalinkCreators: function() {
- if (!this._permalinkCreators) return;
- for (const roomId of Object.keys(this._permalinkCreators)) {
- this._permalinkCreators[roomId].stop();
+ private stopAllPermalinkCreators() {
+ if (!this.permalinkCreators) return;
+ for (const roomId of Object.keys(this.permalinkCreators)) {
+ this.permalinkCreators[roomId].stop();
}
- },
+ }
- _onWidgetEchoStoreUpdate: function() {
+ private onWidgetEchoStoreUpdate = () => {
this.setState({
- showApps: this._shouldShowApps(this.state.room),
+ showApps: this.shouldShowApps(this.state.room),
});
- },
+ };
- _setupRoom: function(room, roomId, joining, shouldPeek) {
+ private setupRoom(room: Room, roomId: string, joining: boolean, shouldPeek: boolean) {
// if this is an unknown room then we're in one of three states:
// - This is a room we can peek into (search engine) (we can /peek)
// - This is a room we can publicly join or were invited to. (we can /join)
@@ -375,7 +437,7 @@ export default createReactClass({
room: room,
peekLoading: false,
});
- this._onRoomLoaded(room);
+ this.onRoomLoaded(room);
}).catch((err) => {
if (this.unmounted) {
return;
@@ -404,9 +466,9 @@ export default createReactClass({
this.setState({isPeeking: false});
}
}
- },
+ }
- _shouldShowApps: function(room) {
+ private shouldShowApps(room: Room) {
if (!BROWSER_SUPPORTS_SANDBOX) return false;
// Check if user has previously chosen to hide the app drawer for this
@@ -417,16 +479,16 @@ export default createReactClass({
// This is confusing, but it means to say that we default to the tray being
// hidden unless the user clicked to open it.
return hideWidgetDrawer === "false";
- },
+ }
- componentDidMount: function() {
- const call = this._getCallForRoom();
+ componentDidMount() {
+ const call = this.getCallForRoom();
const callState = call ? call.call_state : "ended";
this.setState({
callState: callState,
});
- this._updateConfCallNotification();
+ this.updateConfCallNotification();
window.addEventListener('beforeunload', this.onPageUnload);
if (this.props.resizeNotifier) {
@@ -435,16 +497,16 @@ export default createReactClass({
this.onResize();
document.addEventListener("keydown", this.onNativeKeyDown);
- },
+ }
- shouldComponentUpdate: function(nextProps, nextState) {
+ shouldComponentUpdate(nextProps, nextState) {
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
!ObjectUtils.shallowEqual(this.state, nextState));
- },
+ }
- componentDidUpdate: function() {
- if (this._roomView.current) {
- const roomView = this._roomView.current;
+ componentDidUpdate() {
+ if (this.roomView.current) {
+ const roomView = this.roomView.current;
if (!roomView.ondrop) {
roomView.addEventListener('drop', this.onDrop);
roomView.addEventListener('dragover', this.onDragOver);
@@ -458,15 +520,15 @@ export default createReactClass({
// in render() prevents the ref from being set on first mount, so we try and
// catch the messagePanel when it does mount. Because we only want the ref once,
// we use a boolean flag to avoid duplicate work.
- if (this._messagePanel && !this.state.atEndOfLiveTimelineInit) {
+ if (this.messagePanel && !this.state.atEndOfLiveTimelineInit) {
this.setState({
atEndOfLiveTimelineInit: true,
- atEndOfLiveTimeline: this._messagePanel.isAtEndOfLiveTimeline(),
+ atEndOfLiveTimeline: this.messagePanel.isAtEndOfLiveTimeline(),
});
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results.
//
@@ -475,7 +537,7 @@ export default createReactClass({
// update the scroll map before we get unmounted
if (this.state.roomId) {
- RoomScrollStateStore.setScrollState(this.state.roomId, this._getScrollState());
+ RoomScrollStateStore.setScrollState(this.state.roomId, this.getScrollState());
}
if (this.state.shouldPeek) {
@@ -483,14 +545,14 @@ export default createReactClass({
}
// stop tracking room changes to format permalinks
- this._stopAllPermalinkCreators();
+ this.stopAllPermalinkCreators();
- if (this._roomView.current) {
+ if (this.roomView.current) {
// disconnect the D&D event listeners from the room view. This
// is really just for hygiene - we're going to be
// deleted anyway, so it doesn't matter if the event listeners
// don't get cleaned up.
- const roomView = this._roomView.current;
+ const roomView = this.roomView.current;
roomView.removeEventListener('drop', this.onDrop);
roomView.removeEventListener('dragover', this.onDragOver);
roomView.removeEventListener('dragleave', this.onDragLeaveOrEnd);
@@ -520,55 +582,54 @@ export default createReactClass({
document.removeEventListener("keydown", this.onNativeKeyDown);
// Remove RoomStore listener
- if (this._roomStoreToken) {
- this._roomStoreToken.remove();
+ if (this.roomStoreToken) {
+ this.roomStoreToken.remove();
}
// Remove RightPanelStore listener
- if (this._rightPanelStoreToken) {
- this._rightPanelStoreToken.remove();
+ if (this.rightPanelStoreToken) {
+ this.rightPanelStoreToken.remove();
}
- WidgetEchoStore.removeListener('update', this._onWidgetEchoStoreUpdate);
+ WidgetEchoStore.removeListener('update', this.onWidgetEchoStoreUpdate);
- if (this._showReadReceiptsWatchRef) {
- SettingsStore.unwatchSetting(this._showReadReceiptsWatchRef);
- this._showReadReceiptsWatchRef = null;
+ if (this.showReadReceiptsWatchRef) {
+ SettingsStore.unwatchSetting(this.showReadReceiptsWatchRef);
}
// cancel any pending calls to the rate_limited_funcs
- this._updateRoomMembers.cancelPendingCall();
+ this.updateRoomMembers.cancelPendingCall();
// no need to do this as Dir & Settings are now overlays. It just burnt CPU.
// console.log("Tinter.tint from RoomView.unmount");
// Tinter.tint(); // reset colourscheme
- SettingsStore.unwatchSetting(this._layoutWatcherRef);
- },
+ SettingsStore.unwatchSetting(this.layoutWatcherRef);
+ }
- onLayoutChange: function() {
+ private onLayoutChange = () => {
this.setState({
useIRCLayout: SettingsStore.getValue("useIRCLayout"),
});
- },
+ };
- _onRightPanelStoreUpdate: function() {
+ private onRightPanelStoreUpdate = () => {
this.setState({
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
});
- },
+ };
- onPageUnload(event) {
+ private onPageUnload = event => {
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
return event.returnValue =
_t("You seem to be uploading files, are you sure you want to quit?");
- } else if (this._getCallForRoom() && this.state.callState !== 'ended') {
+ } else if (this.getCallForRoom() && this.state.callState !== 'ended') {
return event.returnValue =
_t("You seem to be in a call, are you sure you want to quit?");
}
- },
+ };
// we register global shortcuts here, they *must not conflict* with local shortcuts elsewhere or both will fire
- onNativeKeyDown: function(ev) {
+ private onNativeKeyDown = ev => {
let handled = false;
const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
@@ -592,15 +653,15 @@ export default createReactClass({
ev.stopPropagation();
ev.preventDefault();
}
- },
+ };
- onReactKeyDown: function(ev) {
+ private onReactKeyDown = ev => {
let handled = false;
switch (ev.key) {
case Key.ESCAPE:
if (!ev.altKey && !ev.ctrlKey && !ev.shiftKey && !ev.metaKey) {
- this._messagePanel.forgetReadMarker();
+ this.messagePanel.forgetReadMarker();
this.jumpToLiveTimeline();
handled = true;
}
@@ -611,9 +672,10 @@ export default createReactClass({
handled = true;
}
break;
+ case Key.U: // Mac returns lowercase
case Key.U.toUpperCase():
if (isOnlyCtrlOrCmdIgnoreShiftKeyEvent(ev) && ev.shiftKey) {
- dis.dispatch({ action: "upload_file" })
+ dis.dispatch({ action: "upload_file" }, true);
handled = true;
}
break;
@@ -623,22 +685,23 @@ export default createReactClass({
ev.stopPropagation();
ev.preventDefault();
}
- },
+ };
- onAction: function(payload) {
+ private onAction = payload => {
switch (payload.action) {
case 'message_send_failed':
case 'message_sent':
- this._checkIfAlone(this.state.room);
+ this.checkIfAlone(this.state.room);
break;
case 'post_sticker_message':
- this.injectSticker(
- payload.data.content.url,
- payload.data.content.info,
- payload.data.description || payload.data.name);
- break;
+ this.injectSticker(
+ payload.data.content.url,
+ payload.data.content.info,
+ payload.data.description || payload.data.name);
+ break;
case 'picture_snapshot':
- ContentMessages.sharedInstance().sendContentListToRoom([payload.file], this.state.room.roomId, this.context);
+ ContentMessages.sharedInstance().sendContentListToRoom(
+ [payload.file], this.state.room.roomId, this.context);
break;
case 'notifier_enabled':
case 'upload_started':
@@ -646,7 +709,7 @@ export default createReactClass({
case 'upload_canceled':
this.forceUpdate();
break;
- case 'call_state':
+ case 'call_state': {
// don't filter out payloads for room IDs other than props.room because
// we may be interested in the conf 1:1 room
@@ -654,24 +717,22 @@ export default createReactClass({
return;
}
- var call = this._getCallForRoom();
- var callState;
+ const call = this.getCallForRoom();
+ let callState = "ended";
if (call) {
callState = call.call_state;
- } else {
- callState = "ended";
}
// possibly remove the conf call notification if we're now in
// the conf
- this._updateConfCallNotification();
+ this.updateConfCallNotification();
this.setState({
callState: callState,
});
-
break;
+ }
case 'appsDrawer':
this.setState({
showApps: payload.show,
@@ -704,14 +765,14 @@ export default createReactClass({
matrixClientIsReady: this.context && this.context.isInitialSyncComplete(),
}, () => {
// send another "initial" RVS update to trigger peeking if needed
- this._onRoomViewStoreUpdate(true);
+ this.onRoomViewStoreUpdate(true);
});
}
break;
}
- },
+ };
- onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) {
+ private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: boolean, removed, data) => {
if (this.unmounted) return;
// ignore events for other rooms
@@ -722,11 +783,11 @@ export default createReactClass({
if (data.timeline.getTimelineSet() !== room.getUnfilteredTimelineSet()) return;
if (ev.getType() === "org.matrix.room.preview_urls") {
- this._updatePreviewUrlVisibility(room);
+ this.updatePreviewUrlVisibility(room);
}
if (ev.getType() === "m.room.encryption") {
- this._updateE2EStatus(room);
+ this.updateE2EStatus(room);
}
// ignore anything but real-time updates at the end of the room:
@@ -747,51 +808,45 @@ export default createReactClass({
});
}
}
- },
+ };
- onRoomName: function(room) {
+ private onRoomName = (room: Room) => {
if (this.state.room && room.roomId == this.state.room.roomId) {
this.forceUpdate();
}
- },
+ };
- onRoomRecoveryReminderDontAskAgain: function() {
- // Called when the option to not ask again is set:
- // force an update to hide the recovery reminder
- this.forceUpdate();
- },
-
- onKeyBackupStatus() {
+ private onKeyBackupStatus = () => {
// Key backup status changes affect whether the in-room recovery
// reminder is displayed.
this.forceUpdate();
- },
+ };
- canResetTimeline: function() {
- if (!this._messagePanel) {
+ public canResetTimeline = () => {
+ if (!this.messagePanel) {
return true;
}
- return this._messagePanel.canResetTimeline();
- },
+ return this.messagePanel.canResetTimeline();
+ };
// called when state.room is first initialised (either at initial load,
// after a successful peek, or after we join the room).
- _onRoomLoaded: function(room) {
- this._calculatePeekRules(room);
- this._updatePreviewUrlVisibility(room);
- this._loadMembersIfJoined(room);
- this._calculateRecommendedVersion(room);
- this._updateE2EStatus(room);
- this._updatePermissions(room);
- },
+ private onRoomLoaded = (room: Room) => {
+ this.calculatePeekRules(room);
+ this.updatePreviewUrlVisibility(room);
+ this.loadMembersIfJoined(room);
+ this.calculateRecommendedVersion(room);
+ this.updateE2EStatus(room);
+ this.updatePermissions(room);
+ };
- _calculateRecommendedVersion: async function(room) {
+ private async calculateRecommendedVersion(room: Room) {
this.setState({
upgradeRecommendation: await room.getRecommendedVersion(),
});
- },
+ }
- _loadMembersIfJoined: async function(room) {
+ private async loadMembersIfJoined(room: Room) {
// lazy load members if enabled
if (this.context.hasLazyLoadMembersEnabled()) {
if (room && room.getMyMembership() === 'join') {
@@ -808,9 +863,9 @@ export default createReactClass({
}
}
}
- },
+ }
- _calculatePeekRules: function(room) {
+ private calculatePeekRules(room: Room) {
const guestAccessEvent = room.currentState.getStateEvents("m.room.guest_access", "");
if (guestAccessEvent && guestAccessEvent.getContent().guest_access === "can_join") {
this.setState({
@@ -824,51 +879,51 @@ export default createReactClass({
canPeek: true,
});
}
- },
+ }
- _updatePreviewUrlVisibility: function({roomId}) {
+ private updatePreviewUrlVisibility({roomId}: Room) {
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
const key = this.context.isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled';
this.setState({
showUrlPreview: SettingsStore.getValue(key, roomId),
});
- },
+ }
- onRoom: function(room) {
+ private onRoom = (room: Room) => {
if (!room || room.roomId !== this.state.roomId) {
return;
}
this.setState({
room: room,
}, () => {
- this._onRoomLoaded(room);
+ this.onRoomLoaded(room);
});
- },
+ };
- onDeviceVerificationChanged: function(userId, device) {
+ private onDeviceVerificationChanged = (userId: string, device: object) => {
const room = this.state.room;
if (!room.currentState.getMember(userId)) {
return;
}
- this._updateE2EStatus(room);
- },
+ this.updateE2EStatus(room);
+ };
- onUserVerificationChanged: function(userId, _trustStatus) {
+ private onUserVerificationChanged = (userId: string, trustStatus: object) => {
const room = this.state.room;
if (!room || !room.currentState.getMember(userId)) {
return;
}
- this._updateE2EStatus(room);
- },
+ this.updateE2EStatus(room);
+ };
- onCrossSigningKeysChanged: function() {
+ private onCrossSigningKeysChanged = () => {
const room = this.state.room;
if (room) {
- this._updateE2EStatus(room);
+ this.updateE2EStatus(room);
}
- },
+ };
- _updateE2EStatus: async function(room) {
+ private async updateE2EStatus(room: Room) {
if (!this.context.isRoomEncrypted(room.roomId)) {
return;
}
@@ -877,7 +932,7 @@ export default createReactClass({
// so we don't know what the answer is. Let's error on the safe side and show
// a warning for this case.
this.setState({
- e2eStatus: "warning",
+ e2eStatus: E2EStatus.Warning,
});
return;
}
@@ -886,26 +941,26 @@ export default createReactClass({
this.setState({
e2eStatus: await shieldStatusForRoom(this.context, room),
});
- },
+ }
- updateTint: function() {
+ private updateTint() {
const room = this.state.room;
if (!room) return;
console.log("Tinter.tint from updateTint");
const colorScheme = SettingsStore.getValue("roomColor", room.roomId);
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
- },
+ }
- onAccountData: function(event) {
+ private onAccountData = (event: MatrixEvent) => {
const type = event.getType();
if ((type === "org.matrix.preview_urls" || type === "im.vector.web.settings") && this.state.room) {
// non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls`
- this._updatePreviewUrlVisibility(this.state.room);
+ this.updatePreviewUrlVisibility(this.state.room);
}
- },
+ };
- onRoomAccountData: function(event, room) {
+ private onRoomAccountData = (event: MatrixEvent, room: Room) => {
if (room.roomId == this.state.roomId) {
const type = event.getType();
if (type === "org.matrix.room.color_scheme") {
@@ -915,21 +970,21 @@ export default createReactClass({
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
} else if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") {
// non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls`
- this._updatePreviewUrlVisibility(room);
+ this.updatePreviewUrlVisibility(room);
}
}
- },
+ };
- onRoomStateEvents: function(ev, state) {
+ private onRoomStateEvents = (ev: MatrixEvent, state) => {
// ignore if we don't have a room yet
if (!this.state.room || this.state.room.roomId !== state.roomId) {
return;
}
- this._updatePermissions(this.state.room);
- },
+ this.updatePermissions(this.state.room);
+ };
- onRoomStateMember: function(ev, state, member) {
+ private onRoomStateMember = (ev: MatrixEvent, state, member) => {
// ignore if we don't have a room yet
if (!this.state.room) {
return;
@@ -940,18 +995,18 @@ export default createReactClass({
return;
}
- this._updateRoomMembers(member);
- },
+ this.updateRoomMembers(member);
+ };
- onMyMembership: function(room, membership, oldMembership) {
+ private onMyMembership = (room: Room, membership: string, oldMembership: string) => {
if (room.roomId === this.state.roomId) {
this.forceUpdate();
- this._loadMembersIfJoined(room);
- this._updatePermissions(room);
+ this.loadMembersIfJoined(room);
+ this.updatePermissions(room);
}
- },
+ };
- _updatePermissions: function(room) {
+ private updatePermissions(room: Room) {
if (room) {
const me = this.context.getUserId();
const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me);
@@ -959,15 +1014,14 @@ export default createReactClass({
this.setState({canReact, canReply});
}
- },
+ }
- // rate limited because a power level change will emit an event for every
- // member in the room.
- _updateRoomMembers: rate_limited_func(function(dueToMember) {
+ // rate limited because a power level change will emit an event for every member in the room.
+ private updateRoomMembers = rateLimitedFunc((dueToMember) => {
// a member state changed in this room
// refresh the conf call notification state
- this._updateConfCallNotification();
- this._updateDMState();
+ this.updateConfCallNotification();
+ this.updateDMState();
let memberCountInfluence = 0;
if (dueToMember && dueToMember.membership === "invite" && this.state.room.getInvitedMemberCount() === 0) {
@@ -975,15 +1029,15 @@ export default createReactClass({
// count by 1 to counteract this.
memberCountInfluence = 1;
}
- this._checkIfAlone(this.state.room, memberCountInfluence);
+ this.checkIfAlone(this.state.room, memberCountInfluence);
- this._updateE2EStatus(this.state.room);
- }, 500),
+ this.updateE2EStatus(this.state.room);
+ }, 500);
- _checkIfAlone: function(room, countInfluence) {
+ private checkIfAlone(room: Room, countInfluence?: number) {
let warnedAboutLonelyRoom = false;
if (localStorage) {
- warnedAboutLonelyRoom = localStorage.getItem('mx_user_alone_warned_' + this.state.room.roomId);
+ warnedAboutLonelyRoom = Boolean(localStorage.getItem('mx_user_alone_warned_' + this.state.room.roomId));
}
if (warnedAboutLonelyRoom) {
if (this.state.isAlone) this.setState({isAlone: false});
@@ -993,9 +1047,9 @@ export default createReactClass({
let joinedOrInvitedMemberCount = room.getJoinedMemberCount() + room.getInvitedMemberCount();
if (countInfluence) joinedOrInvitedMemberCount += countInfluence;
this.setState({isAlone: joinedOrInvitedMemberCount === 1});
- },
+ }
- _updateConfCallNotification: function() {
+ private updateConfCallNotification() {
const room = this.state.room;
if (!room || !this.props.ConferenceHandler) {
return;
@@ -1017,9 +1071,9 @@ export default createReactClass({
confMember.membership === "join"
),
});
- },
+ }
- _updateDMState() {
+ private updateDMState() {
const room = this.state.room;
if (room.getMyMembership() != "join") {
return;
@@ -1028,9 +1082,9 @@ export default createReactClass({
if (dmInviter) {
Rooms.setDMRoom(room.roomId, dmInviter);
}
- },
+ }
- onSearchResultsFillRequest: function(backwards) {
+ private onSearchResultsFillRequest = (backwards: boolean) => {
if (!backwards) {
return Promise.resolve(false);
}
@@ -1038,30 +1092,30 @@ export default createReactClass({
if (this.state.searchResults.next_batch) {
debuglog("requesting more search results");
const searchPromise = searchPagination(this.state.searchResults);
- return this._handleSearchResult(searchPromise);
+ return this.handleSearchResult(searchPromise);
} else {
debuglog("no more search results");
return Promise.resolve(false);
}
- },
+ };
- onInviteButtonClick: function() {
+ private onInviteButtonClick = () => {
// call AddressPickerDialog
dis.dispatch({
action: 'view_invite',
roomId: this.state.room.roomId,
});
this.setState({isAlone: false}); // there's a good chance they'll invite someone
- },
+ };
- onStopAloneWarningClick: function() {
+ private onStopAloneWarningClick = () => {
if (localStorage) {
- localStorage.setItem('mx_user_alone_warned_' + this.state.room.roomId, true);
+ localStorage.setItem('mx_user_alone_warned_' + this.state.room.roomId, String(true));
}
this.setState({isAlone: false});
- },
+ };
- onJoinButtonClicked: function(ev) {
+ private onJoinButtonClicked = () => {
// If the user is a ROU, allow them to transition to a PWLU
if (this.context && this.context.isGuest()) {
// Join this room once the user has registered and logged in
@@ -1070,7 +1124,7 @@ export default createReactClass({
action: 'do_after_sync_prepared',
deferred_action: {
action: 'view_room',
- room_id: this._getRoomId(),
+ room_id: this.getRoomId(),
},
});
@@ -1111,8 +1165,7 @@ export default createReactClass({
// return;
} else {
Promise.resolve().then(() => {
- const signUrl = this.props.thirdPartyInvite ?
- this.props.thirdPartyInvite.inviteSignUrl : undefined;
+ const signUrl = this.props.threepidInvite?.signUrl;
dis.dispatch({
action: 'join_room',
opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers },
@@ -1120,11 +1173,10 @@ export default createReactClass({
return Promise.resolve();
});
}
+ };
- },
-
- onMessageListScroll: function(ev) {
- if (this._messagePanel.isAtEndOfLiveTimeline()) {
+ private onMessageListScroll = ev => {
+ if (this.messagePanel.isAtEndOfLiveTimeline()) {
this.setState({
numUnreadMessages: 0,
atEndOfLiveTimeline: true,
@@ -1134,10 +1186,10 @@ export default createReactClass({
atEndOfLiveTimeline: false,
});
}
- this._updateTopUnreadMessagesBar();
- },
+ this.updateTopUnreadMessagesBar();
+ };
- onDragOver: function(ev) {
+ private onDragOver = ev => {
ev.stopPropagation();
ev.preventDefault();
@@ -1154,9 +1206,9 @@ export default createReactClass({
ev.dataTransfer.dropEffect = 'copy';
}
}
- },
+ };
- onDrop: function(ev) {
+ private onDrop = ev => {
ev.stopPropagation();
ev.preventDefault();
ContentMessages.sharedInstance().sendContentListToRoom(
@@ -1164,15 +1216,15 @@ export default createReactClass({
);
this.setState({ draggingFile: false });
dis.fire(Action.FocusComposer);
- },
+ };
- onDragLeaveOrEnd: function(ev) {
+ private onDragLeaveOrEnd = ev => {
ev.stopPropagation();
ev.preventDefault();
this.setState({ draggingFile: false });
- },
+ };
- injectSticker: function(url, info, text) {
+ private injectSticker(url, info, text) {
if (this.context.isGuest()) {
dis.dispatch({action: 'require_registration'});
return;
@@ -1185,9 +1237,9 @@ export default createReactClass({
return;
}
});
- },
+ }
- onSearch: function(term, scope) {
+ private onSearch = (term: string, scope) => {
this.setState({
searchTerm: term,
searchScope: scope,
@@ -1197,8 +1249,8 @@ export default createReactClass({
// if we already have a search panel, we need to tell it to forget
// about its scroll state.
- if (this._searchResultsPanel.current) {
- this._searchResultsPanel.current.resetScrollState();
+ if (this.searchResultsPanel.current) {
+ this.searchResultsPanel.current.resetScrollState();
}
// make sure that we don't end up showing results from
@@ -1212,12 +1264,10 @@ export default createReactClass({
debuglog("sending search request");
const searchPromise = eventSearch(term, roomId);
- this._handleSearchResult(searchPromise);
- },
-
- _handleSearchResult: function(searchPromise) {
- const self = this;
+ this.handleSearchResult(searchPromise);
+ };
+ private handleSearchResult(searchPromise: Promise) {
// keep a record of the current search id, so that if the search terms
// change before we get a response, we can ignore the results.
const localSearchId = this.searchId;
@@ -1226,9 +1276,9 @@ export default createReactClass({
searchInProgress: true,
});
- return searchPromise.then(function(results) {
+ return searchPromise.then((results) => {
debuglog("search complete");
- if (self.unmounted || !self.state.searching || self.searchId != localSearchId) {
+ if (this.unmounted || !this.state.searching || this.searchId != localSearchId) {
console.error("Discarding stale search results");
return;
}
@@ -1240,8 +1290,8 @@ export default createReactClass({
// whether it was used by the search engine or not.
let highlights = results.highlights;
- if (highlights.indexOf(self.state.searchTerm) < 0) {
- highlights = highlights.concat(self.state.searchTerm);
+ if (highlights.indexOf(this.state.searchTerm) < 0) {
+ highlights = highlights.concat(this.state.searchTerm);
}
// For overlapping highlights,
@@ -1250,25 +1300,26 @@ export default createReactClass({
return b.length - a.length;
});
- self.setState({
+ this.setState({
searchHighlights: highlights,
searchResults: results,
});
- }, function(error) {
+ }, (error) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Search failed", error);
Modal.createTrackedDialog('Search failed', '', ErrorDialog, {
title: _t("Search failed"),
- description: ((error && error.message) ? error.message : _t("Server may be unavailable, overloaded, or search timed out :(")),
+ description: ((error && error.message) ? error.message :
+ _t("Server may be unavailable, overloaded, or search timed out :(")),
});
- }).finally(function() {
- self.setState({
+ }).finally(() => {
+ this.setState({
searchInProgress: false,
});
});
- },
+ }
- getSearchResultTiles: function() {
+ private getSearchResultTiles() {
const SearchResultTile = sdk.getComponent('rooms.SearchResultTile');
const Spinner = sdk.getComponent("elements.Spinner");
@@ -1279,20 +1330,20 @@ export default createReactClass({
if (this.state.searchInProgress) {
ret.push(
-
-
);
+
+ );
}
if (!this.state.searchResults.next_batch) {
if (this.state.searchResults.results.length == 0) {
ret.push(
-
{ _t("No results") }
-
,
+
{ _t("No results") }
+ ,
);
} else {
ret.push(
-
{ _t("No more results") }
-
,
+
{ _t("No more results") }
+ ,
);
}
}
@@ -1300,7 +1351,7 @@ export default createReactClass({
// once dynamic content in the search results load, make the scrollPanel check
// the scroll offsets.
const onHeightChanged = () => {
- const scrollPanel = this._searchResultsPanel.current;
+ const scrollPanel = this.searchResultsPanel.current;
if (scrollPanel) {
scrollPanel.checkScroll();
}
@@ -1332,36 +1383,41 @@ export default createReactClass({
if (this.state.searchScope === 'All') {
if (roomId !== lastRoomId) {
ret.push(
-
{ _t("Room") }: { room.name }
-
);
+
{ _t("Room") }: { room.name }
+ );
lastRoomId = roomId;
}
}
const resultLink = "#/room/"+roomId+"/"+mxEv.getId();
- ret.push();
+ ret.push();
}
return ret;
- },
+ }
- onPinnedClick: function() {
+ private onPinnedClick = () => {
const nowShowingPinned = !this.state.showingPinned;
const roomId = this.state.room.roomId;
this.setState({showingPinned: nowShowingPinned, searching: false});
SettingsStore.setValue("PinnedEvents.isOpen", roomId, SettingLevel.ROOM_DEVICE, nowShowingPinned);
- },
+ };
- onSettingsClick: function() {
- dis.dispatch({ action: 'open_room_settings' });
- },
+ private onSettingsClick = () => {
+ dis.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.RoomSummary,
+ });
+ };
- onCancelClick: function() {
+ private onCancelClick = () => {
console.log("updateTint from onCancelClick");
this.updateTint();
if (this.state.forwardingEvent) {
@@ -1371,33 +1427,32 @@ export default createReactClass({
});
}
dis.fire(Action.FocusComposer);
- },
+ };
- onLeaveClick: function() {
+ private onLeaveClick = () => {
dis.dispatch({
action: 'leave_room',
room_id: this.state.room.roomId,
});
- },
+ };
- onForgetClick: function() {
+ private onForgetClick = () => {
dis.dispatch({
action: 'forget_room',
room_id: this.state.room.roomId,
});
- },
+ };
- onRejectButtonClicked: function(ev) {
- const self = this;
+ private onRejectButtonClicked = ev => {
this.setState({
rejecting: true,
});
- this.context.leave(this.state.roomId).then(function() {
+ this.context.leave(this.state.roomId).then(() => {
dis.dispatch({ action: 'view_next_room' });
- self.setState({
+ this.setState({
rejecting: false,
});
- }, function(error) {
+ }, (error) => {
console.error("Failed to reject invite: %s", error);
const msg = error.message ? error.message : JSON.stringify(error);
@@ -1407,14 +1462,14 @@ export default createReactClass({
description: msg,
});
- self.setState({
+ this.setState({
rejecting: false,
rejectError: error,
});
});
- },
+ };
- onRejectAndIgnoreClick: async function() {
+ private onRejectAndIgnoreClick = async () => {
this.setState({
rejecting: true,
});
@@ -1441,69 +1496,69 @@ export default createReactClass({
description: msg,
});
- self.setState({
+ this.setState({
rejecting: false,
rejectError: error,
});
}
- },
+ };
- onRejectThreepidInviteButtonClicked: function(ev) {
+ private onRejectThreepidInviteButtonClicked = ev => {
// We can reject 3pid invites in the same way that we accept them,
// using /leave rather than /join. In the short term though, we
// just ignore them.
// https://github.com/vector-im/vector-web/issues/1134
dis.fire(Action.ViewRoomDirectory);
- },
+ };
- onSearchClick: function() {
+ private onSearchClick = () => {
this.setState({
searching: !this.state.searching,
showingPinned: false,
});
- },
+ };
- onCancelSearchClick: function() {
+ private onCancelSearchClick = () => {
this.setState({
searching: false,
searchResults: null,
});
- },
+ };
// jump down to the bottom of this room, where new events are arriving
- jumpToLiveTimeline: function() {
- this._messagePanel.jumpToLiveTimeline();
+ private jumpToLiveTimeline = () => {
+ this.messagePanel.jumpToLiveTimeline();
dis.fire(Action.FocusComposer);
- },
+ };
// jump up to wherever our read marker is
- jumpToReadMarker: function() {
- this._messagePanel.jumpToReadMarker();
- },
+ private jumpToReadMarker = () => {
+ this.messagePanel.jumpToReadMarker();
+ };
// update the read marker to match the read-receipt
- forgetReadMarker: function(ev) {
+ private forgetReadMarker = ev => {
ev.stopPropagation();
- this._messagePanel.forgetReadMarker();
- },
+ this.messagePanel.forgetReadMarker();
+ };
// decide whether or not the top 'unread messages' bar should be shown
- _updateTopUnreadMessagesBar: function() {
- if (!this._messagePanel) {
+ private updateTopUnreadMessagesBar = () => {
+ if (!this.messagePanel) {
return;
}
- const showBar = this._messagePanel.canJumpToReadMarker();
+ const showBar = this.messagePanel.canJumpToReadMarker();
if (this.state.showTopUnreadMessagesBar != showBar) {
this.setState({showTopUnreadMessagesBar: showBar});
}
- },
+ };
// get the current scroll position of the room, so that it can be
// restored when we switch back to it.
//
- _getScrollState: function() {
- const messagePanel = this._messagePanel;
+ private getScrollState() {
+ const messagePanel = this.messagePanel;
if (!messagePanel) return null;
// if we're following the live timeline, we want to return null; that
@@ -1537,9 +1592,9 @@ export default createReactClass({
focussedEvent: scrollState.trackedScrollToken,
pixelOffset: scrollState.pixelOffset,
};
- },
+ }
- onResize: function() {
+ private onResize = () => {
// It seems flexbox doesn't give us a way to constrain the auxPanel height to have
// a minimum of the height of the video element, whilst also capping it from pushing out the page
// so we have to do it via JS instead. In this implementation we cap the height by putting
@@ -1547,9 +1602,9 @@ export default createReactClass({
// header + footer + status + give us at least 120px of scrollback at all times.
let auxPanelMaxHeight = window.innerHeight -
- (83 + // height of RoomHeader
+ (54 + // height of RoomHeader
36 + // height of the status area
- 72 + // minimum height of the message compmoser
+ 51 + // minimum height of the message compmoser
120); // amount of desired scrollback
// XXX: this is a bit of a hack and might possibly cause the video to push out the page anyway
@@ -1557,121 +1612,108 @@ export default createReactClass({
if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50;
this.setState({auxPanelMaxHeight: auxPanelMaxHeight});
- },
+ };
- onFullscreenClick: function() {
+ private onFullscreenClick = () => {
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
}, true);
- },
+ };
- onMuteAudioClick: function() {
- const call = this._getCallForRoom();
+ private onMuteAudioClick = () => {
+ const call = this.getCallForRoom();
if (!call) {
return;
}
const newState = !call.isMicrophoneMuted();
call.setMicrophoneMuted(newState);
this.forceUpdate(); // TODO: just update the voip buttons
- },
+ };
- onMuteVideoClick: function() {
- const call = this._getCallForRoom();
+ private onMuteVideoClick = () => {
+ const call = this.getCallForRoom();
if (!call) {
return;
}
const newState = !call.isLocalVideoMuted();
call.setLocalVideoMuted(newState);
this.forceUpdate(); // TODO: just update the voip buttons
- },
+ };
- onStatusBarVisible: function() {
+ private onStatusBarVisible = () => {
if (this.unmounted) return;
this.setState({
statusBarVisible: true,
});
- },
+ };
- onStatusBarHidden: function() {
+ private onStatusBarHidden = () => {
// This is currently not desired as it is annoying if it keeps expanding and collapsing
if (this.unmounted) return;
this.setState({
statusBarVisible: false,
});
- },
+ };
/**
* called by the parent component when PageUp/Down/etc is pressed.
*
* We pass it down to the scroll panel.
*/
- handleScrollKey: function(ev) {
+ private handleScrollKey = ev => {
let panel;
- if (this._searchResultsPanel.current) {
- panel = this._searchResultsPanel.current;
- } else if (this._messagePanel) {
- panel = this._messagePanel;
+ if (this.searchResultsPanel.current) {
+ panel = this.searchResultsPanel.current;
+ } else if (this.messagePanel) {
+ panel = this.messagePanel;
}
if (panel) {
panel.handleScrollKey(ev);
}
- },
+ };
/**
* get any current call for this room
*/
- _getCallForRoom: function() {
+ private getCallForRoom() {
if (!this.state.room) {
return null;
}
return CallHandler.getCallForRoom(this.state.room.roomId);
- },
+ }
// this has to be a proper method rather than an unnamed function,
// otherwise react calls it with null on each update.
- _gatherTimelinePanelRef: function(r) {
- this._messagePanel = r;
+ private gatherTimelinePanelRef = r => {
+ this.messagePanel = r;
if (r) {
- console.log("updateTint from RoomView._gatherTimelinePanelRef");
+ console.log("updateTint from RoomView.gatherTimelinePanelRef");
this.updateTint();
}
- },
+ };
- _getOldRoom: function() {
+ private getOldRoom() {
const createEvent = this.state.room.currentState.getStateEvents("m.room.create", "");
if (!createEvent || !createEvent.getContent()['predecessor']) return null;
return this.context.getRoom(createEvent.getContent()['predecessor']['room_id']);
- },
+ }
- _getHiddenHighlightCount: function() {
- const oldRoom = this._getOldRoom();
+ getHiddenHighlightCount() {
+ const oldRoom = this.getOldRoom();
if (!oldRoom) return 0;
return oldRoom.getUnreadNotificationCount('highlight');
- },
+ }
- _onHiddenHighlightsClick: function() {
- const oldRoom = this._getOldRoom();
+ onHiddenHighlightsClick = () => {
+ const oldRoom = this.getOldRoom();
if (!oldRoom) return;
dis.dispatch({action: "view_room", room_id: oldRoom.roomId});
- },
-
- render: function() {
- const RoomHeader = sdk.getComponent('rooms.RoomHeader');
- const ForwardMessage = sdk.getComponent("rooms.ForwardMessage");
- const AuxPanel = sdk.getComponent("rooms.AuxPanel");
- const SearchBar = sdk.getComponent("rooms.SearchBar");
- const PinnedEventsPanel = sdk.getComponent("rooms.PinnedEventsPanel");
- const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
- const TintableSvg = sdk.getComponent("elements.TintableSvg");
- const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
- const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
- const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");
- const RoomRecoveryReminder = sdk.getComponent("rooms.RoomRecoveryReminder");
- const ErrorBoundary = sdk.getComponent("elements.ErrorBoundary");
+ };
+ render() {
if (!this.state.room) {
const loading = !this.state.matrixClientIsReady || this.state.roomLoading || this.state.peekLoading;
if (loading) {
@@ -1692,14 +1734,11 @@ export default createReactClass({
);
} else {
- var inviterName = undefined;
+ let inviterName = undefined;
if (this.props.oobData) {
inviterName = this.props.oobData.inviterName;
}
- var invitedEmail = undefined;
- if (this.props.thirdPartyInvite) {
- invitedEmail = this.props.thirdPartyInvite.invitedEmail;
- }
+ const invitedEmail = this.props.threepidInvite?.toEmail;
// We have no room object for this room, only the ID.
// We've got to this room by following a link, possibly a third party invite.
@@ -1717,7 +1756,7 @@ export default createReactClass({
inviterName={inviterName}
invitedEmail={invitedEmail}
oobData={this.props.oobData}
- signUrl={this.props.thirdPartyInvite ? this.props.thirdPartyInvite.inviteSignUrl : null}
+ signUrl={this.props.threepidInvite?.signUrl}
room={this.state.room}
/>
@@ -1775,13 +1814,13 @@ export default createReactClass({
// We have successfully loaded this room, and are not previewing.
// Display the "normal" room view.
- const call = this._getCallForRoom();
+ const call = this.getCallForRoom();
let inCall = false;
if (call && (this.state.callState !== 'ended' && this.state.callState !== 'ringing')) {
inCall = true;
}
- const scrollheader_classes = classNames({
+ const scrollheaderClasses = classNames({
mx_RoomView_scrollheader: true,
});
@@ -1813,55 +1852,47 @@ export default createReactClass({
this.state.room.userMayUpgradeRoom(this.context.credentials.userId)
);
- const showRoomRecoveryReminder = (
- this.context.isCryptoEnabled() &&
- SettingsStore.getValue("showRoomRecoveryReminder") &&
- this.context.isRoomEncrypted(this.state.room.roomId) &&
- this.context.getKeyBackupEnabled() === false
- );
-
- const hiddenHighlightCount = this._getHiddenHighlightCount();
+ const hiddenHighlightCount = this.getHiddenHighlightCount();
let aux = null;
let previewBar;
let hideCancel = false;
let forceHideRightPanel = false;
- if (this.state.forwardingEvent !== null) {
+ if (this.state.forwardingEvent) {
aux = ;
} else if (this.state.searching) {
hideCancel = true; // has own cancel
- aux = ;
+ aux = ;
} else if (showRoomUpgradeBar) {
aux = ;
hideCancel = true;
- } else if (showRoomRecoveryReminder) {
- aux = ;
- hideCancel = true;
} else if (this.state.showingPinned) {
hideCancel = true; // has own cancel
aux = ;
} else if (myMembership !== "join") {
// We do have a room object for this room, but we're not currently in it.
// We may have a 3rd party invite to it.
- var inviterName = undefined;
+ let inviterName = undefined;
if (this.props.oobData) {
inviterName = this.props.oobData.inviterName;
}
- var invitedEmail = undefined;
- if (this.props.thirdPartyInvite) {
- invitedEmail = this.props.thirdPartyInvite.invitedEmail;
- }
+ const invitedEmail = this.props.threepidInvite?.toEmail;
hideCancel = true;
previewBar = (
-
);
if (!this.state.canPeek) {
@@ -1875,8 +1906,11 @@ export default createReactClass({
}
} else if (hiddenHighlightCount > 0) {
aux = (
-
+
{_t(
"You have %(count)s unread notifications in a prior version of this room.",
{count: hiddenHighlightCount},
@@ -1886,15 +1920,19 @@ export default createReactClass({
}
const auxPanel = (
-
+
{ aux }
);
@@ -1914,7 +1952,7 @@ export default createReactClass({
showApps={this.state.showApps}
e2eStatus={this.state.e2eStatus}
resizeNotifier={this.props.resizeNotifier}
- permalinkCreator={this._getPermalinkCreatorForRoom(this.state.room)}
+ permalinkCreator={this.getPermalinkCreatorForRoom(this.state.room)}
/>;
}
@@ -1934,26 +1972,37 @@ export default createReactClass({
if (call.type === "video") {
zoomButton = (
-
+
);
videoMuteButton =
-
+
;
}
const voiceMuteButton =
-
+
;
// wrap the existing status bar into a 'callStatusBar' which adds more knobs.
@@ -1974,16 +2023,18 @@ export default createReactClass({
if (this.state.searchResults) {
// show searching spinner
if (this.state.searchResults.results === undefined) {
- searchResultsPanel = ();
+ searchResultsPanel = (
+
+ );
} else {
searchResultsPanel = (
-
+
{ this.getSearchResultTiles() }
);
@@ -2009,7 +2060,7 @@ export default createReactClass({
// console.info("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview);
const messagePanel = (
);
+ topUnreadMessagesBar = (
+
+ );
}
let jumpToBottom;
// Do not show JumpToBottomButton if we have search results showing, it makes no sense
@@ -2048,23 +2098,18 @@ export default createReactClass({
onScrollToBottomClick={this.jumpToLiveTimeline}
/>);
}
- const statusBarAreaClass = classNames(
- "mx_RoomView_statusArea",
- {
- "mx_RoomView_statusArea_expanded": isStatusAreaExpanded,
- },
- );
- const fadableSectionClasses = classNames(
- "mx_RoomView_body", "mx_fadable",
- {
- "mx_fadable_faded": this.props.disabled,
- },
- );
+ const statusBarAreaClass = classNames("mx_RoomView_statusArea", {
+ "mx_RoomView_statusArea_expanded": isStatusAreaExpanded,
+ });
+
+ const fadableSectionClasses = classNames("mx_RoomView_body", "mx_fadable", {
+ "mx_fadable_faded": this.props.disabled,
+ });
const showRightPanel = !forceHideRightPanel && this.state.room && this.state.showRightPanel;
const rightPanel = showRightPanel
- ?
+ ?
: null;
const timelineClasses = classNames("mx_RoomView_timeline", {
@@ -2077,7 +2122,7 @@ export default createReactClass({
return (
-
+
-
+
{auxPanel}
@@ -2118,5 +2160,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js
index 51113f4f56..99a3da2565 100644
--- a/src/components/structures/ScrollPanel.js
+++ b/src/components/structures/ScrollPanel.js
@@ -15,7 +15,6 @@ limitations under the License.
*/
import React, {createRef} from "react";
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
import Timer from '../../utils/Timer';
@@ -84,10 +83,8 @@ if (DEBUG_SCROLL) {
* offset as normal.
*/
-export default createReactClass({
- displayName: 'ScrollPanel',
-
- propTypes: {
+export default class ScrollPanel extends React.Component {
+ static propTypes = {
/* stickyBottom: if set to true, then once the user hits the bottom of
* the list, any new children added to the list will cause the list to
* scroll down to show the new element, rather than preserving the
@@ -97,7 +94,7 @@ export default createReactClass({
/* startAtBottom: if set to true, the view is assumed to start
* scrolled to the bottom.
- * XXX: It's likley this is unecessary and can be derived from
+ * XXX: It's likely this is unnecessary and can be derived from
* stickyBottom, but I'm adding an extra parameter to ensure
* behaviour stays the same for other uses of ScrollPanel.
* If so, let's remove this parameter down the line.
@@ -141,6 +138,7 @@ export default createReactClass({
/* style: styles to add to the top-level div
*/
style: PropTypes.object,
+
/* resizeNotifier: ResizeNotifier to know when middle column has changed size
*/
resizeNotifier: PropTypes.object,
@@ -149,36 +147,35 @@ export default createReactClass({
* of the wrapper
*/
fixedChildren: PropTypes.node,
- },
+ };
- getDefaultProps: function() {
- return {
- stickyBottom: true,
- startAtBottom: true,
- onFillRequest: function(backwards) { return Promise.resolve(false); },
- onUnfillRequest: function(backwards, scrollToken) {},
- onScroll: function() {},
- };
- },
+ static defaultProps = {
+ stickyBottom: true,
+ startAtBottom: true,
+ onFillRequest: function(backwards) { return Promise.resolve(false); },
+ onUnfillRequest: function(backwards, scrollToken) {},
+ onScroll: function() {},
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._pendingFillRequests = {b: null, f: null};
if (this.props.resizeNotifier) {
- this.props.resizeNotifier.on("middlePanelResized", this.onResize);
+ this.props.resizeNotifier.on("middlePanelResizedNoisy", this.onResize);
}
this.resetScrollState();
this._itemlist = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this.checkScroll();
- },
+ }
- componentDidUpdate: function() {
+ componentDidUpdate() {
// after adding event tiles, we may need to tweak the scroll (either to
// keep at the bottom of the timeline, or to maintain the view after
// adding events to the top).
@@ -186,9 +183,9 @@ export default createReactClass({
// This will also re-check the fill state, in case the paginate was inadequate
this.checkScroll();
this.updatePreventShrinking();
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
// set a boolean to say we've been unmounted, which any pending
// promises can use to throw away their results.
//
@@ -196,51 +193,53 @@ export default createReactClass({
this.unmounted = true;
if (this.props.resizeNotifier) {
- this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize);
+ this.props.resizeNotifier.removeListener("middlePanelResizedNoisy", this.onResize);
}
- },
+ }
- onScroll: function(ev) {
+ onScroll = ev => {
+ // skip scroll events caused by resizing
+ if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return;
debuglog("onScroll", this._getScrollNode().scrollTop);
this._scrollTimeout.restart();
this._saveScrollState();
this.updatePreventShrinking();
this.props.onScroll(ev);
this.checkFillState();
- },
+ };
- onResize: function() {
+ onResize = () => {
+ debuglog("onResize");
this.checkScroll();
// update preventShrinkingState if present
if (this.preventShrinkingState) {
this.preventShrinking();
}
- },
+ };
// after an update to the contents of the panel, check that the scroll is
// where it ought to be, and set off pagination requests if necessary.
- checkScroll: function() {
+ checkScroll = () => {
if (this.unmounted) {
return;
}
this._restoreSavedScrollState();
this.checkFillState();
- },
+ };
// return true if the content is fully scrolled down right now; else false.
//
// note that this is independent of the 'stuckAtBottom' state - it is simply
// about whether the content is scrolled down right now, irrespective of
// whether it will stay that way when the children update.
- isAtBottom: function() {
+ isAtBottom = () => {
const sn = this._getScrollNode();
// fractional values (both too big and too small)
// for scrollTop happen on certain browsers/platforms
// when scrolled all the way down. E.g. Chrome 72 on debian.
// so check difference <= 1;
return Math.abs(sn.scrollHeight - (sn.scrollTop + sn.clientHeight)) <= 1;
-
- },
+ };
// returns the vertical height in the given direction that can be removed from
// the content box (which has a height of scrollHeight, see checkFillState) without
@@ -273,7 +272,7 @@ export default createReactClass({
// |#########| - |
// |#########| |
// `---------' -
- _getExcessHeight: function(backwards) {
+ _getExcessHeight(backwards) {
const sn = this._getScrollNode();
const contentHeight = this._getMessagesHeight();
const listHeight = this._getListHeight();
@@ -285,10 +284,10 @@ export default createReactClass({
} else {
return contentHeight - (unclippedScrollTop + 2*sn.clientHeight) - UNPAGINATION_PADDING;
}
- },
+ }
// check the scroll state and send out backfill requests if necessary.
- checkFillState: async function(depth=0) {
+ checkFillState = async (depth=0) => {
if (this.unmounted) {
return;
}
@@ -368,10 +367,10 @@ export default createReactClass({
this._fillRequestWhileRunning = false;
this.checkFillState();
}
- },
+ };
// check if unfilling is possible and send an unfill request if necessary
- _checkUnfillState: function(backwards) {
+ _checkUnfillState(backwards) {
let excessHeight = this._getExcessHeight(backwards);
if (excessHeight <= 0) {
return;
@@ -417,10 +416,10 @@ export default createReactClass({
this.props.onUnfillRequest(backwards, markerScrollToken);
}, UNFILL_REQUEST_DEBOUNCE_MS);
}
- },
+ }
// check if there is already a pending fill request. If not, set one off.
- _maybeFill: function(depth, backwards) {
+ _maybeFill(depth, backwards) {
const dir = backwards ? 'b' : 'f';
if (this._pendingFillRequests[dir]) {
debuglog("Already a "+dir+" fill in progress - not starting another");
@@ -456,7 +455,7 @@ export default createReactClass({
return this.checkFillState(depth + 1);
}
});
- },
+ }
/* get the current scroll state. This returns an object with the following
* properties:
@@ -472,9 +471,7 @@ export default createReactClass({
* the number of pixels the bottom of the tracked child is above the
* bottom of the scroll panel.
*/
- getScrollState: function() {
- return this.scrollState;
- },
+ getScrollState = () => this.scrollState;
/* reset the saved scroll state.
*
@@ -488,7 +485,7 @@ export default createReactClass({
* no use if no children exist yet, or if you are about to replace the
* child list.)
*/
- resetScrollState: function() {
+ resetScrollState = () => {
this.scrollState = {
stuckAtBottom: this.props.startAtBottom,
};
@@ -496,20 +493,20 @@ export default createReactClass({
this._pages = 0;
this._scrollTimeout = new Timer(100);
this._heightUpdateInProgress = false;
- },
+ };
/**
* jump to the top of the content.
*/
- scrollToTop: function() {
+ scrollToTop = () => {
this._getScrollNode().scrollTop = 0;
this._saveScrollState();
- },
+ };
/**
* jump to the bottom of the content.
*/
- scrollToBottom: function() {
+ scrollToBottom = () => {
// the easiest way to make sure that the scroll state is correctly
// saved is to do the scroll, then save the updated state. (Calculating
// it ourselves is hard, and we can't rely on an onScroll callback
@@ -517,25 +514,25 @@ export default createReactClass({
const sn = this._getScrollNode();
sn.scrollTop = sn.scrollHeight;
this._saveScrollState();
- },
+ };
/**
* Page up/down.
*
* @param {number} mult: -1 to page up, +1 to page down
*/
- scrollRelative: function(mult) {
+ scrollRelative = mult => {
const scrollNode = this._getScrollNode();
const delta = mult * scrollNode.clientHeight * 0.5;
scrollNode.scrollBy(0, delta);
this._saveScrollState();
- },
+ };
/**
* Scroll up/down in response to a scroll key
* @param {object} ev the keyboard event
*/
- handleScrollKey: function(ev) {
+ handleScrollKey = ev => {
switch (ev.key) {
case Key.PAGE_UP:
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
@@ -561,7 +558,7 @@ export default createReactClass({
}
break;
}
- },
+ };
/* Scroll the panel to bring the DOM node with the scroll token
* `scrollToken` into view.
@@ -574,7 +571,7 @@ export default createReactClass({
* node (specifically, the bottom of it) will be positioned. If omitted, it
* defaults to 0.
*/
- scrollToToken: function(scrollToken, pixelOffset, offsetBase) {
+ scrollToToken = (scrollToken, pixelOffset, offsetBase) => {
pixelOffset = pixelOffset || 0;
offsetBase = offsetBase || 0;
@@ -596,9 +593,9 @@ export default createReactClass({
scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset;
this._saveScrollState();
}
- },
+ };
- _saveScrollState: function() {
+ _saveScrollState() {
if (this.props.stickyBottom && this.isAtBottom()) {
this.scrollState = { stuckAtBottom: true };
debuglog("saved stuckAtBottom state");
@@ -641,9 +638,9 @@ export default createReactClass({
bottomOffset: bottomOffset,
pixelOffset: bottomOffset - viewportBottom, //needed for restoring the scroll position when coming back to the room
};
- },
+ }
- _restoreSavedScrollState: async function() {
+ async _restoreSavedScrollState() {
const scrollState = this.scrollState;
if (scrollState.stuckAtBottom) {
@@ -676,7 +673,8 @@ export default createReactClass({
} else {
debuglog("not updating height because request already in progress");
}
- },
+ }
+
// need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content?
async _updateHeight() {
// wait until user has stopped scrolling
@@ -731,7 +729,7 @@ export default createReactClass({
debuglog("updateHeight to", {newHeight, topDiff});
}
}
- },
+ }
_getTrackedNode() {
const scrollState = this.scrollState;
@@ -764,11 +762,11 @@ export default createReactClass({
}
return scrollState.trackedNode;
- },
+ }
_getListHeight() {
return this._bottomGrowth + (this._pages * PAGE_SIZE);
- },
+ }
_getMessagesHeight() {
const itemlist = this._itemlist.current;
@@ -777,17 +775,17 @@ export default createReactClass({
const firstNodeTop = itemlist.firstElementChild ? itemlist.firstElementChild.offsetTop : 0;
// 18 is itemlist padding
return lastNodeBottom - firstNodeTop + (18 * 2);
- },
+ }
_topFromBottom(node) {
// current capped height - distance from top = distance from bottom of container to top of tracked element
return this._itemlist.current.clientHeight - node.offsetTop;
- },
+ }
/* get the DOM node which has the scrollTop property we care about for our
* message panel.
*/
- _getScrollNode: function() {
+ _getScrollNode() {
if (this.unmounted) {
// this shouldn't happen, but when it does, turn the NPE into
// something more meaningful.
@@ -801,18 +799,18 @@ export default createReactClass({
}
return this._divScroll;
- },
+ }
- _collectScroll: function(divScroll) {
+ _collectScroll = divScroll => {
this._divScroll = divScroll;
- },
+ };
/**
Mark the bottom offset of the last tile so we can balance it out when
anything below it changes, by calling updatePreventShrinking, to keep
the same minimum bottom offset, effectively preventing the timeline to shrink.
*/
- preventShrinking: function() {
+ preventShrinking = () => {
const messageList = this._itemlist.current;
const tiles = messageList && messageList.children;
if (!messageList) {
@@ -836,16 +834,16 @@ export default createReactClass({
offsetNode: lastTileNode,
};
debuglog("prevent shrinking, last tile ", offsetFromBottom, "px from bottom");
- },
+ };
/** Clear shrinking prevention. Used internally, and when the timeline is reloaded. */
- clearPreventShrinking: function() {
+ clearPreventShrinking = () => {
const messageList = this._itemlist.current;
const balanceElement = messageList && messageList.parentElement;
if (balanceElement) balanceElement.style.paddingBottom = null;
this.preventShrinkingState = null;
debuglog("prevent shrinking cleared");
- },
+ };
/**
update the container padding to balance
@@ -855,7 +853,7 @@ export default createReactClass({
from the bottom of the marked tile grows larger than
what it was when marking.
*/
- updatePreventShrinking: function() {
+ updatePreventShrinking = () => {
if (this.preventShrinkingState) {
const sn = this._getScrollNode();
const scrollState = this.scrollState;
@@ -885,9 +883,9 @@ export default createReactClass({
this.clearPreventShrinking();
}
}
- },
+ };
- render: function() {
+ render() {
// TODO: the classnames on the div and ol could do with being updated to
// reflect the fact that we don't necessarily contain a list of messages.
// it's not obvious why we have a separate div and ol anyway.
@@ -905,5 +903,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js
index 7e9d290bce..c1e3ad0cf2 100644
--- a/src/components/structures/SearchBox.js
+++ b/src/components/structures/SearchBox.js
@@ -16,18 +16,15 @@ limitations under the License.
*/
import React, {createRef} from 'react';
-import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { Key } from '../../Keyboard';
import dis from '../../dispatcher/dispatcher';
-import { throttle } from 'lodash';
+import {throttle} from 'lodash';
import AccessibleButton from '../../components/views/elements/AccessibleButton';
import classNames from 'classnames';
-export default createReactClass({
- displayName: 'SearchBox',
-
- propTypes: {
+export default class SearchBox extends React.Component {
+ static propTypes = {
onSearch: PropTypes.func,
onCleared: PropTypes.func,
onKeyDown: PropTypes.func,
@@ -38,35 +35,32 @@ export default createReactClass({
// on room search focus action (it would be nicer to take
// this functionality out, but not obvious how that would work)
enableRoomSearchFocus: PropTypes.bool,
- },
+ };
- getDefaultProps: function() {
- return {
- enableRoomSearchFocus: false,
- };
- },
+ static defaultProps = {
+ enableRoomSearchFocus: false,
+ };
- getInitialState: function() {
- return {
+ constructor(props) {
+ super(props);
+
+ this._search = createRef();
+
+ this.state = {
searchTerm: "",
blurred: true,
};
- },
+ }
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
- this._search = createRef();
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
dis.unregister(this.dispatcherRef);
- },
+ }
- onAction: function(payload) {
+ onAction = payload => {
if (!this.props.enableRoomSearchFocus) return;
switch (payload.action) {
@@ -81,51 +75,51 @@ export default createReactClass({
}
break;
}
- },
+ };
- onChange: function() {
+ onChange = () => {
if (!this._search.current) return;
this.setState({ searchTerm: this._search.current.value });
this.onSearch();
- },
+ };
- onSearch: throttle(function() {
+ onSearch = throttle(() => {
this.props.onSearch(this._search.current.value);
- }, 200, {trailing: true, leading: true}),
+ }, 200, {trailing: true, leading: true});
- _onKeyDown: function(ev) {
+ _onKeyDown = ev => {
switch (ev.key) {
case Key.ESCAPE:
this._clearSearch("keyboard");
break;
}
if (this.props.onKeyDown) this.props.onKeyDown(ev);
- },
+ };
- _onFocus: function(ev) {
+ _onFocus = ev => {
this.setState({blurred: false});
ev.target.select();
if (this.props.onFocus) {
this.props.onFocus(ev);
}
- },
+ };
- _onBlur: function(ev) {
+ _onBlur = ev => {
this.setState({blurred: true});
if (this.props.onBlur) {
this.props.onBlur(ev);
}
- },
+ };
- _clearSearch: function(source) {
+ _clearSearch(source) {
this._search.current.value = "";
this.onChange();
if (this.props.onCleared) {
this.props.onCleared(source);
}
- },
+ }
- render: function() {
+ render() {
// check for collapsed here and
// not at parent so we keep
// searchTerm in our state
@@ -166,5 +160,5 @@ export default createReactClass({
{ clearButton }
);
- },
-});
+ }
+}
diff --git a/src/components/structures/TabbedView.tsx b/src/components/structures/TabbedView.tsx
index 704dbf8832..6bc35eb2a4 100644
--- a/src/components/structures/TabbedView.tsx
+++ b/src/components/structures/TabbedView.tsx
@@ -18,7 +18,6 @@ limitations under the License.
import * as React from "react";
import {_t} from '../../languageHandler';
-import * as PropTypes from "prop-types";
import * as sdk from "../../index";
import AutoHideScrollbar from './AutoHideScrollbar';
import { ReactNode } from "react";
diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js
index 4f8a051e62..135b2a1c5c 100644
--- a/src/components/structures/TagPanel.js
+++ b/src/components/structures/TagPanel.js
@@ -16,7 +16,6 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import TagOrderStore from '../../stores/TagOrderStore';
import GroupActions from '../../actions/GroupActions';
@@ -29,22 +28,18 @@ import { Droppable } from 'react-beautiful-dnd';
import classNames from 'classnames';
import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar";
+import SettingsStore from "../../settings/SettingsStore";
+import UserTagTile from "../views/elements/UserTagTile";
-const TagPanel = createReactClass({
- displayName: 'TagPanel',
+class TagPanel extends React.Component {
+ static contextType = MatrixClientContext;
- statics: {
- contextType: MatrixClientContext,
- },
+ state = {
+ orderedTags: [],
+ selectedTags: [],
+ };
- getInitialState() {
- return {
- orderedTags: [],
- selectedTags: [],
- };
- },
-
- componentDidMount: function() {
+ componentDidMount() {
this.unmounted = false;
this.context.on("Group.myMembership", this._onGroupMyMembership);
this.context.on("sync", this._onClientSync);
@@ -60,7 +55,7 @@ const TagPanel = createReactClass({
});
// This could be done by anything with a matrix client
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
- },
+ }
componentWillUnmount() {
this.unmounted = true;
@@ -69,14 +64,14 @@ const TagPanel = createReactClass({
if (this._tagOrderStoreToken) {
this._tagOrderStoreToken.remove();
}
- },
+ }
- _onGroupMyMembership() {
+ _onGroupMyMembership = () => {
if (this.unmounted) return;
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
- },
+ };
- _onClientSync(syncState, prevState) {
+ _onClientSync = (syncState, prevState) => {
// Consider the client reconnected if there is no error with syncing.
// This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP.
const reconnected = syncState !== "ERROR" && prevState !== syncState;
@@ -84,29 +79,33 @@ const TagPanel = createReactClass({
// Load joined groups
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
}
- },
+ };
- onMouseDown(e) {
+ onMouseDown = e => {
// only dispatch if its not a no-op
if (this.state.selectedTags.length > 0) {
dis.dispatch({action: 'deselect_tags'});
}
- },
+ };
- onCreateGroupClick(ev) {
- ev.stopPropagation();
- dis.dispatch({action: 'view_create_group'});
- },
-
- onClearFilterClick(ev) {
+ onClearFilterClick = ev => {
dis.dispatch({action: 'deselect_tags'});
- },
+ };
+
+ renderGlobalIcon() {
+ if (!SettingsStore.getValue("feature_communities_v2_prototypes")) return null;
+
+ return (
+
;
- }
- },
-});
diff --git a/src/components/views/context_menus/TopLeftMenu.js b/src/components/views/context_menus/TopLeftMenu.js
deleted file mode 100644
index ec99c63724..0000000000
--- a/src/components/views/context_menus/TopLeftMenu.js
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-Copyright 2018, 2019 New Vector Ltd
-Copyright 2019 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 React from 'react';
-import PropTypes from 'prop-types';
-import dis from '../../../dispatcher/dispatcher';
-import { _t } from '../../../languageHandler';
-import LogoutDialog from "../dialogs/LogoutDialog";
-import Modal from "../../../Modal";
-import SdkConfig from '../../../SdkConfig';
-import { getHostingLink } from '../../../utils/HostingLink';
-import {MatrixClientPeg} from '../../../MatrixClientPeg';
-import {MenuItem} from "../../structures/ContextMenu";
-import * as sdk from "../../../index";
-import {getHomePageUrl} from "../../../utils/pages";
-import {Action} from "../../../dispatcher/actions";
-
-export default class TopLeftMenu extends React.Component {
- static propTypes = {
- displayName: PropTypes.string.isRequired,
- userId: PropTypes.string.isRequired,
- onFinished: PropTypes.func,
-
- // Optional function to collect a reference to the container
- // of this component directly.
- containerRef: PropTypes.func,
- };
-
- constructor() {
- super();
- this.viewHomePage = this.viewHomePage.bind(this);
- this.openSettings = this.openSettings.bind(this);
- this.signIn = this.signIn.bind(this);
- this.signOut = this.signOut.bind(this);
- }
-
- hasHomePage() {
- return !!getHomePageUrl(SdkConfig.get());
- }
-
- render() {
- const isGuest = MatrixClientPeg.get().isGuest();
-
- const hostingSignupLink = getHostingLink('user-context-menu');
- let hostingSignup = null;
- if (hostingSignupLink) {
- hostingSignup =
- {_t(
- "Upgrade to your own domain", {},
- {
- a: sub =>
- {sub},
- },
- )}
-
-
-
-
);
diff --git a/src/components/views/messages/UnknownBody.js b/src/components/views/messages/UnknownBody.js
index 6c00921b45..786facc340 100644
--- a/src/components/views/messages/UnknownBody.js
+++ b/src/components/views/messages/UnknownBody.js
@@ -15,13 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React from "react";
+import React, {forwardRef} from "react";
-export default ({mxEvent}) => {
+export default forwardRef(({mxEvent}, ref) => {
const text = mxEvent.getContent().body;
return (
-
+
{ text }
);
-};
+});
diff --git a/src/components/views/right_panel/BaseCard.tsx b/src/components/views/right_panel/BaseCard.tsx
new file mode 100644
index 0000000000..3e95da1bc1
--- /dev/null
+++ b/src/components/views/right_panel/BaseCard.tsx
@@ -0,0 +1,93 @@
+/*
+Copyright 2020 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 React, {ReactNode} from 'react';
+import classNames from 'classnames';
+
+import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
+import {_t} from "../../../languageHandler";
+import AccessibleButton from "../elements/AccessibleButton";
+import defaultDispatcher from "../../../dispatcher/dispatcher";
+import {SetRightPanelPhasePayload} from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
+import {Action} from "../../../dispatcher/actions";
+import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
+
+interface IProps {
+ header?: ReactNode;
+ footer?: ReactNode;
+ className?: string;
+ withoutScrollContainer?: boolean;
+ previousPhase?: RightPanelPhases;
+ onClose?(): void;
+}
+
+interface IGroupProps {
+ className?: string;
+ title: string;
+}
+
+export const Group: React.FC = ({ className, title, children }) => {
+ return
@@ -1482,11 +1460,9 @@ const UserInfoHeader = ({onClose, member, e2eStatus}) => {
;
};
-const UserInfo = ({user, groupId, roomId, onClose, phase=RightPanelPhases.RoomMemberInfo, ...props}) => {
+const UserInfo = ({user, groupId, room, onClose, phase=RightPanelPhases.RoomMemberInfo, ...props}) => {
const cli = useContext(MatrixClientContext);
- // Load room if we are given a room id and memoize it
- const room = useMemo(() => roomId ? cli.getRoom(roomId) : null, [cli, roomId]);
// fetch latest room member if we have a room, so we don't show historical information, falling back to user
const member = useMemo(() => room ? (room.getMember(user.userId) || user) : user, [room, user]);
@@ -1521,15 +1497,16 @@ const UserInfo = ({user, groupId, roomId, onClose, phase=RightPanelPhases.RoomMe
break;
}
- return (
-
-
-
+ let previousPhase: RightPanelPhases;
+ // We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
+ if (room) {
+ previousPhase = RightPanelPhases.RoomMemberList;
+ }
- { content }
-
-
:
+ null;
// TODO: add way to open camera to scan a QR code
return
diff --git a/src/components/views/right_panel/WidgetCard.tsx b/src/components/views/right_panel/WidgetCard.tsx
new file mode 100644
index 0000000000..1677494708
--- /dev/null
+++ b/src/components/views/right_panel/WidgetCard.tsx
@@ -0,0 +1,205 @@
+/*
+Copyright 2020 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 React, {useContext, useEffect} from "react";
+import {Room} from "matrix-js-sdk/src/models/room";
+
+import MatrixClientContext from "../../../contexts/MatrixClientContext";
+import BaseCard from "./BaseCard";
+import WidgetUtils from "../../../utils/WidgetUtils";
+import AccessibleButton from "../elements/AccessibleButton";
+import AppTile from "../elements/AppTile";
+import {_t} from "../../../languageHandler";
+import {useWidgets} from "./RoomSummaryCard";
+import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
+import defaultDispatcher from "../../../dispatcher/dispatcher";
+import {SetRightPanelPhasePayload} from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
+import {Action} from "../../../dispatcher/actions";
+import WidgetStore from "../../../stores/WidgetStore";
+import ActiveWidgetStore from "../../../stores/ActiveWidgetStore";
+import {ChevronFace, ContextMenuButton, useContextMenu} from "../../structures/ContextMenu";
+import IconizedContextMenu, {
+ IconizedContextMenuOption,
+ IconizedContextMenuOptionList,
+} from "../context_menus/IconizedContextMenu";
+import {AppTileActionPayload} from "../../../dispatcher/payloads/AppTileActionPayload";
+import {Capability} from "../../../widgets/WidgetApi";
+import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
+import classNames from "classnames";
+
+interface IProps {
+ room: Room;
+ widgetId: string;
+ onClose(): void;
+}
+
+const WidgetCard: React.FC = ({ room, widgetId, onClose }) => {
+ const cli = useContext(MatrixClientContext);
+
+ const apps = useWidgets(room);
+ const app = apps.find(a => a.id === widgetId);
+ const isPinned = app && WidgetStore.instance.isPinned(app.id);
+
+ const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
+
+ useEffect(() => {
+ if (!app || isPinned) {
+ // stop showing this card
+ defaultDispatcher.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.RoomSummary,
+ });
+ }
+ }, [app, isPinned]);
+
+ // Don't render anything as we are about to transition
+ if (!app || isPinned) return null;
+
+ const header =
+
{ WidgetUtils.getWidgetName(app) }
+ ;
+
+ const canModify = WidgetUtils.canUserModifyWidgets(room.roomId);
+
+ let contextMenu;
+ if (menuDisplayed) {
+ let snapshotButton;
+ if (ActiveWidgetStore.widgetHasCapability(app.id, Capability.Screenshot)) {
+ const onSnapshotClick = () => {
+ WidgetUtils.snapshotWidget(app);
+ closeMenu();
+ };
+
+ snapshotButton = ;
+ }
+
+ let deleteButton;
+ if (canModify) {
+ const onDeleteClick = () => {
+ defaultDispatcher.dispatch({
+ action: Action.AppTileDelete,
+ widgetId: app.id,
+ });
+ closeMenu();
+ };
+
+ deleteButton = ;
+ }
+
+ const onRevokeClick = () => {
+ defaultDispatcher.dispatch({
+ action: Action.AppTileRevoke,
+ widgetId: app.id,
+ });
+ closeMenu();
+ };
+
+ const rect = handle.current.getBoundingClientRect();
+ contextMenu = (
+
+
+ { snapshotButton }
+ { deleteButton }
+
+
+
+ );
+ }
+
+ const onPinClick = () => {
+ WidgetStore.instance.pinWidget(app.id);
+ };
+
+ const onEditClick = () => {
+ WidgetUtils.editWidget(room, app);
+ };
+
+ let editButton;
+ if (canModify) {
+ editButton =
+ { _t("Edit") }
+ ;
+ }
+
+ const pinButtonClasses = canModify ? "" : "mx_WidgetCard_widePinButton";
+
+ let pinButton;
+ if (WidgetStore.instance.canPin(app.id)) {
+ pinButton =
+ { _t("Pin to room") }
+ ;
+ } else {
+ pinButton =
+ { _t("Pin to room") }
+ ;
+ }
+
+ const footer =
+ { editButton }
+ { pinButton }
+
+
+ { contextMenu }
+ ;
+
+ return
+
+ ;
+};
+
+export default WidgetCard;
diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js
deleted file mode 100644
index 2179bd905e..0000000000
--- a/src/components/views/room_settings/ColorSettings.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
-Copyright 2016 OpenMarket Ltd
-
-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 React from 'react';
-import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-
-import Tinter from '../../../Tinter';
-import dis from '../../../dispatcher/dispatcher';
-import SettingsStore from "../../../settings/SettingsStore";
-import {SettingLevel} from "../../../settings/SettingLevel";
-
-const ROOM_COLORS = [
- // magic room default values courtesy of Ribot
- [Tinter.getKeyRgb()[0], Tinter.getKeyRgb()[1]],
- ["#81bddb", "#eaf1f4"],
- ["#bd79cb", "#f3eaf5"],
- ["#c65d94", "#f5eaef"],
- ["#e55e5e", "#f5eaea"],
- ["#eca46f", "#f5eeea"],
- ["#dad658", "#f5f4ea"],
- ["#80c553", "#eef5ea"],
- ["#bb814e", "#eee8e3"],
- //["#595959", "#ececec"], // Grey makes everything appear disabled, so remove it for now
-];
-
-// Dev note: this component is not attached anywhere, but is left here as it
-// has a high possibility of being used in the nearish future.
-// Ref: https://github.com/vector-im/element-web/issues/8421
-
-export default createReactClass({
- displayName: 'ColorSettings',
-
- propTypes: {
- room: PropTypes.object.isRequired,
- },
-
- getInitialState: function() {
- const data = {
- index: 0,
- primary_color: ROOM_COLORS[0][0],
- secondary_color: ROOM_COLORS[0][1],
- hasChanged: false,
- };
- const scheme = SettingsStore.getValueAt(SettingLevel.ROOM_ACCOUNT, "roomColor", this.props.room.roomId);
-
- if (scheme.primary_color && scheme.secondary_color) {
- // We only use the user's scheme if the scheme is valid.
- data.primary_color = scheme.primary_color;
- data.secondary_color = scheme.secondary_color;
- }
- data.index = this._getColorIndex(data);
-
- if (data.index === -1) {
- // append the unrecognised colours to our palette
- data.index = ROOM_COLORS.length;
- ROOM_COLORS.push([
- scheme.primary_color, scheme.secondary_color,
- ]);
- }
- return data;
- },
-
- saveSettings: function() { // : Promise
- if (!this.state.hasChanged) {
- return Promise.resolve(); // They didn't explicitly give a color to save.
- }
- const originalState = this.getInitialState();
- if (originalState.primary_color !== this.state.primary_color ||
- originalState.secondary_color !== this.state.secondary_color) {
- console.log("ColorSettings: Saving new color");
- // We would like guests to be able to set room colour but currently
- // they can't, so we still send the request but display a sensible
- // error if it fails.
- // TODO: Support guests for room color. Technically this is possible via granular settings
- // Granular settings would mean the guest is forced to use the DEVICE level though.
- SettingsStore.setValue("roomColor", this.props.room.roomId, SettingLevel.ROOM_ACCOUNT, {
- primary_color: this.state.primary_color,
- secondary_color: this.state.secondary_color,
- }).catch(function(err) {
- if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN') {
- dis.dispatch({action: 'require_registration'});
- }
- });
- }
- return Promise.resolve(); // no color diff
- },
-
- _getColorIndex: function(scheme) {
- if (!scheme || !scheme.primary_color || !scheme.secondary_color) {
- return -1;
- }
- // XXX: we should validate these values
- for (let i = 0; i < ROOM_COLORS.length; i++) {
- const room_color = ROOM_COLORS[i];
- if (room_color[0] === String(scheme.primary_color).toLowerCase() &&
- room_color[1] === String(scheme.secondary_color).toLowerCase()) {
- return i;
- }
- }
- return -1;
- },
-
- _onColorSchemeChanged: function(index) {
- // preview what the user just changed the scheme to.
- Tinter.tint(ROOM_COLORS[index][0], ROOM_COLORS[index][1]);
- this.setState({
- index: index,
- primary_color: ROOM_COLORS[index][0],
- secondary_color: ROOM_COLORS[index][1],
- hasChanged: true,
- });
- },
-
- render: function() {
- return (
-
- { ROOM_COLORS.map((room_color, i) => {
- let selected;
- if (i === this.state.index) {
- selected = (
-
;
@@ -301,5 +261,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx
index 3274e0e49f..92bbdfeacb 100644
--- a/src/components/views/rooms/RoomList.tsx
+++ b/src/components/views/rooms/RoomList.tsx
@@ -45,6 +45,7 @@ import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu";
import AccessibleButton from "../elements/AccessibleButton";
+import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
interface IProps {
onKeyDown: (ev: React.KeyboardEvent) => void;
@@ -129,7 +130,9 @@ const TAG_AESTHETICS: {
}}
/>
{
e.preventDefault();
@@ -215,7 +218,7 @@ export default class RoomList extends React.PureComponent {
private getRoomDelta = (roomId: string, delta: number, unread = false) => {
const lists = RoomListStore.instance.orderedLists;
- let rooms: Room = [];
+ const rooms: Room = [];
TAG_ORDER.forEach(t => {
let listRooms = lists[t];
@@ -287,7 +290,7 @@ export default class RoomList extends React.PureComponent {
// TODO: Put community invites in a more sensible place (not in the room list)
// See https://github.com/vector-im/element-web/issues/14456
return MatrixClientPeg.get().getGroups().filter(g => {
- return g.myMembership === 'invite';
+ return g.myMembership === 'invite';
}).map(g => {
const avatar = (
{
: TAG_AESTHETICS[orderedTagId];
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
- components.push(
-
- );
+ components.push();
}
return components;
diff --git a/src/components/views/rooms/RoomNameEditor.js b/src/components/views/rooms/RoomNameEditor.js
deleted file mode 100644
index e0c31321c3..0000000000
--- a/src/components/views/rooms/RoomNameEditor.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-Copyright 2016 OpenMarket Ltd
-
-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 React from 'react';
-import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-import {MatrixClientPeg} from "../../../MatrixClientPeg";
-import * as sdk from "../../../index";
-import { _t } from '../../../languageHandler';
-
-export default createReactClass({
- displayName: 'RoomNameEditor',
-
- propTypes: {
- room: PropTypes.object.isRequired,
- },
-
- getInitialState: function() {
- return {
- name: null,
- };
- },
-
- // TODO: [REACT-WARNING] Move this to constructor
- UNSAFE_componentWillMount: function() {
- const room = this.props.room;
- const name = room.currentState.getStateEvents('m.room.name', '');
- const myId = MatrixClientPeg.get().credentials.userId;
- const defaultName = room.getDefaultRoomName(myId);
-
- this.setState({
- name: name ? name.getContent().name : '',
- });
-
- this._placeholderName = _t("Unnamed Room");
- if (defaultName && defaultName !== 'Empty room') { // default name from JS SDK, needs no translation as we don't ever show it.
- this._placeholderName += " (" + defaultName + ")";
- }
- },
-
- getRoomName: function() {
- return this.state.name;
- },
-
- _onValueChanged: function(value, shouldSubmit) {
- this.setState({
- name: value,
- });
- },
-
- render: function() {
- const EditableText = sdk.getComponent("elements.EditableText");
-
- return (
-
-
-
- );
- },
-});
diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js
index d52bbbb0d0..f42e18372a 100644
--- a/src/components/views/rooms/RoomPreviewBar.js
+++ b/src/components/views/rooms/RoomPreviewBar.js
@@ -18,7 +18,6 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import dis from '../../../dispatcher/dispatcher';
@@ -26,6 +25,8 @@ import classNames from 'classnames';
import { _t } from '../../../languageHandler';
import SdkConfig from "../../../SdkConfig";
import IdentityAuthClient from '../../../IdentityAuthClient';
+import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
+import {UPDATE_EVENT} from "../../../stores/AsyncStore";
const MessageCase = Object.freeze({
NotLoggedIn: "NotLoggedIn",
@@ -44,10 +45,8 @@ const MessageCase = Object.freeze({
OtherError: "OtherError",
});
-export default createReactClass({
- displayName: 'RoomPreviewBar',
-
- propTypes: {
+export default class RoomPreviewBar extends React.Component {
+ static propTypes = {
onJoinClick: PropTypes.func,
onRejectClick: PropTypes.func,
onRejectAndIgnoreClick: PropTypes.func,
@@ -84,31 +83,32 @@ export default createReactClass({
// If given, this will be how the room is referred to (eg.
// in error messages).
roomAlias: PropTypes.string,
- },
+ };
- getDefaultProps: function() {
- return {
- onJoinClick: function() {},
- };
- },
+ static defaultProps = {
+ onJoinClick() {},
+ };
- getInitialState: function() {
- return {
- busy: false,
- };
- },
+ state = {
+ busy: false,
+ };
- componentDidMount: function() {
+ componentDidMount() {
this._checkInvitedEmail();
- },
+ CommunityPrototypeStore.instance.on(UPDATE_EVENT, this._onCommunityUpdate);
+ }
- componentDidUpdate: function(prevProps, prevState) {
+ componentDidUpdate(prevProps, prevState) {
if (this.props.invitedEmail !== prevProps.invitedEmail || this.props.inviterName !== prevProps.inviterName) {
this._checkInvitedEmail();
}
- },
+ }
- _checkInvitedEmail: async function() {
+ componentWillUnmount() {
+ CommunityPrototypeStore.instance.off(UPDATE_EVENT, this._onCommunityUpdate);
+ }
+
+ async _checkInvitedEmail() {
// If this is an invite and we've been told what email address was
// invited, fetch the user's account emails and discovery bindings so we
// can check them against the email that was invited.
@@ -141,7 +141,14 @@ export default createReactClass({
}
this.setState({busy: false});
}
- },
+ }
+
+ _onCommunityUpdate = (roomId) => {
+ if (this.props.room && this.props.room.roomId !== roomId) {
+ return;
+ }
+ this.forceUpdate(); // we have nothing to update
+ };
_getMessageCase() {
const isGuest = MatrixClientPeg.get().isGuest();
@@ -193,7 +200,7 @@ export default createReactClass({
} else {
return MessageCase.ViewingRoom;
}
- },
+ }
_getKickOrBanInfo() {
const myMember = this._getMyMember();
@@ -207,9 +214,9 @@ export default createReactClass({
kickerMember.name : myMember.events.member.getSender();
const reason = myMember.events.member.getContent().reason;
return {memberName, reason};
- },
+ }
- _joinRule: function() {
+ _joinRule() {
const room = this.props.room;
if (room) {
const joinRules = room.currentState.getStateEvents('m.room.join_rules', '');
@@ -217,10 +224,17 @@ export default createReactClass({
return joinRules.getContent().join_rule;
}
}
- },
+ }
- _roomName: function(atStart = false) {
- const name = this.props.room ? this.props.room.name : this.props.roomAlias;
+ _communityProfile() {
+ if (this.props.room) return CommunityPrototypeStore.instance.getInviteProfile(this.props.room.roomId);
+ return {displayName: null, avatarMxc: null};
+ }
+
+ _roomName(atStart = false) {
+ let name = this.props.room ? this.props.room.name : this.props.roomAlias;
+ const profile = this._communityProfile();
+ if (profile.displayName) name = profile.displayName;
if (name) {
return name;
} else if (atStart) {
@@ -228,16 +242,16 @@ export default createReactClass({
} else {
return _t("this room");
}
- },
+ }
_getMyMember() {
return (
this.props.room &&
this.props.room.getMember(MatrixClientPeg.get().getUserId())
);
- },
+ }
- _getInviteMember: function() {
+ _getInviteMember() {
const {room} = this.props;
if (!room) {
return;
@@ -249,7 +263,7 @@ export default createReactClass({
}
const inviterUserId = inviteEvent.events.member.getSender();
return room.currentState.getMember(inviterUserId);
- },
+ }
_isDMInvite() {
const myMember = this._getMyMember();
@@ -259,7 +273,7 @@ export default createReactClass({
const memberEvent = myMember.events.member;
const memberContent = memberEvent.getContent();
return memberContent.membership === "invite" && memberContent.is_direct;
- },
+ }
_makeScreenAfterLogin() {
return {
@@ -272,17 +286,17 @@ export default createReactClass({
inviter_name: this.props.oobData ? this.props.oobData.inviterName : null,
}
};
- },
+ }
- onLoginClick: function() {
+ onLoginClick = () => {
dis.dispatch({ action: 'start_login', screenAfterLogin: this._makeScreenAfterLogin() });
- },
+ };
- onRegisterClick: function() {
+ onRegisterClick = () => {
dis.dispatch({ action: 'start_registration', screenAfterLogin: this._makeScreenAfterLogin() });
- },
+ };
- render: function() {
+ render() {
const brand = SdkConfig.get().brand;
const Spinner = sdk.getComponent('elements.Spinner');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -439,7 +453,10 @@ export default createReactClass({
}
case MessageCase.Invite: {
const RoomAvatar = sdk.getComponent("views.avatars.RoomAvatar");
- const avatar = ;
+ const oobData = Object.assign({}, this.props.oobData, {
+ avatarUrl: this._communityProfile().avatarMxc,
+ });
+ const avatar = ;
const inviteMember = this._getInviteMember();
let inviterElement;
@@ -573,5 +590,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/components/views/rooms/RoomRecoveryReminder.js b/src/components/views/rooms/RoomRecoveryReminder.js
deleted file mode 100644
index 859df6dd1b..0000000000
--- a/src/components/views/rooms/RoomRecoveryReminder.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-Copyright 2018, 2019 New Vector Ltd
-Copyright 2020 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 React from "react";
-import PropTypes from "prop-types";
-import * as sdk from "../../../index";
-import { _t } from "../../../languageHandler";
-import Modal from "../../../Modal";
-import {MatrixClientPeg} from "../../../MatrixClientPeg";
-import SettingsStore from "../../../settings/SettingsStore";
-import {SettingLevel} from "../../../settings/SettingLevel";
-
-export default class RoomRecoveryReminder extends React.PureComponent {
- static propTypes = {
- // called if the user sets the option to suppress this reminder in the future
- onDontAskAgainSet: PropTypes.func,
- }
-
- static defaultProps = {
- onDontAskAgainSet: function() {},
- }
-
- constructor(props) {
- super(props);
-
- this.state = {
- loading: true,
- error: null,
- backupInfo: null,
- notNowClicked: false,
- };
- }
-
- componentDidMount() {
- this._loadBackupStatus();
- }
-
- async _loadBackupStatus() {
- try {
- const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
- this.setState({
- loading: false,
- backupInfo,
- });
- } catch (e) {
- console.log("Unable to fetch key backup status", e);
- this.setState({
- loading: false,
- error: e,
- });
- }
- }
-
- showSetupDialog = () => {
- if (this.state.backupInfo) {
- // A key backup exists for this account, but the creating device is not
- // verified, so restore the backup which will give us the keys from it and
- // allow us to trust it (ie. upload keys to it)
- const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
- Modal.createTrackedDialog(
- 'Restore Backup', '', RestoreKeyBackupDialog, null, null,
- /* priority = */ false, /* static = */ true,
- );
- } else {
- Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
- import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
- null, null, /* priority = */ false, /* static = */ true,
- );
- }
- }
-
- onOnNotNowClick = () => {
- this.setState({notNowClicked: true});
- }
-
- onDontAskAgainClick = () => {
- // When you choose "Don't ask again" from the room reminder, we show a
- // dialog to confirm the choice.
- Modal.createTrackedDialogAsync("Ignore Recovery Reminder", "Ignore Recovery Reminder",
- import("../../../async-components/views/dialogs/keybackup/IgnoreRecoveryReminderDialog"),
- {
- onDontAskAgain: async () => {
- await SettingsStore.setValue(
- "showRoomRecoveryReminder",
- null,
- SettingLevel.ACCOUNT,
- false,
- );
- this.props.onDontAskAgainSet();
- },
- onSetup: () => {
- this.showSetupDialog();
- },
- },
- );
- }
-
- onSetupClick = () => {
- this.showSetupDialog();
- }
-
- render() {
- // If there was an error loading just don't display the banner: we'll try again
- // next time the user switchs to the room.
- if (this.state.error || this.state.loading || this.state.notNowClicked) {
- return null;
- }
-
- const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
-
- let setupCaption;
- if (this.state.backupInfo) {
- setupCaption = _t("Connect this session to Key Backup");
- } else {
- setupCaption = _t("Start using Key Backup");
- }
-
- return (
-
-
{_t(
- "Never lose encrypted messages",
- )}
-
-
{_t(
- "Messages in this room are secured with end-to-end " +
- "encryption. Only you and the recipient(s) have the " +
- "keys to read these messages.",
- )}
-
{_t(
- "Securely back up your keys to avoid losing them. " +
- "Learn more.", {},
- {
- // TODO: We don't have this link yet: this will prevent the translators
- // having to re-translate the string when we do.
- a: sub => '',
- },
- )}
{_t(
"Your homeserver does not support cross-signing.",
)}
;
} else if (crossSigningReady) {
summarisedStatus =
✅ {_t(
- "Cross-signing and secret storage are enabled.",
+ "Cross-signing is ready for use.",
)}
;
} else if (crossSigningPrivateKeysInStorage) {
summarisedStatus =
{_t(
- "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.",
)}
;
} else {
summarisedStatus =
{_t(
- "Cross-signing and secret storage are not yet set up.",
+ "Cross-signing is not set up.",
)}
-
- {_t("Reset cross-signing and secret storage")}
-
-
- );
- }
+ const actions = [];
// TODO: determine how better to expose this to users in addition to prompts at login/toast
- let bootstrapButton;
if (!keysExistEverywhere && homeserverSupportsCrossSigning) {
- bootstrapButton = (
-
-
- {_t("Bootstrap cross-signing and secret storage")}
-
-
);
- } else if (this.state.loading) {
- return ;
- } else if (this.state.backupInfo) {
- let clientBackupStatus;
+ } else if (loading) {
+ statusDescription = ;
+ } else if (backupInfo) {
let restoreButtonCaption = _t("Restore from Backup");
if (MatrixClientPeg.get().getKeyBackupEnabled()) {
- clientBackupStatus =
-
{encryptedMessageAreEncrypted}
-
✅ {_t("This session is backing up your keys. ")}
-
;
+ statusDescription =
✅ {_t("This session is backing up your keys. ")}
;
} else {
- clientBackupStatus =
-
{encryptedMessageAreEncrypted}
+ statusDescription = <>
{_t(
"This session is not backing up your keys, " +
"but you do have an existing backup you can restore from " +
@@ -199,19 +241,11 @@ export default class KeyBackupPanel extends React.PureComponent {
"Connect this session to key backup before signing out to avoid " +
"losing any keys that may only be on this session.",
)}
-
;
+ >;
restoreButtonCaption = _t("Connect this session to Key Backup");
}
- let keyStatus;
- if (this.state.backupKeyStored === true) {
- keyStatus = _t("in secret storage");
- } else {
- keyStatus = _t("not stored");
- }
-
let uploadStatus;
- const { sessionsRemaining } = this.state;
if (!MatrixClientPeg.get().getKeyBackupEnabled()) {
// No upload status to show when backup disabled.
uploadStatus = "";
@@ -225,17 +259,17 @@ export default class KeyBackupPanel extends React.PureComponent {
;
}
- let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
+ let backupSigStatuses = backupSigStatus.sigs.map((sig, i) => {
const deviceName = sig.device ? (sig.device.getDisplayName() || sig.device.deviceId) : null;
const validity = sub =>
-
+
{sub}
;
const verify = sub =>
-
+
{sub}
;
- const device = sub => {deviceName};
+ const device = sub => {deviceName};
const fromThisDevice = (
sig.device &&
sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()
@@ -306,55 +340,123 @@ export default class KeyBackupPanel extends React.PureComponent {
{sigStatus}
;
});
- if (this.state.backupSigStatus.sigs.length === 0) {
+ if (backupSigStatus.sigs.length === 0) {
backupSigStatuses = _t("Backup is not signed by any of your sessions");
}
let trustedLocally;
- if (this.state.backupSigStatus.trusted_locally) {
+ if (backupSigStatus.trusted_locally) {
trustedLocally = _t("This backup is trusted because it has been restored on this session");
}
- const buttonRow = (
-
{_t(
+ "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 Recovery Key.",
+ )}
+ );
let warning;
if (!privateShouldBeEncrypted()) {
@@ -329,12 +338,53 @@ export default class SecurityUserSettingsTab extends React.Component {
;
}
+ let privacySection;
+ if (Analytics.canEnable()) {
+ privacySection =
+
{_t("Privacy")}
+
+ {_t("Analytics")}
+
+ {_t(
+ "%(brand)s collects anonymous analytics to allow us to improve the application.",
+ { brand },
+ )}
+
+ {_t("Privacy is important to us, so we don't collect any personal or " +
+ "identifiable data for our analytics.")}
+
+ {_t("Learn more about how we use analytics.")}
+
+
+
+
+ ;
+ }
+
+ const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');
+ let advancedSection;
+ if (SettingsStore.getValue(UIFeature.AdvancedSettings)) {
+ const ignoreUsersPanel = this._renderIgnoredUsers();
+ const invitesPanel = this._renderManageInvites();
+ const e2ePanel = isE2eAdvancedPanelPossible() ? : null;
+ // only show the section if there's something to show
+ if (ignoreUsersPanel || invitesPanel || e2ePanel) {
+ advancedSection = <>
+
- {_t("Where you’re logged in")}
{_t(
"Manage the names of and sign out of your sessions below or " +
@@ -351,30 +401,15 @@ export default class SecurityUserSettingsTab extends React.Component {
- {_t(
- "%(brand)s collects anonymous analytics to allow us to improve the application.",
- { brand },
- )}
-
- {_t("Privacy is important to us, so we don't collect any personal or " +
- "identifiable data for our analytics.")}
-
- {_t("Learn more about how we use analytics.")}
-
-
);
}
diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js
index 4114f6bb22..a78cc10b92 100644
--- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js
@@ -157,6 +157,9 @@ export default class VoiceUserSettingsTab extends React.Component {
label: _t('Default Device'),
};
const getDefaultDevice = (devices) => {
+ // Note we're looking for a device with deviceId 'default' but adding a device
+ // with deviceId == the empty string: this is because Chrome gives us a device
+ // with deviceId 'default', so we're looking for this, not the one we are adding.
if (!devices.some((i) => i.deviceId === 'default')) {
devices.unshift(defaultOption);
return '';
diff --git a/src/components/views/toasts/GenericExpiringToast.tsx b/src/components/views/toasts/GenericExpiringToast.tsx
index 83f43208c4..e63edd8e79 100644
--- a/src/components/views/toasts/GenericExpiringToast.tsx
+++ b/src/components/views/toasts/GenericExpiringToast.tsx
@@ -29,7 +29,15 @@ interface IProps extends IGenericToastProps {
const SECOND = 1000;
-const GenericExpiringToast: React.FC = ({description, acceptLabel, dismissLabel, onAccept, onDismiss, toastKey, numSeconds}) => {
+const GenericExpiringToast: React.FC = ({
+ description,
+ acceptLabel,
+ dismissLabel,
+ onAccept,
+ onDismiss,
+ toastKey,
+ numSeconds,
+}) => {
const onReject = () => {
if (onDismiss) onDismiss();
ToastStore.sharedInstance().dismissToast(toastKey);
diff --git a/src/components/views/toasts/GenericToast.tsx b/src/components/views/toasts/GenericToast.tsx
index 6cd881b9eb..a9c64f1962 100644
--- a/src/components/views/toasts/GenericToast.tsx
+++ b/src/components/views/toasts/GenericToast.tsx
@@ -31,7 +31,13 @@ interface IPropsExtended extends IProps {
onReject();
}
-const GenericToast: React.FC> = ({description, acceptLabel, rejectLabel, onAccept, onReject}) => {
+const GenericToast: React.FC> = ({
+ description,
+ acceptLabel,
+ rejectLabel,
+ onAccept,
+ onReject,
+}) => {
return
{ description }
diff --git a/src/components/views/voip/CallView.tsx b/src/components/views/voip/CallView.tsx
index 8416f56fd9..1d3a62984a 100644
--- a/src/components/views/voip/CallView.tsx
+++ b/src/components/views/voip/CallView.tsx
@@ -97,10 +97,7 @@ export default class CallView extends React.Component {
if (this.props.room) {
const roomId = this.props.room.roomId;
call = CallHandler.getCallForRoom(roomId) ||
- (this.props.ConferenceHandler ?
- this.props.ConferenceHandler.getConferenceCallForRoom(roomId) :
- null
- );
+ (this.props.ConferenceHandler ? this.props.ConferenceHandler.getConferenceCallForRoom(roomId) : null);
if (this.call) {
this.setState({ call: call });
diff --git a/src/components/views/voip/IncomingCallBox.tsx b/src/components/views/voip/IncomingCallBox.tsx
index 00d49b20f5..b7cba7a70f 100644
--- a/src/components/views/voip/IncomingCallBox.tsx
+++ b/src/components/views/voip/IncomingCallBox.tsx
@@ -51,7 +51,7 @@ export default class IncomingCallBox extends React.Component {
private onAction = (payload: ActionPayload) => {
switch (payload.action) {
- case 'call_state':
+ case 'call_state': {
const call = CallHandler.getCall(payload.room_id);
if (call && call.call_state === 'ringing') {
this.setState({
@@ -62,6 +62,7 @@ export default class IncomingCallBox extends React.Component {
incomingCall: null,
});
}
+ }
}
};
diff --git a/src/components/views/voip/VideoFeed.js b/src/components/views/voip/VideoFeed.js
index 527b071942..a0330f8cb1 100644
--- a/src/components/views/voip/VideoFeed.js
+++ b/src/components/views/voip/VideoFeed.js
@@ -17,44 +17,42 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
-export default createReactClass({
- displayName: 'VideoFeed',
-
- propTypes: {
+export default class VideoFeed extends React.Component {
+ static propTypes = {
// maxHeight style attribute for the video element
maxHeight: PropTypes.number,
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize: PropTypes.func,
- },
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount() {
this._vid = createRef();
- },
+ }
componentDidMount() {
this._vid.current.addEventListener('resize', this.onResize);
- },
+ }
componentWillUnmount() {
this._vid.current.removeEventListener('resize', this.onResize);
- },
+ }
- onResize: function(e) {
+ onResize = (e) => {
if (this.props.onResize) {
this.props.onResize(e);
}
- },
+ };
- render: function() {
+ render() {
return (
);
- },
-});
+ }
+}
diff --git a/src/components/views/voip/VideoView.js b/src/components/views/voip/VideoView.js
index a51ab70da9..374a12e82d 100644
--- a/src/components/views/voip/VideoView.js
+++ b/src/components/views/voip/VideoView.js
@@ -18,7 +18,6 @@ limitations under the License.
import React, {createRef} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
@@ -35,10 +34,8 @@ function getFullScreenElement() {
);
}
-export default createReactClass({
- displayName: 'VideoView',
-
- propTypes: {
+export default class VideoView extends React.Component {
+ static propTypes = {
// maxHeight style attribute for the video element
maxHeight: PropTypes.number,
@@ -48,27 +45,28 @@ export default createReactClass({
// a callback which is called when the video element is resized due to
// a change in video metadata
onResize: PropTypes.func,
- },
+ };
+
+ constructor(props) {
+ super(props);
- // TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
- UNSAFE_componentWillMount: function() {
this._local = createRef();
this._remote = createRef();
- },
+ }
- componentDidMount: function() {
+ componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
dis.unregister(this.dispatcherRef);
- },
+ }
- getRemoteVideoElement: function() {
+ getRemoteVideoElement = () => {
return ReactDOM.findDOMNode(this._remote.current);
- },
+ };
- getRemoteAudioElement: function() {
+ getRemoteAudioElement = () => {
// this needs to be somewhere at the top of the DOM which
// always exists to avoid audio interruptions.
// Might as well just use DOM.
@@ -78,17 +76,17 @@ export default createReactClass({
+ "You need to add an to the DOM.");
}
return remoteAudioElement;
- },
+ };
- getLocalVideoElement: function() {
+ getLocalVideoElement = () => {
return ReactDOM.findDOMNode(this._local.current);
- },
+ };
- setContainer: function(c) {
+ setContainer = (c) => {
this.container = c;
- },
+ };
- onAction: function(payload) {
+ onAction = (payload) => {
switch (payload.action) {
case 'video_fullscreen': {
if (!this.container) {
@@ -117,9 +115,9 @@ export default createReactClass({
break;
}
}
- },
+ };
- render: function() {
+ render() {
const VideoFeed = sdk.getComponent('voip.VideoFeed');
// if we're fullscreen, we don't want to set a maxHeight on the video element.
@@ -140,5 +138,5 @@ export default createReactClass({
);
- },
-});
+ }
+}
diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts
new file mode 100644
index 0000000000..e8eb0c23b4
--- /dev/null
+++ b/src/contexts/RoomContext.ts
@@ -0,0 +1,48 @@
+/*
+Copyright 2019 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 { createContext } from "react";
+
+import {IState} from "../components/structures/RoomView";
+
+const RoomContext = createContext({
+ roomLoading: true,
+ peekLoading: false,
+ shouldPeek: true,
+ membersLoaded: false,
+ numUnreadMessages: 0,
+ draggingFile: false,
+ searching: false,
+ guestsCanJoin: false,
+ canPeek: false,
+ showApps: false,
+ isAlone: false,
+ isPeeking: false,
+ showingPinned: false,
+ showReadReceipts: true,
+ showRightPanel: true,
+ joining: false,
+ atEndOfLiveTimeline: true,
+ atEndOfLiveTimelineInit: false,
+ showTopUnreadMessagesBar: false,
+ statusBarVisible: false,
+ canReact: false,
+ canReply: false,
+ useIRCLayout: false,
+ matrixClientIsReady: false,
+});
+RoomContext.displayName = "RoomContext";
+export default RoomContext;
diff --git a/src/createRoom.ts b/src/createRoom.ts
index 23a664a4c4..09de265ebc 100644
--- a/src/createRoom.ts
+++ b/src/createRoom.ts
@@ -26,8 +26,8 @@ import dis from "./dispatcher/dispatcher";
import * as Rooms from "./Rooms";
import DMRoomMap from "./utils/DMRoomMap";
import {getAddressType} from "./UserAddress";
-
-const E2EE_WK_KEY = "im.vector.riot.e2ee";
+import { getE2EEWellKnown } from "./utils/WellKnownUtils";
+import GroupStore from "./stores/GroupStore";
// we define a number of interfaces which take their names from the js-sdk
/* eslint-disable camelcase */
@@ -80,6 +80,7 @@ interface IOpts {
encryption?: boolean;
inlineErrors?: boolean;
andView?: boolean;
+ associatedWithCommunity?: string;
}
/**
@@ -182,6 +183,10 @@ export default function createRoom(opts: IOpts): Promise {
} else {
return Promise.resolve();
}
+ }).then(() => {
+ if (opts.associatedWithCommunity) {
+ return GroupStore.addRoomToGroup(opts.associatedWithCommunity, roomId, false);
+ }
}).then(function() {
// NB createRoom doesn't block on the client seeing the echo that the
// room has been created, so we race here with the client knowing that
@@ -294,12 +299,11 @@ export async function ensureDMExists(client: MatrixClient, userId: string): Prom
return roomId;
}
-export function privateShouldBeEncrypted() {
- const clientWellKnown = MatrixClientPeg.get().getClientWellKnown();
- if (clientWellKnown && clientWellKnown[E2EE_WK_KEY]) {
- const defaultDisabled = clientWellKnown[E2EE_WK_KEY]["default"] === false;
+export function privateShouldBeEncrypted(): boolean {
+ const e2eeWellKnown = getE2EEWellKnown();
+ if (e2eeWellKnown) {
+ const defaultDisabled = e2eeWellKnown["default"] === false;
return !defaultDisabled;
}
-
return true;
}
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
index 6fb71df30d..26d585b76e 100644
--- a/src/dispatcher/actions.ts
+++ b/src/dispatcher/actions.ts
@@ -94,4 +94,14 @@ export enum Action {
* Trigged after the phase of the right panel is set. Should be used with AfterRightPanelPhaseChangePayload.
*/
AfterRightPanelPhaseChange = "after_right_panel_phase_change",
+
+ /**
+ * Requests that the AppTile deletes the widget. Should be used with the AppTileActionPayload.
+ */
+ AppTileDelete = "appTile_delete",
+
+ /**
+ * Requests that the AppTile revokes the widget. Should be used with the AppTileActionPayload.
+ */
+ AppTileRevoke = "appTile_revoke",
}
diff --git a/res/css/views/rooms/_RoomRecoveryReminder.scss b/src/dispatcher/payloads/AppTileActionPayload.ts
similarity index 52%
rename from res/css/views/rooms/_RoomRecoveryReminder.scss
rename to src/dispatcher/payloads/AppTileActionPayload.ts
index 09b28ae235..3cdb0f8c1f 100644
--- a/res/css/views/rooms/_RoomRecoveryReminder.scss
+++ b/src/dispatcher/payloads/AppTileActionPayload.ts
@@ -1,5 +1,5 @@
/*
-Copyright 2018 New Vector Ltd
+Copyright 2020 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,26 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-.mx_RoomRecoveryReminder {
- display: flex;
- flex-direction: column;
- text-align: center;
- background-color: $room-warning-bg-color;
- padding: 20px;
- border: 1px solid $primary-hairline-color;
- border-bottom: unset;
-}
+import { ActionPayload } from "../payloads";
+import { Action } from "../actions";
-.mx_RoomRecoveryReminder_header {
- font-weight: bold;
- margin-bottom: 1em;
-}
-
-.mx_RoomRecoveryReminder_body {
- margin-bottom: 1em;
-}
-
-.mx_RoomRecoveryReminder_secondary {
- font-size: 90%;
- margin-top: 1em;
+export interface AppTileActionPayload extends ActionPayload {
+ action: Action.AppTileDelete | Action.AppTileRevoke;
+ widgetId: string;
}
diff --git a/src/dispatcher/payloads/SetRightPanelPhasePayload.ts b/src/dispatcher/payloads/SetRightPanelPhasePayload.ts
index 75dea9f3df..4126e8a669 100644
--- a/src/dispatcher/payloads/SetRightPanelPhasePayload.ts
+++ b/src/dispatcher/payloads/SetRightPanelPhasePayload.ts
@@ -34,4 +34,5 @@ export interface SetRightPanelPhaseRefireParams {
groupRoomId?: string;
// XXX: The type for event should 'view_3pid_invite' action's payload
event?: any;
+ widgetId?: string;
}
diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts
new file mode 100644
index 0000000000..79f3e539cd
--- /dev/null
+++ b/src/hooks/useIsEncrypted.ts
@@ -0,0 +1,36 @@
+/*
+Copyright 2020 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 {useCallback, useState} from "react";
+import {MatrixClient} from "matrix-js-sdk/src/client";
+import {MatrixEvent} from "matrix-js-sdk/src/models/event";
+import {Room} from "matrix-js-sdk/src/models/room";
+
+import {useEventEmitter} from "./useEventEmitter";
+
+// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined
+export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined {
+ const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined);
+
+ const update = useCallback((event: MatrixEvent) => {
+ if (room && event.getType() === "m.room.encryption") {
+ setIsEncrypted(cli.isRoomEncrypted(room.roomId));
+ }
+ }, [cli, room]);
+ useEventEmitter(room ? room.currentState : undefined, "RoomState.events", update);
+
+ return isEncrypted;
+}
diff --git a/src/hooks/useLocalStorageState.ts b/src/hooks/useLocalStorageState.ts
new file mode 100644
index 0000000000..ce3b574f86
--- /dev/null
+++ b/src/hooks/useLocalStorageState.ts
@@ -0,0 +1,44 @@
+/*
+Copyright 2020 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 {Dispatch, SetStateAction, useCallback, useEffect, useState} from "react";
+
+const getValue = (key: string, initialValue: T): T => {
+ try {
+ const item = window.localStorage.getItem(key);
+ return item ? JSON.parse(item) : initialValue;
+ } catch (error) {
+ return initialValue;
+ }
+};
+
+// Hook behaving like useState but persisting the value to localStorage. Returns same as useState
+export const useLocalStorageState = (key: string, initialValue: T) => {
+ const lsKey = "mx_" + key;
+
+ const [value, setValue] = useState(getValue(lsKey, initialValue));
+
+ useEffect(() => {
+ setValue(getValue(lsKey, initialValue));
+ }, [lsKey, initialValue]);
+
+ const _setValue: Dispatch> = useCallback((v: T) => {
+ window.localStorage.setItem(lsKey, JSON.stringify(v));
+ setValue(v);
+ }, [lsKey]);
+
+ return [value, _setValue];
+};
diff --git a/src/i18n/strings/cs.json b/src/i18n/strings/cs.json
index 7f799072cb..4d9d27363f 100644
--- a/src/i18n/strings/cs.json
+++ b/src/i18n/strings/cs.json
@@ -2164,5 +2164,54 @@
"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.": "Sem přídejte servery a uživatele, které chcete ignorovat. Hvězdička pro %(brand)s zastupuje libovolný počet kterýchkoliv znaků. Např. @bot:* bude ignorovat všechny uživatele se jménem „bot“ na kterémkoliv serveru.",
"Signature upload success": "Podpis úspěšně nahrán",
"Signature upload failed": "Podpis se nepodařilo nahrát",
- "If the other version of %(brand)s is still open in another tab, please close it as using %(brand)s on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Je-li jiná verze programu %(brand)s stále otevřená na jiné kartě, tak ji prosím zavřete, neboť užívání programu %(brand)s stejným hostitelem se zpožděným nahráváním současně povoleným i zakázaným bude působit problémy."
+ "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.": "Je-li jiná verze programu %(brand)s stále otevřená na jiné kartě, tak ji prosím zavřete, neboť užívání programu %(brand)s stejným hostitelem se zpožděným nahráváním současně povoleným i zakázaným bude působit problémy.",
+ "Unexpected server error trying to leave the room": "Neočekávaná chyba serveru při odcházení z místnosti",
+ "The person who invited you already left the room.": "Uživatel který vás pozval už místnosti není.",
+ "The person who invited you already left the room, or their server is offline.": "Uživatel který vás pozvat už odešel z místnosti a nebo je jeho server offline.",
+ "You left the call": "Odešli jste z hovoru",
+ "%(senderName)s left the call": "%(senderName)s opustil/a hovor",
+ "Call ended": "Hovor skončil",
+ "You started a call": "Začali jste hovor",
+ "%(senderName)s started a call": "%(senderName)s začal/a hovor",
+ "Waiting for answer": "Čekání na odpověď",
+ "%(senderName)s is calling": "%(senderName)s volá",
+ "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s",
+ "%(senderName)s: %(message)s": "%(senderName)s: %(message)s",
+ "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s",
+ "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s",
+ "Change notification settings": "Upravit nastavení oznámení",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Prototyp komunit verze 2. Vyžaduje kompatibilní domovský server. Experimentální - používejte opatrně.",
+ "Use custom size": "Použít vlastní velikost",
+ "Use a more compact ‘Modern’ layout": "Používat kompaktní ‘Moderní’ vzhled",
+ "Use a system font": "Používat systémové nastavení písma",
+ "System font name": "Jméno systémového písma",
+ "Uploading logs": "Nahrávání záznamů",
+ "Downloading logs": "Stahování záznamů",
+ "Unknown caller": "Neznámý volající",
+ "Incoming voice call": "Příchozí hovor",
+ "Incoming video call": "Příchozí videohovor",
+ "Incoming call": "Příchozí hovor",
+ "Your server isn't responding to some requests.": "Váš server neodpovídá na některé požadavky.",
+ "Master private key:": "Hlavní soukromý klíč:",
+ "%(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 nemůže v prohlížeči lokálně bezpečně uložit zprávy. Použijte %(brand)s Desktop aby fungovalo vyhledávání v šifrovaných zprávách.",
+ "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Váš administrátor vypnul šifrování ve výchozím nastavení soukromých místností a přímých chatů.",
+ "To link to this room, please add an address.": "Přidejte prosím místnosti adresu aby na ní šlo odkazovat.",
+ "The authenticity of this encrypted message can't be guaranteed on this device.": "Pravost této šifrované zprávy nelze na tomto zařízení ověřit.",
+ "Emoji picker": "Výběr emoji",
+ "No recently visited rooms": "Žádné nedávno navštívené místnosti",
+ "People": "Lidé",
+ "Explore public rooms": "Prozkoumat veřejné místnosti",
+ "Custom Tag": "Vlastní štítek",
+ "Can't see what you’re looking for?": "Nikde nevidíte co hledáte?",
+ "Explore all public rooms": "Prozkoumat všechny veřejné místnosti",
+ "%(count)s results|other": "%(count)s výsledků",
+ "Preparing to download logs": "Příprava na stažení záznamů",
+ "Download logs": "Stáhnout záznamy",
+ "a new cross-signing key signature": "nový podpis klíče pro cross-signing",
+ "a key signature": "podpis klíče",
+ "%(brand)s encountered an error during upload of:": "%(brand)s narazil na chybu při nahrávání:",
+ "Upload completed": "Nahrávání dokončeno",
+ "Cancelled signature upload": "Nahrávání podpisu zrušeno",
+ "Unable to upload": "Nelze nahrát",
+ "Server isn't responding": "Server neodpovídá"
}
diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json
index 3d5ba3722e..14a87f8308 100644
--- a/src/i18n/strings/de_DE.json
+++ b/src/i18n/strings/de_DE.json
@@ -572,7 +572,7 @@
"was unbanned %(count)s times|one": "wurde entbannt",
"%(oneUser)schanged their name %(count)s times|one": "%(oneUser)shat den Namen geändert",
"%(items)s and %(count)s others|other": "%(items)s und %(count)s andere",
- "%(items)s and %(count)s others|one": "%(items)s und noch jemand",
+ "%(items)s and %(count)s others|one": "%(items)s und ein weiteres Raummitglied",
"An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Eine E-Mail wurde an %(emailAddress)s gesendet. Folge dem in der E-Mail enthaltenen Link und klicke dann unten.",
"The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Die Sichtbarkeit von '%(roomName)s' in %(groupId)s konnte nicht aktualisiert werden.",
"Visibility in Room List": "Sichtbarkeit in Raum-Liste",
@@ -784,7 +784,7 @@
"Checking for an update...": "Nach Updates suchen...",
"Missing roomId.": "Fehlende Raum-ID.",
"Every page you use in the app": "Jede Seite, die du in der App benutzt",
- "e.g. ": "z.B. ",
+ "e.g. ": "z. B. ",
"Your device resolution": "Deine Bildschirmauflösung",
"Popout widget": "Widget ausklinken",
"Always show encryption icons": "Immer Verschlüsselungssymbole zeigen",
@@ -889,12 +889,12 @@
"Go back to set it again.": "Gehe zurück und setze es erneut.",
"Download": "Herunterladen",
"Print it and store it somewhere safe": "Drucke ihn aus und lagere ihn an einem sicheren Ort",
- "Save it on a USB key or backup drive": "Speichere ihn auf einem USB-Schlüssel oder Sicherungsslaufwerk",
+ "Save it on a USB key or backup drive": "Speichere ihn auf einem USB-Schlüssel oder Sicherungslaufwerk",
"Copy it to your personal cloud storage": "Kopiere ihn in deinen persönlichen Cloud-Speicher",
"Unable to create key backup": "Konnte Schlüsselsicherung nicht erstellen",
"Retry": "Erneut probieren",
- "Unable to restore backup": "Konnte Sicherung nicht wiederherstellen",
- "No backup found!": "Keine Sicherung gefunden!",
+ "Unable to restore backup": "Konnte Schlüsselsicherung nicht wiederherstellen",
+ "No backup found!": "Keine Schlüsselsicherung gefunden!",
"This looks like a valid recovery key!": "Dies sieht wie ein gültiger Wiederherstellungsschlüssel aus!",
"Not a valid recovery key": "Kein valider Wiederherstellungsschlüssel",
"There was an error joining the room": "Es gab einen Fehler beim Raum-Beitreten",
@@ -934,7 +934,7 @@
"Use a longer keyboard pattern with more turns": "Nutze ein längeres Tastaturmuster mit mehr Abwechslung",
"Straight rows of keys are easy to guess": "Gerade Reihen von Tasten sind einfach zu erraten",
"Custom user status messages": "Angepasste Nutzerstatus-Nachrichten",
- "Unable to load key backup status": "Konnte Status des Schlüsselbackups nicht laden",
+ "Unable to load key backup status": "Konnte Status der Schlüsselsicherung nicht laden",
"Don't ask again": "Nicht erneut fragen",
"Set up": "Einrichten",
"Please review and accept all of the homeserver's policies": "Bitte prüfen und akzeptieren Sie alle Richtlinien des Heimservers",
@@ -942,7 +942,7 @@
"That doesn't look like a valid email address": "Sieht nicht nach einer validen E-Mail-Adresse aus",
"Unable to load commit detail: %(msg)s": "Konnte Commit-Details nicht laden: %(msg)s",
"Checking...": "Überprüfe...",
- "Unable to load backup status": "Konnte Backupstatus nicht laden",
+ "Unable to load backup status": "Konnte Sicherungsstatus nicht laden",
"Failed to decrypt %(failedCount)s sessions!": "Konnte %(failedCount)s Sitzungen nicht entschlüsseln!",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Greifen Sie auf Ihre sichere Nachrichtenhistorie zu und richten Sie einen sicheren Nachrichtenversand ein, indem Sie Ihre Wiederherstellungspassphrase eingeben.",
"If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Wenn du deinen Wiederherstellungspassphrase vergessen hast, kannst du deinen Wiederherstellungsschlüssel benutzen oder neue Wiederherstellungsoptionen einrichten",
@@ -992,7 +992,7 @@
"You've successfully verified this user.": "Du hast diesen Benutzer erfolgreich verifiziert.",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Sichere Nachrichten mit diesem Benutzer sind Ende-zu-Ende-verschlüsselt und können nicht von Dritten gelesen werden.",
"Got It": "Verstanden",
- "Verify this user by confirming the following number appears on their screen.": "Verifizieren Sie diesen Benutzer, indem Sie bestätigen, dass die folgende Nummer auf dessen Bildschirm erscheint.",
+ "Verify this user by confirming the following number appears on their screen.": "Verifiziere diese Nutzer!n, indem du bestätigst, dass die folgende Nummer auf dessen Bildschirm erscheint.",
"Yes": "Ja",
"No": "Nein",
"We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Wir haben dir eine E-Mail geschickt, um deine Adresse zu überprüfen. Bitte folge den Anweisungen dort und klicke dann auf die Schaltfläche unten.",
@@ -1034,7 +1034,7 @@
"%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s hat den Raum auf eingeladene User beschränkt.",
"%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s änderte die Zutrittsregel auf '%(rule)s'",
"%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s erlaubte Gäste diesem Raum beizutreten.",
- "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s hat verboten, dass Gäste diesem Raum beitreten.",
+ "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s hat Gästen verboten diesem Raum beizutreten.",
"%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s änderte den Gastzugriff auf '%(rule)s'",
"Group & filter rooms by custom tags (refresh to apply changes)": "Gruppiere & filtere Räume nach eigenen Tags (neu laden um Änderungen zu übernehmen)",
"Unable to find a supported verification method.": "Konnte kein unterstützte Verifikationsmethode finden.",
@@ -1111,7 +1111,7 @@
"Ignored users": "Ignorierte Benutzer",
"Key backup": "Schlüsselsicherung",
"Gets or sets the room topic": "Frage das Thema des Raums ab oder setze es",
- "Verify this user by confirming the following emoji appear on their screen.": "Verifizieren Sie diesen Benutzer, indem Sie bestätigen, dass folgendes Emoji auf dessen Bildschirm erscheint.",
+ "Verify this user by confirming the following emoji appear on their screen.": "Verifiziere diese Nutzer!n, indem du bestätigst, dass folgendes Emoji auf dessen Bildschirm erscheint.",
"Missing media permissions, click the button below to request.": "Fehlende Medienberechtigungen. Drücke auf den Knopf unten, um sie anzufordern.",
"Request media permissions": "Medienberechtigungen anfordern",
"Main address": "Primäre Adresse",
@@ -1128,7 +1128,7 @@
"Back up your keys before signing out to avoid losing them.": "Sichere deine Schlüssel bevor du dich abmeldest, damit du sie nicht verlierst.",
"Start using Key Backup": "Beginne Schlüsselsicherung zu nutzen",
"Credits": "Danksagungen",
- "Starting backup...": "Starte Backup...",
+ "Starting backup...": "Starte Sicherung...",
"Success!": "Erfolgreich!",
"Your keys are being backed up (the first backup could take a few minutes).": "Deine Schlüssel werden gesichert (Das erste Backup könnte ein paar Minuten in Anspruch nehmen).",
"Voice & Video": "Sprach- & Videoanruf",
@@ -1328,7 +1328,7 @@
"Find a room…": "Suche einen Raum…",
"Find a room… (e.g. %(exampleRoom)s)": "Suche einen Raum… (z.B. %(exampleRoom)s)",
"If you can't find the room you're looking for, ask for an invite or Create a new room.": "Wenn du den gesuchten Raum nicht finden kannst, frage nach einer Einladung für den Raum oder Erstelle einen neuen Raum.",
- "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.": "Alternativ kannst du versuchen, den öffentlichen Server unter turn.matrix.org zu verwenden. Allerdings wird dieser nicht so zuverlässig sein, und deine IP-Adresse mit diesem teilen. Du kannst dies auch in den Einstellungen konfigurieren.",
+ "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.": "Alternativ kannst du versuchen, den öffentlichen Server unter turn.matrix.org zu verwenden. Allerdings wird dieser nicht so zuverlässig sein, und deine IP-Adresse mit diesem Server teilen. Du kannst dies auch in den Einstellungen konfigurieren.",
"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.": "Diese Handlung erfordert es, auf den Standard-Identitätsserver zuzugreifen, um eine E-Mail Adresse oder Telefonnummer zu validieren, aber der Server hat keine Nutzungsbedingungen.",
"Only continue if you trust the owner of the server.": "Fahre nur fort, wenn du den Inhaber*innen des Servers vertraust.",
"Trust": "Vertrauen",
@@ -1337,7 +1337,7 @@
"Use an identity server to invite by email. Manage in Settings.": "Nutze einen Identitätsserver, um über E-Mail Einladungen zu verschicken. Verwalte es in den Einstellungen.",
"%(name)s (%(userId)s)": "%(name)s (%(userId)s)",
"Try out new ways to ignore people (experimental)": "Versuche neue Möglichkeiten, um Menschen zu ignorieren (experimentell)",
- "Send read receipts for messages (requires compatible homeserver to disable)": "Schicke Lesebestätigungen für Nachrichten (erfordert kompatiblen Heimserver zum Deaktivieren)",
+ "Send read receipts for messages (requires compatible homeserver to disable)": "Lesebestätigungen für Nachrichten senden (Deaktivieren erfordert einen kompatiblen Heimserver)",
"My Ban List": "Meine Bannliste",
"This is your list of users/servers you have blocked - don't leave the room!": "Dies ist die Liste von Benutzer*innen/Servern, die du blockiert hast - verlasse den Raum nicht!",
"Accept to continue:": "Akzeptiere , um fortzufahren:",
@@ -1380,11 +1380,11 @@
"Manage": "Verwalten",
"Securely cache encrypted messages locally for them to appear in search results.": "Speichere verschlüsselte Nachrichten sicher lokal zwischen, sodass sie in Suchergebnissen erscheinen können.",
"Enable": "Aktivieren",
- "Connecting to integration manager...": "Verbinden zum Integrationsmanager...",
+ "Connecting to integration manager...": "Verbinde mit Integrationsmanager...",
"Cannot connect to integration manager": "Verbindung zum Integrationsmanager fehlgeschlagen",
"The integration manager is offline or it cannot reach your homeserver.": "Der Integrationsmanager ist offline oder er kann den Heimserver nicht erreichen.",
"not stored": "nicht gespeichert",
- "Backup has a signature from unknown user with ID %(deviceId)s": "Backup hat eine Signatur von Unbekanntem Nutzer mit ID %(deviceId)s",
+ "Backup has a signature from unknown user with ID %(deviceId)s": "Die Sicherung hat eine Signatur von unbekanntem/r Nutzer!n mit ID %(deviceId)s",
"Backup key stored: ": "Backup Schlüssel gespeichert: ",
"Clear notifications": "Benachrichtigungen löschen",
"Disconnect from the identity server and connect to instead?": "Verbindung vom Identitätsserver trennen und stattdessen zu verbinden?",
@@ -1431,9 +1431,9 @@
"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!": "ACHTUNG: SCHLÜSSEL-VERIFIZIERUNG FEHLGESCHLAGEN! Der Signierschlüssel für %(userId)s und Sitzung %(deviceId)s ist \"%(fprint)s\", was nicht mit dem bereitgestellten Schlüssel \"%(fingerprint)s\" übereinstimmt. Das könnte bedeuten, dass deine Kommunikation abgehört wird!",
"Never send encrypted messages to unverified sessions from this session": "Sende niemals verschlüsselte Nachrichten von dieser Sitzung zu unverifizierten Sitzungen",
"Never send encrypted messages to unverified sessions in this room from this session": "Sende niemals verschlüsselte Nachrichten von dieser Sitzung zu unverifizierten Sitzungen in diesem Raum",
- "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.": "Durch die Änderung des Passworts werden derzeit alle End-zu-End-Verschlüsselungsschlüssel in allen Sitzungen zurückgesetzt, sodass der verschlüsselte Chat-Verlauf nicht mehr lesbar ist, es sei denn, Sie exportieren zuerst Ihre Raumschlüssel und importieren sie anschließend wieder. In Zukunft wird dies verbessert werden.",
+ "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.": "Durch die Änderung des Passworts werden derzeit alle Ende-zu-Ende-Verschlüsselungsschlüssel in allen Sitzungen zurückgesetzt, sodass der verschlüsselte Chat-Verlauf nicht mehr lesbar ist, es sei denn, du exportierst zuerst deine Raumschlüssel und importierst sie anschließend wieder. In Zukunft wird dies verbessert werden.",
"Delete %(count)s sessions|other": "Lösche %(count)s Sitzungen",
- "Backup is not signed by any of your sessions": "Die Sicherung ist von keiner Ihrer Sitzungen unterzeichnet",
+ "Backup is not signed by any of your sessions": "Die Sicherung wurde von keiner deiner Sitzungen unterzeichnet",
"Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Ihr Passwort wurde erfolgreich geändert. Sie erhalten keine Push-Benachrichtigungen zu anderen Sitzungen, bis Sie sich wieder bei diesen anmelden",
"Notification sound": "Benachrichtigungston",
"Set a new custom sound": "Setze einen neuen benutzerdefinierten Ton",
@@ -1569,7 +1569,7 @@
"%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s hat die alternative Adresse %(addresses)s für diesen Raum entfernt.",
"%(senderName)s changed the alternative addresses for this room.": "%(senderName)s hat die alternative Adresse für diesen Raum geändert.",
"%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s hat die Haupt- und Alternativadresse für diesen Raum geändert.",
- "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s entfernte die Ausschluss-Regel für Nutzer, die %(glob)s entsprechen",
+ "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s entfernte die Ausschluss-Regel für Nutzer!nnen, die %(glob)s entsprechen",
"%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s entfernte die Ausschluss-Regel für Räume, die %(glob)s entsprechen",
"%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s entfernte die Ausschluss-Regel für Server, die %(glob)s entsprechen",
"%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s entfernte die Ausschluss-Regel, die %(glob)s entspricht",
@@ -1587,8 +1587,8 @@
"Reject & Ignore user": "Ablehnen & Nutzer ignorieren",
"%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ändert eine Ausschluss-Regel von %(oldGlob)s nach %(newGlob)s, wegen %(reason)s",
"%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ändert eine Ausschluss-Regel für Räume von %(oldGlob)s nach %(newGlob)s, wegen %(reason)s",
- "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Erlaube den Standard-Server zur Anrufunterstützung (turn.matrix.org) zu verwenden wenn dein Heimserver keinen eigenen anbietet (deine IP Adresse wird bei dem Anruf übermittelt)",
- "Show more": "mehr",
+ "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Auf den Server turn.matrix.org zurückgreifen, falls deine Heimserver keine Anruf-Assistenz anbietet (deine IP-Adresse wird während eines Anrufs geteilt)",
+ "Show more": "Mehr zeigen",
"This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.": "Diese Sitzung speichert deine Schlüssel nicht, du kannst sie aber an die Schlüsselsicherung anschließen.",
"Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "Verbinde diese Sitzung mit deiner Schlüsselsicherung bevor du dich abmeldest, um den Verlust von Schlüsseln zu vermeiden.",
"This backup is trusted because it has been restored on this session": "Dieser Sicherung wird vertraut, da sie während dieser Sitzung wiederhergestellt wurde",
@@ -1631,13 +1631,13 @@
"Copy": "In Zwischenablage kopieren",
"Make a copy of your recovery key": "Speichere deinen Wiederherstellungsschlüssel",
"Sends a message as html, without interpreting it as markdown": "Verschickt eine Nachricht im html-Format, ohne sie in Markdown zu formatieren",
- "Show rooms with unread notifications first": "Räume mit nicht gelesenen Benachrichtungen zuerst zeigen",
- "Show shortcuts to recently viewed rooms above the room list": "Kurzbefehlezu den kürzlich gesichteteten Räumen über der Raumliste anzeigen",
- "Use Single Sign On to continue": "Nutze „Single Sign-On“ (Einmal-Anmeldung) um fortzufahren",
- "Confirm adding this email address by using Single Sign On to prove your identity.": "Bestätige das Hinzufügen dieser E-Mail-Adresse mit „Single Sign-On“, um deine Identität nachzuweisen.",
+ "Show rooms with unread notifications first": "Räume mit ungelesenen Benachrichtigungen zuerst zeigen",
+ "Show shortcuts to recently viewed rooms above the room list": "Kurzbefehle zu den kürzlich gesichteten Räumen über der Raumliste anzeigen",
+ "Use Single Sign On to continue": "Verwende Single Sign on um fortzufahren",
+ "Confirm adding this email address by using Single Sign On to prove your identity.": "Bestätige die hinzugefügte E-Mail-Adresse mit Single Sign-On, um deine Identität nachzuweisen.",
"Single Sign On": "Single Sign-On",
- "Confirm adding email": "Hinzufügen der E-Mail-Adresse bestätigen",
- "Confirm adding this phone number by using Single Sign On to prove your identity.": "Bestätige das Hinzufügen dieser Telefonnummer, indem du deine Identität mittels „Single Sign-On“ nachweist.",
+ "Confirm adding email": "Bestätige hinzugefügte E-Mail-Addresse",
+ "Confirm adding this phone number by using Single Sign On to prove your identity.": "Bestätige die hinzugefügte Telefonnummer, indem du deine Identität mittels Single Sign-On nachweist.",
"Click the button below to confirm adding this phone number.": "Klicke unten die Schaltfläche, um die hinzugefügte Telefonnummer zu bestätigen.",
"If you cancel now, you won't complete your operation.": "Wenn du jetzt abbrichst, wirst du deinen Vorgang nicht fertigstellen.",
"%(name)s is requesting verification": "%(name)s fordert eine Verifizierung an",
@@ -1645,14 +1645,14 @@
"Command failed": "Befehl fehlgeschlagen",
"Could not find user in room": "Der Benutzer konnte im Raum nicht gefunden werden",
"Click the button below to confirm adding this email address.": "Klicke unten auf die Schaltfläche, um die hinzugefügte E-Mail-Adresse zu bestätigen.",
- "Confirm adding phone number": "Hinzufügen der Telefonnummer bestätigen",
+ "Confirm adding phone number": "Bestätige hinzugefügte Telefonnummer",
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ändert eine Ausschluss-Regel für Server von %(oldGlob)s nach %(newGlob)s wegen %(reason)s",
"%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s erneuert eine Ausschluss-Regel von %(oldGlob)s nach %(newGlob)s wegen %(reason)s",
"Not Trusted": "Nicht vertraut",
"Manually Verify by Text": "Verifiziere manuell mit einem Text",
"Interactively verify by Emoji": "Verifiziere interaktiv mit Emojis",
"Support adding custom themes": "Unterstütze das Hinzufügen von benutzerdefinierten Designs",
- "Ask this user to verify their session, or manually verify it below.": "Bitte diese/n Nutzer!n, seine/ihre Sitzung zu verifizieren, oder verifiziere diese unten manuell.",
+ "Ask this user to verify their session, or manually verify it below.": "Bitte diesen Nutzer, seine Sitzung zu verifizieren, oder verifiziere diesen unten manuell.",
"a few seconds from now": "in ein paar Sekunden",
"Manually verify all remote sessions": "Verifiziere alle Remotesitzungen",
"Confirm the emoji below are displayed on both sessions, in the same order:": "Bestätige, dass die unten angezeigten Emojis auf beiden Sitzungen in der selben Reihenfolge angezeigt werden:",
@@ -1724,7 +1724,7 @@
"Upgrade this room to the recommended room version": "Aktualisiere diesen Raum auf die empfohlene Raumversion",
"this room": "Dieser Raum",
"View older messages in %(roomName)s.": "Zeige alte Nachrichten in %(roomName)s.",
- "Send a bug report with logs": "Sende Fehlermeldung mit Protokoll",
+ "Send a bug report with logs": "Sende einen Fehlerbericht mit Logs",
"Verify all your sessions to ensure your account & messages are safe": "Verifiziere alle deine Sitzungen, um dein Konto und deine Nachrichten zu schützen",
"Verify your other session using one of the options below.": "Verifiziere deine andere Sitzung mit einer der folgenden Optionen.",
"You signed in to a new session without verifying it:": "Du hast dich in einer neuen Sitzung angemeldet ohne sie zu verifizieren:",
@@ -1732,16 +1732,16 @@
"Upgrade": "Hochstufen",
"Verify the new login accessing your account: %(name)s": "Verifiziere die neue Anmeldung an deinem Konto: %(name)s",
"From %(deviceName)s (%(deviceId)s)": "Von %(deviceName)s (%(deviceId)s)",
- "Your homeserver does not support cross-signing.": "Dein Heimserver unterstützt cross-signing nicht.",
+ "Your homeserver does not support cross-signing.": "Dein Heimserver unterstützt kein Cross-Signing.",
"Cross-signing and secret storage are enabled.": "Cross-signing und der sichere Speicher wurden eingerichtet.",
- "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Dein Konto hat eine cross-signing Identität im sicheren Speicher aber diese Sitzung wird noch nicht vertraut.",
- "Cross-signing and secret storage are not yet set up.": "Cross-signing und der sichere Speicher wurden noch nicht eingerichtet.",
- "Reset cross-signing and secret storage": "Setze cross-signing und den sicheren Speicher zurück",
- "Bootstrap cross-signing and secret storage": "Richte cross-signing und den sicheren Speicher ein",
+ "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Dein Konto hat eine Cross-Signing-Identität im sicheren Speicher, der von dieser Sitzung jedoch noch nicht vertraut wird.",
+ "Cross-signing and secret storage are not yet set up.": "Cross-Signing und der sichere Speicher sind noch nicht eingerichtet.",
+ "Reset cross-signing and secret storage": "Cross-Signing und den sicheren Speicher zurücksetzen",
+ "Bootstrap cross-signing and secret storage": "Richte Cross-Signing und den sicheren Speicher ein",
"unexpected type": "unbekannter Typ",
- "Cross-signing public keys:": "Öffentliche Cross-signing Schlüssel:",
+ "Cross-signing public keys:": "Öffentliche Cross-Signing-Schlüssel:",
"in memory": "im Speicher",
- "Cross-signing private keys:": "Private Cross-signing Schlüssel:",
+ "Cross-signing private keys:": "Private Cross-Signing-Schlüssel:",
"in secret storage": "im sicheren Speicher",
"Self signing private key:": "Selbst signierter privater Schlüssel:",
"cached locally": "lokal zwischengespeichert",
@@ -1750,13 +1750,13 @@
"Session backup key:": "Sitzungswiederherstellungsschlüssel:",
"Secret storage public key:": "Öffentlicher Schlüssel des sicheren Speichers:",
"in account data": "in den Kontodaten",
- "Homeserver feature support:": "Heimserverunterstützung:",
+ "Homeserver feature support:": "Home-Server-Funktionsunterstützung:",
"exists": "existiert",
"Delete sessions|other": "Lösche Sitzungen",
"Delete sessions|one": "Lösche Sitzung",
- "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Sitzungen eines Benutzers einzeln verifizieren. Geräten, die ein Benutzer als vertrauenswürdig markiert hat, wird nicht automatisch vertraut (cross-signing).",
+ "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Alle Sitzungen einzeln verifizieren, anstatt auch Sitzungen zu vertrauen, die durch Cross-Signing verifiziert sind.",
"Securely cache encrypted messages locally for them to appear in search results, using ": "Der Zwischenspeicher für die lokale Suche in verschlüsselten Nachrichten benötigt ",
- " to store messages from ": " um Nachrichten aus ",
+ " to store messages from ": " um Nachrichten zu speichern von ",
"%(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 benötigt weitere Komponenten um verschlüsselte Nachrichten lokal zu durchsuchen. Wenn du diese Funktion testen möchtest kannst du dir deine eigene Version von %(brand)s Desktop mit der integrierten Suchfunktion bauen.",
"Backup has a valid signature from this user": "Die Sicherung hat eine gültige Signatur dieses Benutzers",
"Backup has a invalid signature from this user": "Die Sicherung hat eine ungültige Signatur dieses Benutzers",
@@ -2094,7 +2094,7 @@
"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.": "Ein Widget unter %(widgetUrl)s möchte deine Identität überprüfen. Wenn du dies zulässt, kann das Widget deine Nutzer-ID überprüfen, jedoch keine Aktionen in deinem Namen ausführen.",
"Unable to access secret storage. Please verify that you entered the correct recovery passphrase.": "Der sichere Speicher konnte nicht geladen werden. Bitte stelle sicher dass du die richtige Wiederherstellungspassphrase eingegeben hast.",
"Backup could not be decrypted with this recovery key: please verify that you entered the correct recovery key.": "Die Sicherung konnte nicht mit dem angegebenen Wiederherstellungsschlüssel entschlüsselt werden: Bitte überprüfe ob du den richtigen Wiederherstellungsschlüssel eingegeben hast.",
- "Backup could not be decrypted with this recovery passphrase: please verify that you entered the correct recovery passphrase.": "Die Sicherung konnte mit diesem Wiederherstellungsschlüssel nicht entschlüsselt werden: Bitte überprüfe ob du den richtigen Wiederherstellungspassphrase eingegeben hast.",
+ "Backup could not be decrypted with this recovery passphrase: please verify that you entered the correct recovery passphrase.": "Die Sicherung konnte mit diesem Wiederherstellungsschlüssel nicht entschlüsselt werden: Bitte überprüfe ob du die richtige Wiederherstellungspassphrase eingegeben hast.",
"Nice, strong password!": "Super, ein starkes Passwort!",
"Other users can invite you to rooms using your contact details": "Andere Benutzer können dich mit deinen Kontaktdaten in Räume einladen",
"Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.": "Lege eine E-Mail für die Kontowiederherstellung fest. Verwende optional E-Mail oder Telefon, um von Anderen gefunden zu werden.",
@@ -2408,5 +2408,54 @@
"Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "Bewahre deinen Sicherheitsschlüssel an einem sicheren Ort wie z. B. in einem Passwort-Manager oder einem Safe auf. Er wird zum Schutz deiner verschlüsselten Daten verwendet.",
"If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "Wenn du jetzt abbrichst, kannst du verschlüsselte Nachrichten und Daten verlieren, wenn du den Zugriff auf deine Logins verlierst.",
"You can also set up Secure Backup & manage your keys in Settings.": "Du kannst auch in den Einstellungen eine Sicherung erstellen & deine Schlüssel verwalten.",
- "Set up Secure backup": "Sicheres Backup einrichten"
+ "Set up Secure backup": "Sicheres Backup einrichten",
+ "Show message previews for reactions in DMs": "Anzeigen einer Nachrichtenvorschau für Reaktionen in DMs",
+ "Show message previews for reactions in all rooms": "Zeigen Sie eine Nachrichtenvorschau für Reaktionen in allen Räumen an",
+ "Uploading logs": "Protokolle werden hochgeladen",
+ "Downloading logs": "Protokolle werden heruntergeladen",
+ "Explore public rooms": "Erkunde öffentliche Räume",
+ "Can't see what you’re looking for?": "Kannst du nicht finden wonach du suchst?",
+ "Explore all public rooms": "Erkunde alle öffentlichen Räume",
+ "%(count)s results|other": "%(count)s Ergebnisse",
+ "Preparing to download logs": "Bereite das Herunterladen der Protokolle vor",
+ "Download logs": "Protokolle herunterladen",
+ "Unexpected server error trying to leave the room": "Unerwarteter Server-Fehler beim Versuch den Raum zu verlassen",
+ "Error leaving room": "Fehler beim Verlassen des Raums",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 Prototyp. Benötigt einen kompatiblen Heimserver. Höchst experimentell - mit Vorsicht verwenden.",
+ "Explore rooms in %(communityName)s": "Erkunde Räume in %(communityName)s",
+ "Set up Secure Backup": "Schlüsselsicherung einrichten",
+ "Information": "Information",
+ "Add another email": "Weitere E-Mail-Adresse hinzufügen",
+ "Send %(count)s invites|other": "%(count)s Einladungen senden",
+ "There was an error creating your community. The name may be taken or the server is unable to process your request.": "Beim Erstellen deiner Community ist ein Fehler aufgetreten. Entweder ist der Name schon vergeben oder der Server kann die Anfrage nicht verarbeiten.",
+ "Community ID: +:%(domain)s": "Community-ID: +:%(domain)s",
+ "Explore community rooms": "Entdecke Community Räume",
+ "You can change this later if needed.": "Falls nötig, kannst du es später noch ändern.",
+ "What's the name of your community or team?": "Welchen Namen hat deine Community oder dein Team?",
+ "Enter name": "Namen eingeben",
+ "Add image (optional)": "Bild hinzufügen (optional)",
+ "Create a room in %(communityName)s": "Erstelle einen Raum in %(communityName)s",
+ "Create community": "Erstelle Community",
+ "Cross-signing and secret storage are ready for use.": "Cross-Signing und der sichere Speicher sind bereit zur Benutzung.",
+ "Cross-signing is ready for use, but secret storage is currently not being used to backup your keys.": "Cross-Signing ist bereit, aber der sichere Speicher wird noch nicht als Schlüsselbackup benutzt.",
+ "People you know on %(brand)s": "Leute, die du auf %(brand)s kennst",
+ "Send %(count)s invites|one": "%(count)s Einladung senden",
+ "Invite people to join %(communityName)s": "Lade Leute ein %(communityName)s beizutreten",
+ "An image will help people identify your community.": "Ein Bild hilft anderen, deine Community zu Identifizieren.",
+ "Use this when referencing your community to others. The community ID cannot be changed.": "Verwende dies, um deine Community von andere referenzieren zu lassen. Die Community-ID kann später nicht geändert werden.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "Private Räume können nur auf Einladung gefunden und betreten werden. Öffentliche Räume können von jedem/r gefunden und betreten werden.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "Private Räume können nur auf Einladung gefunden und betreten werden. Öffentliche Räume können von jedem/r in dieser Community gefunden und betreten werden.",
+ "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "Du solltest dies aktivieren, wenn der Raum nur für die Zusammenarbeit mit internen Teams auf deinem Heimserver verwendet wird. Dies kann später nicht mehr geändert werden.",
+ "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.": "Du solltest dies deaktivieren, wenn der Raum für die Zusammenarbeit mit externen Teams auf deren Home-Server verwendet wird. Dies kann später nicht mehr geändert werden.",
+ "Block anyone not part of %(serverName)s from ever joining this room.": "Blockiere alle, die nicht Teil von %(serverName)s sind, diesen Raum jemals zu betreten.",
+ "Privacy": "Privatsphäre",
+ "There was an error updating your community. The server is unable to process your request.": "Beim Aktualisieren deiner Community ist ein Fehler aufgetreten. Der Server kann deine Anfrage nicht verarbeiten.",
+ "Update community": "Community aktualisieren",
+ "May include members not in %(communityName)s": "Kann Mitglieder enthalten, die nicht in %(communityName)s enthalten sind",
+ "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.": "Starte ein Gespräch mit jemandem unter Verwendung seines/ihres Namens, Nutzernamens (wie ) oder E-Mail-Adresse. Dadurch werden sie nicht zu %(communityName)s eingeladen. Klicke hier hier, um jemanden zu %(communityName)s einzuladen.",
+ "Failed to find the general chat for this community": "Der allgemeine Chat für diese Community konnte nicht gefunden werden",
+ "Community settings": "Community-Einstellungen",
+ "User settings": "Nutzer-Einstellungen",
+ "Community and user menu": "Community- und Nutzer-Menü",
+ "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Stellt ( ͡° ͜ʖ ͡°) einer Klartextnachricht voran"
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 8bfc3ed703..d7360430ae 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -50,7 +50,10 @@
"You cannot place a call with yourself.": "You cannot place a call with yourself.",
"Call in Progress": "Call in Progress",
"A call is currently being placed!": "A call is currently being placed!",
- "A call is already in progress!": "A call is already in progress!",
+ "End Call": "End Call",
+ "Remove the group call from the room?": "Remove the group call from the room?",
+ "Cancel": "Cancel",
+ "You don't have permission to remove the call from the room": "You don't have permission to remove the call from the room",
"Permission Required": "Permission Required",
"You do not have permission to start a conference call in this room": "You do not have permission to start a conference call in this room",
"Replying With Files": "Replying With Files",
@@ -62,11 +65,6 @@
"Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
"The server does not support the room version specified.": "The server does not support the room version specified.",
"Failure to create room": "Failure to create room",
- "Cancel entering passphrase?": "Cancel entering passphrase?",
- "Are you sure you want to cancel entering passphrase?": "Are you sure you want to cancel entering passphrase?",
- "Go Back": "Go Back",
- "Cancel": "Cancel",
- "Setting up keys": "Setting up keys",
"Sun": "Sun",
"Mon": "Mon",
"Tue": "Tue",
@@ -142,6 +140,10 @@
"Missing room_id in request": "Missing room_id in request",
"Room %(roomId)s not visible": "Room %(roomId)s not visible",
"Missing user_id in request": "Missing user_id in request",
+ "Cancel entering passphrase?": "Cancel entering passphrase?",
+ "Are you sure you want to cancel entering passphrase?": "Are you sure you want to cancel entering passphrase?",
+ "Go Back": "Go Back",
+ "Setting up keys": "Setting up keys",
"Messages": "Messages",
"Actions": "Actions",
"Advanced": "Advanced",
@@ -149,6 +151,7 @@
"Command error": "Command error",
"Usage": "Usage",
"Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Prepends ¯\\_(ツ)_/¯ to a plain-text message",
+ "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message",
"Sends a message as plain text, without interpreting it as markdown": "Sends a message as plain text, without interpreting it as markdown",
"Sends a message as html, without interpreting it as markdown": "Sends a message as html, without interpreting it as markdown",
"Searches DuckDuckGo for results": "Searches DuckDuckGo for results",
@@ -205,8 +208,6 @@
"Displays list of commands with usages and descriptions": "Displays list of commands with usages and descriptions",
"Displays information about a user": "Displays information about a user",
"Send a bug report with logs": "Send a bug report with logs",
- "Logs sent": "Logs sent",
- "Thank you!": "Thank you!",
"Opens chat with the given user": "Opens chat with the given user",
"Sends a message to the given user": "Sends a message to the given user",
"Displays action": "Displays action",
@@ -279,6 +280,9 @@
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
+ "Group call modified by %(senderName)s": "Group call modified by %(senderName)s",
+ "Group call started by %(senderName)s": "Group call started by %(senderName)s",
+ "Group call ended by %(senderName)s": "Group call ended by %(senderName)s",
"%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s removed the rule banning users matching %(glob)s",
"%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s removed the rule banning rooms matching %(glob)s",
"%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s removed the rule banning servers matching %(glob)s",
@@ -347,6 +351,10 @@
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
"Not a valid %(brand)s keyfile": "Not a valid %(brand)s keyfile",
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
+ "Unexpected server error trying to leave the room": "Unexpected server error trying to leave the room",
+ "Can't leave Server Notices room": "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.",
+ "Error leaving room": "Error leaving room",
"Unrecognised address": "Unrecognised address",
"You do not have permission to invite people to this room.": "You do not have permission to invite people to this room.",
"User %(userId)s is already in the room": "User %(userId)s is already in the room",
@@ -382,6 +390,7 @@
"Common names and surnames are easy to guess": "Common names and surnames are easy to guess",
"Straight rows of keys are easy to guess": "Straight rows of keys are easy to guess",
"Short keyboard patterns are easy to guess": "Short keyboard patterns are easy to guess",
+ "Unknown App": "Unknown App",
"Help us improve %(brand)s": "Help us improve %(brand)s",
"Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.",
"I want to help": "I want to help",
@@ -402,13 +411,12 @@
"Set password": "Set password",
"To return to your account in future you need to set a password": "To return to your account in future you need to set a password",
"Set Password": "Set Password",
- "Set up encryption": "Set up encryption",
+ "Set up Secure Backup": "Set up Secure Backup",
"Encryption upgrade available": "Encryption upgrade available",
"Verify this session": "Verify this session",
- "Set up": "Set up",
"Upgrade": "Upgrade",
"Verify": "Verify",
- "Verify yourself & others to keep your chats safe": "Verify yourself & others to keep your chats safe",
+ "Safeguard against losing access to encrypted messages & data": "Safeguard against losing access to encrypted messages & data",
"Other users may not trust it": "Other users may not trust it",
"New login. Was this you?": "New login. Was this you?",
"Verify the new login accessing your account: %(name)s": "Verify the new login accessing your account: %(name)s",
@@ -440,6 +448,7 @@
"%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s",
"%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s",
"Change notification settings": "Change notification settings",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.",
"New spinner design": "New spinner design",
"Message Pinning": "Message Pinning",
"Custom user status messages": "Custom user status messages",
@@ -464,8 +473,6 @@
"Show timestamps in 12 hour format (e.g. 2:30pm)": "Show timestamps in 12 hour format (e.g. 2:30pm)",
"Always show message timestamps": "Always show message timestamps",
"Autoplay GIFs and videos": "Autoplay GIFs and videos",
- "Always show encryption icons": "Always show encryption icons",
- "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Show a reminder to enable Secure Message Recovery in encrypted rooms",
"Enable automatic language detection for syntax highlighting": "Enable automatic language detection for syntax highlighting",
"Show avatars in user and room mentions": "Show avatars in user and room mentions",
"Enable big emoji in chat": "Enable big emoji in chat",
@@ -640,26 +647,22 @@
"Confirm password": "Confirm password",
"Change Password": "Change Password",
"Your homeserver does not support cross-signing.": "Your homeserver does not support cross-signing.",
- "Cross-signing and secret storage are enabled.": "Cross-signing and secret storage are enabled.",
+ "Cross-signing is ready for use.": "Cross-signing is ready for use.",
"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.": "Cross-signing and secret storage are not yet set up.",
- "Reset cross-signing and secret storage": "Reset cross-signing and secret storage",
- "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage",
- "well formed": "well formed",
- "unexpected type": "unexpected type",
+ "Cross-signing is not set up.": "Cross-signing is not set up.",
+ "Set up": "Set up",
+ "Reset": "Reset",
"Cross-signing public keys:": "Cross-signing public keys:",
"in memory": "in memory",
"not found": "not found",
"Cross-signing private keys:": "Cross-signing private keys:",
"in secret storage": "in secret storage",
+ "not found in storage": "not found in storage",
"Master private key:": "Master private key:",
"cached locally": "cached locally",
"not found locally": "not found locally",
"Self signing private key:": "Self signing private key:",
"User signing private key:": "User signing private key:",
- "Session backup key:": "Session backup key:",
- "Secret storage public key:": "Secret storage public key:",
- "in account data": "in account data",
"Homeserver feature support:": "Homeserver feature support:",
"exists": "exists",
"Your homeserver does not support session management.": "Your homeserver does not support session management.",
@@ -678,6 +681,7 @@
"Public Name": "Public Name",
"Last seen": "Last seen",
"Failed to set display name": "Failed to set display name",
+ "Encryption": "Encryption",
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
"Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ",
" to store messages from ": " to store messages from ",
@@ -690,36 +694,6 @@
"Connecting to integration manager...": "Connecting to integration manager...",
"Cannot connect to integration manager": "Cannot connect to integration manager",
"The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.",
- "Delete Backup": "Delete Backup",
- "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "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.": "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": "Unable to load key backup status",
- "Restore from Backup": "Restore from Backup",
- "This session is backing up your keys. ": "This session is backing up your keys. ",
- "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.",
- "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 before signing out to avoid losing any keys that may only be on this session.",
- "Connect this session to Key Backup": "Connect this session to Key Backup",
- "not stored": "not stored",
- "Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
- "All keys backed up": "All keys backed up",
- "Backup has a valid signature from this user": "Backup has a valid signature from this user",
- "Backup has a invalid signature from this user": "Backup has a invalid signature from this user",
- "Backup has a signature from unknown user with ID %(deviceId)s": "Backup has a signature from unknown user with ID %(deviceId)s",
- "Backup has a signature from unknown session with ID %(deviceId)s": "Backup has a signature from unknown session with ID %(deviceId)s",
- "Backup has a valid signature from this session": "Backup has a valid signature from this session",
- "Backup has an invalid signature from this session": "Backup has an invalid signature from this session",
- "Backup has a valid signature from verified session ": "Backup has a valid signature from verified session ",
- "Backup has a valid signature from unverified session ": "Backup has a valid signature from unverified session ",
- "Backup has an invalid signature from verified session ": "Backup has an invalid signature from verified session ",
- "Backup has an invalid signature from unverified 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": "This backup is trusted because it has been restored on this session",
- "Backup version: ": "Backup version: ",
- "Algorithm: ": "Algorithm: ",
- "Backup key stored: ": "Backup key stored: ",
- "Your keys are not being backed up from this session.": "Your keys are not being backed up from this session.",
- "Back up your keys before signing out to avoid losing them.": "Back up your keys before signing out to avoid losing them.",
- "Start using Key Backup": "Start using Key Backup",
"Error saving email notification preferences": "Error saving email notification preferences",
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
"Keywords": "Keywords",
@@ -751,6 +725,43 @@
"Display Name": "Display Name",
"Profile picture": "Profile picture",
"Save": "Save",
+ "Delete Backup": "Delete Backup",
+ "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.",
+ "Unable to load key backup status": "Unable to load key backup status",
+ "Restore from Backup": "Restore from Backup",
+ "This session is backing up your keys. ": "This session is backing up your keys. ",
+ "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.",
+ "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 before signing out to avoid losing any keys that may only be on this session.",
+ "Connect this session to Key Backup": "Connect this session to Key Backup",
+ "Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
+ "All keys backed up": "All keys backed up",
+ "Backup has a valid signature from this user": "Backup has a valid signature from this user",
+ "Backup has a invalid signature from this user": "Backup has a invalid signature from this user",
+ "Backup has a signature from unknown user with ID %(deviceId)s": "Backup has a signature from unknown user with ID %(deviceId)s",
+ "Backup has a signature from unknown session with ID %(deviceId)s": "Backup has a signature from unknown session with ID %(deviceId)s",
+ "Backup has a valid signature from this session": "Backup has a valid signature from this session",
+ "Backup has an invalid signature from this session": "Backup has an invalid signature from this session",
+ "Backup has a valid signature from verified session ": "Backup has a valid signature from verified session ",
+ "Backup has a valid signature from unverified session ": "Backup has a valid signature from unverified session ",
+ "Backup has an invalid signature from verified session ": "Backup has an invalid signature from verified session ",
+ "Backup has an invalid signature from unverified 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": "This backup is trusted because it has been restored on this session",
+ "Backup version:": "Backup version:",
+ "Algorithm:": "Algorithm:",
+ "Your keys are not being backed up from this session.": "Your keys are not being backed up from this session.",
+ "Back up your keys before signing out to avoid losing them.": "Back up your keys before signing out to avoid losing them.",
+ "well formed": "well formed",
+ "unexpected type": "unexpected type",
+ "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 Recovery 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 Recovery Key.",
+ "Backup key stored:": "Backup key stored:",
+ "not stored": "not stored",
+ "Backup key cached:": "Backup key cached:",
+ "Secret storage public key:": "Secret storage public key:",
+ "in account data": "in account data",
+ "Secret storage:": "Secret storage:",
+ "ready": "ready",
+ "not ready": "not ready",
"Identity Server URL must be HTTPS": "Identity Server URL must be HTTPS",
"Not a valid Identity Server (status code %(code)s)": "Not a valid Identity Server (status code %(code)s)",
"Could not connect to Identity Server": "Could not connect to Identity Server",
@@ -821,20 +832,19 @@
"Account management": "Account management",
"Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!",
"Deactivate Account": "Deactivate Account",
- "General": "General",
- "Discovery": "Discovery",
"Deactivate account": "Deactivate account",
+ "Discovery": "Discovery",
+ "General": "General",
"Legal": "Legal",
"Credits": "Credits",
"For help with using %(brand)s, click here.": "For help with using %(brand)s, click here.",
"For help with using %(brand)s, click here or start a chat with our bot using the button below.": "For help with using %(brand)s, click here or start a chat with our bot using the button below.",
"Chat with %(brand)s Bot": "Chat with %(brand)s Bot",
- "Help & About": "Help & About",
"Bug reporting": "Bug reporting",
"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.": "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.",
"Submit debug logs": "Submit debug logs",
- "Clear cache and reload": "Clear cache and reload",
"To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.",
+ "Help & About": "Help & About",
"FAQ": "FAQ",
"Keyboard Shortcuts": "Keyboard Shortcuts",
"Versions": "Versions",
@@ -844,6 +854,7 @@
"Identity Server is": "Identity Server is",
"Access Token:": "Access Token:",
"click to reveal": "click to reveal",
+ "Clear cache and reload": "Clear cache and reload",
"Labs": "Labs",
"Customise your experience with experimental labs features. Learn more.": "Customise your experience with experimental labs features. Learn more.",
"Ignored/Blocked": "Ignored/Blocked",
@@ -897,17 +908,17 @@
"Bulk options": "Bulk options",
"Accept all %(invitedRooms)s invites": "Accept all %(invitedRooms)s invites",
"Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites",
- "Key backup": "Key backup",
+ "Secure Backup": "Secure Backup",
"Message search": "Message search",
"Cross-signing": "Cross-signing",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.",
- "Security & Privacy": "Security & Privacy",
- "Where you’re logged in": "Where you’re logged in",
- "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Manage the names of and sign out of your sessions below or verify them in your User Profile.",
- "A session's public name is visible to people you communicate with": "A session's public name is visible to people you communicate with",
+ "Privacy": "Privacy",
"%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s collects anonymous analytics to allow us to improve the application.",
"Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "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.": "Learn more about how we use analytics.",
+ "Where you’re logged in": "Where you’re logged in",
+ "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Manage the names of and sign out of your sessions below or verify them in your User Profile.",
+ "A session's public name is visible to people you communicate with": "A session's public name is visible to people you communicate with",
"No media permissions": "No media permissions",
"You may need to manually permit %(brand)s to access your microphone/webcam": "You may need to manually permit %(brand)s to access your microphone/webcam",
"Missing media permissions, click the button below to request.": "Missing media permissions, click the button below to request.",
@@ -934,12 +945,11 @@
"This room is bridging messages to the following platforms. Learn more.": "This room is bridging messages to the following platforms. Learn more.",
"This room isn’t bridging messages to any platforms. Learn more.": "This room isn’t bridging messages to any platforms. Learn more.",
"Bridges": "Bridges",
- "Room Addresses": "Room Addresses",
"URL Previews": "URL Previews",
+ "Room Addresses": "Room Addresses",
"Uploaded sound": "Uploaded sound",
"Sounds": "Sounds",
"Notification sound": "Notification sound",
- "Reset": "Reset",
"Set a new custom sound": "Set a new custom sound",
"Browse": "Browse",
"Change room avatar": "Change room avatar",
@@ -987,7 +997,7 @@
"Members only (since the point in time of selecting this option)": "Members only (since the point in time of selecting this option)",
"Members only (since they were invited)": "Members only (since they were invited)",
"Members only (since they joined)": "Members only (since they joined)",
- "Encryption": "Encryption",
+ "Security & Privacy": "Security & Privacy",
"Once enabled, encryption cannot be disabled.": "Once enabled, encryption cannot be disabled.",
"Encrypted": "Encrypted",
"Who can access this room?": "Who can access this room?",
@@ -1020,8 +1030,6 @@
"Remove %(phone)s?": "Remove %(phone)s?",
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.",
"Phone Number": "Phone Number",
- "Cannot add any more widgets": "Cannot add any more widgets",
- "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.",
"Add a widget": "Add a widget",
"Drop File Here": "Drop File Here",
"Drop file here to upload": "Drop file here to upload",
@@ -1056,6 +1064,7 @@
"and %(count)s others...|other": "and %(count)s others...",
"and %(count)s others...|one": "and one other...",
"Invite to this room": "Invite to this room",
+ "Invite to this community": "Invite to this community",
"Invited": "Invited",
"Filter room members": "Filter room members",
"%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (power %(powerLevelNumber)s)",
@@ -1105,10 +1114,8 @@
"(~%(count)s results)|other": "(~%(count)s results)",
"(~%(count)s results)|one": "(~%(count)s result)",
"Join Room": "Join Room",
- "Settings": "Settings",
"Forget room": "Forget room",
"Search": "Search",
- "Share room": "Share room",
"Invites": "Invites",
"Favourites": "Favourites",
"People": "People",
@@ -1116,6 +1123,7 @@
"Rooms": "Rooms",
"Add room": "Add room",
"Create new room": "Create new room",
+ "Explore community rooms": "Explore community rooms",
"Explore public rooms": "Explore public rooms",
"Low priority": "Low priority",
"System Alerts": "System Alerts",
@@ -1124,6 +1132,7 @@
"Can't see what you’re looking for?": "Can't see what you’re looking for?",
"Explore all public rooms": "Explore all public rooms",
"%(count)s results|other": "%(count)s results",
+ "%(count)s results|one": "%(count)s result",
"This room": "This room",
"Joining room …": "Joining room …",
"Loading …": "Loading …",
@@ -1162,11 +1171,6 @@
"%(roomName)s is not accessible at this time.": "%(roomName)s is not accessible at this time.",
"Try again later, or ask a room admin to check if you have access.": "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 was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.",
- "Never lose encrypted messages": "Never lose encrypted messages",
- "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
- "Securely back up your keys to avoid losing them. Learn more.": "Securely back up your keys to avoid losing them. Learn more.",
- "Not now": "Not now",
- "Don't ask me again": "Don't ask me again",
"Appearance": "Appearance",
"Show rooms with unread messages first": "Show rooms with unread messages first",
"Show previews of messages": "Show previews of messages",
@@ -1186,6 +1190,7 @@
"Favourited": "Favourited",
"Favourite": "Favourite",
"Low Priority": "Low Priority",
+ "Settings": "Settings",
"Leave Room": "Leave Room",
"Room options": "Room options",
"%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.",
@@ -1193,7 +1198,6 @@
"%(count)s unread messages.|other": "%(count)s unread messages.",
"%(count)s unread messages.|one": "1 unread message.",
"Unread messages.": "Unread messages.",
- "Add a topic": "Add a topic",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.",
"This room has already been upgraded.": "This room has already been upgraded.",
"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.",
@@ -1257,6 +1261,7 @@
"URL previews are disabled by default for participants in this room.": "URL previews are disabled by default for participants in this room.",
"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.": "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.",
"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.": "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.",
+ "Back": "Back",
"Waiting for you to accept on your other session…": "Waiting for you to accept on your other session…",
"Waiting for %(displayName)s to accept…": "Waiting for %(displayName)s to accept…",
"Accepting…": "Accepting…",
@@ -1274,7 +1279,18 @@
"Yours, or the other users’ internet connection": "Yours, or the other users’ internet connection",
"Yours, or the other users’ session": "Yours, or the other users’ session",
"Members": "Members",
- "Files": "Files",
+ "Room Info": "Room Info",
+ "Widgets": "Widgets",
+ "Unpin app": "Unpin app",
+ "Edit widgets, bridges & bots": "Edit widgets, bridges & bots",
+ "Add widgets, bridges & bots": "Add widgets, bridges & bots",
+ "Not encrypted": "Not encrypted",
+ "About": "About",
+ "%(count)s people|other": "%(count)s people",
+ "%(count)s people|one": "%(count)s person",
+ "Show files": "Show files",
+ "Share room": "Share room",
+ "Room settings": "Room settings",
"Trusted": "Trusted",
"Not trusted": "Not trusted",
"%(count)s verified sessions|other": "%(count)s verified sessions",
@@ -1352,6 +1368,12 @@
"You cancelled verification.": "You cancelled verification.",
"Verification cancelled": "Verification cancelled",
"Compare emoji": "Compare emoji",
+ "Take a picture": "Take a picture",
+ "Remove for everyone": "Remove for everyone",
+ "Remove for me": "Remove for me",
+ "Edit": "Edit",
+ "Pin to room": "Pin to room",
+ "You can only pin 2 widgets at a time": "You can only pin 2 widgets at a time",
"Sunday": "Sunday",
"Monday": "Monday",
"Tuesday": "Tuesday",
@@ -1369,7 +1391,6 @@
"Error decrypting audio": "Error decrypting audio",
"React": "React",
"Reply": "Reply",
- "Edit": "Edit",
"Message Actions": "Message Actions",
"Attachment": "Attachment",
"Error decrypting attachment": "Error decrypting attachment",
@@ -1413,11 +1434,10 @@
"Click to view edits": "Click to view edits",
"Edited at %(date)s. Click to view edits.": "Edited at %(date)s. Click to view edits.",
"edited": "edited",
- "Can't load this message": "Can't load this message",
"Submit logs": "Submit logs",
+ "Can't load this message": "Can't load this message",
"Failed to load group members": "Failed to load group members",
"Filter community members": "Filter community members",
- "Invite to this community": "Invite to this community",
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?",
"Removing a room from the community will also remove it from the community page.": "Removing a room from the community will also remove it from the community page.",
"Failed to remove room from community": "Failed to remove room from community",
@@ -1463,8 +1483,8 @@
"Delete widget": "Delete widget",
"Failed to remove widget": "Failed to remove widget",
"An error ocurred whilst trying to remove the widget from the room": "An error ocurred whilst trying to remove the widget from the room",
- "Minimize apps": "Minimize apps",
- "Maximize apps": "Maximize apps",
+ "Minimize widget": "Minimize widget",
+ "Maximize widget": "Maximize widget",
"Popout widget": "Popout widget",
"More options": "More options",
"Join": "Join",
@@ -1479,8 +1499,8 @@
"Rotate Right": "Rotate Right",
"Rotate clockwise": "Rotate clockwise",
"Download this file": "Download this file",
+ "Information": "Information",
"Language Dropdown": "Language Dropdown",
- "Manage Integrations": "Manage Integrations",
"%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s",
"%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)sjoined %(count)s times",
"%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sjoined",
@@ -1548,8 +1568,7 @@
"Room directory": "Room directory",
"Sign in with single sign-on": "Sign in with single sign-on",
"And %(count)s more...|other": "And %(count)s more...",
- "ex. @bob:example.com": "ex. @bob:example.com",
- "Add User": "Add User",
+ "Home": "Home",
"Enter a server name": "Enter a server name",
"Looks good": "Looks good",
"Can't find this server or its room list": "Can't find this server or its room list",
@@ -1579,6 +1598,8 @@
"Close dialog": "Close dialog",
"Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.",
"Preparing to send logs": "Preparing to send logs",
+ "Logs sent": "Logs sent",
+ "Thank you!": "Thank you!",
"Failed to send logs: ": "Failed to send logs: ",
"Preparing to download logs": "Preparing to download logs",
"Reminder: Your browser is unsupported, so your experience may be unpredictable.": "Reminder: Your browser is unsupported, so your experience may be unpredictable.",
@@ -1592,16 +1613,31 @@
"Unable to load commit detail: %(msg)s": "Unable to load commit detail: %(msg)s",
"Unavailable": "Unavailable",
"Changelog": "Changelog",
+ "Email address": "Email address",
+ "Add another email": "Add another email",
+ "People you know on %(brand)s": "People you know on %(brand)s",
+ "Hide": "Hide",
+ "Show": "Show",
+ "Skip": "Skip",
+ "Send %(count)s invites|other": "Send %(count)s invites",
+ "Send %(count)s invites|one": "Send %(count)s invite",
+ "Invite people to join %(communityName)s": "Invite people to join %(communityName)s",
"You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)",
"Removing…": "Removing…",
- "Destroy cross-signing keys?": "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 cross-signing keys",
"Confirm Removal": "Confirm Removal",
"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.": "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.",
"Clear all data in this session?": "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.": "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.",
"Clear all data": "Clear all data",
+ "There was an error creating your community. The name may be taken or the server is unable to process your request.": "There was an error creating your community. The name may be taken or the server is unable to process your request.",
+ "Community ID: +:%(domain)s": "Community ID: +:%(domain)s",
+ "Use this when referencing your community to others. The community ID cannot be changed.": "Use this when referencing your community to others. The community ID cannot be changed.",
+ "You can change this later if needed.": "You can change this later if needed.",
+ "What's the name of your community or team?": "What's the name of your community or team?",
+ "Enter name": "Enter name",
+ "Create": "Create",
+ "Add image (optional)": "Add image (optional)",
+ "An image will help people identify your community.": "An image will help people identify your community.",
"Community IDs cannot be empty.": "Community IDs cannot be empty.",
"Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Community IDs may only contain characters a-z, 0-9, or '=_-./'",
"Something went wrong whilst creating your community": "Something went wrong whilst creating your community",
@@ -1610,20 +1646,23 @@
"Example": "Example",
"Community ID": "Community ID",
"example": "example",
- "Create": "Create",
"Please enter a name for the room": "Please enter a name for the room",
- "Set a room address to easily share your room with other people.": "Set a room address to easily share your room with other people.",
- "This room is private, and can only be joined by invitation.": "This room is private, and can only be joined by invitation.",
+ "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.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.",
"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.",
+ "Your server requires encryption to be enabled in private rooms.": "Your server requires encryption to be enabled in private rooms.",
"Enable end-to-end encryption": "Enable end-to-end encryption",
+ "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.",
+ "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.": "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.",
"Create a public room": "Create a public room",
"Create a private room": "Create a private room",
+ "Create a room in %(communityName)s": "Create a room in %(communityName)s",
"Name": "Name",
"Topic (optional)": "Topic (optional)",
"Make this room public": "Make this room public",
"Hide advanced": "Hide advanced",
"Show advanced": "Show advanced",
- "Block users on other matrix homeservers from joining this room (This setting cannot be changed later!)": "Block users on other matrix homeservers from joining this room (This setting cannot be changed later!)",
+ "Block anyone not part of %(serverName)s from ever joining this room.": "Block anyone not part of %(serverName)s from ever joining this room.",
"Create Room": "Create Room",
"Sign out": "Sign out",
"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": "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",
@@ -1641,7 +1680,6 @@
"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.": "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.": "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.",
"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)": "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)",
- "Back": "Back",
"Send": "Send",
"Send Custom Event": "Send Custom Event",
"You must specify an event type!": "You must specify an event type!",
@@ -1658,6 +1696,8 @@
"Verification Requests": "Verification Requests",
"Toolbox": "Toolbox",
"Developer Tools": "Developer Tools",
+ "There was an error updating your community. The server is unable to process your request.": "There was an error updating your community. The server is unable to process your request.",
+ "Update community": "Update community",
"An error has occurred.": "An error has occurred.",
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you 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.": "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
@@ -1680,11 +1720,15 @@
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s",
"Recent Conversations": "Recent Conversations",
"Suggestions": "Suggestions",
+ "May include members not in %(communityName)s": "May include members not in %(communityName)s",
"Recently Direct Messaged": "Recently Direct Messaged",
"Direct Messages": "Direct Messages",
"Start a conversation with someone using their name, username (like ) or email address.": "Start a conversation with someone using their name, username (like ) or email address.",
+ "Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).",
+ "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here",
"Go": "Go",
"Invite someone using their name, username (like ), email address or share this room.": "Invite someone using their name, username (like ), email address or share this room.",
+ "Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.",
"a new master key signature": "a new master key signature",
"a new cross-signing key signature": "a new cross-signing key signature",
"a device cross-signing signature": "a device cross-signing signature",
@@ -1701,6 +1745,8 @@
"Clear cache and resync": "Clear cache and resync",
"%(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 now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!",
"Updating %(brand)s": "Updating %(brand)s",
+ "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
+ "Start using Key Backup": "Start using Key Backup",
"I don't want my encrypted messages": "I don't want my encrypted messages",
"Manually export keys": "Manually export keys",
"You'll lose access to your encrypted messages": "You'll lose access to your encrypted messages",
@@ -1769,9 +1815,7 @@
"Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.",
"Verification Pending": "Verification Pending",
"Please check your email and click on the link it contains. Once this is done, click continue.": "Please check your email and click on the link it contains. Once this is done, click continue.",
- "Email address": "Email address",
"This will allow you to reset your password and receive notifications.": "This will allow you to reset your password and receive notifications.",
- "Skip": "Skip",
"A username can only contain lower case letters, numbers and '=_-./'": "A username can only contain lower case letters, numbers and '=_-./'",
"Username not available": "Username not available",
"Username invalid: %(errMessage)s": "Username invalid: %(errMessage)s",
@@ -1836,6 +1880,13 @@
"Enter your Security Phrase or to continue.": "Enter your Security Phrase or to continue.",
"Security Key": "Security Key",
"Use your Security Key to continue.": "Use your Security Key to continue.",
+ "Destroy cross-signing keys?": "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 cross-signing keys",
+ "Confirm encryption setup": "Confirm encryption setup",
+ "Click the button below to confirm setting up encryption.": "Click the button below to confirm setting up encryption.",
+ "Unable to set up keys": "Unable to set up keys",
+ "Retry": "Retry",
"Restoring keys from backup": "Restoring keys from backup",
"Fetching keys from server...": "Fetching keys from server...",
"%(completed)s of %(total)s keys restored": "%(completed)s of %(total)s keys restored",
@@ -1859,10 +1910,6 @@
"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 key.": "Access your secure message history and set up secure messaging by entering your recovery key.",
"If you've forgotten your recovery key you can ": "If you've forgotten your recovery key you can ",
- "Private Chat": "Private Chat",
- "Public Chat": "Public Chat",
- "Custom": "Custom",
- "Address (optional)": "Address (optional)",
"Reject invitation": "Reject invitation",
"Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?",
"Unable to reject invite": "Unable to reject invite",
@@ -1879,27 +1926,14 @@
"Source URL": "Source URL",
"Collapse Reply Thread": "Collapse Reply Thread",
"Report Content": "Report Content",
- "Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
- "Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
- "Notification settings": "Notification settings",
- "All messages (noisy)": "All messages (noisy)",
- "Mentions only": "Mentions only",
- "Leave": "Leave",
- "Forget": "Forget",
- "Direct Chat": "Direct Chat",
"Clear status": "Clear status",
"Update status": "Update status",
"Set status": "Set status",
"Set a new status...": "Set a new status...",
"View Community": "View Community",
- "Hide": "Hide",
- "Home": "Home",
- "Sign in": "Sign in",
- "Help": "Help",
+ "Unpin": "Unpin",
"Reload": "Reload",
"Take picture": "Take picture",
- "Remove for everyone": "Remove for everyone",
- "Remove for me": "Remove for me",
"This room is public": "This room is public",
"Away": "Away",
"User Status": "User Status",
@@ -1936,6 +1970,7 @@
"Phone": "Phone",
"Not sure of your password? Set a new one": "Not sure of your password? Set a new one",
"Sign in with": "Sign in with",
+ "Sign in": "Sign in",
"No identity server is configured so you cannot add an email address in order to reset your password in the future.": "No identity server is configured so you cannot add an email address in order to reset your password in the future.",
"If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?",
"Use an email address to recover your account": "Use an email address to recover your account",
@@ -1967,11 +2002,6 @@
"Sign in to your Matrix account on %(serverName)s": "Sign in to your Matrix account on %(serverName)s",
"Sign in to your Matrix account on ": "Sign in to your Matrix account on ",
"Sign in with SSO": "Sign in with SSO",
- "Sorry, your browser is not able to run %(brand)s.": "Sorry, your browser is not able to run %(brand)s.",
- "%(brand)s uses many advanced browser features, some of which are not available or experimental in your current browser.": "%(brand)s uses many advanced browser features, some of which are not available or experimental in your current browser.",
- "Please install Chrome, Firefox, or Safari for the best experience.": "Please install Chrome, Firefox, or Safari for the best experience.",
- "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!",
- "I understand the risks and wish to continue": "I understand the risks and wish to continue",
"Couldn't load page": "Couldn't load page",
"You must register to use this functionality": "You must register to use this functionality",
"You must join the room to see its files": "You must join the room to see its files",
@@ -1998,6 +2028,7 @@
"You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.",
"Leave Community": "Leave Community",
"Leave %(groupName)s?": "Leave %(groupName)s?",
+ "Leave": "Leave",
"Unable to leave community": "Unable to leave community",
"Community Settings": "Community Settings",
"Want more than a community? Get your own server": "Want more than a community? Get your own server",
@@ -2028,10 +2059,7 @@
"Failed to reject invitation": "Failed to reject invitation",
"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.",
"Are you sure you want to leave the room '%(roomName)s'?": "Are you sure you want to leave the room '%(roomName)s'?",
- "Failed to leave room": "Failed to leave room",
- "Can't leave Server Notices room": "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.",
- "Unknown error": "Unknown error",
+ "Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
"Signed Out": "Signed Out",
"For security, this session has been signed out. Please sign in again.": "For security, this session has been signed out. Please sign in again.",
"Terms and Conditions": "Terms and Conditions",
@@ -2071,6 +2099,7 @@
"Find a room…": "Find a room…",
"Find a room… (e.g. %(exampleRoom)s)": "Find a room… (e.g. %(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.",
+ "Explore rooms in %(communityName)s": "Explore rooms in %(communityName)s",
"Clear filter": "Clear filter",
"Search rooms": "Search rooms",
"You can't send any messages until you review and agree to our terms and conditions.": "You can't send any messages until you review and agree to our terms and conditions.",
@@ -2097,19 +2126,25 @@
"Click to mute video": "Click to mute video",
"Click to unmute audio": "Click to unmute audio",
"Click to mute audio": "Click to mute audio",
+ "Create community": "Create community",
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.",
"Failed to load timeline position": "Failed to load timeline position",
"Uploading %(filename)s and %(count)s others|other": "Uploading %(filename)s and %(count)s others",
"Uploading %(filename)s and %(count)s others|zero": "Uploading %(filename)s",
"Uploading %(filename)s and %(count)s others|one": "Uploading %(filename)s and %(count)s other",
+ "Failed to find the general chat for this community": "Failed to find the general chat for this community",
+ "Feedback": "Feedback",
+ "Notification settings": "Notification settings",
+ "Security & privacy": "Security & privacy",
+ "All settings": "All settings",
+ "Community settings": "Community settings",
+ "User settings": "User settings",
"Switch to light mode": "Switch to light mode",
"Switch to dark mode": "Switch to dark mode",
"Switch theme": "Switch theme",
- "Security & privacy": "Security & privacy",
- "All settings": "All settings",
- "Feedback": "Feedback",
"User menu": "User menu",
+ "Community and user menu": "Community and user menu",
"Could not load user profile": "Could not load user profile",
"Verify this login": "Verify this login",
"Session verified": "Session verified",
@@ -2201,21 +2236,36 @@
"Room Autocomplete": "Room Autocomplete",
"Users": "Users",
"User Autocomplete": "User Autocomplete",
- "Passphrases must match": "Passphrases must match",
- "Passphrase must not be empty": "Passphrase must not be empty",
- "Export room keys": "Export room keys",
- "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.",
- "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 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.",
- "Enter passphrase": "Enter passphrase",
- "Confirm passphrase": "Confirm passphrase",
- "Export": "Export",
- "Import room keys": "Import room keys",
- "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.",
- "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
- "File to import": "File to import",
- "Import": "Import",
- "Confirm encryption setup": "Confirm encryption setup",
- "Click the button below to confirm setting up encryption.": "Click the button below to confirm setting up encryption.",
+ "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.",
+ "For maximum security, this should be different from your account password.": "For maximum security, this should be different from your account password.",
+ "Enter a recovery passphrase": "Enter a recovery passphrase",
+ "Great! This recovery passphrase looks strong enough.": "Great! This recovery passphrase looks strong enough.",
+ "Set up with a recovery key": "Set up with a recovery key",
+ "That matches!": "That matches!",
+ "Use a different passphrase?": "Use a different passphrase?",
+ "That doesn't match.": "That doesn't match.",
+ "Go back to set it again.": "Go back to set it again.",
+ "Please enter your recovery passphrase a second time to confirm.": "Please enter your recovery passphrase a second time to confirm.",
+ "Repeat your recovery passphrase...": "Repeat your recovery passphrase...",
+ "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.": "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.",
+ "Keep a copy of it somewhere secure, like a password manager or even a safe.": "Keep a copy of it somewhere secure, like a password manager or even a safe.",
+ "Your recovery key": "Your recovery key",
+ "Download": "Download",
+ "Your recovery key has been copied to your clipboard, paste it to:": "Your recovery key has been copied to your clipboard, paste it to:",
+ "Your recovery key is in your Downloads folder.": "Your recovery key is in your Downloads folder.",
+ "Print it and store it somewhere safe": "Print it and store it somewhere safe",
+ "Save it on a USB key or backup drive": "Save it on a USB key or backup drive",
+ "Copy it to your personal cloud storage": "Copy it to your personal cloud storage",
+ "Your keys are being backed up (the first backup could take a few minutes).": "Your keys are being backed up (the first backup could take a few minutes).",
+ "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.",
+ "Set up Secure Message Recovery": "Set up Secure Message Recovery",
+ "Secure your backup with a recovery passphrase": "Secure your backup with a recovery passphrase",
+ "Confirm your recovery passphrase": "Confirm your recovery passphrase",
+ "Make a copy of your recovery key": "Make a copy of your recovery key",
+ "Starting backup...": "Starting backup...",
+ "Success!": "Success!",
+ "Create key backup": "Create key backup",
+ "Unable to create key backup": "Unable to create key backup",
"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": "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.",
@@ -2227,51 +2277,30 @@
"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.": "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": "Enter a recovery passphrase",
- "Great! This recovery passphrase looks strong enough.": "Great! This recovery passphrase looks strong enough.",
- "That matches!": "That matches!",
- "Use a different passphrase?": "Use a different passphrase?",
- "That doesn't match.": "That doesn't match.",
- "Go back to set it again.": "Go back to set it again.",
"Enter your recovery passphrase a second time to confirm it.": "Enter your recovery passphrase a second time to confirm it.",
- "Confirm your recovery passphrase": "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.",
- "Download": "Download",
"Unable to query secret storage status": "Unable to query secret storage status",
- "Retry": "Retry",
"If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "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.": "You can also set up Secure Backup & manage your keys in Settings.",
- "Set up Secure backup": "Set up Secure backup",
"Upgrade your encryption": "Upgrade your encryption",
"Set a Security Phrase": "Set a Security Phrase",
"Confirm Security Phrase": "Confirm Security Phrase",
"Save your Security Key": "Save your Security Key",
"Unable to set up secret storage": "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.": "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.",
- "For maximum security, this should be different from your account password.": "For maximum security, this should be different from your account password.",
- "Set up with a recovery key": "Set up with a recovery key",
- "Please enter your recovery passphrase a second time to confirm.": "Please enter your recovery passphrase a second time to confirm.",
- "Repeat your recovery passphrase...": "Repeat your recovery passphrase...",
- "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.": "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.",
- "Keep a copy of it somewhere secure, like a password manager or even a safe.": "Keep a copy of it somewhere secure, like a password manager or even a safe.",
- "Your recovery key": "Your recovery key",
- "Your recovery key has been copied to your clipboard, paste it to:": "Your recovery key has been copied to your clipboard, paste it to:",
- "Your recovery key is in your Downloads folder.": "Your recovery key is in your Downloads folder.",
- "Print it and store it somewhere safe": "Print it and store it somewhere safe",
- "Save it on a USB key or backup drive": "Save it on a USB key or backup drive",
- "Copy it to your personal cloud storage": "Copy it to your personal cloud storage",
- "Your keys are being backed up (the first backup could take a few minutes).": "Your keys are being backed up (the first backup could take a few minutes).",
- "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.",
- "Set up Secure Message Recovery": "Set up Secure Message Recovery",
- "Secure your backup with a recovery passphrase": "Secure your backup with a recovery passphrase",
- "Make a copy of your recovery key": "Make a copy of your recovery key",
- "Starting backup...": "Starting backup...",
- "Success!": "Success!",
- "Create key backup": "Create key backup",
- "Unable to create key backup": "Unable to create key backup",
- "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.",
- "If you don't want to set this up now, you can later in Settings.": "If you don't want to set this up now, you can later in Settings.",
- "Don't ask again": "Don't ask again",
+ "Passphrases must match": "Passphrases must match",
+ "Passphrase must not be empty": "Passphrase must not be empty",
+ "Unknown error": "Unknown error",
+ "Export room keys": "Export room keys",
+ "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.",
+ "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 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.",
+ "Enter passphrase": "Enter passphrase",
+ "Confirm passphrase": "Confirm passphrase",
+ "Export": "Export",
+ "Import room keys": "Import room keys",
+ "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.",
+ "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
+ "File to import": "File to import",
+ "Import": "Import",
"New Recovery Method": "New Recovery Method",
"A new recovery passphrase and key for Secure Messages have been detected.": "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.",
diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json
index a4249a93eb..a1275fb089 100644
--- a/src/i18n/strings/en_US.json
+++ b/src/i18n/strings/en_US.json
@@ -618,5 +618,37 @@
"Try using turn.matrix.org": "Try using turn.matrix.org",
"Messages": "Messages",
"Actions": "Actions",
- "Other": "Other"
+ "Other": "Other",
+ "Confirm": "Confirm",
+ "Add Email Address": "Add 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": "Confirm adding phone number",
+ "Click the button below to confirm adding this phone number.": "Click the button below to confirm adding this phone number.",
+ "Add Phone Number": "Add Phone Number",
+ "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "Whether you're using %(brand)s on a device where touch is the primary input mechanism",
+ "Whether you're using %(brand)s as an installed Progressive Web App": "Whether you're using %(brand)s as an installed Progressive Web App",
+ "Your user agent": "Your user agent",
+ "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.": "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.",
+ "Cancel entering passphrase?": "Cancel entering passphrase?",
+ "Are you sure you want to cancel entering passphrase?": "Are you sure you want to cancel entering passphrase?",
+ "Go Back": "Go Back",
+ "Setting up keys": "Setting up keys",
+ "Room name or address": "Room name or address",
+ "Identity server has no terms of service": "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.": "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": "Trust",
+ "%(name)s is requesting verification": "%(name)s is requesting verification",
+ "Sign In or Create Account": "Sign In or Create Account",
+ "Use your account or create a new one to continue.": "Use your account or create a new one to continue.",
+ "Create Account": "Create Account",
+ "Sign In": "Sign In",
+ "Custom (%(level)s)": "Custom (%(level)s)",
+ "Sends a message as plain text, without interpreting it as markdown": "Sends a message as plain text, without interpreting it as markdown",
+ "Sends a message as html, without interpreting it as markdown": "Sends a message as html, without interpreting it as 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": "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 the avatar of the current room",
+ "Changes your avatar in all rooms": "Changes your avatar in all rooms"
}
diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json
index 8d07db7eaf..aec575b8b4 100644
--- a/src/i18n/strings/eo.json
+++ b/src/i18n/strings/eo.json
@@ -858,7 +858,7 @@
"Gift": "Donaco",
"Light bulb": "Lampo",
"Book": "Libro",
- "Pencil": "Grifelo",
+ "Pencil": "Krajono",
"Scissors": "Tondilo",
"Key": "Ŝlosilo",
"Hammer": "Martelo",
@@ -2387,5 +2387,25 @@
"Enable advanced debugging for the room list": "Ŝalti altnivelan erarserĉadon por la ĉambrobreto",
"* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s",
"Custom Tag": "Propra etikedo",
- "Feedback": "Prikomenti"
+ "Feedback": "Prikomenti",
+ "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 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",
+ "Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "Via servilo ne respondas al iuj el viaj petoj. Vidu sube kelkon de la plej probablaj kialoj.",
+ "The server (%(serverName)s) took too long to respond.": "La servilo (%(serverName)s) tro longe ne respondis.",
+ "Your firewall or anti-virus is blocking the request.": "Via fajroŝirmilo aŭ kontraŭvirusilo blokas la peton.",
+ "A browser extension is preventing the request.": "Kromprogramo de la foliumilo malhelpas la peton.",
+ "The server is offline.": "La servilo estas eksterreta.",
+ "The server has denied your request.": "La servilo rifuzis vian peton.",
+ "Your area is experiencing difficulties connecting to the internet.": "Via loko nun havas problemojn pri interreta konekto.",
+ "A connection error occurred while trying to contact the server.": "Eraris konekto dum provo kontakti la servilon.",
+ "The server is not configured to indicate what the problem is (CORS).": "La servilo ne estas agordita por indiki la problemon (CORS).",
+ "Recent changes that have not yet been received": "Freŝaj ŝanĝoj ankoraŭ ne ricevitaj",
+ "No files visible in this room": "Neniuj dosieroj videblas en ĉi tiu ĉambro",
+ "You have no visible notifications in this room.": "Vi havas neniujn videblajn sciigojn en ĉi tiu ĉambro.",
+ "%(brand)s Android": "%(brand)s por Android"
}
diff --git a/src/i18n/strings/es.json b/src/i18n/strings/es.json
index 1619bb7616..307c8c10c9 100644
--- a/src/i18n/strings/es.json
+++ b/src/i18n/strings/es.json
@@ -50,7 +50,7 @@
"Deops user with given id": "Degrada al usuario con la ID dada",
"Default": "Por Defecto",
"Disinvite": "Deshacer invitación",
- "Displays action": "Muestra la acción",
+ "Displays action": "Hacer una acción",
"Download %(text)s": "Descargar %(text)s",
"Email": "Correo electrónico",
"Email address": "Dirección de correo electrónico",
@@ -285,7 +285,7 @@
"Uploading %(filename)s and %(count)s others|one": "Subiendo %(filename)s y otros %(count)s",
"Uploading %(filename)s and %(count)s others|other": "Subiendo %(filename)s y otros %(count)s",
"Upload avatar": "Subir avatar",
- "Upload Failed": "No Se Pudo Subir",
+ "Upload Failed": "Subida fallida",
"Upload file": "Subir archivo",
"Upload new:": "Subir nuevo:",
"Usage": "Uso",
@@ -397,7 +397,7 @@
"This Room": "Esta sala",
"Resend": "Reenviar",
"Room not found": "Sala no encontrada",
- "Messages containing my display name": "Mensajes que contienen mi nombre público",
+ "Messages containing my display name": "Mensajes que contengan mi nombre público",
"Messages in one-to-one chats": "Mensajes en conversaciones uno a uno",
"Unavailable": "No disponible",
"View Decrypted Source": "Ver Fuente Descifrada",
@@ -472,7 +472,7 @@
"Unhide Preview": "Mostrar Vista Previa",
"Unable to join network": "No se puede unir a la red",
"Sorry, your browser is not able to run %(brand)s.": "¡Lo sentimos! Su navegador no puede ejecutar %(brand)s.",
- "Messages in group chats": "Mensajes en conversaciones en grupo",
+ "Messages in group chats": "Mensajes en conversaciones grupales",
"Yesterday": "Ayer",
"Error encountered (%(errorDetail)s).": "Error encontrado (%(errorDetail)s).",
"Low Priority": "Prioridad Baja",
@@ -518,7 +518,7 @@
"Failed to invite the following users to %(groupId)s:": "No se pudo invitar a los siguientes usuarios a %(groupId)s:",
"Failed to invite users to community": "No se pudo invitar usuarios a la comunidad",
"Failed to invite users to %(groupId)s": "No se pudo invitar usuarios a %(groupId)s",
- "Failed to add the following rooms to %(groupId)s:": "No se pudo añadir a las siguientes salas a %(groupId)s:",
+ "Failed to add the following rooms to %(groupId)s:": "No se pudieron añadir las siguientes salas a %(groupId)s:",
"Restricted": "Restringido",
"Missing roomId.": "Falta el Id de sala.",
"Ignores a user, hiding their messages from you": "Ignora a un usuario, ocultando sus mensajes",
@@ -537,7 +537,7 @@
"Not a valid %(brand)s keyfile": "No es un archivo de claves de %(brand)s válido",
"Message Pinning": "Mensajes con chincheta",
"Always show encryption icons": "Mostrar siempre iconos de cifrado",
- "Automatically replace plain text Emoji": "Sustituir automáticamente Emojis de texto",
+ "Automatically replace plain text Emoji": "Reemplazar automáticamente texto por Emojis",
"Mirror local video feed": "Clonar transmisión de video local",
"Send analytics data": "Enviar datos de análisis de estadísticas",
"Enable inline URL previews by default": "Habilitar vistas previas de URL en línea por defecto",
@@ -802,7 +802,7 @@
"Old cryptography data detected": "Se detectó información de criptografía antigua",
"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.": "Se detectó una versión más antigua de %(brand)s. Esto habrá provocado que la criptografía de extremo a extremo funcione incorrectamente en la versión más antigua. Los mensajes cifrados de extremo a extremo intercambiados recientemente mientras usaba la versión más antigua puede que no sean descifrables con esta versión. Esto también puede hacer que fallen con la más reciente. Si experimenta problemas, desconecte y vuelva a ingresar. Para conservar el historial de mensajes, exporte y vuelva a importar sus claves.",
"Your Communities": "Sus Comunidades",
- "Did you know: you can use communities to filter your %(brand)s experience!": "Sabía que: puede usar comunidades para filtrar su experiencia con %(brand)s",
+ "Did you know: you can use communities to filter your %(brand)s experience!": "Sabía que: puede usar comunidades para filtrar su experiencia con %(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.": "Para configurar un filtro, arrastre un avatar de comunidad sobre el panel de filtro en la parte izquierda de la pantalla. Puede pulsar sobre un avatar en el panel de filtro en cualquier momento para ver solo las salas y personas asociadas con esa comunidad.",
"Error whilst fetching joined communities": "Error al recuperar las comunidades a las que estás unido",
"Create a new community": "Crear una comunidad nueva",
@@ -927,22 +927,22 @@
"Custom user status messages": "Mensajes de estado de usuario personalizados",
"Group & filter rooms by custom tags (refresh to apply changes)": "Agrupa y filtra salas por etiquetas personalizadas (refresca para aplicar cambios)",
"Render simple counters in room header": "Muestra contadores simples en la cabecera de la sala",
- "Enable Emoji suggestions while typing": "Habiliatar sugerencia de Emojis mientras se teclea",
+ "Enable Emoji suggestions while typing": "Habilitar sugerencia de Emojis mientras se teclea",
"Show a placeholder for removed messages": "Mostrar una marca para los mensaje borrados",
- "Show join/leave messages (invites/kicks/bans unaffected)": "Mostrar mensajes de unir/salir (no afecta a invitaciones/pateos/baneos )",
+ "Show join/leave messages (invites/kicks/bans unaffected)": "Mostrar mensajes de entrada/salida (no afecta a invitaciones/expulsiones/baneos)",
"Show avatar changes": "Mostrar cambios de avatar",
"Show display name changes": "Muestra cambios en los nombres",
- "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mostrar ecordatorio para habilitar 'Recuperación Segura de Mensajes ' en sala cifradas",
+ "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mostrar un recordatorio para habilitar 'Recuperación Segura de Mensajes' en sala cifradas",
"Show avatars in user and room mentions": "Mostrar avatares en menciones a usuarios y salas",
"Enable big emoji in chat": "Habilitar emojis grandes en el chat",
"Send typing notifications": "Enviar notificaciones de tecleo",
"Allow Peer-to-Peer for 1:1 calls": "Permitir conexión de pares en llamadas individuales",
- "Prompt before sending invites to potentially invalid matrix IDs": "Pedir confirmación antes de enviar invitaciones a IDs de matrix que parezcan inválidos",
+ "Prompt before sending invites to potentially invalid matrix IDs": "Pedir confirmación antes de enviar invitaciones a IDs de matrix que parezcan inválidas",
"Show developer tools": "Mostrar herramientas de desarrollador",
"Messages containing my username": "Mensajes que contengan mi nombre",
"Messages containing @room": "Mensajes que contengan @room",
- "Encrypted messages in one-to-one chats": "Mensajes cifrados en salas 1 a 1",
- "Encrypted messages in group chats": "Mensajes cifrados en chats grupales",
+ "Encrypted messages in one-to-one chats": "Mensajes cifrados en salas uno a uno",
+ "Encrypted messages in group chats": "Mensajes cifrados en conversaciones grupales",
"The other party cancelled the verification.": "El otro lado canceló la verificación.",
"Verified!": "¡Verificado!",
"You've successfully verified this user.": "Has verificado correctamente a este usuario.",
@@ -1162,7 +1162,7 @@
"%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s hizo una llamada de vídeo (no soportada por este navegador)",
"%(name)s (%(userId)s)": "%(name)s (%(userId)s)",
"Try out new ways to ignore people (experimental)": "Pruebe nuevas formas de ignorar a usuarios (experimental)",
- "Match system theme": "Usar el tema del sistema",
+ "Match system theme": "Utilizar el mismo tema del sistema",
"Show previews/thumbnails for images": "Mostrar vistas previas para las imágenes",
"When rooms are upgraded": "Cuando las salas son actualizadas",
"My Ban List": "Mi lista de baneos",
@@ -1246,7 +1246,7 @@
"Are you sure you want to sign out?": "¿Estás seguro de que quieres salir?",
"Message edits": "Ediciones del mensaje",
"New session": "Nueva sesión",
- "Use this session to verify your new one, granting it access to encrypted messages:": "Usa esta sesión para verificar tu nueva sesión, dándola acceso a mensajes encriptados:",
+ "Use this session to verify your new one, granting it access to encrypted messages:": "Usa esta sesión para verificar tu nueva sesión, dándole acceso a mensajes encriptados:",
"If you didn’t sign in to this session, your account may be compromised.": "Si no te conectaste a esta sesión, es posible que tu cuenta haya sido comprometida.",
"This wasn't me": "No fui yo",
"If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Si encuentras algún error o quieres compartir una opinión, por favor, contacta con nosotros en GitHub.",
@@ -1318,7 +1318,7 @@
"Your user agent": "Tu agente de usuario",
"If you cancel now, you won't complete verifying the other user.": "Si cancelas ahora, no completarás la verificación del otro usuario.",
"If you cancel now, you won't complete verifying your other session.": "Si cancelas ahora, no completarás la verificación de tu otra sesión.",
- "Cancel entering passphrase?": "¿Cancelar la introducción de frase de contraseña?",
+ "Cancel entering passphrase?": "¿Cancelar el ingresar tu contraseña de recuperación?",
"%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s actualizó la regla bloqueando salas que coinciden con %(glob)s por %(reason)s",
"%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s actualizó la regla bloqueando servidores que coinciden con %(glob)s por %(reason)s",
"%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s actualizó una regla de bloqueo correspondiente a %(glob)s por %(reason)s",
@@ -1356,7 +1356,7 @@
"Compare unique emoji": "Comparar emoji único",
"Compare a unique set of emoji if you don't have a camera on either device": "Comparar un conjunto de emojis si no tienes cámara en ninguno de los dispositivos",
"Start": "Inicio",
- "Waiting for %(displayName)s to verify…": "Esperando la verificación de %(displayName)s …",
+ "Waiting for %(displayName)s to verify…": "Esperando la verificación de %(displayName)s…",
"Review": "Revise",
"in secret storage": "en almacén secreto",
"Secret storage public key:": "Clave pública del almacén secreto:",
@@ -1436,7 +1436,7 @@
"If you cancel now, you won't complete your operation.": "Si cancela ahora, no completará la operación.",
"Review where you’re logged in": "Revise dónde hizo su registro",
"New login. Was this you?": "Nuevo registro. ¿Fuiste tú?",
- "%(name)s is requesting verification": "%(name)s solicita verificación",
+ "%(name)s is requesting verification": "%(name)s solicita verificación",
"Sign In or Create Account": "Iniciar sesión o Crear una cuenta",
"Use your account or create a new one to continue.": "Usa tu cuenta existente o crea una nueva para continuar.",
"Create Account": "Crear cuenta",
@@ -1471,11 +1471,11 @@
"Show shortcuts to recently viewed rooms above the room list": "Mostrar atajos a las salas recientemente vistas por encima de la lista de salas",
"Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Permitir el servidor de respaldo de asistencia de llamadas turn.matrix.org cuando su servidor doméstico no lo ofrece (su dirección IP se compartiría durante una llamada)",
"Send read receipts for messages (requires compatible homeserver to disable)": "Enviar recibos de lectura de mensajes (requiere un servidor local compatible para desactivarlo)",
- "Manually verify all remote sessions": "Verifica manualmente todas las sesiones remotas",
+ "Manually verify all remote sessions": "Verificar manualmente todas las sesiones remotas",
"Confirm the emoji below are displayed on both sessions, in the same order:": "Confirma que los emoji de abajo se muestran en el mismo orden en ambas sesiones:",
"Verify this session by confirming the following number appears on its screen.": "Verifique esta sesión confirmando que el siguiente número aparece en su pantalla.",
"Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": "Esperando a que su otra sesión, %(deviceName)s (%(deviceId)s), verifica…",
- "Cancelling…": "Anulando …",
+ "Cancelling…": "Anulando…",
"Verify all your sessions to ensure your account & messages are safe": "Verifica todas tus sesiones abiertas para asegurarte de que tu cuenta y tus mensajes estén seguros",
"Set up": "Configurar",
"Verify the new login accessing your account: %(name)s": "Verifique el nuevo ingreso que está accediendo a su cuenta: %(name)s",
@@ -1614,7 +1614,7 @@
"Can't find this server or its room list": "No puedo encontrar este servidor o su lista de salas",
"All rooms": "Todas las salas",
"Your server": "Tu",
- "Are you sure you want to remove %(serverName)s": "¿ Está seguro de querer eliminar %(serverName)s?",
+ "Are you sure you want to remove %(serverName)s": "¿Está seguro de querer eliminar %(serverName)s ?",
"Remove server": "Quitar servidor",
"Matrix": "Matrix",
"Add a new server": "Añadir un nuevo servidor",
@@ -1914,7 +1914,7 @@
"Unable to restore backup": "No se pudo restaurar la copia de seguridad",
"No backup found!": "¡No se encontró una copia de seguridad!",
"Keys restored": "Se restauraron las claves",
- "Failed to decrypt %(failedCount)s sessions!": "¡Error en descifrar %(failedCount) sesiones!",
+ "Failed to decrypt %(failedCount)s sessions!": "¡Error al descifrar %(failedCount)s sesiones!",
"Successfully restored %(sessionCount)s keys": "%(sessionCount)s claves restauradas con éxito",
"Warning: you should only set up key backup from a trusted computer.": "Advertencia: deberías configurar la copia de seguridad de claves solamente usando un ordenador de confianza.",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Acceda a su historial de mensajes seguros y configure la mensajería segura introduciendo su contraseña de recuperación.",
@@ -2075,5 +2075,65 @@
"%(targetName)s changed their avatar": "%(targetName)s ha cambiado su avatar",
"You changed the room name": "Has cambiado el nombre de la sala",
"%(senderName)s changed the room name": "%(senderName)s cambio el nombre de la sala",
- "You invited %(targetName)s": "Has invitado a %(targetName)s"
+ "You invited %(targetName)s": "Has invitado a %(targetName)s",
+ "Are you sure you want to cancel entering passphrase?": "¿Estas seguro que quieres cancelar el ingresar tu contraseña de recuperación?",
+ "Go Back": "No cancelar",
+ "Joins room with given address": "Entrar a la sala con la dirección especificada",
+ "Unrecognised room address:": "No se encuentra la dirección de la sala:",
+ "Opens chat with the given user": "Abrir una conversación con el usuario especificado",
+ "Sends a message to the given user": "Enviar un mensaje al usuario especificado",
+ "Light": "Claro",
+ "Dark": "Oscuro",
+ "Unexpected server error trying to leave the room": "Error inesperado del servidor al abandonar esta sala",
+ "Error leaving room": "Error al salir de la sala",
+ "Your homeserver has exceeded its user limit.": "Tú servidor ha excedido su limite de usuarios.",
+ "Your homeserver has exceeded one of its resource limits.": "Tú servidor ha excedido el limite de sus recursos.",
+ "Contact your server admin.": "Contacta con el administrador del servidor.",
+ "The person who invited you already left the room.": "La persona que te invito abandono la sala.",
+ "The person who invited you already left the room, or their server is offline.": "La persona que te invito abandono la sala, o puede que su servidor se encuentre desconectado.",
+ "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s",
+ "%(senderName)s: %(message)s": "%(senderName)s: %(message)s",
+ "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s",
+ "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s",
+ "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Tu nueva sesión se encuentra verificada ahora. Ahora tiene acceso a los mensajes encriptados y otros usuarios verán la sesión como verificada.",
+ "Your new session is now verified. Other users will see it as trusted.": "Tu sesión se encuentra ahora verificada. Otros usuarios la verán como confiable.",
+ "This session is encrypting history using the new recovery method.": "Esta sesión se encuentra encriptando el historial usando el nuevo método de verificación.",
+ "Change notification settings": "Cambiar los ajustes de notificaciones",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Prototipo de comunidades v2. Requiere un servidor compatible. Altamente experimental - usar con precuación.",
+ "Font size": "Tamaño de la fuente",
+ "Use custom size": "Utilizar un tamaño personalizado",
+ "Use a more compact ‘Modern’ layout": "Usar un diseño más 'moderno' y compacto",
+ "Use a system font": "Utilizar una fuente del sistema",
+ "System font name": "Nombre de la fuente",
+ "Enable experimental, compact IRC style layout": "Activar el diseño de IRC compacto, en prueba",
+ "Uploading logs": "Subiendo registros",
+ "Downloading logs": "Descargando registro",
+ "Incoming voice call": "Llamada de voz entrante",
+ "Incoming video call": "Videollamada entrante",
+ "Incoming call": "Llamada entrante",
+ "Waiting for your other session to verify…": "Esperando a tu otra sesión confirme…",
+ "Your server isn't responding to some requests.": "Tú servidor no esta respondiendo a ciertas solicitudes.",
+ "There are advanced notifications which are not shown here.": "Hay configuraciones avanzadas que no se muestran aquí.",
+ "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Puede que las hayas configurado en otro cliente además de %(brand)s. No puedes cambiarlas en %(brand)s pero sus efectos siguen aplicándose.",
+ "New version available. Update now.": "Nueva versión disponible. Actualiza ahora.",
+ "Hey you. You're the best!": "Oye tú. ¡Eres el mejor!",
+ "Size must be a number": "El tamaño debe ser un dígito",
+ "Custom font size can only be between %(min)s pt and %(max)s pt": "El tamaño de la fuente solo puede estar entre los valores %(min)s y %(max)s",
+ "Use between %(min)s pt and %(max)s pt": "Utiliza un valor entre %(min)s y %(max)s",
+ "Message layout": "Diseño del mensaje",
+ "Compact": "Compacto",
+ "Modern": "Moderno",
+ "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Inserta el nombre de la fuente instalada en tu sistema y %(brand)s intentara utilizarla.",
+ "Customise your appearance": "Personaliza tu apariencia",
+ "Appearance Settings only affect this %(brand)s session.": "Cambiar las opciones de apariencia solo afecta esta %(brand)s sesión.",
+ "Please verify the room ID or address and try again.": "Por favor, verifica la ID o dirección de esta sala e inténtalo de nuevo.",
+ "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "El administrador del servidor domestico ha deshabilitado la encriptación de extremo a extremo en salas privadas y mensajes directos.",
+ "To link to this room, please add an address.": "Para vincular esta sala, por favor añade una dirección.",
+ "The authenticity of this encrypted message can't be guaranteed on this device.": "La autenticidad de estos mensajes encriptados no pueden ser garantizados en este dispositivo.",
+ "No recently visited rooms": "No hay salas visitadas recientemente",
+ "People": "Gente",
+ "Explore public rooms": "Buscar salas publicas",
+ "Can't see what you’re looking for?": "¿No encuentras nada de lo que buscas?",
+ "Explore all public rooms": "Buscar todas las salas publicas",
+ "%(count)s results|other": "%(count)s resultados"
}
diff --git a/src/i18n/strings/et.json b/src/i18n/strings/et.json
index 95253f5256..5500a4bd02 100644
--- a/src/i18n/strings/et.json
+++ b/src/i18n/strings/et.json
@@ -170,7 +170,7 @@
"Are you sure you want to remove %(serverName)s": "Kas sa oled kindel et soovid eemadlada %(serverName)s",
"Remove server": "Eemalda server",
"%(networkName)s rooms": "%(networkName)s jututoad",
- "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.": "Kas sa oled kindel et soovid eemaldada (kustutada) seda sündmust? Pane tähele, et see muutus võib tagasi pöörduda, kui muudad hiljem jututoa nime või teemanime.",
+ "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.": "Kas sa oled kindel et soovid eemaldada (kustutada) seda sündmust? Pane tähele, et see muutus võib tagasi pöörduda, kui muudad hiljem jututoa nime või teema nime.",
"Sign out and remove encryption keys?": "Logi välja ja eemalda krüptimisvõtmed?",
"Upload files (%(current)s of %(total)s)": "Lae failid üles (%(current)s / %(total)s)",
"Upload files": "Lae failid üles",
@@ -650,7 +650,7 @@
"Where you’re logged in": "Kus sa oled võrku loginud",
"Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Halda alljärgnevas oma sessioonide nimesid, logi neist välja või verifitseeri neid oma kasutajaprofiilis.",
"A session's public name is visible to people you communicate with": "Sessiooni avalik nimi on nähtav neile, kellega sa suhtled",
- "%(brand)s collects anonymous analytics to allow us to improve the application.": "Võimaldamaks meil rakendust parandada kogub %(brand)s anonüümset analüütikat.",
+ "%(brand)s collects anonymous analytics to allow us to improve the application.": "Võimaldamaks meil rakendust parandada kogub %(brand)s anonüümset teavet rakenduse kasutuse kohta.",
"Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privaatsus on meile oluline ning seega me ei kogu ei isiklikke ega isikustatavaid andmeid.",
"Learn more about how we use analytics.": "Loe lisaks kuidas me kasutama analüütikat.",
"No media permissions": "Meediaõigused puuduvad",
@@ -839,7 +839,7 @@
"Heart": "Süda",
"Smiley": "Smaili",
"Robot": "Robot",
- "Hat": "Müts",
+ "Hat": "Kübar",
"Glasses": "Prillid",
"Spanner": "Mutrivõti",
"Santa": "Jõuluvana",
@@ -870,7 +870,7 @@
"Anchor": "Ankur",
"Headphones": "Kõrvaklapid",
"Folder": "Kaust",
- "Pin": "Knopka",
+ "Pin": "Nööpnõel",
"Verify all your sessions to ensure your account & messages are safe": "Selleks et sinu konto ja sõnumid oleks turvatud, verifitseeri kõik oma sessioonid",
"Later": "Hiljem",
"Review": "Vaata üle",
@@ -1025,7 +1025,7 @@
"Permissions": "Õigused",
"Select the roles required to change various parts of the room": "Vali rollid, mis on vajalikud jututoa eri osade muutmiseks",
"Enable encryption?": "Kas võtame krüptimise kasutusele?",
- "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.": "Kui kord juba kasutusele võetud, siis krüptimist enam hiljem ära lõpetada ei saa. Krüptitud sõnumeid ei saa lugeda ei vaheapealses veebiliikluses ega serveris ja vaid jututoa liikmed saavad neid lugeda. Krüptimise kasutusele võtmine takistada nii robotite kui sõnumisildade tööd. Lisateave krüptimise kohta.",
+ "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.": "Kui kord juba kasutusele võetud, siis krüptimist enam hiljem ära lõpetada ei saa. Krüptitud sõnumeid ei saa lugeda ei vaheapealses veebiliikluses ega serveris ja vaid jututoa liikmed saavad neid lugeda. Krüptimise kasutusele võtmine võib takistada nii robotite kui sõnumisildade tööd. Lisateave krüptimise kohta.",
"Guests cannot join this room even if explicitly invited.": "Külalised ei saa selle jututoaga liituda ka siis, kui neid on otseselt kutsutud.",
"Click here to fix": "Parandamiseks klõpsi siia",
"Server error": "Serveri viga",
@@ -1334,7 +1334,7 @@
"If you cancel now, you won't complete your operation.": "Kui sa katkestad nüüd, siis sul jääb pooleliolev tegevus lõpetamata.",
"Cancel entering passphrase?": "Kas katkestame paroolifraasi sisestamise?",
"Enter passphrase": "Sisesta paroolifraas",
- "Setting up keys": "Võtamevõtmed kasutusele",
+ "Setting up keys": "Võtame krüptovõtmed kasutusele",
"Room name or address": "Jututoa nimi või aadress",
"Unable to enable Notifications": "Teavituste kasutusele võtmine ei õnnestunud",
"This email address was not found": "Seda e-posti aadressi ei leidunud",
@@ -2289,8 +2289,8 @@
"All keys backed up": "Kõik krüptovõtmed on varundatud",
"Backup has a valid signature from this user": "Varukoopial on selle kasutaja kehtiv allkiri",
"Backup has a invalid signature from this user": "Varukoopial on selle kasutaja vigane allkiri",
- "Backup has a signature from unknown user with ID %(deviceId)s": "Varukoopial tundmatu kasutaja allkiri seadme tunnusega %(deviceId)s",
- "Backup has a signature from unknown session with ID %(deviceId)s": "Varukoopial tundmatu sessiooni allkiri seadme tunnusega %(deviceId)s",
+ "Backup has a signature from unknown user with ID %(deviceId)s": "Varukoopial on tundmatu kasutaja allkiri seadme tunnusega %(deviceId)s",
+ "Backup has a signature from unknown session with ID %(deviceId)s": "Varukoopial on tundmatu sessiooni allkiri seadme tunnusega %(deviceId)s",
"Backup has a valid signature from this session": "Varukoopial on selle sessiooni kehtiv allkiri",
"Backup has an invalid signature from this session": "Varukoopial on selle sessiooni vigane allkiri",
"Backup is not signed by any of your sessions": "Varunduse andmetel pole mitte ühegi sinu sessiooni allkirja",
@@ -2403,5 +2403,61 @@
"You have no visible notifications in this room.": "Jututoas pole nähtavaid teavitusi.",
"You're all caught up.": "Ei tea... kõik vist on nüüd tehtud.",
"You’re all caught up": "Ei tea... kõik vist on nüüd tehtud",
- "%(brand)s Android": "%(brand)s Android"
+ "%(brand)s Android": "%(brand)s Android",
+ "Show message previews for reactions in DMs": "Näita eelvaates otsesõnumitele regeerimisi",
+ "Show message previews for reactions in all rooms": "Näita kõikides jututubades eelvaadetes sõnumitele regeerimisi",
+ "Master private key:": "Üldine privaatvõti:",
+ "Recent changes that have not yet been received": "Hiljutised muudatused, mis pole veel alla laetud või saabunud",
+ "Explore public rooms": "Sirvi avalikke jututubasid",
+ "Forces the current outbound group session in an encrypted room to be discarded": "Sunnib loobuma praeguse krüptitud jututoa rühmavestluse seansist",
+ "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.": "Oled varem kasutanud %(brand)s serveriga %(host)s ja lubanud andmete laisa laadimise. Selles versioonis on laisk laadimine keelatud. Kuna kohalik vahemälu nende kahe seadistuse vahel ei ühildu, peab %(brand)s sinu konto uuesti sünkroonima.",
+ "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.": "Kui %(brand)s teine versioon on mõnel teisel vahekaardil endiselt avatud, palun sulge see. %(brand)s kasutamine samal serveril põhjustab vigu olukorras, kus laisk laadimine on samal ajal lubatud ja keelatud.",
+ "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 vanema versiooni andmed on tuvastatud. See kindlasti põhjustab läbiva krüptimise tõrke vanemas versioonis. Läbivalt krüptitud sõnumid, mida on vanema versiooni kasutamise ajal hiljuti vahetatud, ei pruugi selles versioonis olla dekrüptitavad. See võib põhjustada vigu ka selle versiooniga saadetud sõnumite lugemisel. Kui teil tekib probleeme, logige välja ja uuesti sisse. Sõnumite ajaloo säilitamiseks eksportige ja uuesti importige oma krüptovõtmed.",
+ "Navigation": "Navigeerimine",
+ "Uploading logs": "Laen üles logisid",
+ "Downloading logs": "Laen alla logisid",
+ "Can't see what you’re looking for?": "Kas sa ei leia seda, mida otsisid?",
+ "Explore all public rooms": "Sirvi kõiki avalikke jututubasid",
+ "%(count)s results|other": "%(count)s tulemust",
+ "Preparing to download logs": "Valmistun logikirjete allalaadimiseks",
+ "Download logs": "Lae logikirjed alla",
+ "Unexpected server error trying to leave the room": "Jututoast lahkumisel tekkis serveris ootamatu viga",
+ "Error leaving room": "Viga jututoast lahkumisel",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Kogukondade v2 prototüüp. Eeldab, et koduserver toetab sellist funktsionaalsust. Lahendus on esialgne ja katseline - kui kasutad, siis väga ettevaatlikult.",
+ "Explore rooms in %(communityName)s": "Uuri jututubasid %(communityName)s kogukonnas",
+ "Set up Secure Backup": "Võta kasutusele turvaline varundus",
+ "Information": "Teave",
+ "Add another email": "Lisa veel üks e-posti aadress",
+ "People you know on %(brand)s": "%(brand)s kasutajad, keda sa tead",
+ "Send %(count)s invites|other": "Saada %(count)s kutset",
+ "Send %(count)s invites|one": "Saada %(count)s kutse",
+ "Invite people to join %(communityName)s": "Kutsu kasutajaid %(communityName)s kogukonna liikmeks",
+ "There was an error creating your community. The name may be taken or the server is unable to process your request.": "Kogukonna loomisel tekkis viga. Selline nimi kas on juba kasutusel või server ei saa hetkel seda päringut töödelda.",
+ "Community ID: +:%(domain)s": "Kogukonna tunnus: +:%(domain)s",
+ "Use this when referencing your community to others. The community ID cannot be changed.": "Viidates kogukonnale kasuta seda tunnust. Kogukonna tunnust ei ole võimalik muuta.",
+ "You can change this later if needed.": "Kui vaja, siis sa saad seda hiljem muuta.",
+ "What's the name of your community or team?": "Mis on sinu kogukonna või tiimi nimi?",
+ "Enter name": "Sisesta nimi",
+ "Add image (optional)": "Lisa pilt (kui soovid)",
+ "An image will help people identify your community.": "Pilt aitab inimestel teie kogukonda ära tunda.",
+ "Create community": "Loo kogukond",
+ "Explore community rooms": "Sirvi kogukonna jututubasid",
+ "Create a room in %(communityName)s": "Loo uus jututuba %(communityName)s kogukonda",
+ "Cross-signing and secret storage are ready for use.": "Risttunnustamine ja turvahoidla on kasutamiseks valmis.",
+ "Cross-signing is ready for use, but secret storage is currently not being used to backup your keys.": "Risttunnustamine on kasutamiseks valmis, kuid turvahoidla ei ole hetkel krüptovõtmete varundamiseks kasutusel.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "Omavahelisi jututubasid on võimalik leida ning nendega liituda vaid kutse alusel. Avalikke jututubasid saavad kõik leida ning nendega liituda.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "Omavahelisi jututubasid on võimalik leida ning nendega liituda vaid kutse alusel. Selles kogukonnas saavad avalikke jututubasid kõik leida ning nendega liituda.",
+ "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "Sa võid sellise võimaluse kasutusele võtta, kui seda jututuba kasutatakse vaid organisatsioonisiseste tiimide ühistööks oma koduserveri piires. Seda ei saa hiljem muuta.",
+ "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.": "Sa võid sellise võimaluse jätta kasutusele võtmata, kui seda jututuba kasutatakse erinevate väliste tiimide ühistööks kasutades erinevaid koduservereid. Seda ei saa hiljem muuta.",
+ "Block anyone not part of %(serverName)s from ever joining this room.": "Keela kõikide niisuguste kasutajate liitumine selle jututoaga, kelle kasutajakonto ei asu %(serverName)s koduserveris.",
+ "May include members not in %(communityName)s": "Siin võib leiduda kasutajaid, kes ei ole %(communityName)s kogukonna liikmed",
+ "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.": "Alusta vestust teise osapoolega tema nime, kasutajanime (näiteks ) või e-posti aadressi alusel. Sellega aga sa ei kutsu teda %(communityName)s kogukonna liikmeks. Kui soovid kedagi kutsuda %(communityName)s kogukonda, siis vajuta siia.",
+ "There was an error updating your community. The server is unable to process your request.": "Sinu kogukonna andmete uuendamisel tekkis viga. Server ei suuda sinu päringut töödelda.",
+ "Update community": "Uuenda kogukonda",
+ "Failed to find the general chat for this community": "Ei õnnestunud tuvastada selle kogukonna üldist rühmavestlust",
+ "Community settings": "Kogukonna seadistused",
+ "User settings": "Kasutaja seadistused",
+ "Community and user menu": "Kogukonna ja kasutaja menüü",
+ "Privacy": "Privaatsus",
+ "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Lisa ( ͡° ͜ʖ ͡°) smaili vormindamata sõnumi algusesse"
}
diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json
index 42f9d74502..42eead2057 100644
--- a/src/i18n/strings/fr.json
+++ b/src/i18n/strings/fr.json
@@ -2377,5 +2377,23 @@
"%(brand)s Web": "%(brand)s Web",
"%(brand)s Desktop": "%(brand)s Desktop",
"%(brand)s iOS": "%(brand)s iOS",
- "%(brand)s X for Android": "%(brand)s X pour Android"
+ "%(brand)s X for Android": "%(brand)s X pour Android",
+ "Are you sure you want to cancel entering passphrase?": "Souhaitez-vous vraiment annuler l'entrée de la phrase de passe ?",
+ "Unexpected server error trying to leave the room": "Erreur de serveur inattendue en essayant de quitter le salon",
+ "Error leaving room": "Erreur en essayant de quitter le salon",
+ "The person who invited you already left the room.": "La personne vous ayant invité a déjà quitté le salon.",
+ "The person who invited you already left the room, or their server is offline.": "La personne vous ayant invité a déjà quitté le salon, ou son serveur est hors-ligne.",
+ "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s",
+ "Change notification settings": "Modifier les paramètres de notification",
+ "Show message previews for reactions in DMs": "Afficher la prévisualisation des messages pour les réactions dans les messages privés",
+ "Show message previews for reactions in all rooms": "Afficher la prévisualisation des messages pour les réactions dans tous les salons",
+ "Enable advanced debugging for the room list": "Activer le débogage avancé pour la liste de salons",
+ "Uploading logs": "Téléversement des journaux",
+ "Downloading logs": "Téléchargement des journaux",
+ "Your server isn't responding to some requests.": "Votre serveur ne répond pas à certaines requêtes.",
+ "Cross-signing and secret storage are ready for use.": "La signature croisée et le coffre secret sont prêt à l'emploi.",
+ "Cross-signing is ready for use, but secret storage is currently not being used to backup your keys.": "La signature croisée est prête à l'emploi, mais le coffre secret n'est pas actuellement utilisé pour sauvegarder vos clés.",
+ "Master private key:": "Clé privée maîtresse :",
+ "%(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 ne peut actuellement mettre en cache vos messages chiffrés localement de manière sécurisée via le navigateur Web. Utilisez %(brand)s Desktop pour que les messages chiffrés apparaissent dans vos résultats de recherche.",
+ "There are advanced notifications which are not shown here.": "Des notifications avancées ne sont pas affichées ici."
}
diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json
index db8a8f8100..b8dcc48b68 100644
--- a/src/i18n/strings/gl.json
+++ b/src/i18n/strings/gl.json
@@ -1884,7 +1884,7 @@
"Message layout": "Disposición da mensaxe",
"Compact": "Compacta",
"Modern": "Moderna",
- "Power level": "Poderío",
+ "Power level": "Nivel de permisos",
"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.": "Verifica este dispositivo para marcalo como confiable. Confiando neste dispositivo permite que ti e outras usuarias estedes máis tranquilas ao utilizar mensaxes cifradas.",
"Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "Ao verificar este dispositivo marcaralo como confiable, e as usuarias que confiaron en ti tamén confiarán nel.",
"Waiting for partner to confirm...": "Agardando a que o compañeiro confirme...",
@@ -2233,7 +2233,7 @@
"Alt": "Alt",
"Alt Gr": "Alt Gr",
"Shift": "Maiús",
- "Super": "Super",
+ "Super": "Súper",
"Ctrl": "Ctrl",
"Toggle Bold": "Activa Resaltar",
"Toggle Italics": "Activa Cursiva",
@@ -2410,5 +2410,53 @@
"You’re all caught up": "Xa estás ó día",
"You have no visible notifications in this room.": "Non tes notificacións visibles nesta sala.",
"%(brand)s Android": "%(brand)s Android",
- "Master private key:": "Chave mestra principal:"
+ "Master private key:": "Chave mestra principal:",
+ "Show message previews for reactions in DMs": "Mostrar vista previa das mensaxes para reaccións en MDs",
+ "Show message previews for reactions in all rooms": "Mostrar vista previa das mensaxes para reaccións en todas as salas",
+ "Explore public rooms": "Explorar salas públicas",
+ "Uploading logs": "Subindo o rexistro",
+ "Downloading logs": "Descargando o rexistro",
+ "Can't see what you’re looking for?": "¿Non atopas o que buscas?",
+ "Explore all public rooms": "Explora todas as salas públicas",
+ "%(count)s results|other": "%(count)s resultados",
+ "Preparing to download logs": "Preparándose para descargar rexistro",
+ "Download logs": "Descargar rexistro",
+ "Unexpected server error trying to leave the room": "Fallo non agardado no servidor ó intentar saír da sala",
+ "Error leaving room": "Erro ó saír da sala",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Prototipos de Comunidades v2. Require un servidor compatible. Característica experimental - usa con tino.",
+ "Explore rooms in %(communityName)s": "Explorar salas en %(communityName)s",
+ "Set up Secure Backup": "Configurar Copia de apoio Segura",
+ "Cross-signing and secret storage are ready for use.": "A Sinatura-Cruzada e o almacenaxe segredo están listos para usar.",
+ "Cross-signing is ready for use, but secret storage is currently not being used to backup your keys.": "A Sinatura-Cruzada está preparada para usala, mais o almacenaxe segredo aínda non foi usado para facer copia das chaves.",
+ "Explore community rooms": "Explorar salas da comunidade",
+ "Information": "Información",
+ "Add another email": "Engadir outro email",
+ "People you know on %(brand)s": "Persoas que coñeces en %(brand)s",
+ "Send %(count)s invites|other": "Enviar %(count)s convites",
+ "Send %(count)s invites|one": "Enviar %(count)s convite",
+ "Invite people to join %(communityName)s": "Convida a persoas a unirse a %(communityName)s",
+ "There was an error creating your community. The name may be taken or the server is unable to process your request.": "Algo fallou ó crear a túa comunidade. O nome podería estar pillado ou o servidor non pode procesar a túa solicitude.",
+ "Community ID: +:%(domain)s": "ID da comunidade: +:%(domain)s",
+ "Use this when referencing your community to others. The community ID cannot be changed.": "Usa esto cando queiras falar sobre a túa comunidade. O ID da comunidade non se pode cambiar.",
+ "You can change this later if needed.": "Podes cambiar esto máis tarde se o precisas.",
+ "What's the name of your community or team?": "¿Cómo se chama a túa comunidade ou equipo?",
+ "Enter name": "Escribe o nome",
+ "Add image (optional)": "Engade unha imaxe (optativo)",
+ "An image will help people identify your community.": "Unha imaxe axudaralle á xente a identificar a túa comunidade.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "As salas privadas só se poden atopar e unirse por convite. As salas públicas son accesibles para calquera.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "As salas privadas só poden ser atopadas e unirse por convite. As salas públicas son accesibles para calquera nesta comunidade.",
+ "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "Pode resultar útil se a sala vai ser utilizada só polo equipo de xestión interna do servidor. Non se pode cambiar máis tarde.",
+ "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.": "Poderías desactivalo se a sala vai ser utilizada para colaborar con equipos externos que teñen o seu propio servidor. Esto non se pode cambiar máis tarde.",
+ "Create a room in %(communityName)s": "Crear unha sala en %(communityName)s",
+ "Block anyone not part of %(serverName)s from ever joining this room.": "Evitar que calquera externo a %(serverName)s se poida unir a esta sala.",
+ "Create community": "Crear comunidade",
+ "Privacy": "Privacidade",
+ "There was an error updating your community. The server is unable to process your request.": "Algo fallou ó actualizar a comunidade. O servidor non é quen de procesar a solicitude.",
+ "Update community": "Actualizar comunidade",
+ "May include members not in %(communityName)s": "Podería incluir membros que non están en %(communityName)s",
+ "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.": "Iniciar unha conversa con alguén utilizando o seu nome, nome de usuaria (como ) ou enderezo de email. Esto non as convidará a %(communityName)s. Para convidar a alguén a %(communityName)s, preme aquí.",
+ "Failed to find the general chat for this community": "Non se atopou o chat xenérico para esta comunidade",
+ "Community settings": "Axustes da comunidade",
+ "User settings": "Axustes de usuaria",
+ "Community and user menu": "Menú de usuaria e comunidade"
}
diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json
index 209c237c0c..a9e209c169 100644
--- a/src/i18n/strings/hu.json
+++ b/src/i18n/strings/hu.json
@@ -483,7 +483,7 @@
"Community ID": "Közösség azonosító",
"Add rooms to the community summary": "Szobák hozzáadása a közösségi összefoglalóhoz",
"Add users to the community summary": "Felhasználók hozzáadása a közösségi összefoglalóhoz",
- "Failed to update community": "Közösség frissítése sikertelen",
+ "Failed to update community": "Közösség módosítása sikertelen",
"Leave Community": "Közösség elhagyása",
"Add rooms to this community": "Szobák hozzáadása ehhez a közösséghez",
"%(inviter)s has invited you to join this community": "%(inviter)s meghívott ebbe a közösségbe",
@@ -811,7 +811,7 @@
"This room is used for important messages from the Homeserver, so you cannot leave it.": "Ez a szoba fontos szerverüzenetek közlésére jött létre, nem tudsz kilépni belőle.",
"No Audio Outputs detected": "Nem található hang kimenet",
"Audio Output": "Hang kimenet",
- "Share Link to User": "Hivatkozás megosztása felhasználóval",
+ "Share Link to User": "A felhasználóra mutató hivatkozás",
"Share room": "Szoba megosztása",
"Share Room": "Szoba megosztása",
"Link to most recent message": "A legfrissebb üzenetre hivatkozás",
@@ -987,7 +987,7 @@
"Send typing notifications": "Gépelés visszajelzés küldése",
"Enable Community Filter Panel": "Közösségi szűrő panel bekapcsolása",
"Messages containing my username": "Üzenetek amik a nevemet tartalmazzák",
- "The other party cancelled the verification.": "A másik fél törölte az ellenőrzést.",
+ "The other party cancelled the verification.": "A másik fél megszakította az ellenőrzést.",
"Verified!": "Ellenőrizve!",
"You've successfully verified this user.": "Sikeresen ellenőrizted ezt a felhasználót.",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Az üzenetek a felhasználóval végponttól végpontig titkosítva vannak és azt más nem tudja elolvasni.",
@@ -1630,7 +1630,7 @@
"%(role)s in %(roomName)s": "%(role)s a szobában: %(roomName)s",
"Messages in this room are end-to-end encrypted.": "Az üzenetek a szobában végponttól végpontig titkosítottak.",
"Security": "Biztonság",
- "Verify": "Ellenőriz",
+ "Verify": "Ellenőrzés",
"Any of the following data may be shared:": "Az alábbi adatok közül bármelyik megosztásra kerülhet:",
"Your display name": "Megjelenítési neved",
"Your avatar URL": "Profilképed URL-je",
@@ -1888,7 +1888,7 @@
"You've successfully verified %(displayName)s!": "Sikeresen ellenőrizted a felhasználót: %(displayName)s!",
"Got it": "Értem",
"Encryption enabled": "Titkosítás bekapcsolva",
- "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Ebben a szobában az üzenetek végpontok között titkosítottak. További információkért és ellenőrzéshez nyisd meg a felhasználó profilját.",
+ "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Ebben a szobában az üzenetek végpontok között titkosítottak. További információkért és az ellenőrzéshez nyisd meg a felhasználók profiljait!",
"Encryption not enabled": "Titkosítás nincs engedélyezve",
"The encryption used by this room isn't supported.": "A szobában használt titkosítás nem támogatott.",
"Clear all data in this session?": "Minden adat törlése ebben a munkamenetben?",
@@ -2109,7 +2109,7 @@
"Server did not return valid authentication information.": "A szerver semmilyen érvényes azonosítási információt sem küldött vissza.",
"There was a problem communicating with the server. Please try again.": "A szerverrel való kommunikációval probléma történt. Kérlek próbáld újra.",
"Sign in with SSO": "Belépés SSO-val",
- "Welcome to %(appName)s": "Üdv itt: %(appName)s",
+ "Welcome to %(appName)s": "Üdvözöl az %(appName)s",
"Liberate your communication": "Szabadítsd fel a kommunikációdat",
"Send a Direct Message": "Közvetlen üzenet küldése",
"Explore Public Rooms": "Nyilvános szobák felderítése",
@@ -2177,7 +2177,7 @@
"Waiting for your other session to verify…": "A másik munkameneted ellenőrzésére várunk…",
"You've successfully verified your device!": "Sikeresen ellenőrizted az eszközödet!",
"Message deleted": "Üzenet törölve",
- "Message deleted by %(name)s": "%(name)s törölte az üzenetet",
+ "Message deleted by %(name)s": "%(name)s törölte ezt az üzenetet",
"QR Code": "QR kód",
"To continue, use Single Sign On to prove your identity.": "A folytatáshoz a személyazonosságod megerősítéséhez használd az egyszeri bejelentkezést.",
"Confirm to continue": "Erősítsd meg a továbblépéshez",
@@ -2234,12 +2234,12 @@
"Emoji picker": "Emodzsi választó",
"No recently visited rooms": "Nincsenek nemrégiben meglátogatott szobák",
"People": "Emberek",
- "Sort by": "Rendezve:",
+ "Sort by": "Rendezés",
"Unread rooms": "Olvasatlan szobák",
"Always show first": "Mindig az elsőt mutatja",
"Show": "Mutat",
"Message preview": "Üzenet előnézet",
- "List options": "Lista beállítások",
+ "List options": "Lista beállításai",
"Show %(count)s more|other": "Még %(count)s megjelenítése",
"Show %(count)s more|one": "Még %(count)s megjelenítése",
"Leave Room": "Szoba elhagyása",
@@ -2404,5 +2404,58 @@
"Your area is experiencing difficulties connecting to the internet.": "Probléma az Internet elérésben.",
"A connection error occurred while trying to contact the server.": "Kapcsolati hiba lépett fel miközben a szervert próbáltad elérni.",
"The server is not configured to indicate what the problem is (CORS).": "A szerver nincs beállítva, hogy megmutassa mi okozhatta a hibát (CORS).",
- "Recent changes that have not yet been received": "Legutóbbi változások amik még nem érkeztek meg"
+ "Recent changes that have not yet been received": "Legutóbbi változások amik még nem érkeztek meg",
+ "Show message previews for reactions in DMs": "Üzenet előnézet mutatása a reakcióhoz a közvetlen beszélgetéseknél",
+ "Show message previews for reactions in all rooms": "Üzenet előnézet mutatása a reakciókhoz minden szobában",
+ "Master private key:": "Privát elsődleges kulcs:",
+ "No files visible in this room": "Ebben a szobában nincsenek fájlok",
+ "Attach files from chat or just drag and drop them anywhere in a room.": "Csatolj fájlt a csevegésből vagy húzd és ejtsd bárhova a szobában.",
+ "You’re all caught up": "Mindent elolvastál",
+ "You have no visible notifications in this room.": "Nincsenek látható értesítéseid ebben a szobában.",
+ "%(brand)s Android": "%(brand)s Android",
+ "Explore public rooms": "Nyilvános szobák felderítése",
+ "Unexpected server error trying to leave the room": "Váratlan szerver hiba lépett fel a szobából való kilépés közben",
+ "Error leaving room": "A szoba elhagyásakor hiba történt",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Közösségek v2 prototípus. Kompatibilis matrix szervert igényel. Erősen kísérleti állapotban van - körültekintően használd.",
+ "Uploading logs": "Napló feltöltése folyamatban",
+ "Downloading logs": "Napló letöltése folyamatban",
+ "Can't see what you’re looking for?": "Nem találod amit keresel?",
+ "Explore all public rooms": "Fedezd fel a nyilvános szobákat",
+ "%(count)s results|other": "%(count)s találat",
+ "Information": "Információ",
+ "Preparing to download logs": "Napló előkészítése feltöltéshez",
+ "Download logs": "Napló letöltése",
+ "Add another email": "Másik e-mail hozzáadása",
+ "People you know on %(brand)s": "Akiket ismerhetsz itt: %(brand)s",
+ "Send %(count)s invites|other": "%(count)s meghívó küldése",
+ "Send %(count)s invites|one": "%(count)s meghívó küldése",
+ "Invite people to join %(communityName)s": "Hívj meg embereket ide: %(communityName)s",
+ "There was an error creating your community. The name may be taken or the server is unable to process your request.": "A közösség létrehozásánál hiba történt. A név már foglalt vagy a szerver nem tudja feldolgozni a kérést.",
+ "Community ID: +:%(domain)s": "Közösség azon.: +:%(domain)s",
+ "Use this when referencing your community to others. The community ID cannot be changed.": "Ha másoknál hivatkozol a közösségre ezt használd. A közösség azonosítót nem lehet megváltoztatni.",
+ "You can change this later if needed.": "Később megváltoztathatod ha kell.",
+ "What's the name of your community or team?": "Mi a közösséged vagy csoportod neve?",
+ "Enter name": "Név megadása",
+ "Add image (optional)": "Kép hozzáadása (opcionális)",
+ "An image will help people identify your community.": "A kép segít az embereknek a közösség azonosításában.",
+ "Explore rooms in %(communityName)s": "Fedezd fel a szobákat itt: %(communityName)s",
+ "Create community": "Közösség létrehozása",
+ "Set up Secure Backup": "Biztonsági mentés beállítása",
+ "Explore community rooms": "Fedezd fel a közösségi szobákat",
+ "Create a room in %(communityName)s": "Készíts szobát itt: %(communityName)s",
+ "Cross-signing and secret storage are ready for use.": "Az eszközök közti hitelesítés és a biztonsági tároló kész a használatra.",
+ "Cross-signing is ready for use, but secret storage is currently not being used to backup your keys.": "Az eszközök közti hitelesítés kész a használatra, de a biztonsági tároló nincs használva a kulcsok mentéséhez.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "Privát szobák csak meghívóval találhatók meg és meghívóval lehet belépni. A nyilvános szobákat bárki megtalálhatja és be is léphet.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "Privát szobák csak meghívóval találhatók meg és meghívóval lehet belépni. A nyilvános szobákat a közösség bármely tagja megtalálhatja és be is léphet.",
+ "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "Beállíthatod, ha a szobát csak egy belső csoport használja majd a matrix szervereden. Ezt később nem lehet megváltoztatni.",
+ "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.": "Ne engedélyezd ezt, ha a szobát külső csapat is használja másik matrix szerverről. Később nem lehet megváltoztatni.",
+ "Block anyone not part of %(serverName)s from ever joining this room.": "A szobába való belépés megtagadása mindenkitől ki nem ezt a matrix szervert használja: %(serverName)s.",
+ "There was an error updating your community. The server is unable to process your request.": "A közösség módosításakor hiba történt. A szerver nem tudja feldolgozni a kérést.",
+ "Update community": "Közösség módosítása",
+ "May include members not in %(communityName)s": "Olyan tagok is lehetnek akik nincsenek ebben a közösségben: %(communityName)s",
+ "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.": "Kezdj beszélgetést valakivel akár a neve, felhasználói neve (mint ) vagy az e-mail címe segítségével. %(communityName)s közösségbe nem lesznek meghívva. Ha valakit meg szeretnél hívni ide: %(communityName)s, kattints ide.",
+ "Failed to find the general chat for this community": "Ehhez a közösséghez nem található általános csevegés",
+ "Community settings": "Közösségi beállítások",
+ "User settings": "Felhasználói beállítások",
+ "Community and user menu": "Közösségi és felhasználói menü"
}
diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json
index d86070018b..48e2b2df20 100644
--- a/src/i18n/strings/it.json
+++ b/src/i18n/strings/it.json
@@ -2413,5 +2413,44 @@
"Attach files from chat or just drag and drop them anywhere in a room.": "Allega file dalla chat o trascinali in qualsiasi punto in una stanza.",
"You’re all caught up": "Non hai nulla di nuovo da vedere",
"You have no visible notifications in this room.": "Non hai alcuna notifica visibile in questa stanza.",
- "%(brand)s Android": "%(brand)s Android"
+ "%(brand)s Android": "%(brand)s Android",
+ "Show message previews for reactions in DMs": "Mostra anteprime messaggi per le reazioni nei messaggi diretti",
+ "Show message previews for reactions in all rooms": "Mostra anteprime messaggi per le reazioni in tutte le stanze",
+ "Explore public rooms": "Esplora stanze pubbliche",
+ "Uploading logs": "Invio dei log",
+ "Downloading logs": "Scaricamento dei log",
+ "Can't see what you’re looking for?": "Non vedi quello che cerchi?",
+ "Explore all public rooms": "Esplora tutte le stanze pubbliche",
+ "%(count)s results|other": "%(count)s risultati",
+ "Preparing to download logs": "Preparazione al download dei log",
+ "Download logs": "Scarica i log",
+ "Unexpected server error trying to leave the room": "Errore inaspettato del server tentando di abbandonare la stanza",
+ "Error leaving room": "Errore uscendo dalla stanza",
+ "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Prototipi di comunità v2. Richiede un homeserver compatibile. Altamente sperimentale - usa con attenzione.",
+ "Cross-signing and secret storage are ready for use.": "La firma incrociata e l'archivio segreto sono pronti all'uso.",
+ "Cross-signing is ready for use, but secret storage is currently not being used to backup your keys.": "La firma incrociata è pronta all'uso, ma l'archivio segreto attualmente non è usato per fare il backup delle tue chiavi.",
+ "Explore community rooms": "Esplora stanze della comunità",
+ "Information": "Informazione",
+ "Add another email": "Aggiungi un'altra email",
+ "People you know on %(brand)s": "Persone che conosci su %(brand)s",
+ "Send %(count)s invites|other": "Manda %(count)s inviti",
+ "Send %(count)s invites|one": "Manda %(count)s invito",
+ "Invite people to join %(communityName)s": "Invita persone ad unirsi a %(communityName)s",
+ "There was an error creating your community. The name may be taken or the server is unable to process your request.": "Si è verificato un errore nella creazione della comunità. Il nome potrebbe essere già in uso o il server non riesce ad elaborare la richiesta.",
+ "Community ID: +:%(domain)s": "ID comunità: +:%(domain)s",
+ "Use this when referencing your community to others. The community ID cannot be changed.": "Usalo quando ti riferisci alla comunità con gli altri. L'ID della comunità non può essere cambiato.",
+ "You can change this later if needed.": "Puoi cambiarlo più tardi se necessario.",
+ "What's the name of your community or team?": "Qual è il nome della tua comunità o squadra?",
+ "Enter name": "Inserisci nome",
+ "Add image (optional)": "Aggiungi immagine (facoltativo)",
+ "An image will help people identify your community.": "Un'immagine aiuterà le persone ad identificare la tua comunità.",
+ "Create a room in %(communityName)s": "Crea una stanza in %(communityName)s",
+ "Explore rooms in %(communityName)s": "Esplora le stanze in %(communityName)s",
+ "Create community": "Crea comunità",
+ "Set up Secure Backup": "Imposta il Backup Sicuro",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "Le stanze private possono essere trovate e visitate solo con invito. Le stanze pubbliche invece sono aperte a tutti.",
+ "Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "Le stanze private possono essere trovate e visitate solo con invito. Le stanze pubbliche invece sono aperte a tutti i membri di questa comunità.",
+ "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "Dovresti attivarlo se questa stanza verrà usata solo per collaborazioni tra squadre interne nel tuo homeserver. Non può essere cambiato in seguito.",
+ "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.": "Dovresti disattivarlo se questa stanza verrà usata per collaborazioni con squadre esterne che hanno il loro homeserver. Non può essere cambiato in seguito.",
+ "Block anyone not part of %(serverName)s from ever joining this room.": "Blocca l'accesso alla stanza per chiunque non faccia parte di %(serverName)s."
}
diff --git a/src/i18n/strings/ja.json b/src/i18n/strings/ja.json
index ff2afb67be..4edf415efb 100644
--- a/src/i18n/strings/ja.json
+++ b/src/i18n/strings/ja.json
@@ -579,7 +579,7 @@
"%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s は退出しました",
"%(oneUser)sleft %(count)s times|other": "%(oneUser)s は %(count)s 回退出しました",
"%(oneUser)sleft %(count)s times|one": "%(oneUser)s は退出しました",
- "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s が%(count)s 回参加し、退出した",
+ "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s が %(count)s 回参加し、退出しました",
"%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s は参加して退出しました",
"%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s が %(count)s 回参加し退出しました",
"%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s が参加し退出しました",
@@ -668,7 +668,7 @@
"Update any local room aliases to point to the new room": "新しいルームを指すようにローカルルームのエイリアスを更新する",
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "古いバージョンの部屋でのユーザーの発言を停止し、新しい部屋に移動するようユーザーに通知するメッセージを投稿する",
"Mention": "記載",
- "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)s が %(count)s 回招待を撤回した",
+ "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)s が %(count)s 回招待を取り消しました",
"was unbanned %(count)s times|one": "ブロック解除されました",
"Put a link back to the old room at the start of the new room so people can see old messages": "新しい部屋の始めに古い部屋にリンクを張って、人々が古いメッセージを見ることができるようにする",
"Sign out": "サインアウト",
@@ -1373,5 +1373,19 @@
"Show %(count)s more|one": "さらに %(count)s 件を表示",
"%(num)s minutes ago": "%(num)s 分前",
"%(num)s hours ago": "%(num)s 時間前",
- "%(num)s days ago": "%(num)s 日前"
+ "%(num)s days ago": "%(num)s 日前",
+ "Favourited": "お気に入り登録中",
+ "Room options": "部屋の設定",
+ "Ignored users": "無視しているユーザー",
+ "Show tray icon and minimize window to it on close": "トレイアイコンを表示しウィンドウを閉じても最小化して待機する",
+ "This message cannot be decrypted": "メッセージが復号できません",
+ "Unencrypted": "暗号化されていません",
+ "Encrypted by a deleted session": "削除済みのセッションによる暗号化",
+ "Scroll to most recent messages": "最新のメッセージを表示",
+ "Emoji picker": "絵文字を選択",
+ "All rooms": "全ての部屋",
+ "Your server": "あなたのサーバー",
+ "Matrix": "Matrix",
+ "Add a new server": "新しいサーバーを追加",
+ "Server name": "サーバー名"
}
diff --git a/src/i18n/strings/kab.json b/src/i18n/strings/kab.json
index 6073fbfd38..f5efc1bb87 100644
--- a/src/i18n/strings/kab.json
+++ b/src/i18n/strings/kab.json
@@ -354,7 +354,7 @@
"Please check your email and click on the link it contains. Once this is done, click continue.": "Ma ulac aɣilif, senqed imayl-ik/im syen sit ɣef useɣwen i yellan. Akken ara yemmed waya, sit ad tkemmleḍ.",
"This will allow you to reset your password and receive notifications.": "Ayagi ad ak(akem)-yeǧǧ ad twennzeḍ awal-ik/im uffir yerna ad d-tremseḍ ilɣa.",
"A username can only contain lower case letters, numbers and '=_-./'": "Isem n useqdac yezmer kan ad yegber isekkilen imeẓyanen, izwilen neɣ '=_-./'",
- "Username invalid: %(errMessage)s": "Isem n useqdac d armeɣtu",
+ "Username invalid: %(errMessage)s": "Isem n useqdac d arameɣtu: %(errMessage)s",
"An error occurred: %(error_string)s": "Tella-d tuccḍa: %(error_string)s",
"To get started, please pick a username!": "I wakken ad tebduḍ, ttxil-k/m fren isem n useqdac!",
"This will be your account name on the homeserver, or you can pick a different server.": "Wagi ad yili d isem-ik/im deg usebter agejdan, neɣ tzemreḍ ad tferneḍ aqeddac-nniḍen.",
@@ -480,7 +480,7 @@
"Compact": "Akussem",
"Modern": "Atrar",
"Online": "Srid",
- "Mention": "Abder",
+ "Mention": "Abdar",
"Verify session": "Asenqed n tɣimit",
"Message edits": "Tiẓrigin n yizen",
"Your account is not secure": "Amiḍan-ik·im d araɣelsan",
@@ -568,9 +568,9 @@
"%(displayName)s is typing …": "%(displayName)s yettaru-d …",
"%(names)s and %(count)s others are typing …|other": "%(names)s d %(count)s wiyaḍ ttarun-d …",
"%(names)s and %(count)s others are typing …|one": "%(names)s d wayeḍ-nniḍen yettaru-d …",
- "%(names)s and %(lastPerson)s are typing …": "%(names)s d %(count)s ttarun-d …",
- "%(items)s and %(count)s others|other": "%(names)s d %(count)s wiyaḍ",
- "%(items)s and %(count)s others|one": "%(names)s d wayeḍ-nniḍen",
+ "%(names)s and %(lastPerson)s are typing …": "%(names)s d %(lastPerson)s ttarun-d …",
+ "%(items)s and %(count)s others|other": "%(items)s d %(count)s wiyaḍ",
+ "%(items)s and %(count)s others|one": "%(items)s d wayeḍ-nniḍen",
"%(items)s and %(lastItem)s": "%(items)s d %(lastItem)s",
"a few seconds ago": "kra n tesinin seg yimir-nni",
"about a minute ago": "tasdidt seg yimir-nni",
@@ -647,9 +647,9 @@
" to store messages from ": " i usekles n yiznan sɣur ",
"rooms.": "tixxamin.",
"Connecting to integration manager...": "Tuqqna ɣer umsefrak n useddu...",
- "Cannot connect to integration manager": "Ur nessaweḍ ara ad neqqen ɣer umsefrak n useddu...",
+ "Cannot connect to integration manager": "Ur nessaweḍ ara ad neqqen ɣer umsefrak n useddu",
"Delete Backup": "Kkes aḥraz",
- "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Iznan yettwawgelhen ttuḥerzen s uwgelhen n yixef ɣer yixef. Ala kečč d unermas (inermasen) i yesεan tisura akken ad ɣren iznan-a.",
+ "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Iznan yettwawgelhen ttuḥerzen s uwgelhen n yixef ɣer yixef. Ala kečč d uɣerwaḍ (yiɣerwaḍen) i yesεan tisura akken ad ɣren iznan-a.",
"This session is backing up your keys. ": "Tiɣimit tḥerrez tisura-inek·inem. ",
"Connect this session to Key Backup": "Qqen tiɣimit-a ɣer uḥraz n tsarut",
"Server Name": "Isem n uqeddac",
@@ -719,7 +719,7 @@
"%(num)s hours ago": "%(num)s usrag seg yimir-nni",
"about a day ago": "azal n wass seg yimir-nni",
"%(num)s days ago": "%(num)s wussan seg yimir-nni",
- "a few seconds from now": "Kra n tesinin seg yimir-a",
+ "a few seconds from now": "kra n tesinin seg yimir-a",
"%(name)s (%(userId)s)": "%(name)s (%(userId)s)",
"Not a valid %(brand)s keyfile": "Afaylu n tsarut %(brand)s d arameɣtu",
"User %(user_id)s does not exist": "Aseqdac %(user_id)s ulac-it",
@@ -731,9 +731,9 @@
"Avoid dates and years that are associated with you": "Zgel izmaz akked iseggasen i icudden ɣur-k",
"System font name": "Isem n tsefsit n unagraw",
"Send analytics data": "Azen isefka n tesleḍt",
- "Cancelling…": "Asefsex...",
- "They match": "Mṣadan",
- "They don't match": "Ur mṣadan ara",
+ "Cancelling…": "Asefsex…",
+ "They match": "Msaḍan",
+ "They don't match": "Ur msaḍan ara",
"Dog": "Aqjun",
"Horse": "Aεewdiw",
"Pig": "Ilef",
@@ -789,5 +789,1626 @@
"%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "%(senderName)s yekkes tansa-nni-nniḍen %(addresses)s i texxamt-a.",
"%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s yekkes tansa-nni tayeḍ %(addresses)s i texxamt-a.",
"%(senderName)s changed the alternative addresses for this room.": "%(senderName)s ibeddel tansa-nni tayeḍ n texxamt-a.",
- "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s ibeddel tansa tagejdant d tansa-nni tayeḍ i texxamt-a."
+ "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s ibeddel tansa tagejdant d tansa-nni tayeḍ i texxamt-a.",
+ "Sends a message as html, without interpreting it as markdown": "Yuzen izen d html war ma isegza-t s tukksa n tecreḍt",
+ "Deops user with given id": "Aseqdac Deops s usulay i d-yettunefken",
+ "Sends the given message coloured as a rainbow": "Yuzen iznan i d-yettunefken yeɣman s yiniten am teslit n Unẓar",
+ "Sends the given emote coloured as a rainbow": "Yuzen tanfalit i d-yettunefken yeɣman s yiniten am teslit n Unẓar",
+ "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s yeqbel tinnubga i %(displayName)s.",
+ "%(senderName)s changed the addresses for this room.": "%(senderName)s ibeddel tansiwin n texxamt-a.",
+ "(not supported by this browser)": "(ur yettusefrak ara sɣur iminig-a)",
+ "%(senderName)s answered the call.": "%(senderName)s yerra ɣef usiwel.",
+ "(could not connect media)": "(tuqqna n umidya tegguma)",
+ "%(senderName)s placed a voice call.": "%(senderName)s isɛedda asiwel s taɣect.",
+ "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s isɛedda asiwel s taɣect. (ur yettusefrak ara s yiming-a)",
+ "%(senderName)s placed a video call.": "%(senderName)s isɛedda asiwel s tvidyut.",
+ "%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s isɛedda asiwel s tvidyut. (ur yettusefrak ara s yiming-a)",
+ "%(senderName)s made future room history visible to anyone.": "%(senderName)s yerra amazray n texxamt i d-iteddun yettban i yal amdan.",
+ "%(senderName)s changed the pinned messages for the room.": "%(senderName)s ibeddel iznan yerzin n texxamt.",
+ "%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s awiǧit yettwabeddel sɣur %(senderName)s",
+ "Manually Verify by Text": "Senqed s ufus s ttawil n uḍris",
+ "Interactively verify by Emoji": "Senqed amyigew s yimujit",
+ "Cannot reach homeserver": "Anekcum ɣer uqeddac agejdan d awezɣi",
+ "Cannot reach identity server": "Anekcum ɣer uqeddac n tmagit d awezɣi",
+ "No homeserver URL provided": "Ulac URL n uqeddac agejdan i d-yettunefken",
+ "about a minute from now": "akka tsasdidt seg yimir-a",
+ "%(num)s minutes from now": "%(num)s tesdidin seg yimir-nni",
+ "about an hour from now": "akka asrag seg yimir-a",
+ "%(num)s hours from now": "%(num)s yisragen seg yimir-a",
+ "about a day from now": "akka ass seg yimir-a",
+ "%(num)s days from now": "%(num)s wussan seg yimir-a",
+ "Unrecognised address": "Tansa ur tettwassen ara",
+ "You do not have permission to invite people to this room.": "Ur tesεiḍ ara tasiregt ad d-necdeḍ imdanen ɣer texxamt-a.",
+ "User %(userId)s is already in the room": "Aseqdac %(userId)s yella yakan deg texxamt",
+ "User %(user_id)s may or may not exist": "Aseqdac %(user_id)s yezmer yella, yezmer ulac-it",
+ "The user's homeserver does not support the version of the room.": "Aqeddac agejdan n useqdac ur issefrek ara lqem n texxamt yettwafernen.",
+ "All-uppercase is almost as easy to guess as all-lowercase": "Meṛṛa isekkilen imeqranen fessus-it i usumer ɣef akk isekkilen imeẓẓyanen",
+ "Recent years are easy to guess": "Iseggasen n melmi kan sehlen i tifin",
+ "Dates are often easy to guess": "Izemzen sehlen i tiftin",
+ "This is a top-10 common password": "Wagi d awal uffir gar 10 yimezwura yettwassnen",
+ "This is a top-100 common password": "Wagi d awal uffir gar 100 yimezwura yettwassnen",
+ "This is a very common password": "Wagi d awal uffir yettwassnen",
+ "I want to help": "Bɣiɣ ad d-muddeɣ tallalt",
+ "Enable them now": "Sermed-iten tura",
+ "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s",
+ "Change notification settings": "Snifel iɣewwaren n yilɣa",
+ "Match system theme": "Asentel n unagraw yemṣadan",
+ "Never send encrypted messages to unverified sessions from this session": "Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara seg tɣimit-a",
+ "Messages in group chats": "Iznan n yidiwenniyen n ugraw",
+ "Call invitation": "Ancad n tinnubga",
+ "Messages sent by bot": "Iznan yettwaznen s Bot",
+ "When rooms are upgraded": "Mi ara ttwaleqqment texxamin",
+ "My Ban List": "Tabdart-inu n tigtin",
+ "Incoming voice call": "Asiwel s taɣect ikcem-d",
+ "Incoming video call": "Asiwel s tvidyut ikcem-d",
+ "Incoming call": "Asiwel i d-ikecmen",
+ "Got It": "Awi-t",
+ "From %(deviceName)s (%(deviceId)s)": "Seg %(deviceName)s (%(deviceId)s)",
+ "Accept to continue:": "Qbel i wakken ad tkemmleḍ:",
+ "This bridge was provisioned by .": "Tileggit-a tella-d sɣur .",
+ "This bridge is managed by .": "Tileggit-a tettusefrak sɣur .",
+ "Workspace: %(networkName)s": "Tallunt n uxeddim: %(networkName)s",
+ "Channel: %(channelName)s": "Abadu: %(channelName)s",
+ "Upload new:": "Asali amaynut:",
+ "New passwords don't match": "Awalen uffiren imaynuten ur mṣadan ara",
+ "Passwords can't be empty": "Awalen uffiren ur ilaq ara ad ilin d ilmawen",
+ "in account data": "deg yisefka n umiḍan",
+ "Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "Sentem tukksa n tɣimiyin-a s useqdec n unekcum asuf i ubeggen n timagit-ik(im).",
+ "Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "Sentem tukksa n tɣimit-a s useqdec n unekcum asuf i ubeggen n timagit-ik·im.",
+ "Confirm deleting these sessions": "Sentem tukksa n tɣimiyin-a",
+ "Restore from Backup": "Tiririt seg uḥraz",
+ "All keys backed up": "Akk tisura ttwaḥerzent",
+ "Backup version: ": "Lqem n uḥraz: ",
+ "Failed to change settings": "Asnifel n yiɣewwaren ur yeddi ara",
+ "Failed to update keywords": "Aleqqem n wawalen ufrinen ur yeddi ara",
+ "Enable notifications for this account": "Sens ilɣa i umiḍan-a",
+ "Enable email notifications": "Sens ilɣa n yimayla",
+ "Notification targets": "Isaḍasen n yilɣa",
+ "Advanced notification settings": "Iɣewwaren n yilɣa leqqayen",
+ "Enable desktop notifications for this session": "Sens ilɣa n tnirawt i tɣimit-a",
+ "Enable audible notifications for this session": "Sens ilɣa imsiwal i texxamt",
+ "Upgrade to your own domain": "Leqqem ɣer taɣult-inek kečč",
+ "Profile picture": "Tugna n umaɣnu",
+ "Checking server": "Asenqed n uqeddac",
+ "Change identity server": "Snifel aqeddac n timagit",
+ "You should:": "Aql-ak·am:",
+ "Disconnect anyway": "Ɣas akken ffeɣ seg tuqqna",
+ "Do not use an identity server": "Ur seqdac ara aqeddac n timagt",
+ "Manage integrations": "Sefrek imsidf",
+ "Checking for an update...": "Anadi n lqem...",
+ "Downloading update...": "Asali n lqem...",
+ "New version available. Update now.": "Lqem amaynut yella. Leqqem tura.",
+ "Check for update": "Nadi lqem",
+ "Invalid theme schema.": "Azenziɣ n usentel d arameɣtu.",
+ "Theme added!": "Asentel yettwarnan!",
+ "Custom theme URL": "Sagen URL n usentel",
+ "Add theme": "Rnu asentel",
+ "Customise your appearance": "Err arwes-ik·im d udmawan",
+ "Set a new account password...": "Sbadu awal uffir amaynut n umiḍan...",
+ "Account management": "Asefrek n umiḍan",
+ "Deactivate Account": "Sens amiḍan",
+ "Deactivate account": "Sens amiḍan",
+ "Bug reporting": "Aneqqis n wabug",
+ "Submit debug logs": "Azen iɣmisen n wabug",
+ "Clear cache and reload": "Sfeḍ takatut tuffirt syen sali-d",
+ "%(brand)s version:": "Lqem %(brand)s:",
+ "olm version:": "lqem n olm:",
+ "Ignored/Blocked": "Yettunfen/Yettusweḥlen",
+ "Error unsubscribing from list": "Tuccḍa deg usefsex n ujerred seg texxamt",
+ "Server rules": "Ilugan n uqeddac",
+ "User rules": "Ilugan n useqdac",
+ "You are currently ignoring:": "Aql-ak tura tuɣaleḍ deg rrif:",
+ "Ignored users": "Iseqdacen yettunfen",
+ "Personal ban list": "Tabdart n tigtin tudmawant",
+ "Server or user ID to ignore": "Asulay n uqeddac neɣ n useqdac ara yuɣalen deg rrif",
+ "eg: @bot:* or example.org": "eg: @bot:* neɣ amedya.org",
+ "Room list": "Tabdart n texxamt",
+ "Autocomplete delay (ms)": "Tanzagt n usmad awurman (ms)",
+ "": "",
+ "Session ID:": "Asulay n tɣimit:",
+ "Message search": "Anadi n yizen",
+ "Default Device": "Ibenk arussin",
+ "Voice & Video": "Ameslaw & Tavidyut",
+ "Upgrade this room to the recommended room version": "Leqqem taxxamt-a ɣer lqem n texxamt yelhan",
+ "this room": "taxxamt-a",
+ "Internal room ID:": "Asulay n texxamt tagensant:",
+ "Room version": "Lqem n texxamt",
+ "Room version:": "Lqem n texxamt:",
+ "Open Devtools": "Ldi Devtools",
+ "Notification sound": "Imesli i yilɣa",
+ "Change main address for the room": "Beddel tansa tagejdant n texxamt",
+ "Change permissions": "Beddel tisirag",
+ "Change topic": "Beddel asentel",
+ "Upgrade the room": "Leqqem taxxamt",
+ "Enable room encryption": "Rmed awgelhen n texxamt",
+ "Failed to unban": "Sefsex aḍraq yugi ad yeddu",
+ "Banned by %(displayName)s": "Yettwagi sɣur %(displayName)s",
+ "Send messages": "Azen iznan",
+ "Invite users": "Nced-d iseqdacen",
+ "Change settings": "Snifel iɣewwaren",
+ "Kick users": "Suffeɣ iseqdacen",
+ "Ban users": "Agi yiseqdacen",
+ "Remove messages": "Kkes iznan",
+ "Privileged Users": "Iseqdacen i yettwafernen",
+ "Muted Users": "Iseqdacen i isusmen",
+ "Banned users": "Iseqdacen i yettwagin",
+ "Enable encryption?": "Rmed awgelhen?",
+ "Remove %(email)s?": "Kkes %(email)s?",
+ "Unable to add email address": "D awezɣi ad ternuḍ tansa n yimayl",
+ "Remove %(phone)s?": "Kkes %(phone)s?",
+ "This room is end-to-end encrypted": "Taxxamt-a tettwawgelhen seg yixef ɣer yixef",
+ "Edit message": "Ẓreg izen",
+ "Key request sent.": "Asuter n tsarut yettwazen.",
+ "This message cannot be decrypted": "Izen-a ur yezmir ara ad yettuwgelhen",
+ "Encrypted by a deleted session": "Yettuwgelhen s texxamt yettwakksen",
+ "Scroll to most recent messages": "Drurem ɣer yiznan akk n melmi kan",
+ "Close preview": "Mdel taskant",
+ "and %(count)s others...|other": "d %(count)s wiyaḍ...",
+ "and %(count)s others...|one": "d wayeḍ-nniḍen...",
+ "Invite to this room": "Nced-d ɣer texxamt-a",
+ "Filter room members": "Sizdeg iɛeggalen n texxamt",
+ "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (i iǧehden %(powerLevelNumber)s",
+ "Voice call": "Asiwel s taɣect",
+ "Video call": "Asiwel s tvidyut",
+ "Send an encrypted reply…": "Azen tiririt yettuwgelhen…",
+ "Send a reply…": "Azen tiririt…",
+ "Send an encrypted message…": "Azen izen yettuwgelhen…",
+ "Send a message…": "Azen izen…",
+ "Italics": "Uknan",
+ "No pinned messages.": "Ulac iznan yerzin.",
+ "Pinned Messages": "Iznan yerzin",
+ "Online for %(duration)s": "Srid azal n %(duration)s",
+ "Idle for %(duration)s": "D arurmid azal n %(duration)s",
+ "Offline for %(duration)s": "Beṛṛa n tuqqna azal n %(duration)s",
+ "Seen by %(userName)s at %(dateTime)s": "Iwala-t %(userName)s at %(dateTime)s",
+ "Replying": "Tiririt",
+ "Guests can join": "Inebgawen zemren ad ttekkin",
+ "(~%(count)s results)|one": "(~%(count)s igmaḍ)",
+ "Join Room": "Rnu ɣer texxamt",
+ "Forget room": "Tettuḍ taxxamt",
+ "Rooms": "Timɣiwent",
+ "Custom Tag": "Sagen tabzimt",
+ "This room": "Taxxamt-a",
+ "Loading …": "La d-yettali…",
+ "Rejecting invite …": "Tigtin n tinnubga…",
+ "Join the conversation with an account": "Ttekki deg udiwenni s umiḍan",
+ "Loading room preview": "Taskant n texxamt i la d-tettali",
+ "Re-join": "Ales attekki",
+ "Try to join anyway": "Ɣas akken ɛreḍ ad tettekkiḍ",
+ "Join the discussion": "Ttekki deg udiwenni",
+ "Start chatting": "Bdu adiwenni",
+ "%(roomName)s is not accessible at this time.": "%(roomName)s ulac anekcum ɣer-s akka tura.",
+ "Show previews of messages": "Sken tiskanin n yiznan",
+ "Jump to first unread room.": "Ɛeddi ɣer texxamt tamezwarut ur nettwaɣra ara.",
+ "Jump to first invite.": "Ɛreddi ɣer tinnubga tamezwarut.",
+ "Add room": "Rnu taxxamt",
+ "All messages": "Iznan i meṛṛa",
+ "Mentions & Keywords": "Ibdaren & Awalen ufrinen",
+ "Forget Room": "Tettuḍ taxxamt",
+ "Leave Room": "Ffeɣ seg texxamt",
+ "Add a topic": "Rnu asentel",
+ "This Room": "Taxxamt-a",
+ "Search…": "Nadi…",
+ "Send as message": "Azen-it d izen",
+ "Add some now": "Rnu kra tura",
+ "Hide Stickers": "Ffer istikiyen",
+ "Failed to revoke invite": "Asefsex n tinnubga ur yeddi ara",
+ "Admin Tools": "Ifecka n unedbal",
+ "Revoke invite": "Sefesex tinnubga",
+ "Invited by %(sender)s": "Yettunced-d sɣur %(sender)s",
+ "not specified": "ur iban ara",
+ "Other published addresses:": "Tansiwin-nniḍen i d-yeffɣen:",
+ "Invalid community ID": "Asulay n temɣiwent d arussin",
+ "Start Verification": "Bdu asenqed",
+ "Verify User": "Senqed aseqdac",
+ "Your messages are not secure": "Iznan-inek·inem d ariɣelsanen",
+ "Hide verified sessions": "Ffer tiɣimiyin yettwasneqden",
+ "%(count)s sessions|other": "Tiɣimiyin n %(count)s",
+ "Hide sessions": "Ffer tiɣimiyin",
+ "Jump to read receipt": "Ɛeddi ɣer tɣuri n wawwaḍ",
+ "Share Link to User": "Bḍu aseɣwen d useqdac",
+ "Disinvite this user?": "Kkes-d tinnubga n useqdac?",
+ "Kick this user?": "Suffeɣ aseqdac-a?",
+ "Remove %(count)s messages|one": "Kkes 1 izen",
+ "Remove recent messages": "Kkes iznan n melmi kan",
+ "Unban this user?": "Sefsex aḍraq n useqdac-a?",
+ "Ban this user?": "Zgel aseqdac-a?",
+ "Failed to mute user": "Tasusmi n useqdac ur yeddi ara",
+ "Remove from community": "Kkes seg temɣiwent",
+ "Disinvite this user from community?": "Kkes tinnubga n useqdac-a seg temɣiwent?",
+ "Remove this user from community?": "Kkes aseqdac-a seg temɣiwent?",
+ "Failed to withdraw invitation": "Tukksa n tinnubga ur yeddi ara",
+ "Deactivate user?": "Kkes aseqdac-a?",
+ "Deactivate user": "Kkes aseqdac",
+ "Verify by scanning": "Senqed s usiggez",
+ "Verify by emoji": "Senqed s yimujit",
+ "Verification timed out.": "Yemmed wakud n usenqed.",
+ "%(displayName)s cancelled verification.": "%(displayName)s isefsex asenqed.",
+ "You cancelled verification.": "Tesfesxeḍ asenqed.",
+ "Verification cancelled": "Yefsex usenqed",
+ "Encryption enabled": "Awgelhen ur yeddi ara",
+ "Decrypt %(text)s": "Wgelhen %(text)s",
+ "Download %(text)s": "Sader %(text)s",
+ "You verified %(name)s": "Tezsneqdeḍ %(name)s",
+ "%(name)s cancelled verifying": "%(name)s isefsex asenqed",
+ "You accepted": "Tqebleḍ",
+ "%(name)s accepted": "%(name)s yettwaqbel",
+ "You declined": "Tugiḍ",
+ "You cancelled": "Tesfesxeḍ",
+ "%(name)s declined": "%(name)s yettwagi",
+ "%(name)s cancelled": "%(name)s yettwasefsex",
+ "%(name)s wants to verify": "%(name)s yebɣa ad isenqed",
+ "Message deleted by %(name)s": "Izen yettwakkes sɣur %(name)s",
+ "Message deleted on %(date)s": "Izen yettwakkes deg %(date)s",
+ "Add an Integration": "Rnu asidef",
+ "Can't load this message": "Yegguma ad d-yali yizen-a",
+ "Submit logs": "Azen iɣmisen",
+ "Filter community members": "Sizdeg imttekkiyen n texxamt",
+ "Invite to this community": "Ancad ɣer temɣiwent",
+ "Visibility in Room List": "Abani n tebdart n texxamin",
+ "Only visible to community members": "Yettban kan i yimttekkiyen n temɣiwent",
+ "Add rooms to this community": "Rnu tixxamin ɣer temɣiwent",
+ "Filter community rooms": "Sizdeg tixxamin ɣer temɣiwent",
+ "Smileys & People": "Acmumeḥ & Imdanen",
+ "Animals & Nature": "Iɣersiwen & ugama",
+ "Activities": "Irmad",
+ "Travel & Places": "Inig & Imukan",
+ "Cancel search": "Sefsex anadi",
+ "Your user ID": "Asulay-ik·m n useqdac",
+ "Your theme": "Asentel-inek·inem",
+ "Room ID": "Asulay n texxamt",
+ "Widget ID": "Asulay n yiwiǧit",
+ "Download this file": "Sali-d afaylu-a",
+ "Manage Integrations": "Sefrek imsidaf",
+ "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s",
+ "Power level": "Sagen aswir",
+ "Custom level": "Sagen aswir",
+ "In reply to": "Deg tririt i",
+ "e.g. my-room": "e.g. taxxamt-inu",
+ "Please provide a room address": "Ttxil-k·m mudd-d tansa n texxamt",
+ "Sign in with single sign-on": "Qqen s unekcum asuf",
+ "And %(count)s more...|other": "D %(count)s ugar...",
+ "Enter a server name": "Sekcem isem n uqeddac",
+ "Matrix": "Matrix",
+ "Matrix ID": "Asulay n Matrix",
+ "Matrix Room ID": "Asulay n n texxamt n Matrix",
+ "The following users may not exist": "Iseqdacen i d-iteddun yezmer ad ilin ulac-iten",
+ "Invite anyway": "Ɣas akken nced-d",
+ "Preparing to send logs": "Aheyyi n tuzna n yiɣmisen",
+ "Failed to send logs: ": "Tuzna n yiɣmisen ur teddi ara: ",
+ "Send logs": "Azen iɣmisen",
+ "Clear all data": "Sfeḍ meṛṛa isefka",
+ "Create Community": "Rnu tamɣiwent",
+ "Community Name": "Isem n temɣiwent",
+ "Please enter a name for the room": "Ttxil-k·m sekcem isem i texxamt",
+ "Enable end-to-end encryption": "Awgelhen seg yixef ɣer yixef ur yeddi ara",
+ "Topic (optional)": "Asentel (afrayan)",
+ "Make this room public": "Err taxxamt-a d tazayezt",
+ "Continue With Encryption Disabled": "Kemmel s uwgelhen yensan",
+ "Confirm your account deactivation by using Single Sign On to prove your identity.": "Sentem asensi n umiḍan s useqdec n unekcum asuf i ubeggen n timagit-ik·im.",
+ "Confirm account deactivation": "Sentem asensi n umiḍan",
+ "Send Custom Event": "Azen tadyant tudmawant",
+ "Event sent!": "Tadyant tettwazen!",
+ "Send Account Data": "Azen isefka n umiḍan",
+ "Filter results": "Igmaḍ n usizdeg",
+ "Verification Requests": "Tuttriwin n usenqed",
+ "Waiting for partner to confirm...": "Aṛaǧu n umendad ad isentem...",
+ "Incoming Verification Request": "Tuttra n usenqed i d-ikecmen",
+ "Confirm to continue": "Sentem i wakken ad tkemmleḍ",
+ "Failed to invite the following users to chat: %(csvUsers)s": "Ancad n yiseqdacen i d-iteddun ɣer udiwenni ur yeddi ara: %(csvUsers)s",
+ "Failed to find the following users": "Ur nessaweḍ ara ad naf iseqdacen",
+ "Recent Conversations": "Idiwenniyen n melmi kan",
+ "Direct Messages": "Iznan usligen",
+ "Upload completed": "Asali yemmed",
+ "Signature upload success": "Asali n uzmul yedda akken iwata",
+ "Clear cache and resync": "Sfeḍ takatut tuffirt syen ales amtawi",
+ "Failed to upgrade room": "Aleqqem n texxamt ur yeddi ara",
+ "Upgrade this room to version %(version)s": "Leqqem taxxamt-a ɣer lqem amaynut %(version)s",
+ "Upgrade Room Version": "Lqem n uleqqem n texxamt",
+ "Automatically invite users": "Nced-d iseqdacen s wudem awurman",
+ "Upgrade private room": "Leqqem taxxamt tusligt",
+ "Upgrade public room": "Leqqem taxxamt tazayezt",
+ "Server isn't responding": "Ulac tiririt sɣur aqeddac",
+ "The server is offline.": "Aqeddac ha-t-an beṛṛa n tuqqna.",
+ "Clear Storage and Sign Out": "Sfeḍ aklas syen ffeɣ seg tuqqna",
+ "Send Logs": "Azen iɣmisen",
+ "Unable to restore session": "D awezɣi ad d-tuɣal texxamt",
+ "Verification Pending": "Asenqed yettṛaǧu",
+ "Share User": "Bḍu aseqdac",
+ "Share Community": "Bḍu tamɣiwent",
+ "Link to selected message": "Aseɣwen n yizen i yettwafernen",
+ "Missing session data": "Isefka n tɣimit xuṣṣen",
+ "Upload all": "Sali-d kullec",
+ "Cancel All": "Sefsex kullec",
+ "Verify other session": "Senqed tiɣimit tayeḍ",
+ "Verification Request": "Asuter n usenqed",
+ "Use your Security Key to continue.": "Seqdec tasarut-ik·im n tɣellist akken ad tkemmleḍ.",
+ "Incorrect recovery passphrase": "Tafyirt tuffirt n uεeddi d tarameɣtut",
+ "Unable to restore backup": "Tiririt n uḥraz tugi ad teddu",
+ "Keys restored": "Tisura ttwaskelsent",
+ "Enter recovery passphrase": "Sekcem tafyirt tuffirt n tririt",
+ "Enter recovery key": "Sekcem tasarut tririt",
+ "Private Chat": "Adiwenni uslig",
+ "Public Chat": "Adiwenni azayez",
+ "Address (optional)": "Tansa (tafrayan)",
+ "Reject invitation": "Agi tinnubga",
+ "Unable to reject invite": "Tegtin n tinnubga tegguma ad teddu",
+ "Resend edit": "Ales tuzna n useẓreg",
+ "Resend removal": "Azen tikkelt-nniḍen tukksa",
+ "Cancel Sending": "Sefsex tuzna",
+ "Share Permalink": "Bḍu aseɣwen ameɣlal",
+ "Share Message": "Bḍu izen",
+ "Collapse Reply Thread": "Fneẓ asqerdec n tririt",
+ "Report Content": "Agbur n uneqqis",
+ "All messages (noisy)": "Iznan i meṛṛa (sɛan ṣṣut)",
+ "Direct Chat": "Adiwenni uslig",
+ "Clear status": "Sfeḍ addaden",
+ "Update status": "Leqqem addaden",
+ "Set a new status...": "Sbadu addad amaynut...",
+ "View Community": "Wali tamɣiwent",
+ "Remove for everyone": "Kkes i meṛṛa",
+ "Remove for me": "Kkes i nekk",
+ "User Status": "Addaden n useqdac",
+ "Start authentication": "Bdu alɣu",
+ "Sign in with SSO": "Anekcum s SSO",
+ "Couldn't load page": "Asali n usebter ur yeddi ara",
+ "Add rooms to the community summary": "Rnu tixxamin ɣer ugzul n temɣiwent",
+ "Which rooms would you like to add to this summary?": "Anti tixxamin i tebɣiḍ ad tent-ternuḍ ɣer uzwel-a?",
+ "Add to summary": "Rnu ɣer ugzul",
+ "Add a Room": "Rnu taxxamt",
+ "Add users to the community summary": "Rnu iseqdacen ɣer ugzul n temɣiwent",
+ "Who would you like to add to this summary?": "Anwa i tebɣiḍ ad t-ternuḍ ɣer ugzul-a?",
+ "Add a User": "Rnu aseqdac",
+ "Failed to update community": "Aleqqem n temɣiwent ur yeddi ara",
+ "Unable to accept invite": "Aqbal n tinnubga d awezɣi",
+ "Unable to join community": "Timerna ɣer temɣiwent d awezɣi",
+ "Leave Community": "Ffeɣ seg temɣiwent",
+ "Leave %(groupName)s?": "Ffeɣ seg %(groupName)s?",
+ "Unable to leave community": "D awezɣi ad teffɣeḍ seg temɣiwent",
+ "Community Settings": "Iɣewwaren n temɣiwent",
+ "Featured Users:": "Iseqdacen i ifazen:",
+ "Join this community": "Rnu ɣer temɣiwent-a",
+ "Leave this community": "Ffeɣ seg temɣiwent-a",
+ "You are an administrator of this community": "Aql-ak·akem d (t)anedbal(t) n temɣiwent-a",
+ "You are a member of this community": "Aql-ak·akem d (t)aɛeggal(t) n temɣiwent-a",
+ "Who can join this community?": "Anwa i izemren ad d-yernu ɣer temɣiwent-a?",
+ "Long Description (HTML)": "Aglam ɣezzifen (HTML)",
+ "Community %(groupId)s not found": "Ur tettwaf ara temɣiwent %(groupId)s",
+ "This homeserver does not support communities": "Aqeddac-a agejdan ur issefrek ara timɣiwanin",
+ "Failed to load %(groupId)s": "Asali n %(groupId)s ur yeddi ara",
+ "Welcome to %(appName)s": "Ansuf ɣer %(appName)s",
+ "Send a Direct Message": "Azen izen uslig",
+ "Failed to reject invitation": "Tigtin n tinnubga ur yeddi ara",
+ "Failed to leave room": "Tuffɣa seg texxamt ur yeddi ara",
+ "Signed Out": "Yeffeɣ seg tuqqna",
+ "Self-verification request": "Asuter n usenqed awurman",
+ "Create a new community": "Rnu tamɣiwent tamaynut",
+ "Remove from Directory": "Kkes seg ukaram",
+ "Unable to join network": "Timerna ɣer uzeṭṭa d tawezɣit",
+ "Clear filter": "Sfeḍ asizdeg",
+ "%(count)s of your messages have not been sent.|one": "Izen-inek·inem ur yettwazen ara.",
+ "Room": "Taxxamt",
+ "Failed to reject invite": "Tigtin n tinnubga ur yeddi ara",
+ "Click to unmute video": "Sit i wakken ad tesremdeḍ tavidyut",
+ "Click to mute video": "Sit i wakken ad tsenseḍ tavidyut",
+ "Click to unmute audio": "Sit i wakken ad tesremdeḍ ameslaw",
+ "Click to mute audio": "Sit i wakken ad tsenseḍ ameslaw",
+ "Switch to light mode": "Uɣal ɣer uskar aceɛlal",
+ "Switch to dark mode": "Uɣal ɣer uskar aberkan",
+ "Switch theme": "Abeddel n usentel",
+ "All settings": "Akk iɣewwaren",
+ "Verify this login": "Senqed anekcam-a",
+ "A new password must be entered.": "Awal uffir amaynut ilaq ad yettusekcem.",
+ "Your Matrix account on ": "Amiḍan-ik·im Matrix deg ",
+ "Send Reset Email": "Azen imayl n uwennez",
+ "Set a new password": "Sbadu awal uffir amaynut",
+ "General failure": "Tuccḍa tamatut",
+ "This account has been deactivated.": "Amiḍan-a yettuḥbes.",
+ "Continue with previous account": "Kemmel s umiḍan yezrin",
+ "Log in to your new account.": "Kcem ɣer umiḍan-ik·im amaynut.",
+ "%(brand)s Web": "%(brand)s Web",
+ "%(brand)s Desktop": "%(brand)s n tnarit",
+ "%(brand)s iOS": "%(brand)s iOS",
+ "%(brand)s Android": "%(brand)s Andriod",
+ "Incorrect password": "Awal uffir d arameɣtu",
+ "Failed to re-authenticate": "Aɛiwed n usesteb ur yeddi ara",
+ "Command Autocomplete": "Asmad awurman n tiludna",
+ "Emoji Autocomplete": "Asmad awurman n yimujit",
+ "Enter a recovery passphrase": "Sekcem tafyirt tuffirt n tririt",
+ "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Seqdec aqeddac n timagit i uncad s yimayl. Sit, tkemmleḍ aseqdec n uqeddac n timagit amezwer (%(defaultIdentityServerName)s) neɣ sefrek deg yiɣewwaren.",
+ "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!": "ƔUR-K·M: tASARUT N USENQED UR TEDDI ARA! Tasarut n uzmul n %(userId)s akked tɣimit %(deviceId)s d \"%(fprint)s\" ur imṣada ara d tsarut i d-yettunefken \"%(fingerprint)s\". Ayagi yezmer ad d-yini tiywalin-ik·im ttusweḥlent!",
+ "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Tasarut n uzmul i d-tefkiḍ temṣada d tsarut n uzmul i d-tremseḍ seg tɣimit %(userId)s's %(deviceId)s. Tiɣimit tettucreḍ tettwasenqed.",
+ "Displays list of commands with usages and descriptions": "Yeskan tabdart n tiludna s usegdec d uglam",
+ "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s yermed aɣawas i %(groups)s deg texxamt-a.",
+ "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s isens aɣawas i %(groups)s deg texxamt-a.",
+ "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s yermed aɣawas i %(newGroups)s syen isens aɣawas i %(oldGroups)s deg texxamt-a.",
+ "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s yeḥwi tinubga i %(targetDisplayName)s i uttekkki deg texxamt.",
+ "Unicorn": "Azara",
+ "Penguin": "Awarfus",
+ "Octopus": "Azayz",
+ "Globe": "Amaḍal",
+ "Pizza": "Tapizzat",
+ "Spanner": "Tasarut",
+ "Santa": "Santa",
+ "Hourglass": "Amasrag",
+ "Scissors": "Timqestin",
+ "Hammer": "Tafḍist",
+ "Train": "Tamacint",
+ "Aeroplane": "Asafag",
+ "Rocket": "Timeẓdit",
+ "Guitar": "Tagitaṛt",
+ "Trumpet": "Lɣiḍa",
+ "Bell": "Anayna",
+ "Pin": "Amessak",
+ "Your server isn't responding to some requests.": "Aqeddac-inek·inem ur d-yettarra ara ɣef kra n yisuturen.",
+ "Decline (%(counter)s)": "Agi (%(counter)s)",
+ "Failed to upload profile picture!": "Asali n tewlaft n umaɣnu ur yeddui ara!",
+ "No display name": "Ulac meffer isem",
+ "Export E2E room keys": "Sifeḍ tisura n texxamt E2E",
+ "Do you want to set an email address?": "Tebɣiḍ ad tazneḍ tansa n yimayl?",
+ "Your homeserver does not support cross-signing.": "Aqeddac-ik·im agejdan ur yessefrak ara azmul anmidag.",
+ "Cross-signing and secret storage are enabled.": "Azmul anmidag d uklas uffir ur ttwaremden ara.",
+ "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Amiḍan-inek·inem ɣer-s timagit n uzmul anmidag deg uklas uffir, maca mazal ur yettwaman ara sɣur taxxamt-a.",
+ "Cross-signing and secret storage are not yet set up.": "Azmul anmidag d uklas uffir mazal ar tura ur ttusbadeun ara.",
+ "Reset cross-signing and secret storage": "Wennez azmul anmidag d uklas uffir",
+ "Bootstrap cross-signing and secret storage": "Azmul anmidag s tazwara d uklas uffir",
+ "well formed": "imsel akken iwata",
+ "unexpected type": "anaw ur nettwaṛǧa ara",
+ "Cross-signing public keys:": "Tisura n uzmul anmidag tizuyaz:",
+ "in memory": "deg tkatut",
+ "Cross-signing private keys:": "Tisura tusligin n uzmul anmidag:",
+ "Create room": "Rnu taxxamt",
+ "System Alerts": "Ilɣa n unagraw",
+ "Forget this room": "Ttu taxxamt-a",
+ "Reject & Ignore user": "Agi & Zgel aseqdac",
+ "%(roomName)s does not exist.": "%(roomName)s ulac-it.",
+ "Don't ask me again": "Ur d-sutur ara tikelt-nniḍen",
+ "Show rooms with unread messages first": "Sken tixxamin yesεan iznan ur nettwaɣra ara d timezwura",
+ "List options": "Tixtiṛiyin n tebdart",
+ "Show %(count)s more|other": "Sken %(count)s ugar",
+ "Show %(count)s more|one": "Sken %(count)s ugar",
+ "Use default": "Seqdec udem amezwer",
+ "Notification options": "Tixtiṛiyin n wulɣu",
+ "Room options": "Tixtiṛiyin n texxamt",
+ "%(count)s unread messages including mentions.|one": "1 ubdar ur nettwaɣra ara.",
+ "%(count)s unread messages.|other": "Iznan ur nettwaɣra ara %(count)s.",
+ "%(count)s unread messages.|one": "1 yizen ur nettwaɣra ara.",
+ "Unread messages.": "Iznan ur nettwaɣra ara.",
+ "All Rooms": "Akk tixxamin",
+ "Unknown Command": "Taladna tarussint",
+ "Show Stickers": "Sken istikiyen",
+ "Mark all as read": "Creḍ kullec yettwaɣra",
+ "Error creating address": "Tuccḍa deg tmerna n tensa",
+ "Error removing address": "Tuccḍa deg tukksa n tensa",
+ "Main address": "Tansa tagejdant",
+ "Local address": "Tansa tadigant",
+ "Published Addresses": "Tansiwin tizuyaz",
+ "Local Addresses": "Tansiwin tidiganin",
+ "Room Name": "Isem n texxamt",
+ "Room Topic": "Asentel n texxamt",
+ "Room avatar": "Avaṭar n texxamt",
+ "Accepting…": "Aqbal…",
+ "Your homeserver": "Aqeddac-ik·im agejdan",
+ "Accepting …": "Aqbal…",
+ "Your display name": "Isem-ik·im yettwaskanen",
+ "Your avatar URL": "URL n avatar-inek·inem",
+ "%(brand)s URL": "%(brand)s URL",
+ "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "Aseqdec n uwiǧit-a yezmer ad yebḍu isefka d %(widgetDomain)s & amsefrak-inek·inem n umsidef.",
+ "Using this widget may share data with %(widgetDomain)s.": "Aseqdec n uwiǧit-a yezmer ad bḍun yisefka d %(widgetDomain)s.",
+ "Widgets do not use message encryption.": "Iwiǧiten ur seqdacen ara awgelhen n yiznan.",
+ "Widget added by": "Awiǧit yettwarna sɣur",
+ "This widget may use cookies.": "Awiǧit-a yezmer ad iseqdec inagan n tuqqna.",
+ "Delete Widget": "Kkes awiǧit",
+ "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Tukksan n uwiǧit, ad t-tekkes akk i yiseqdacen n texxamt-nni. D tidet tebɣiḍ ad tekkseḍ awiǧit-a?",
+ "Delete widget": "Kkes awiǧit",
+ "Failed to remove widget": "Tukksa n uwiǧit ur teddi ara",
+ "An error ocurred whilst trying to remove the widget from the room": "Tella-d tuccḍa lawan n tukksa n uwiǧit seg texxamt",
+ "Minimize apps": "Semi isnasen",
+ "Maximize apps": "Semer isnasen",
+ "Popout widget": "Awiǧit attalan",
+ "Please create a new issue on GitHub so that we can investigate this bug.": "Ttxil-k·m rnu ugur amaynut deg GitHub akken ad nessiweḍ ad nezrew abug-a.",
+ "expand": "snefli",
+ "You cannot delete this image. (%(code)s)": "Ur tezmireḍ ara ad tekkseḍ tugna-a. (%(code)s)",
+ "Uploaded on %(date)s by %(user)s": "Yuli-d deg %(date)s sɣur %(user)s",
+ "Rotate Left": "Zzi ɣer uzelmaḍ",
+ "Rotate Right": "Zzi ɣer uyeffus",
+ "Language Dropdown": "Tabdart n udrurem n tutlayin",
+ "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)srnan-d %(count)s tikkal",
+ "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)srnan-d",
+ "%(oneUser)sjoined %(count)s times|other": "%(oneUser)syerna-d %(count)s tikkal",
+ "%(oneUser)sjoined %(count)s times|one": "%(oneUser)syerna-d",
+ "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)sffɣen %(count)s tikkal",
+ "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s ffɣen",
+ "%(oneUser)sleft %(count)s times|other": "%(oneUser)s yeffeɣ %(count)s tikkal",
+ "%(oneUser)sleft %(count)s times|one": "%(oneUser)s yeffeɣ",
+ "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)srnan-d syen ffɣen %(count)s tikkal",
+ "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)srnan-d syen ffɣen",
+ "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)syerna-d syen yeffeɣ %(count)s tikkal",
+ "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)syerna-d syen yeffeɣ",
+ "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)sffɣen syen uɣalen-d %(count)s tikkal",
+ "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)sffɣen syen uɣalen-d",
+ "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)syeffeɣ-d syen yuɣal-d %(count)s tikkal",
+ "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)syeffeɣ-d syen yuɣal-d",
+ "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)sugin tinubgiwin-nsen %(count)s tikkal",
+ "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)sugin tinubgiwin-nsen",
+ "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)syugi tinubga-ines %(count)s tikkal",
+ "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)syugi tinubga-ines",
+ "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)sunfen i tinubgiwin-nsen yettwagin %(count)s tikkal",
+ "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "%(severalUsers)sunfen i tinubgiwin-nsen yettwagin",
+ "%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)syunef i tinubga-ines yettwagin %(count)s tikkal",
+ "%(oneUser)shad their invitation withdrawn %(count)s times|one": "%(oneUser)syunef i tinubga-ines yettwagin",
+ "were invited %(count)s times|other": "ttwanecden-d %(count)s tikkal",
+ "were invited %(count)s times|one": "ttwanecden-d",
+ "was invited %(count)s times|other": "yettwanced-d %(count)s tikkal",
+ "was invited %(count)s times|one": "yettwanced-d",
+ "were banned %(count)s times|other": "ttwazeglen %(count)s tikkal",
+ "were banned %(count)s times|one": "ttwazeglen",
+ "was banned %(count)s times|other": "yettwazgel %(count)s tikkal",
+ "was banned %(count)s times|one": "yettwazgel",
+ "were unbanned %(count)s times|other": "ur ttwazeglen ara %(count)s tikkal",
+ "were unbanned %(count)s times|one": "ur ttwazeglen ara",
+ "was unbanned %(count)s times|other": "ur yettwazgel ara %(count)s tikkal",
+ "was unbanned %(count)s times|one": "ur yettwazgel ara",
+ "were kicked %(count)s times|other": "ttwasuffɣen %(count)s tikkal",
+ "were kicked %(count)s times|one": "ttwasuffɣen",
+ "was kicked %(count)s times|other": "yettwasuffeɣ %(count)s tikkal",
+ "was kicked %(count)s times|one": "yettwasuffeɣ",
+ "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)sbeddlen ismawen-nsen %(count)s tikkal",
+ "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)sbeddlen ismawen-nsen",
+ "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)sibeddel isem-is %(count)s tikkal",
+ "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)sibeddel isem-is",
+ "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)sbeddlen ivaṭaren-nsen %(count)s tikkal",
+ "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)sbeddlen ivaṭaren-nsen",
+ "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)sibeddel avaṭar-ines %(count)s tikkal",
+ "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)sibeddel avaṭar-ines",
+ "%(severalUsers)smade no changes %(count)s times|other": "%(severalUsers)sur gin ara isnifal %(count)s tikkal",
+ "%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)sur gin ara isnifal",
+ "%(oneUser)smade no changes %(count)s times|other": "%(oneUser)sur ye gi ara isnifal %(count)s tikkal",
+ "%(oneUser)smade no changes %(count)s times|one": "%(oneUser)sur ye gi ara isnifal",
+ "QR Code": "Tangalt QR",
+ "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "YEgguma ad d-tali tedyant iɣef d-ttunefk tririt, ahat d tilin ur telli ara neɣ ur tesɛiḍ ara tisirag ad tt-twaliḍ.",
+ "Room address": "Tansa n texxamt",
+ "Some characters not allowed": "Kra n yisekkilen ur ttusirgen ara",
+ "This address is available to use": "Tansa-a tella i useqdec",
+ "This address is already in use": "Tansa-a ha-tt-an yakan deg useqdec",
+ "Room directory": "Akaram n texxamt",
+ "ex. @bob:example.com": "am. @bob:amedya.com",
+ "Looks good": "Ayagi yettban yelha",
+ "Can't find this server or its room list": "D awezɣi ad d-naf aqeddac-a neɣ tabdart-is n texxamt",
+ "All rooms": "Akk tixxamin",
+ "Your server": "Aqeddac-ik·im",
+ "Are you sure you want to remove %(serverName)s": "D tidet tebɣiḍ ad tekkseḍ %(serverName)s",
+ "Remove server": "Kkes aqeddac",
+ "Add a new server": "Rnu aqeddac amaynut",
+ "Enter the name of a new server you want to explore.": "Sekcem isem n uqeddac amaynut i tebɣiḍ ad tesnirmeḍ.",
+ "Add a new server...": "Rnu aqeddac amaynut...",
+ "%(networkName)s rooms": "Tixxamin %(networkName)s",
+ "Matrix rooms": "Tixxamin n Matrix",
+ "That doesn't look like a valid email address": "Ur tettban ara d tansa n yimayl tameɣtut",
+ "You have entered an invalid address.": "Teskecmeḍ tansa n yimayl tarameɣtut.",
+ "Try using one of the following valid address types: %(validTypesList)s.": "Ɛreḍ ad tesqedceḍ yiwen seg wanawen n tansa tameɣtut i d-iteddun: %(validTypesList)s.",
+ "Use an identity server to invite by email. Use the default (%(defaultIdentityServerName)s) or manage in Settings.": "Seqdec aqeddac n timagit i uncad s yimayl. Seqdec (%(defaultIdentityServerName)s) amezwer neɣ sefrek deg yiɣewwaren.",
+ "Use an identity server to invite by email. Manage in Settings.": "Seqdec aqeddac n timagit i uncad s yimayl. Sefrek deg yiɣewwaren.",
+ "This room is public": "Taxxamt-a d tazayezt",
+ "Terms and Conditions": "Tiwtilin d tfadiwin",
+ "Review terms and conditions": "Senqed tiwtilin d tfadiwin",
+ "Your Communities": "Timɣiwnin-inek·inem",
+ "Communities": "Timɣiwnin",
+ "Remove %(name)s from the directory?": "Kkes %(name)s seg ukaram?",
+ "delete the address.": "kkes tansa.",
+ "Room not found": "Ur tettwaf ara texxamt",
+ "Find a room…": "Af-d taxxamt…",
+ "Search rooms": "Nadi tixxamin",
+ "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s yuzen tinubga i %(targetDisplayName)s i wakken ad d-yernu ɣer texxamt.",
+ "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s yerra amazray n texxamt tamaynut yettban i meṛṛa iɛeggalen n texxamt, segmi ara d-ttwanecden.",
+ "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s yerra amazray n texxamt tamaynut yettban i meṛṛa iɛeggalen n texxamt, segmi ara d-rnun.",
+ "%(senderName)s made future room history visible to all room members.": "%(senderName)s yerra amazray n texxamt tamaynut yettban i meṛṛa iɛeggalen n texxamt.",
+ "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s yerra amazray n texxamt tamaynut yettban i wid ur nettwassen ara (%(visibility)s).",
+ "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s seg %(fromPowerLevel)s ɣer %(toPowerLevel)s",
+ "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s yettwabeddel uswir afellay n %(powerLevelDiffText)s.",
+ "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s yekkes alugen i yugin iseqdacen yemṣadan d %(glob)s",
+ "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s yekkes alugen i yugin tixxamin yemṣadan d %(glob)s",
+ "%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s yekkes alugen i yugin iqeddacen yemṣadan d %(glob)s",
+ "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s yekkes alugen n tigtin yemṣadan d %(glob)s",
+ "%(senderName)s updated an invalid ban rule": "%(senderName)s ileqqem alugen n tigtin arameɣtu",
+ "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s ileqqem alugen i yugin iseqdacen yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s ileqqem alugen i yugin tixxamin yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s ileqqem alugen i yugin iqeddacen yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s ileqqem alugen n tigtin yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s yerna alugen i yugin iseqdacen yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s yerna alugen i yugin tixxamin yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s yerna alugen i yugin iqeddacen yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s yerna alugen yemṣadan d %(glob)s i %(reason)s",
+ "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ibeddel alugen i yugin iseqdacen yemṣadan d %(oldGlob)s deg %(newGlob)s yemṣadan i %(reason)s",
+ "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ibeddel alugen i yugin tixxamin yemṣadan d %(oldGlob)s deg %(newGlob)s yemṣadan i %(reason)s",
+ "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ibeddel alugen i yugin tixxamin iqeddacen d %(oldGlob)s deg %(newGlob)s yemṣadan i %(reason)s",
+ "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ibeddel alugen i yemṣadan d %(oldGlob)s deg %(newGlob)s yemṣadan i %(reason)s",
+ "You signed in to a new session without verifying it:": "Teqqneḍ ɣer tɣimit war ma tesneqdeḍ-tt:",
+ "Verify your other session using one of the options below.": "Senqed tiɣimiyin-ik·im tiyaḍ s useqdec yiwet seg textiṛiyin ddaw.",
+ "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) yeqqen ɣer tɣimit tamaynut war ma isenqed-itt:",
+ "Ask this user to verify their session, or manually verify it below.": "Suter deg useqdac-a ad isenqed tiɣimit-is, neɣ senqed-itt ddaw s ufus.",
+ "Ensure you have a stable internet connection, or get in touch with the server admin": "Ḍmen qbel tesɛiḍ tuqqna i igerrzen, neɣ nermes anedbal n uqeddac",
+ "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "Suter deg %(brand)s unedbal ad isenqed tawila-ik·im n unekcam arameɣtu neɣ i d-yuɣalen.",
+ "The message you are trying to send is too large.": "Izen i tettaɛraḍeḍ ad t-tazneḍ ɣezzif aṭas.",
+ "This homeserver has hit its Monthly Active User limit.": "Aqeddac-a agejdan yewweḍ ɣer talast n useqdac urmid n wayyur.",
+ "Please contact your service administrator to continue using the service.": "Ttxil-k·m nermes anedbal-ik·im n uqeddac i wakken ad tkemmleḍ aseqdec n uqeddac.",
+ "Unable to connect to Homeserver. Retrying...": "Yegguma ad yeqqen ɣer uqeddac agejdan. Ales aneɛruḍ...",
+ "Use a few words, avoid common phrases": "Seqdec kra n wawalen, sinef i tefyar i d-yettuɣalen",
+ "No need for symbols, digits, or uppercase letters": "Ulayɣer izamulen, izwilen d yisekkilen imeqqranen",
+ "Make a copy of your recovery key": "Eg anɣal i tsarut-ik·im n uɛeddi",
+ "Create key backup": "Rnu aḥraz n tsarut",
+ "Unable to create key backup": "Yegguma ad yernu uḥraz n tsarut",
+ "If you don't want to set this up now, you can later in Settings.": "Ma yella ur tebɣiḍ ara ad t-tesbaduḍ tura, tzemreḍ ad t-tgeḍ mbeɛd deg yiɣewwaren.",
+ "A new recovery passphrase and key for Secure Messages have been detected.": "Tasarut tuffirt n uɛeddi tamaynut d tsarut i tɣellist n yiznan ttwafent.",
+ "This session is encrypting history using the new recovery method.": "Tiɣimit-a, amazray-ines awgelhen yesseqdac tarrayt n uɛeddi tamaynut.",
+ "If disabled, messages from encrypted rooms won't appear in search results.": "Ma yella tensa, iznan n texxamin tiwgelhanin ur d-ttbanen ara deg yigmaḍ n unadi.",
+ "%(brand)s is securely caching encrypted messages locally for them to appear in search results:": "%(brand)s iteffer iznan iwgelhanen idiganen s wudem aɣelsan i wakken ad d-banen deg yigmaḍ n unadi:",
+ "Message downloading sleep time(ms)": "Akud n usgunfu n usali n yiznan (ms)",
+ "Dismiss read marker and jump to bottom": "Zgel ticreḍt n tɣuri, tɛeddiḍ d akessar",
+ "Show display name changes": "Sken isnifal n yisem yettwaskanen",
+ "Show read receipts sent by other users": "Sken awwaḍen n tɣuri yettwaznen sɣur yiseqdacen-nniḍen",
+ "Show timestamps in 12 hour format (e.g. 2:30pm)": "Sken azemzakud s umasal 12 yisragen (am. 14:30)",
+ "Always show message timestamps": "Sken yal tikkelt azemzakud n yiznan",
+ "Autoplay GIFs and videos": "Taɣuri tawurmant n GIFs d tvidyutin",
+ "When I'm invited to a room": "Mi ara d-ttunecdeɣ ɣer texxamt",
+ "This is your list of users/servers you have blocked - don't leave the room!": "Tagi d tabdart-ik·im n yiseqdacen/yiqeddacen i tesweḥleḍ - ur teffeɣ ara seg texxamt!",
+ "Active call": "Asiwel urmid",
+ "Verified!": "Yettwasenqed!",
+ "Scan this unique code": "Ḍumm tangalt-a tasuft",
+ "Compare unique emoji": "Serwes gar yimujiten asufen",
+ "in secret storage": "deg uklas uffir",
+ "Master private key:": "Tasarut tusligt tagejdant:",
+ "cached locally": "yettwaffer s wudem adigan",
+ "not found locally": "ulac s wudem adigan",
+ "Self signing private key:": "Tasarut tusligt n uzmul awurman:",
+ "User signing private key:": "Tasarut tusligt n uzmul n useqdac:",
+ "Session backup key:": "Tasarut n uḥraz n tɣimit:",
+ "Secret storage public key:": "Tasarut tazayezt n uḥraz uffir:",
+ "Homeserver feature support:": "Asefrek n tmahilt n Homeserver:",
+ "exists": "yella",
+ "Your homeserver does not support session management.": "Aqeddac-ik·im agejdan ur yessefrak ara asefrek n tɣimit.",
+ "Unable to load session list": "Asali n tebdart n tɣimit ur yeddi ara",
+ "Click the button below to confirm deleting these sessions.|other": "Sit ɣef tqeffalt ddaw akken ad tesnetmeḍ tukksa n tɣimiyin-a.",
+ "Click the button below to confirm deleting these sessions.|one": "Sit ɣef tqeffalt ddaw akken ad tesnetmeḍ tukksa n tɣimit-a.",
+ "Unable to load key backup status": "Asali n waddad n uḥraz n tsarut ur yeddi ara",
+ "not stored": "ur yettusekles ara",
+ "Backing up %(sessionsRemaining)s keys...": "Aḥraz n tsura %(sessionsRemaining)s...",
+ "Backup has a valid signature from this user": "Aḥraz ɣer-s azmul ameɣtu sɣur aseqdac-a",
+ "Backup has a invalid signature from this user": "Aḥraz ɣer-s azmul arameɣtu sɣur aseqdac-a",
+ "Backup has a signature from unknown user with ID %(deviceId)s": "Aḥraz ɣer-s azmul sɣur useqdac arussin s usulay %(deviceId)s",
+ "Backup has a signature from unknown session with ID %(deviceId)s": "Aḥraz ɣer-s azmul seg tiɣimit arussin s usulay %(deviceId)s",
+ "Backup has a valid signature from this session": "Aḥraz ɣer-s azmul ameɣtu seg tɣimit-a",
+ "Backup has an invalid signature from this session": "Aḥraz ɣer-s azmul arameɣtu seg tɣimit-a",
+ "Backup has a valid signature from verified session ": "Aḥraz ɣer-s azmul ameɣtu seg tɣimit yettwasneqden ",
+ "Backup has a valid signature from unverified session ": "Aḥraz ɣer-s azmul ameɣtu seg tɣimit ur yettwasneqden ara ",
+ "Backup has an invalid signature from verified session ": "Aḥraz ɣer-s azmul arameɣtu seg tɣimit yettwasneqden ",
+ "Backup has an invalid signature from unverified session ": "Aḥraz ɣer-s azmul arameɣtu seg tɣimit ur yettwasneqden ara ",
+ "Backup is not signed by any of your sessions": "Aḥraz ur yettuzmel ara ula seg yiwet n tɣimit-ik·im",
+ "Algorithm: ": "Alguritm: ",
+ "Backup key stored: ": "Tasarut n uḥraz tettwasekles: ",
+ "Your keys are not being backed up from this session.": "Tisura-inek·inem ur ttwaḥrazent ara seg tɣimit-a.",
+ "Start using Key Backup": "Bdu aseqdec n uḥraz n tsarut",
+ "Flair": "Lbenna",
+ "Failed to change password. Is your password correct?": "Asnifel n wawal uffir ur yeddi ara. Awal-ik·im d ameɣtu?",
+ "Email addresses": "Tansiwin n yimayl",
+ "Phone numbers": "Uṭṭunen n tiliɣri",
+ "Language and region": "Tutlayt d temnaḍt",
+ "Yours, or the other users’ session": "Tiɣimit-ik·im neɣ tin n yiseqdacen wiyaḍ",
+ "Not trusted": "Ur yettwattkal ara",
+ "%(count)s verified sessions|other": "%(count)s isenqed tiɣimiyin",
+ "%(count)s verified sessions|one": "1 n tɣimit i yettwasneqden",
+ "%(count)s sessions|one": "Tiɣimit n %(count)s",
+ "Direct message": "Izen uslig",
+ "Demote yourself?": "Ṣubb deg usellun-ik·im?",
+ "Demote": "Ṣubb deg usellun",
+ "Disinvite": "Kkes-d tinnubga",
+ "Kick": "Suffeɣ",
+ "Failed to kick": "Asuffeɣ ur yeddi ara",
+ "No recent messages by %(user)s found": "Ulac iznan i yettwafen sɣur %(user)s",
+ "Try scrolling up in the timeline to see if there are any earlier ones.": "Ɛreḍ adrurem deg wazemzakud i wakken ad twaliḍ ma yella llan wid yellan uqbel.",
+ "Remove recent messages by %(user)s": "Kkes iznan n melmi kan sɣur %(user)s",
+ "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|other": "Aql-ak·akem akken ara tekkseḍ iznan n %(count)s sɣur %(user)s. Ulac tuɣalin ɣer deffir deg waya. Tebɣiḍ ad tkemmleḍ?",
+ "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|one": "Aql-ak·akem akken ara tekkseḍ 1 yizen sɣur %(user)s. Ulac tuɣalin ɣer deffir deg waya. Tebɣiḍ ad tkemmleḍ?",
+ "For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.": "I tugget meqqren n yiznan, ayagi yezmer ad yeṭṭef kra n wakud. Ṛǧu ur sirin ara amsaɣ-ik·im deg leɛḍil.",
+ "Remove %(count)s messages|other": "Kkes iznan n %(count)s",
+ "Ban": "Agi",
+ "Failed to ban user": "Tigtin n useqdac ur yeddi ara",
+ "Failed to remove user from community": "Tukksa n useqdac seg temɣiwent ur yeddi ara",
+ "%(role)s in %(roomName)s": "%(role)s deg %(roomName)s",
+ "Failed to change power level": "Asnifel n uswir afellay ur yeddi ara",
+ "Failed to deactivate user": "Asensi n useqdac ur yeddi ara",
+ "This client does not support end-to-end encryption.": "Amsaɣ-a ur yessefrak ara awgelhen seg yixef ɣer yixef.",
+ "Ask %(displayName)s to scan your code:": "Suter deg %(displayName)s aḍummu n tengalt-ik·im:",
+ "If you can't scan the code above, verify by comparing unique emoji.": "Ma yella ur tezmireḍ ara ad tḍummeḍ tangalt nnig, senqed s userwes s yimujiten asufen.",
+ "Verify by comparing unique emoji.": "Senqed s userwes s yimujiten asufen.",
+ "Almost there! Is your other session showing the same shield?": "Qrib ad tawḍeḍ! Wissen ma yella tiɣimit-ik·im-nniḍen kifkif aɣar i d-teskanay?",
+ "Almost there! Is %(displayName)s showing the same shield?": "Qrib ad tawḍeḍ! Wissen ma yella%(displayName)s kifkif aɣar i d-yeskanay?",
+ "Verify all users in a room to ensure it's secure.": "Senqed akk iseqdacen yellan deg texxamt i wakken ad tḍemneḍ d taɣelsant.",
+ "In encrypted rooms, verify all users to ensure it’s secure.": "Deg texxamin tiwgelhanin, senqed akk iseqdacen i wakken ad tḍemneḍ d tiɣelsanin.",
+ "You've successfully verified your device!": "Tesneqdeḍ akken iwata ibenk-inek·inem!",
+ "You've successfully verified %(deviceName)s (%(deviceId)s)!": "Tesneqdeḍ akken iwata %(deviceName)s (%(deviceId)s)!",
+ "You've successfully verified %(displayName)s!": "Tesneqdeḍ akken iwata %(displayName)s!",
+ "Start verification again from the notification.": "Bdu asenqed daɣen seg ulɣu.",
+ "Start verification again from their profile.": "Bdu asenqed daɣen seg umaɣnu-nsen.",
+ "You cancelled verification on your other session.": "Tesfesxeḍ asenqed deg tɣimiyin tiyaḍ.",
+ "Compare emoji": "Serwes imujiten",
+ "Encryption not enabled": "Awgelhen ur yermid ara",
+ "The encryption used by this room isn't supported.": "Awgelhen yettusqedcen ur yettusefrak ara s texxamt-a.",
+ "Error decrypting audio": "Tuccḍa deg uwgelhen n umeslaw",
+ "React": "Sedmer",
+ "Message Actions": "Tigawin n yizen",
+ "Invalid file%(extra)s": "D afaylu %(extra)s arameɣtu",
+ "Error decrypting image": "Tuccḍa deg uwgelhen n tugna",
+ "Show image": "Sken tugna",
+ "Invalid base_url for m.identity_server": "D arameɣtu base_url i m.identity_server",
+ "Signing In...": "Anekcum ɣer...",
+ "If you've joined lots of rooms, this might take a while": "Ma yella tettekkaḍ deg waṭas n texxamin, ayagi yezmer ad yeṭṭef kra n wakud",
+ "Set a display name:": "Sbadu isem n uskan:",
+ "Upload an avatar:": "Sali-d avaṭar:",
+ "Use Recovery Key": "Seqdec tasarut n uɛeddi",
+ "Emoji": "Imujit",
+ "For maximum security, this should be different from your account password.": "I wugar n tɣellist, wagi ilaq ad yemgarad ɣef wawal uffir n umiḍan-ik·im.",
+ "Set up with a recovery key": "Sbadu s tsarut n uɛeddi",
+ "Please enter your recovery passphrase a second time to confirm.": "Ttxil-ik·im sekcem tafyirt-ik·im tuffirt n uɛeddi tikkelt tis sant i usentem.",
+ "Repeat your recovery passphrase...": "Ales-as i tefyirt-ik·im tuffirt n uɛeddi...",
+ "Keep a copy of it somewhere secure, like a password manager or even a safe.": "Ḥrez anɣal-ines deg wadeg aɣelsan, am umsefrak n wawalen uffiren neɣ am usenduq iǧehden.",
+ "Your recovery key": "Tasarut-ik·im n uɛeddi",
+ "Your recovery key has been copied to your clipboard, paste it to:": "Tasarut-ik·im n uɛeddi tettwanɣel ɣer ɣef wafus, senteḍ-itt deg:",
+ "Your recovery key is in your Downloads folder.": "Tasarut-ik·im n tririt ha-tt-an deg ufaylu n yisidar.",
+ "Print it and store it somewhere safe": "Siggez-itt syen kles-itt deg wadeg aɣelsan",
+ "Save it on a USB key or backup drive": "Sekles-itt ɣef tsarut USB neɣ deg yibenk n uḥraz",
+ "Copy it to your personal cloud storage": "Nɣel-itt ɣer uklas-ik·im n usigna udmawan",
+ "Your keys are being backed up (the first backup could take a few minutes).": "Tisura-ik·im la ttwaḥrazent (aḥraz amezwaru yezmer ad yeṭṭef kra n tesdidin).",
+ "Set up Secure Message Recovery": "Sbadu iznan iɣelsanen n tririt",
+ "Secure your backup with a recovery passphrase": "Ḍmen aḥrazen-inek·inem s tefyirt tuffirt n uɛeddi",
+ "Unexpected error resolving homeserver configuration": "Tuccḍa ur nettwaṛǧa ara lawan n uṣeggem n twila n uqeddac agejdan",
+ "Unexpected error resolving identity server configuration": "Tuccḍa ur nettwaṛǧa ara lawan n uṣeggem n uqeddac n timagit",
+ "This homeserver has exceeded one of its resource limits.": "Aqeddac-a agejdan iɛedda yiwet seg tlisa-ines tiɣbula.",
+ "Your browser does not support the required cryptography extensions": "Iminig-ik·im ur issefrak ara iseɣzaf n uwgelhen yettusran",
+ "Authentication check failed: incorrect password?": "Asenqed n usesteb ur yeddi ara: awal uffir d arameɣtu?",
+ "Can't leave Server Notices room": "Ur nezmir ara ad neǧǧ taxxamt n yiwenniten n uqeddac",
+ "This room is used for important messages from the Homeserver, so you cannot leave it.": "Taxxamt-a tettuseqdac i yiznan yesɛan azal sɣur aqeddac agejdan, ɣef waya ur tezmireḍ ara ad tt-teǧǧeḍ.",
+ "Error leaving room": "Tuccaḍa deg tuffɣa seg texxamt",
+ "The user must be unbanned before they can be invited.": "Aseqdac ilaq ad yettwakkes uqbel ad izmiren ad t-id-snubegten.",
+ "Use a longer keyboard pattern with more turns": "Seqdec talɣa n unasiw ɣezzifen s wugar n tuzzyiwin",
+ "Capitalization doesn't help very much": "Tira timeqqranin ur tettɛawan ara aṭas",
+ "Reversed words aren't much harder to guess": "Awalen imettiyen ur weɛrit ara i tifin",
+ "Predictable substitutions like '@' instead of 'a' don't help very much": "Isnifal yettbeddilen am '@' deg wadeg n 'a' ur ttɛawanen ara aṭas",
+ "Repeats like \"aaa\" are easy to guess": "Allus am \"aaa\" fessus i usumer",
+ "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Allus am \"abcabcabc\" yewɛer cwiṭ i tifin ɣef \"abc\"",
+ "Sequences like abc or 6543 are easy to guess": "Asemyizwer am abc neɣ 6543 fessus i usumer",
+ "This is similar to a commonly used password": "Wagi kifkif am wawal uffir yettwaseqdacen acḥal n tikkal",
+ "A word by itself is easy to guess": "Awal s timmad-is fessus i usumer",
+ "Names and surnames by themselves are easy to guess": "Ismawen d yismawen n useqdac s timmad-nsen fessusit i usumer",
+ "Common names and surnames are easy to guess": "Ismawen d yismawen n useqdac yettwassnen fessusit i usumer",
+ "Straight rows of keys are easy to guess": "Idurren ubdisen n tsura fessusit i ussumer",
+ "Short keyboard patterns are easy to guess": "Tinerufin n unasiw amecṭuḥ fessusit i ussumer",
+ "Help us improve %(brand)s": "Mudd-aɣ-d tallalt ad nesnerni %(brand)s",
+ "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "Azen inesfka n useqdec udrig ayen ara aɣ-iɛawnen ad nesnerni %(brand)s. Ayagi ad isseqdec inagan n tuqqna.",
+ "Review where you’re logged in": "Senqed ansi i d-tkecmeḍ",
+ "Verify all your sessions to ensure your account & messages are safe": "Senqed akk tiqimiyin-ik·im i wakken ad tḍemneḍ amiḍan-ik·m & yiznan d iɣelsanen",
+ "You are not receiving desktop notifications": "Ur d-termiseḍ ara ilɣa n tnarit",
+ "Your homeserver has exceeded its user limit.": "Aqeddac-inek·inem agejdan yewweḍ ɣer talast n useqdac.",
+ "Your homeserver has exceeded one of its resource limits.": "Aqeddac-inek·inem agejdan iɛedda yiwet seg tlisa-ines tiɣbula.",
+ "Contact your server admin.": "Nermes anedbal-inek·inem n uqeddac.",
+ "To return to your account in future you need to set a password": "Akken ad tuɣaleḍ ɣer umiḍan-ik·im ɣer sdat tesriḍ ad tesbaduḍ awal uffir",
+ "New spinner design": "Afeṣṣel amaynut n tuzzya",
+ "Render simple counters in room header": "Err amsiḍen afessa ɣef uqerru n texxamt",
+ "Multiple integration managers": "Imsefrak n waṭas n yimsidaf",
+ "Try out new ways to ignore people (experimental)": "Ɛreḍ iberdan-nniḍen i tigtin n yimdanen (armitan)",
+ "Show message previews for reactions in DMs": "Sken timeẓriwin n yiznan i tsedmirin deg DMs",
+ "Show message previews for reactions in all rooms": "Sken timeẓriwin n yiznan i tsedmirin deg meṛṛa tixxamin",
+ "Enable advanced debugging for the room list": "Rmed tamseɣtayt leqqayen i tebdart n texxamt",
+ "Enable big emoji in chat": "Rmed imujit ameqqran deg udiwenni",
+ "Automatically replace plain text Emoji": "Semselsi iujit n uḍris aččuran s wudem awurman",
+ "Enable Community Filter Panel": "Rmed agalis n umsizdeg n temɣiwent",
+ "Use a system font": "Seqdec tasefsit n unagraw",
+ "Size must be a number": "Teɣzi ilaq ad tili d uṭṭun",
+ "Message layout": "Talɣa n yizen",
+ "Discovery": "Tagrut",
+ "Help & About": "Tallalt & Ɣef",
+ "Homeserver is": "Aqeddac agejdan d",
+ "Identity Server is": "Aqeddac n timagit d",
+ "Access Token:": "Ajuṭu n unekcum:",
+ "click to reveal": "sit i ubeggen",
+ "Labs": "Tinarimin",
+ "Customise your experience with experimental labs features. Learn more.": "Sagen tarmit-ik·im s tmahilin n tinarimin tirmitanin. Issin ugar.",
+ "Error adding ignored user/server": "Tuccḍa deg tmerna n useqdac/uqeddac yettwanfen",
+ "Something went wrong. Please try again or view your console for hints.": "Yella wayen ur nteddu ara akken iwata, ma ulac aɣilif ales tikkelt-nniḍen neɣ senqed tadiwent-ik·im i yiwellihen.",
+ "Error subscribing to list": "Tuccḍa deg ujerred ɣef tebdart",
+ "Please verify the room ID or address and try again.": "Ma ulac aɣilif senqed asulay n texxamt neɣ tansa syen ɛreḍ tikkelt-nniḍen.",
+ "Error removing ignored user/server": "Tuccḍa deg tukksa n useqdac/uqeddac yettwanfen",
+ "Please try again or view your console for hints.": "Ma ulac aɣilif ales tikkelt-nniḍen neɣ senqed tadiwent-ik·im i yiwellihen.",
+ "Ban list rules - %(roomName)s": "Ilugan n tebdart n tigtin - %(roomName)s",
+ "You have not ignored anyone.": "Ur tunifeḍ ula i yiwen.",
+ "You are not subscribed to any lists": "Ur tettwajerrdeḍ ula deg yiwet n tebdart",
+ "View rules": "Senqed ilugan",
+ "You are currently subscribed to:": "Aql-ak·akem akka tura tjerrdeḍ ɣer:",
+ "⚠ These settings are meant for advanced users.": "⚠ Iɣewwaren-a n yiseqdac ifazen.",
+ "Subscribed lists": "Tibdarin n ujerred",
+ "Import E2E room keys": "Kter tisura n texxamt E2E",
+ "Cryptography": "Awgelhan",
+ "Session key:": "Tasarut n tɣimit:",
+ "Bulk options": "Tixtiṛiyin s ubleɣ",
+ "Accept all %(invitedRooms)s invites": "Qbel akk tinubgiwin %(invitedRooms)s",
+ "Reject all %(invitedRooms)s invites": "Agi akk tinubgiwin %(invitedRooms)s",
+ "Key backup": "Araz n tsarut",
+ "Cross-signing": "Azmul anmidag",
+ "Security & Privacy": "Taɣellist & tbaḍnit",
+ "Where you’re logged in": "Ansi i d-tkecmeḍ",
+ "Learn more about how we use analytics.": "Issin ugar ɣef wamek i nesseqdac tasleḍt.",
+ "No media permissions": "Ulac tisirag n umidyat",
+ "Missing media permissions, click the button below to request.": "Ulac tisirag n umidyat, sit ɣef tqeffalt ddaw i usentem.",
+ "Request media permissions": "Suter tisirag n umidyat",
+ "No Audio Outputs detected": "Ulac tuffɣiwin n umeslaw i d-yettwafen",
+ "No Microphones detected": "Ulac isawaḍen i d-yettwafen",
+ "No Webcams detected": "Ulac tikamiṛatin i d-yettwafen",
+ "Audio Output": "Tuffɣa n umeslaw",
+ "View older messages in %(roomName)s.": "Senqed iznan iqburen deg %(roomName)s.",
+ "Room information": "Talɣut n texxamt",
+ "Developer options": "Tixtiṛiyin s uneflay",
+ "This room is bridging messages to the following platforms. Learn more.": "Taxxamt-a tettcuddu iznan ɣer tɣerɣar i d-iteddun. Issin ugar.",
+ "This room isn’t bridging messages to any platforms. Learn more.": "Taxxamt-a ur tettcuddu ara iznan ɣer tɣerɣar i d-iteddun. Issin ugar.",
+ "Bridges": "Tileggiyin",
+ "Room Addresses": "Tansiwin n texxamt",
+ "URL Previews": "Tiskanin n URL",
+ "Uploaded sound": "Ameslaw i d-yulin",
+ "Set a new custom sound": "Sbadu ameslaw udmawan amaynut",
+ "Change room avatar": "Beddel avaṭar n texxamt",
+ "Change room name": "Beddel isem n texxamt",
+ "Change history visibility": "Beddel amazray n texxamt",
+ "Modify widgets": "Snifel iwiǧiten",
+ "Unban": "Asefsex n tigtin",
+ "Error changing power level requirement": "Tuccḍa deg usnifel n tuttra n uswir afellay",
+ "Error changing power level": "Tuccḍa deg usnifel n uswir afellay",
+ "Notify everyone": "Selɣu yal yiwen",
+ "Send %(eventType)s events": "Azen tidyanin n %(eventType)s",
+ "Roles & Permissions": "Timlellay & Tisirag",
+ "Click here to fix": "Sit dagi i uṣeggem",
+ "To link to this room, please add an address.": "I ucuddu ɣer texxamt-a, ttxil-k·m rnu tansa.",
+ "Only people who have been invited": "Ala imdanen i d-yettusnubegten",
+ "Anyone who knows the room's link, apart from guests": "Yal win·tin yessnen aseɣwen n texxamt slid inebgawen",
+ "Anyone who knows the room's link, including guests": "Yal win·tin yessnen aseɣwen n texxamt rnu-d ɣer-sen inebgawen",
+ "Members only (since the point in time of selecting this option)": "Iɛeggalen kan (segmi yebda ufran n textiṛit-a)",
+ "Members only (since they were invited)": "Iɛeggalen kan (segmi ara d-ttwanecden)",
+ "Members only (since they joined)": "Iɛeggalen kan (segmi ara d-ttwarnun)",
+ "Encrypted": "Yettwawgelhen",
+ "Who can access this room?": "Anwa i izemren ad d-yernu ɣer texxamt-a?",
+ "Who can read history?": "Anwa i izemren ad d-iɣer amazray?",
+ "Unable to revoke sharing for email address": "Asefsex n beṭṭu n tansa n yimayl ur yeddi ara",
+ "Unable to share email address": "Beṭṭu n tansa n yimayl ur yeddi ara",
+ "Your email address hasn't been verified yet": "Tansa n yimayl-ik·im ur tettwasenqed ara akka ar tura",
+ "Unable to verify email address.": "Asenqed n tansa n yimayl ur yeddi ara.",
+ "Verify the link in your inbox": "Senqed aseɣwen deg tbewwaḍt-ik·im n yimayl",
+ "Revoke": "Ḥwi",
+ "Unable to revoke sharing for phone number": "Aḥwi n beṭṭu n tansa n yimayl ur yeddi ara",
+ "Unable to share phone number": "Beṭṭu n wuṭṭun n tilifun ur yeddi ara",
+ "Unable to verify phone number.": "Asenqed n wuṭṭun n tilifun ur yeddi ara.",
+ "Incorrect verification code": "Tangalt n usenqed d tarussint",
+ "Please enter verification code sent via text.": "Ttxil-k·m sekcem tangalt n usenqed i ak·am-d-yettwaznen s SMS.",
+ "Unable to remove contact information": "Tukksa n talɣut n unermas ur teddi ara",
+ "Invalid Email Address": "Tansa n yimayl d tarameɣtut",
+ "This doesn't appear to be a valid email address": "Tagi ur tettban ara d tansa n yimayl tameɣtut",
+ "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "Izen n uḍris yettwazen ɣer +%(msisdn)s. Ttxil-k·m sekcem tangalt n usenqed yellan deg-s.",
+ "Cannot add any more widgets": "Ur yezmir ara ad yernu ugar n yiwiǧiten",
+ "Add a widget": "Rnu awiǧit",
+ "Drop File Here": "Sers afaylu dagi",
+ "Drop file here to upload": "Eǧǧ afaylu dagi i usali",
+ " (unsupported)": " ·(ur yettwasefrak ara)",
+ "Join as voice or video.": "Ttekki d taɣuct neɣ tavidyut.",
+ "Ongoing conference call%(supportedText)s.": "Asarag s usiwel iteddu%(supportedText)s.",
+ "This user has not verified all of their sessions.": "Aseqdac-a ur issenqed ara akk tiɣimiyin-ines.",
+ "You have not verified this user.": "Ur tesneqdeḍ aea aseqdac-a.",
+ "You have verified this user. This user has verified all of their sessions.": "Tesneqdeḍ aseqdac-a. Aseqdac-a issenqed akk tiɣimiyin-ines.",
+ "Someone is using an unknown session": "Yella win yesseqdacen tiɣimit tarussint",
+ "Everyone in this room is verified": "Yal yiwen deg taxxamt-a yettwasenqed",
+ "Mod": "Atrar",
+ "This event could not be displayed": "Tadyant-a ur tezmir ad d-tettwaskan",
+ "%(senderName)s sent an image": "%(senderName)s yuzen-d tugna",
+ "%(senderName)s sent a video": "%(senderName)s yuzen-d tavidyut",
+ "%(senderName)s uploaded a file": "%(senderName)s yessuli-d afaylu",
+ "Your key share request has been sent - please check your other sessions for key share requests.": "Asuter-ik·im n beṭṭ n tsarut yettwazen - ttxil-k·m senqed tiɣimiyin-ik·im-nniḍen i yisutar n beṭṭu n tsarut.",
+ "Re-request encryption keys from your other sessions.": "Suter i tikkelt-nniḍen tisura n uwgelhen seg tɣimiyin-ik·im tiyaḍ.",
+ "Encrypted by an unverified session": "Yettuwgelhen s tɣimit ur nettwasenqed ara",
+ "Unencrypted": "Ur yettwawgelhen ara",
+ "The authenticity of this encrypted message can't be guaranteed on this device.": "Asesteb n yizen-a awgelhen ur yettwaḍman ara deg yibenk-a.",
+ "Please select the destination room for this message": "Ttxil-k·m fren taxxamt n userken n yizen-a",
+ "Invited": "Yettwancad",
+ "Hangup": "Ɛelleq",
+ "Emoji picker": "Amefran n yimujit",
+ "The conversation continues here.": "Adiwenni yettkemmil dagi.",
+ "This room has been replaced and is no longer active.": "Taxxamt-a ad tettusmelsi, dayen d tarurmidt.",
+ "You do not have permission to post to this room": "Ur tesεiḍ ara tasiregt ad d-tsuffɣeḍ deg texxamt-a",
+ "Code block": "Iḥder n tengalt",
+ "Unpin Message": "Senser-d izen",
+ "Jump to message": "Ɛeddi ɣer yizen",
+ "%(duration)ss": "%(duration)ss",
+ "%(duration)sm": "%(duration)sm",
+ "%(duration)sh": "%(duration)sh",
+ "%(duration)sd": "%(duration)sd",
+ "Unknown for %(duration)s": "D arussin azal n %(duration)s",
+ "Offline": "Beṛṛa n tuqqna",
+ "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Iwala-t %(displayName)s (%(userName)s) ɣef %(dateTime)s",
+ "Room %(name)s": "Taxxamt %(name)s",
+ "No recently visited rooms": "Ulac taxxamt yemmeẓren melmi kan",
+ "No rooms to show": "Ulac tixxamin i uskan",
+ "Unnamed room": "Taxxamt war isem",
+ "World readable": "Amaḍal yettwaɣran",
+ "(~%(count)s results)|other": "(~%(count)s igmaḍ)",
+ "Share room": "Bḍu taxxamt",
+ "Invites": "Inced-d",
+ "Start chat": "Bdu adiwenni",
+ "Create new room": "Rnu taxxamt tamaynut",
+ "Explore public rooms": "Snirem tixxamin tizuyaz",
+ "Low priority": "Tazwart taddayt",
+ "Historical": "Amazray",
+ "Can't see what you’re looking for?": "Ur yezmir ara ad iwali acu i tettnadiḍ?",
+ "Explore all public rooms": "Snirem akk tixxamin tizuyaz",
+ "%(count)s results|other": "%(count)s yigmaḍ",
+ "Joining room …": "Rnu ɣer texxamt…",
+ "You were kicked from %(roomName)s by %(memberName)s": "Tettwasuffɣeḍ-d seg %(roomName)s sɣur %(memberName)s",
+ "Reason: %(reason)s": "Taɣzint: %(reason)s",
+ "You were banned from %(roomName)s by %(memberName)s": "Tettwaɛezleḍ-d seg %(roomName)s sɣur %(memberName)s",
+ "Something went wrong with your invite to %(roomName)s": "Yella wayen ur nteddu ara akken ilaq d tinubga-ik·im ɣer %(roomName)s",
+ "unknown error code": "tangalt n tuccḍa tarussint",
+ "You can only join it with a working invite.": "Tzemreḍ kan ad ternuḍ ɣer-s ala s tinubga n uxeddim.",
+ "You can still join it because this is a public room.": "Mazal tzemreḍ ad ternuḍ ɣer-s acku taxxamt-a d tazayezt.",
+ "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "Tinubga-a ɣer %(roomName)s tettwazen i %(email)s ur nettwacudd ara d umiḍan-ik·im",
+ "Link this email with your account in Settings to receive invites directly in %(brand)s.": "Qqen imayl-a ɣer umiḍan-ik·im deg yiɣewwaren i wakken ad d-tremseḍ tinubgiwin srid deg %(brand)s.",
+ "This invite to %(roomName)s was sent to %(email)s": "Tinubga-a ɣer %(roomName)s tettwazen i %(email)s",
+ "Use an identity server in Settings to receive invites directly in %(brand)s.": "Seqdec aqeddac n timagit deg yiɣewwaren i wakken ad d-tremseḍ tinubgiwin srid deg %(brand)s.",
+ "Share this email in Settings to receive invites directly in %(brand)s.": "Bḍu imayl-a deg yiɣewwaren i wakken ad d-tremseḍ tinubgiwin srid deg %(brand)s.",
+ "Do you want to chat with %(user)s?": "Tebɣiḍ ad temmeslayeḍ d %(user)s?",
+ " wants to chat": " yebɣa ad immeslay",
+ "Do you want to join %(roomName)s?": "Tebɣiḍ ad tettekkiḍ deg %(roomName)s?",
+ " invited you": " inced-ik·im",
+ "You're previewing %(roomName)s. Want to join it?": "Tessenqadeḍ %(roomName)s. Tebɣiḍ ad ternuḍ ɣur-s?",
+ "%(roomName)s can't be previewed. Do you want to join it?": "%(roomName)s ur tezmir ara ad tettwasenqed. Tebɣiḍ ad ternuḍ ɣer-s?",
+ "Favourited": "Yettusmenyaf",
+ "Favourite": "Asmenyif",
+ "Low Priority": "Tazwart taddayt",
+ "%(count)s unread messages including mentions.|other": "%(count)s yiznan ur nettwaɣra ara rnu ɣer-sen ibdaren.",
+ "This room has already been upgraded.": "Taxxamt-a tettuleqqam yakan.",
+ "This room is running room version , which this homeserver has marked as unstable.": "Taxxamt-a tesedday lqem n texxamt , i yecreḍ uqeddac-a agejdan ur yerkid ara.",
+ "Only room administrators will see this warning": "Ala inedbalen kan n texxamt ara iwalin tuccḍa-a",
+ "Server unavailable, overloaded, or something else went wrong.": "Aqeddac ulac-it, neɣ iɛebba aṭas neɣ yella wayen ur nteddu ara akken ilaq.",
+ "You're all caught up.": "Tessawḍeḍ ad tqeḍɛeḍ kullec.",
+ "The server has denied your request.": "Aqeddac yugi asuter-ik·im.",
+ "Your area is experiencing difficulties connecting to the internet.": "Tamnaḍt-ik·im temlal-d uguren n tuqqna ɣer internet.",
+ "A connection error occurred while trying to contact the server.": "Tuccḍa deg tuqqna lawan n uneɛruḍ ad nnermes aqeddac.",
+ "The server is not configured to indicate what the problem is (CORS).": "Aqeddac ur yettusesteb ara i wakken ad d-imel anida-t wugur (CORPS).",
+ "Recent changes that have not yet been received": "Isnifal imaynuten ur d-newwiḍ ara akka ar tura",
+ "Sign out and remove encryption keys?": "Ffeɣ syen kkes tisura tiwgelhanin?",
+ "You have successfully set a password!": "Tesbaduḍ akken iwata awal uffir!",
+ "You have successfully set a password and an email address!": "Tesbaduḍ akken iwata awal uffird tansa n yimayl!",
+ "You can now return to your account after signing out, and sign in on other devices.": "Tzemreḍ tura ad tuɣaleḍ ɣer umiḍan-ik·im mbeɛd mi d-teffɣeḍ, syen kcem ɣer yibenkan-nniḍen.",
+ "Remember, you can always set an email address in user settings if you change your mind.": "Cfu, tzemreḍ melmi i ak-yehwa ad tesbaduḍ tansa n yimayl deg yiɣewwaren n useqdac ma yella tbeddleḍ ṛṛay-ik·im.",
+ "(HTTP status %(httpStatus)s)": "(HTTP addad %(httpStatus)s)",
+ "Please set a password!": "Ttxil-ik·im sbadu awal uffir!",
+ "This will allow you to return to your account after signing out, and sign in on other sessions.": "Ayagi ad ak·akem-yeǧǧ ad tuɣaleḍ ɣer umiḍan-ik·im mbeɛd mi d-teffɣeḍ, syen kcem ɣer yibenkan-nniḍen.",
+ "Share Room": "Bḍu taxxamt",
+ "Link to most recent message": "Aseɣwen n yizen akk aneggaru",
+ "Share Room Message": "Bḍu izen n texxamt",
+ "Command Help": "Tallalt n tiludna",
+ "Integration Manager": "Amsefrak n umsidef",
+ "Find others by phone or email": "Af-d wiyaḍ s tiliɣri neɣ s yimayl",
+ "Be found by phone or email": "Ad d-yettwaf s tiliɣri neɣ s yimayl",
+ "Upload files (%(current)s of %(total)s)": "Sali-d ifuyla (%(current)s ɣef %(total)s)",
+ "Liberate your communication": "Serreḥ i teywalt-ik·im",
+ "Explore Public Rooms": "Snirem tixxamin tizuyaz",
+ "Create a Group Chat": "Rnu adiwenni n ugraw",
+ "This room is not public. You will not be able to rejoin without an invite.": "Taxxamt-a mačči d tazayezt. Ur tezmireḍ ara ad ternuḍ ɣer-s war tinubga.",
+ "Are you sure you want to leave the room '%(roomName)s'?": "S tidet tebɣiḍ ad teǧǧeḍ taxxamt '%(roomName)s'?",
+ "For security, this session has been signed out. Please sign in again.": "Ɣef ssebba n tɣellist, taxxamt-a ad temdel. Ttxil-k·m ɛreḍ tikkelt-nniḍen.",
+ "Old cryptography data detected": "Ala isefka iweglehnen i d-iteffɣen",
+ "%(creator)s created and configured the room.": "%(creator)s yerna-d taxxamt syen yeswel taxxamt.",
+ "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.": "Tzemreḍ ad tjerrdeḍ, maca kra n tmahilin ur ttilint ara almi yuɣal-d uqeddac n tmagit. Ma mazal tettwaliḍ alɣu-a, senqed tawila-inek•inem neɣ nermes anedbal n uqeddac.",
+ "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.": "Tzemreḍ ad talseḍ awennez i wawal-ik•im uffir, maca kra n tmahilin ur ttilint ara almi yuɣal-d uqeddac n tmagit. Ma mazal tettwaliḍ alɣu-a, senqed tawila-inek•inem neɣ nermes anedbal n uqeddac.",
+ "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.": "Tzemreḍ ad teqqneḍ, maca kra n tmahilin ur ttilint ara almi yuɣal-d uqeddac n tmagit. Ma mazal tettwaliḍ alɣu-a senqed tawila-inek•inem neɣ nermes anedbal n uqeddac.",
+ "Verify yourself & others to keep your chats safe": "Senqed iman-ik•im d wiyaḍ akken ad qqimen yidiwenniyen-ik•im d iɣellsanen",
+ "The person who invited you already left the room.": "Amdan i k•kem-iɛerḍen dayen yeǧǧa taxxamt.",
+ "The person who invited you already left the room, or their server is offline.": "Amdan i k•kem-iɛerḍen dayen yeǧǧa taxxamt, neɣ d aqeddac-is i d aruqqin.",
+ "Show info about bridges in room settings": "Sken-d tilɣa ɣef teqneṭrin deg yiɣewwaṛen n texxamt",
+ "Enable Emoji suggestions while typing": "Rmed asumer n yimujiten deg wakud n tira",
+ "Use a more compact ‘Modern’ layout": "Seqdec taneɣruft 'tatrart' yessden ugar",
+ "Show a placeholder for removed messages": "Sken-d iznan yettwakksen",
+ "Show join/leave messages (invites/kicks/bans unaffected)": "Sken iznan n tmerna d tuffɣa (tinubgiwin/asufeɣ/anfay ur ttwaḥsaben ara)",
+ "Enable automatic language detection for syntax highlighting": "Rmed tifin tawurmant n tutlayt i useɣti n tira",
+ "Show avatars in user and room mentions": "Sken ivaṭaren deg yibdaren n useqdac neɣ n texxamt",
+ "Never send encrypted messages to unverified sessions in this room from this session": "Ur ttazen ara akk iznan yettwawgelhen ɣer tɣimiyin ur nettusenqad ara seg tɣimit-a",
+ "Enable URL previews by default for participants in this room": "Rmed tiskanin n URL s wudem amezwer i yimttekkiyen deg texxamt-a",
+ "Allow Peer-to-Peer for 1:1 calls": "Sireg isawalen udem e wudem i 1:1",
+ "Enable inline URL previews by default": "Rmed tiskanin n URL srid s wudem amezwer",
+ "Enable URL previews for this room (only affects you)": "Rmed tiskanin n URL i texxamt-a (i ak·akem-yeɛnan kan)",
+ "Enable widget screenshots on supported widgets": "Rmed tuṭṭfiwin n ugdil n uwiǧit deg yiwiǧiten yettwasferken",
+ "Identity Server (%(server)s)": "Aqeddac n timagit (%(server)s)",
+ "Identity Server": "Aqeddac n timagit",
+ "Enter a new identity server": "Sekcem aqeddac n timagit amaynut",
+ "No update available.": "Ulac lqem i yellan.",
+ "Hey you. You're the best!": "Kečč·kemm. Ulac win i ak·akem-yifen!",
+ "Use between %(min)s pt and %(max)s pt": "Seqdec gar %(min)s pt d %(max)s pt",
+ "Explore Room State": "Snirem addad n texxamt",
+ "Explore Account Data": "Snirem isefka n umiḍan",
+ "View Servers in Room": "Senqed iqeddacen deg texxamt",
+ "Toolbox": "Tabewwaḍt n yifecka",
+ "Developer Tools": "Ifecka n uneflay",
+ "An error has occurred.": "Tella-d tuccḍa.",
+ "Integrations are disabled": "Imsidaf ttwasensen",
+ "Integrations not allowed": "Imsidaf ur ttusirgen ara",
+ "a new master key signature": "tasarut tusligt tagejdant tamaynut",
+ "a new cross-signing key signature": "azmul amaynut n tsarut n uzmul amdigan",
+ "a device cross-signing signature": "azmul n uzmul amdigan n yibenk",
+ "a key signature": "azmul n tsarut",
+ "%(brand)s encountered an error during upload of:": "%(brand)s yemlal-d d tuccḍa mi ara d-yessalay:",
+ "Cancelled signature upload": "Asali n uzmul yettwasefsex",
+ "Unable to upload": "Yegguma ad d-yali",
+ "Signature upload failed": "Asali n uzmul ur yeddi ara",
+ "Incompatible local cache": "Tuffra tadigant ur temṣada ara",
+ "Room Settings - %(roomName)s": "Iɣewwaren n texxamt - %(roomName)s",
+ "The room upgrade could not be completed": "Aleqqem n texxamt yegguma ad yemmed",
+ "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Sken asmekti i urmed n tririt n yiznan iɣellsanen deg texxamin yettwawgelhen",
+ "Show hidden events in timeline": "Sken-d ineḍruyen yeffren deg uzray",
+ "Enable message search in encrypted rooms": "Rmed anadi n yiznan deg texxamin yettwawgelhen",
+ "Manually verify all remote sessions": "Senqed s ufus akk tiɣimiyin tinmeggagin",
+ "IRC display name width": "Tehri n yisem i d-yettwaseknen IRC",
+ "Collecting app version information": "Alqaḍ n telɣa n lqem n usnas",
+ "Uploading logs": "Asali n yiɣmisen",
+ "Downloading logs": "Asader n yiɣmisen",
+ "Messages in one-to-one chats": "Iznan deg yidiwenniyen usriden",
+ "Encrypted messages in one-to-one chats": "Iznan yettwawgelhen deg yidiwenniyen usriden",
+ "Encrypted messages in group chats": "Iznan yettwawgelhen deg yidiwenniyen n ugraw",
+ "Unknown caller": "Asiwel arussin",
+ "The other party cancelled the verification.": "Wayeḍ issefsex asenqed.",
+ "You've successfully verified this user.": "Tesneqdeḍ aseqdac-a akken iwata.",
+ "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Iznan iɣellsanen akked useqdac-a ttwawgelhen seg yixef ɣer yixef yerna yiwen ur yezmir ad ten-iɣeṛ.",
+ "Verify this session by completing one of the following:": "Senqed tiɣimit-a s usmad n tigawin-a:",
+ "Confirm the emoji below are displayed on both sessions, in the same order:": "Sentem dakken imujiten seddaw ttbanen-d deg tɣimiyin i snat, s yiwen n umyizwer:",
+ "Verify this user by confirming the following emoji appear on their screen.": "Senqed aseqdac-a s usentem dakken imujiten-a ttbanen-d ɣef ugdil-is.",
+ "Verify this session by confirming the following number appears on its screen.": "Senqed tiɣimit-a s usentem dakken amḍan-a ittban-d ɣef ugdil-is.",
+ "Verify this user by confirming the following number appears on their screen.": "Senqed aseqdac-a s usentem dakken amḍan-a ittban-d ɣef ugdil-is.",
+ "Waiting for your other session to verify…": "Deg uraǧu n usenqed n tɣimit-ik•im-nniḍen…",
+ "Thumbs up": "Adebbuz d asawen",
+ "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.": "Abeddel n wawal uffir ad yales awennez i tsura akk n uwgelhen seg yixef ɣer yixef deg tɣimiyin akk, d ayen ara yerren amazray n udiwenni ur yettwaɣer ara, anagar ma tsifḍeḍ tisura-inek•inem n uwgelhen seg tazwara ad tɛawdeḍ ad tent-tketreḍ. Ɣer sdat, aya ad yennerni.",
+ "Forces the current outbound group session in an encrypted room to be discarded": "Ḥettem tiɣimit n ugraw ara d-yeffɣen akka tura deg texxamt tawgelhant ad tettwakkes",
+ "Unexpected server error trying to leave the room": "Tuccḍa n uqeddac ur nettwaṛǧa ara lawan n tuffɣa seg texxamt",
+ "Prompt before sending invites to potentially invalid matrix IDs": "Suter send tuzna n tnubgiwin i yisulayen i izmren ad ilin d arimeɣta",
+ "Show shortcuts to recently viewed rooms above the room list": "Sken inegzumen i texxamin i d-ibanen melmi kan nnig tebdart n texxamt",
+ "Send read receipts for messages (requires compatible homeserver to disable)": "Azen inagan n tɣuri i yiznan (yesra aqeddac agejdan yemṣadan i wakken ad yens)",
+ "Show previews/thumbnails for images": "Sken tiskanin/tinfulin i tugniwin",
+ "How fast should messages be downloaded.": "Acḥal i ilaq ad yili urured i wakken ad d-adren yiznan.",
+ "Enable experimental, compact IRC style layout": "Rmed aseflu n uɣanib n IRC armitan, ussid",
+ "Waiting for %(displayName)s to verify…": "Aṛaǧu n %(displayName)s i usenqed…",
+ "Securely cache encrypted messages locally for them to appear in search results, using ": "Ḥrez iznan iwgelhanen idiganen s wudem awurman i wakken ad d-banen deg yigmaḍ n unadi, s useqdec ",
+ "Securely cache encrypted messages locally for them to appear in search results.": "Ḥrez iznan iwgelhanen idiganen s wudem awurman i wakken ad d-banen deg yigmaḍ n unadi.",
+ "The integration manager is offline or it cannot reach your homeserver.": "Amsefrak n umsidef ha-t-an beṛṛa n tuqqna neɣ ur yezmir ara ad yaweḍ ɣer uqeddac-ik·im agejdan.",
+ "This backup is trusted because it has been restored on this session": "Aḥraz yettwaḍman acku yuɣal-d seg tɣimit-a",
+ "Back up your keys before signing out to avoid losing them.": "Ḥrez tisura-ik·im send tuffɣa i wakken ur ttruḥunt ara.",
+ "Error saving email notification preferences": "Tuccḍa deg usekles n yismenyaf n ulɣu n yimayl",
+ "An error occurred whilst saving your email notification preferences.": "Tella-d tuccḍa lawan n usekles n yismenyaf n ulɣu n yimayl.",
+ "Can't update user notification settings": "D awezɣi ad ttwaleqqmen iɣewwaren n yilɣa n useqdac",
+ "Messages containing keywords": "Iznan ideg llan awalen ufrinen",
+ "Notify for all other messages/rooms": "Ṭṭef-d ilɣa i meṛṛa iznan/tixxamin",
+ "Notify me for anything else": "Azen-iyi-d ilɣa i wayen akk ara yellan",
+ "All notifications are currently disabled for all targets.": "Meṛṛa ilɣa nsan akka tura i meṛṛa isaḍasen.",
+ "On": "Yermed",
+ "Noisy": "Sɛan ṣṣut",
+ "wait and try again later": "ṛǧu syen ɛreḍ tikkelt-nniḍen",
+ "You must specify an event type!": "Ilaq ad d-tferneḍ anaw n tedyant!",
+ "Failed to send custom event.": "Ur teddi ara tuzna n tedyant tudmawant.",
+ "Event Type": "Anaw n tedyant",
+ "State Key": "Tasarut n waddad",
+ "Event Content": "Agbur n tedyant",
+ "This session, or the other session": "Tiɣimita, neɣ tiɣimit tayeḍ",
+ "If you didn’t sign in to this session, your account may be compromised.": "Ma yella ur teqqineḍ ara ɣer tɣimit-a, amiḍan-ik·im yezmer ad yettwaker.",
+ "Please fill why you're reporting.": "Ttxil-k·m ini-aɣ-d ayɣer i d-tettazneḍ alɣu.",
+ "Report Content to Your Homeserver Administrator": "Ttxil-k·m azen aneqqis i unedbal-ik·im n usebter agejdan",
+ "Wrong Recovery Key": "Mačči d tasarut-ik·im n uɛeddi tagi",
+ "Invalid Recovery Key": "Tasarut-ik·im n uɛeddi d tarameɣtut",
+ "Security Phrase": "Tafyirt n tɣellist",
+ "Restoring keys from backup": "Tiririt n tsura seg uḥraz",
+ "Fetching keys from server...": "Tiririt n tsura seg uḥraz...",
+ "%(completed)s of %(total)s keys restored": "%(completed)s n %(total)s tsura i yettwarran",
+ "Unable to load backup status": "Yegguma ad d-yali waddad n uḥraz",
+ "Recovery key mismatch": "Tasarut n tririt ur temṣada ara",
+ "No backup found!": "Ulac aḥraz yettwafen!",
+ "Failed to decrypt %(failedCount)s sessions!": "Tukksa n uwgelhen n tɣimiyin %(failedCount)s ur yeddi ara!",
+ "Successfully restored %(sessionCount)s keys": "Tiririt n tsura n %(sessionCount)s yedda akken iwata",
+ "This looks like a valid recovery key!": "Ayagi yettban am wakken tasarut n tririt d tameɣtut!",
+ "Not a valid recovery key": "Tasarut n tririt mačči d tameɣtut",
+ "Are you sure you want to reject the invitation?": "S tidet tebɣiḍ ad tesfesxeḍ tinubga?",
+ "Resend %(unsentCount)s reaction(s)": "Ales tuzna n tsedmirt (tsedmirin) %(unsentCount)s",
+ "Forward Message": "Welleh izen",
+ "Pin Message": "Rzi izen",
+ "View Decrypted Source": "Senqed taɣbalut tawgelhent",
+ "Unhide Preview": "Sban-d taskant",
+ "Take picture": "Ṭṭef-d tawleft",
+ "Away": "Akin",
+ "This homeserver would like to make sure you are not a robot.": "Aqeddac-a aqejdan yesra ad iẓer ma mačči d aṛubut i telliḍ.",
+ "Country Dropdown": "Tabdart n udrurem n tmura",
+ "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.": "Tzemreḍ ad tesqedceḍ tixtiṛiyin n uqeddac udmawan i wakken ad teqqneḍ ɣer iqeddacen-nniḍen n Matrix s ufran n URL n uqeddac agejdan yemgaraden. Ayagi ad ak-yeǧǧ ad tesqedceḍ %(brand)s s umiḍan n Matrix yellan ɣef uqeddac agejdan yemgaraden.",
+ "Confirm your identity by entering your account password below.": "Sentem timagit-ik·im s usekcem n wawal uffir n umiḍan-ik·im ddaw.",
+ "Please review and accept all of the homeserver's policies": "Ttxil-k·m senqed syen qbel tisertiyin akk n uqeddac agejdan",
+ "Please review and accept the policies of this homeserver:": "Ttxil-k·m senqed syen qbel tisertiyin n uqeddac-a agejdan:",
+ "An email has been sent to %(emailAddress)s": "Yettwazen yimayl ɣer %(emailAddress)s",
+ "Token incorrect": "Ajuṭu d arameɣtu",
+ "Identity Server URL": "URL n uqeddac n timagit",
+ "Other servers": "Iqeddacen wiya",
+ "Sign in to your Matrix account on %(serverName)s": "Qqen ɣer umiḍan-ik·im n Matrix deg %(serverName)s",
+ "Sorry, your browser is not able to run %(brand)s.": "Suref-aɣ, iminig-ik·im ur yezmir ara ad iseddu %(brand)s.",
+ "You must register to use this functionality": "Ilaq-ak·am ad teskelseḍ i wakken ad tesxedmeḍ tamahilt-a",
+ "No files visible in this room": "Ulac ifuyla i d-ibanen deg texxamt-a",
+ "Featured Rooms:": "Tixxamin i ifazen:",
+ "Upload avatar": "Sali-d avaṭar",
+ "Failed to forget room %(errCode)s": "Tatut n texxamt %(errCode)s ur teddi ara",
+ "Find a room… (e.g. %(exampleRoom)s)": "Af-d taxxamt… (am. %(exampleRoom)s)",
+ "Search failed": "Ur iddi ara unadi",
+ "No more results": "Ulac ugar n yigmaḍ",
+ "Fill screen": "Agdil aččuran",
+ "Uploading %(filename)s and %(count)s others|other": "Asali n %(filename)s d %(count)s wiyaḍ-nniḍen",
+ "Uploading %(filename)s and %(count)s others|zero": "Asali n %(filename)s",
+ "Uploading %(filename)s and %(count)s others|one": "Asali n %(filename)s d %(count)s wayeḍ-nniḍen",
+ "Security & privacy": "Taɣellist & tbaḍnit",
+ "User menu": "Umuɣ n useqdac",
+ "Could not load user profile": "Yegguma ad d-yali umaɣnu n useqdac",
+ "Session verified": "Tiɣimit tettwasenqed",
+ "Failed to send email": "Tuzna n yimayl ur teddi ara",
+ "New passwords must match each other.": "Awalen uffiren imaynuten ilaq ad mṣadan.",
+ "Your Matrix account on %(serverName)s": "Amiḍan-ik·im Matrix deg %(serverName)s",
+ "I have verified my email address": "Sneqdeɣ tansa-inu n yimayl",
+ "Return to login screen": "Uɣal ɣer ugdil n tuqqna",
+ "Incorrect username and/or password.": "Isem n uqeddac d/neɣ awal uffir d arameɣtu.",
+ "Registration Successful": "Asekles yemmed akken iwata",
+ "Save your Security Key": "Sekles tasarut-ik·im n tɣellist",
+ "Unable to set up secret storage": "Asbadu n uklas uffir d awezɣi",
+ "Paperclip": "Tamessakt n lkaɣeḍ",
+ "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Tettḥeqqeḍ? Ad tesruḥeḍ iznan-ik•im yettwawgelhen ma tisura-k•m ur klisent ara akken ilaq.",
+ "Cactus": "Akermus",
+ "Enter keywords separated by a comma:": "Sekcem awalen uffiren gar-asen tafrayt:",
+ "Add an email address to configure email notifications": "Rnu tansa n yimayl i uswel n yilɣa s yimayl",
+ "Notifications on the following keywords follow rules which can’t be displayed here:": "Ilɣa deg wawalen-a ufranen i d-iteddun ṭṭafaren ilugan ur yezmiren ara ad d-ttwaskanen ara da:",
+ "Unable to fetch notification target list": "D awazɣi ad d-nerr tabdart n yisaḍasen n yilɣa",
+ "There are advanced notifications which are not shown here.": "Llan yilɣa leqqayen ur d-nettwaskan ara da.",
+ "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Ahat tsewleḍ-ten deg yimsaɣ-nniḍen mačči deg %(brand)s. Ur tezmireḍ ara ad ten-tṣeggmeḍ deg %(brand)s maca mazal-iten teddun.",
+ "Show message in desktop notification": "Sken-d iznan deg yilɣa n tnarit",
+ "Identity Server URL must be HTTPS": "URL n uqeddac n timagit ilaq ad yili d HTTPS",
+ "Not a valid Identity Server (status code %(code)s)": "Aqeddac n timagit mačči d ameɣtu (status code %(code)s)",
+ "Could not connect to Identity Server": "Ur izmir ara ad yeqqen ɣer uqeddac n timagit",
+ "Disconnect from the identity server and connect to instead?": "Ffeɣ seg tuqqna n uqeddac n timagit syen qqen ɣer deg wadeg-is?",
+ "Terms of service not accepted or the identity server is invalid.": "Tiwtilin n uqeddac ur ttwaqbalent ara neɣ aqeddac n timagit d arameɣtu.",
+ "The identity server you have chosen does not have any terms of service.": "Aqeddac n timagit i tferneḍ ulac akk ɣer-s tiwtilin n uqeddac.",
+ "Disconnect identity server": "Ffeɣ seg tuqqna n uqeddac n timagit",
+ "Disconnect from the identity server ?": "Ffeɣ seg tuqqna n uqeddac n timagi t?",
+ "You should remove your personal data from identity server before disconnecting. Unfortunately, identity server is currently offline or cannot be reached.": "Ilaq-ak·am ad tekkseḍ isefka-inek·inem udmawanen seg uqeddac n timagit send ad teffɣeḍ seg tuqqna. Nesḥassef, aqeddac n timagit akka tura ha-t beṛṛa n tuqqna neɣ awwaḍ ɣer-s ulamek.",
+ "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "senqed izegrar n yiming-ik·im i kra n wayen i izemren ad isewḥel aqeddac n timagit (am Privacy Badger)",
+ "contact the administrators of identity server ": "nermes inedbalen n uqeddac n timagit ",
+ "You are still sharing your personal data on the identity server .": "Mazal-ik·ikem tbeṭṭuḍ isefka-inek·inem udmawanen ɣef uqeddac n timagit .",
+ "Error encountered (%(errorDetail)s).": "Tuccaḍ i d-yettwamuggren (%(errorDetail)s).",
+ "Custom font size can only be between %(min)s pt and %(max)s pt": "Teɣzi n tsefsit tudmawant tezmer kan ad tili gar %(min)s pt d %(max)s pt",
+ "Error downloading theme information.": "Tuccḍa deg usali n telɣut n usentel.",
+ "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Sbadu isem n tsefsit yettwasbedden ɣef unagraw-ik·im & %(brand)s ad yeɛreḍ ad t-isseqdec.",
+ "Appearance Settings only affect this %(brand)s session.": "Ala iɣewwaren n urwes i izemren ad beddlen kra deg tɣimit-a %(brand)s.",
+ "Deactivating your account is a permanent action - be careful!": "Asensi n umiḍan-inek·inem d ayen ara yilin i lebda - Ɣur-k·m!",
+ "For help with using %(brand)s, click here.": "I tallalt n useqdec n %(brand)s, sit dagi.",
+ "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "I tallalt ɣef useqdec n %(brand)s, sit dagi neɣ bdu adiwenni d wabuṭ-nneɣ s useqdec n tqeffalt ddaw.",
+ "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.": "Ma yella tuzneḍ ugur deg Github, iɣmisen n temseɣtit zemren ad aɣ-ɛiwnen ad negzu ugur. Iɣmisen n temseɣtit deg-sen isefka n useqdec n usnas am yisem n useqdec, am yisulayen neɣ am yismawen i yettunefken i texxamin neɣ i yigrawen ɣer wuɣur terziḍ d yismawen n useqdac n yiseqdacen-nniḍen. Ulac deg-sen iznan.",
+ "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "I wakken ad d-tazneḍ ugur n tɣellist i icudden ɣer Matrix, ttxil-k·m ɣer tasertit n ukcaf n tɣellist deg Matrix.org.",
+ "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.": "Rnu dagi iseqdacen d yiqeddacen i tebɣiḍ ad tzegleḍ. Seqdec izamelen n yitran i wakken %(brand)s ad yemṣada d yal asekkil. D amedya, @bot:* izeggel akk iseqdacen i yesɛan isem \"abuṭ\" ɣef yal aqeddac.",
+ "Subscribing to a ban list will cause you to join it!": "Amulteɣ ɣer tebdart n tegtin ad ak·akem-yawi ad tettekkiḍ deg-s!",
+ "If this isn't what you want, please use a different tool to ignore users.": "Ma yella ayagi mačči d ayen i tebɣiḍ, ttxil-k·m seqdec afecku-nniḍen i wakken ad tzegleḍ iseqdacen.",
+ "Room ID or address of ban list": "Asulay n texxamt neɣ tansa n tebdart n tegtin",
+ "Start automatically after system login": "Bdu s wudem awurman seld tuqqna ɣer unagraw",
+ "Always show the window menu bar": "Afeggag n wumuɣ n usfaylu eǧǧ-it yettban",
+ "Show tray icon and minimize window to it on close": "Sken tagnit n ufeggag n waddad, tsemziḍ asfaylu n umdal",
+ "Read Marker lifetime (ms)": "Ɣer tanzagt n tudert n tecreḍt (ms)",
+ "Read Marker off-screen lifetime (ms)": "Ɣer tanzagt n tudert n tecreḍt beṛṛa n ugdil (ms)",
+ "Unignore": "Ur yettwazgel ara",
+ "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Anedbal-ik·im n uqeddac issens awgelhen seg yixef ɣer yixef s wudem amezwer deg texxamin tusligin & yiznan usriden.",
+ "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Sefrek ismawen syen ffeɣ seg tɣimiyin-ik·im ddaw neɣ senqed-itent deg umaɣnu-ik·im n useqdac.",
+ "A session's public name is visible to people you communicate with": "Isem n tiɣimit tazayezt yettban i yimdanen wukud tettmeslayeḍ",
+ "%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s ileqqeḍ tasleḍt tudrigt i wakken ad aɣ-iɛawen ad nesnerni asnas.",
+ "You have ignored this user, so their message is hidden. Show anyways.": "Tzegleḍ useqdac-a, ihi iznan-ines ffren. Ɣas akken sken-iten-id.",
+ "You cancelled verifying %(name)s": "Tesfesxeḍ asenqed n %(name)s",
+ "Declining …": "Tigtin…",
+ "You sent a verification request": "Tuzneḍ asuter n usenqed",
+ "Error decrypting video": "Tuccḍa deg uwgelhen n tvidyut",
+ "Reactions": "Tisedmirin",
+ " reacted with %(content)s": " isedmer s %(content)s",
+ "reacted with %(shortName)s": "issedmer s %(shortName)s",
+ "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s ibeddel avaṭar i %(roomName)s",
+ "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s yekkes avaṭar n texxamt.",
+ "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s ibeddel avaṭar n texxamt i ",
+ "This room is a continuation of another conversation.": "Taxxamt-a d akemmel n udiwenni-nniḍen.",
+ "Click here to see older messages.": "Sit da i wakken ad twaliḍ iznan iqdimen.",
+ "Failed to copy": "Anɣal ur yeddi ara",
+ "Edited at %(date)s": "Yettwaẓreg deg %(date)s",
+ "Click to view edits": "Sit i wakken ad twaliḍ aseẓreg",
+ "Edited at %(date)s. Click to view edits.": "Yettwaẓreg deg %(date)s. Sit i wakken ad twaliḍ iseẓrag.",
+ "Failed to load group members": "Ur yeddi ara usali n yiɛeggalen n ugraw",
+ "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Tebɣiḍ s tidet ad tekkseḍ '%(roomName)s' seg %(groupId)s?",
+ "Removing a room from the community will also remove it from the community page.": "Tukksa n texxamt seg temɣiwent ad tt-yekkes ula seg usebter n temɣiwent.",
+ "Failed to remove room from community": "Tukksa n texxamt seg temɣiwent ur yeddi ara",
+ "Failed to remove '%(roomName)s' from %(groupId)s": "Ur teddi ara tukksa n '%(roomName)s' seg %(groupId)s",
+ "Something went wrong!": "Yella wayen ur nteddu ara akken iwata!",
+ "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Abani n '%(roomName)s' deg %(groupId)s yegguma ad ttuleqqem.",
+ "Visible to everyone": "Iban i medden akk",
+ "Something went wrong when trying to get your communities.": "Yella wayen ur nteddu ara akken deg uneɛruḍ n wawwaḍ ɣer temɣiwnin-ik·im.",
+ "Display your community flair in rooms configured to show it.": "Sken lbenna n temɣiwent-ik·im deg texxamin yettusewlen ad ttwaskanent.",
+ "You're not currently a member of any communities.": "Akka tura ur telliḍ d aɛeggal ula deg yiwet temɣiwent.",
+ "Frequently Used": "Yettuseqdac s waṭas",
+ "Quick Reactions": "Tisedmirin tiruradin",
+ "Unknown Address": "D tansa tarussint",
+ "Any of the following data may be shared:": "Yal yiwen seg yisefka i d-iteddun zemren ad ttwabḍun:",
+ "Invite anyway and never warn me again": "Ɣas akken nced-d yerna ur iyi-id-ttɛeggin ara akk",
+ "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "Ttxil-k·m ini-aɣ-d acu ur nteddu ara akken ilaq neɣ, akken i igerrez, rnu ugur deg Github ara ad d-igelmen ugur.",
+ "Preparing to download logs": "Aheyyi i usali n yiɣmisen",
+ "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Ulac ula d yiwen da! Tebɣiḍ ad d-necdeḍ wiyaḍ neɣ aḥbas n uɛeggen ɣef texxamt tilemt?",
+ "You seem to be in a call, are you sure you want to quit?": "Tettbaneḍ aql-ak·akem deg useiwel, tebɣiḍ s tidet ad teffɣeḍ?",
+ "Failed to load timeline position": "Asali n yideg n tesnakudt ur yeddi ara",
+ "Sign in instead": "Kcem axiṛ",
+ "Invalid homeserver discovery response": "Tiririt n usnirem n uqeddac agejdan d tarameɣtut",
+ "Failed to get autodiscovery configuration from server": "Awway n uswel n usnirem awurman seg uqeddac ur yeddi ara",
+ "Invalid base_url for m.homeserver": "D arameɣtu base_url i m.homeserver",
+ "Homeserver URL does not appear to be a valid Matrix homeserver": "URL n uqeddac agejdan ur yettban ara d aqeddac agejdan n Matrix ameɣtu",
+ "Invalid identity server discovery response": "Tiririt n usnirem n uqeddac n timagitn d tarameɣtut",
+ "Identity server URL does not appear to be a valid identity server": "URL n uqeddac n timagit ur yettban ara d aqeddac n timagit ameɣtu",
+ "This homeserver does not support login using email address.": "Aqeddac-a agejdan ur yessefrak ara inekcum s useqdec n tansa n yimayl.",
+ "Please contact your service administrator to continue using this service.": "Ttxil-k·m nermes anedbal-ik·im n uqeddac i wakken ad tkemmleḍ aseqdec n yibenk-a.",
+ "Failed to fetch avatar URL": "Tiririt n URL ur teddi ara",
+ "Unable to query for supported registration methods.": "Anadi n tarrayin n usekles yettusefraken d awezi.",
+ "Registration has been disabled on this homeserver.": "Aklas yensa deg uqeddac-a agejdan.",
+ "This server does not support authentication with a phone number.": "Aqeddac-a ur yessefrak ara asesteb s wuṭṭun n tilifun.",
+ "You can now close this window or log in to your new account.": "Tzemreḍ tura ad tmedleḍ asfaylu-a neɣ kcem ɣer umiḍan-ik·im amaynut.",
+ "Use Recovery Key or Passphrase": "Seqdec tasarut tuffirt neɣ tafyirt tuffirt n uεeddi",
+ "This requires the latest %(brand)s on your other devices:": "Ayagi yesra %(brand)s tineggura ɣef yibenkan-ik·im wiyaḍ:",
+ "or another cross-signing capable Matrix client": "neɣ amsaɣ-nniḍen n Matrix yemṣadan d uzmul amdigan",
+ "Your new session is now verified. Other users will see it as trusted.": "Tiɣimit-ik·im tamaynut tettwasenqed tura. Ad tt-walin wiyaḍ tettwaḍman.",
+ "Failed to re-authenticate due to a homeserver problem": "Allus n usesteb ur yeddi ara ssebbba n wugur deg uqeddac agejdan",
+ "Enter your password to sign in and regain access to your account.": "Sekcem awal-ik·im uffir i wakken ad teqqneḍ syen ad tkecmeḍ i tikkelt tayeḍ ɣer umiḍan-ik·im.",
+ "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "Seqdec tafyirt tuffirt i tessneḍ kan kečč·kemm, syen sekles ma tebɣiḍ tasarut n tɣellist i useqdec-ines i uḥraz.",
+ "Restore your key backup to upgrade your encryption": "Err-d aḥraz n tsarut-ik·im akken ad tleqqmeḍ awgelhen-ik·im",
+ "You'll need to authenticate with the server to confirm the upgrade.": "Ad teḥqiǧeḍ asesteb s uqeddac i wakken ad tesnetmeḍ lqem.",
+ "Unable to query secret storage status": "Tuttra n waddad n uklas uffir ur teddi ara",
+ "You can also set up Secure Backup & manage your keys in Settings.": "Tzemreḍ daɣen aḥraz uffir & tesferkeḍ tisura-ik·im deg yiɣewwaren.",
+ "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "Ad d-terreḍ anɣal awgelhan n tsura-ik·im ɣef uqeddac-nneɣ. Ḥrez aḥrazen s tefyirt tuffirt n uɛeddi.",
+ "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.": "War aswel n Secure Message Recovery, ur tettizmireḍ ara ad d-terreḍ amazray-ik·im n yiznan iwgelhanen ma yella teffɣeḍ neɣ tesqedceḍ tiɣimit-nniḍen.",
+ "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "War aswel n Secure Message Recovery, ad tmedleḍ amazray-ik·im n yiznan uffiren ma yella teffɣeḍ.",
+ "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.": "Ma yella ur tesbaduḍ ara tarrayt n tririt tamaynut, yezmer ad yili umaker ara iɛerḍen ad yekcem ɣer umiḍan-ik·im. Beddel awal uffir n umiḍan-ik·im syen sbadu tarrayt n tririt tamaynut din din deg yiɣewwaren.",
+ "This session has detected that your recovery passphrase and key for Secure Messages have been removed.": "Tiɣimit-a tufa-d tafyirt-ik·im tuffirt n tririt d tsarut-ik·im n yiznan uffiren ttwakksent.",
+ "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.": "Ma yella ur tekkiseḍ ara tarrayt n tririt tamaynut, yezmer ad yili umaker ara iɛerḍen ad yekcem ɣer umiḍan-ik·im. Beddel awal uffir n umiḍan-ik·im syen sbadu tarrayt n tririt tamaynut din din deg yiɣewwaren.",
+ "Mirror local video feed": "Asbani n usuddem n tvidyut tadigant",
+ "Low bandwidth mode": "Askar n tehri n tesfift adday",
+ "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Sireg aqeddac n tallalt i yisawalen n ufran aneggaru turn.matrix.org ma yili aqeddac-ik·im agejdan ur d-yettmudd ara yiwen (tansa-ik·im n IP ad tettwabḍu lawan n usiwel)",
+ "Compare a unique set of emoji if you don't have a camera on either device": "Serwes tagrumma n yimujiten asufen ma yella ur tesɛiḍ ara takamiṛat ɣef yiwen seg sin yibenkan",
+ "Unable to find a supported verification method.": "D awezɣi ad d-naf tarrayt n usenqed yettusefraken.",
+ "Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": "Deg uṛaǧu n tɣimit-ik·im tayeḍ, %(deviceName)s (%(deviceId)s), i usenqed…",
+ "To be secure, do this in person or use a trusted way to communicate.": "I wakken ad tḍemneḍ taɣellistik·im, eg ayagi s timmad-ik·im neɣ seqdec abrid n teywalt iɣef ara tettekleḍ.",
+ "You may need to manually permit %(brand)s to access your microphone/webcam": "Ilaq-ak·am ahat ad tesirgeḍ s ufus %(brand)s i unekcum ɣer usawaḍ/webcam",
+ "This room is not accessible by remote Matrix servers": "Anekcum er texxamt-a ulamek s yiqeddacen n Matrix inmeggagen",
+ "No users have specific privileges in this room": "Ulac aqeddac yesan taseglut tuzzigtt deg texxamt-a",
+ "Select the roles required to change various parts of the room": "Fren timlilin yettusran i usnifel n yiḥricen yemgaraden n texxamt",
+ "Guests cannot join this room even if explicitly invited.": "Ur zmiren ara inebgawen ad d-rnun ɣer texxamt-a alamma ttusnubegten-d s tidet.",
+ "Once enabled, encryption cannot be disabled.": "Akken ara yettwarmad, awgelhen ur yettizmir ara ad yens.",
+ "Click the link in the email you received to verify and then click continue again.": "Sit ɣef useɣwen yella deg yimayl i teṭṭfeḍ i usenqed syen sit tikkelt tayeḍ ad tkemmleḍ.",
+ "Discovery options will appear once you have added an email above.": "Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ imayl s ufella.",
+ "Discovery options will appear once you have added a phone number above.": "Tixtiṛiyin n usnirem ad d-banent akken ara ternuḍ uṭṭun n tilifun s ufella.",
+ "The maximum permitted number of widgets have already been added to this room.": "Amḍan afellay yettusirgen n yiwiǧiten yettwarna yakan ɣer texxamt-a.",
+ "This room doesn't exist. Are you sure you're at the right place?": "Taxxamt-a ulac-itt. Tetteḥqeḍ aql-ak·akem deg wadeg i iṣeḥḥan?",
+ "Try again later, or ask a room admin to check if you have access.": "Ɛreḍ tikkelt-nniḍen ticki, neɣ suter deg unedbal n texxamt ad iwali ma tzemreḍ ad tkecmeḍ.",
+ "%(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 yuɣal-d lawan n uneɛruḍ n unekcum ɣer texxamt. Ma yella izen-a twalaḍ-t ur tebniḍ fell-as, ttxil-k·m azen aneqqis n wabug.",
+ "Never lose encrypted messages": "Ur ttamdal ara akk iznan iwgelhanen",
+ "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Iznan deg texxamt-a ttwaḥerzen s uwgelhen n yixef ɣer yixef. Ala kečč·kemm d uɣerwaḍ (yiɣerwaḍen) i yesεan tisura akken ad ɣren iznan-a.",
+ "Securely back up your keys to avoid losing them. Learn more.": "Ḥrez tisura-k·m s wudem aɣelsan i wakken ur ak·am-ttṛuḥunt ara. Issin ugar",
+ "Unrecognised command: %(commandText)s": "Taladna d tarussint: %(commandText)s",
+ "Hint: Begin your message with // to start it with a slash.": "Taxballut: Bdu izen-ik·im s // i wakken ad t-tebduḍ s uṣlac.",
+ "Failed to connect to integration manager": "Tuqqna ɣer umsefrak n umsidef ur yeddi ara",
+ "Jump to first unread message.": "Ɛeddi ɣer yizen amezwaru ur nettwaɣra ara.",
+ "Error updating main address": "Tuccḍa deg usali n tensa tagejdant",
+ "You don't have permission to delete the address.": "Ur tesɛiḍ ara tisirag i wakken ad tekkseḍ tansa.",
+ "This room has no local addresses": "Taxxamt-a ur tesɛi ara tansiwin tidiganin",
+ "Error updating flair": "Tuccḍa deg uleqqem n lbenna",
+ "'%(groupId)s' is not a valid community ID": "'%(groupId)s' mačči d asulay n temɣiwent ameɣtu",
+ "Use bots, bridges, widgets and sticker packs": "Seqdec abuten, tileggiyin, iwiǧiten d tɣawsiwin n umyintaḍ",
+ "To continue you need to accept the terms of this service.": "I wakken ad tkemmleḍ tesriḍ ad tqebleḍ tiwtilin n umeẓlu-a.",
+ "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "Afaylu-a ɣezzif aṭas i wakken ad d-yali. Talast n teɣzi n ufaylu d %(limit)s maca afaylu-a d %(sizeOfThisFile)s.",
+ "These files are too large to upload. The file size limit is %(limit)s.": "Ifuyla-a ɣezzifit aṭas i wakken ad d-alin. Talast n teɣzi n ufaylu d %(limit)s.",
+ "Some files are too large to be uploaded. The file size limit is %(limit)s.": "Kra n yifuyla ɣezzifit aṭas i wakken ad d-alin. Talast n teɣzi n ufaylu d %(limit)s.",
+ "Upload %(count)s other files|other": "Sali-d %(count)s ifuyla-nniḍen",
+ "Upload %(count)s other files|one": "Sali-d %(count)s afaylu-nniḍen",
+ "Upload Error": "Tuccḍa deg usali",
+ "A widget would like to verify your identity": "Awiǧit yebɣa ad issenqed timagit-inek·inem",
+ "Remember my selection for this widget": "Cfu ɣef tefrant-inu i uwiǧit-a",
+ "Wrong file type": "Anaw n yifuyla d arameɣtu",
+ "Looks good!": "Yettban igerrez!",
+ "Enter your Security Phrase or to continue.": "Sekcem tafyirt-ik·im n tɣellist neɣ