From 577c411a397e2b14c061e05958cb7370255f5ed9 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 14 Jan 2019 17:10:20 +0000 Subject: [PATCH 001/481] experimental fix for https://github.com/vector-im/riot-web/issues/2985 needs server to support 1600x1200 thumbnails for retina large ones. ideally need to cap maximum thumbnail size to 800x600 rather than expand to arbitrary widths. need to check that luke's funky timeline code doesn't get confused between naturalWidth and infoWidth etc. also need to consider whether to encode a resolution metric in the event rather than lying about resolution. --- package.json | 1 + src/ContentMessages.js | 34 +++++++++++++++++++-- src/components/views/messages/MImageBody.js | 10 ++++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7b55a09948..82246534a2 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "matrix-js-sdk": "0.14.2", "optimist": "^0.6.1", "pako": "^1.0.5", + "png-chunks-extract": "^1.0.0", "prop-types": "^15.5.8", "qrcode-react": "^0.1.16", "querystring": "^0.2.0", diff --git a/src/ContentMessages.js b/src/ContentMessages.js index f2bbdfafe5..e4c62b5de1 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -25,6 +25,7 @@ import { _t } from './languageHandler'; const Modal = require('./Modal'); const encrypt = require("browser-encrypt-attachment"); +const png_chunks_extract = require("png-chunks-extract"); // Polyfill for Canvas.toBlob API using Canvas.toDataURL require("blueimp-canvas-to-blob"); @@ -32,6 +33,9 @@ require("blueimp-canvas-to-blob"); const MAX_WIDTH = 800; const MAX_HEIGHT = 600; +// scraped out of a macOS hidpi (5660ppm) screenshot png +// 5669 px (x-axis) , 5669 px (y-axis) , per metre +const PHYS_HIDPI = [0x00, 0x00, 0x16, 0x25, 0x00, 0x00, 0x16, 0x25, 0x01]; /** * Create a thumbnail for a image DOM element. @@ -102,10 +106,34 @@ function loadImageElement(imageFile) { const objectUrl = URL.createObjectURL(imageFile); img.src = objectUrl; + // check for hi-dpi PNGs and fudge display resolution as needed. + // this is mainly needed for macOS screencaps + let hidpi = false; + if (imageFile.type === "image/png") { + // in practice macOS happens to order the chunks so they fall in + // the first 0x1000 bytes (thanks to a massive ICC header). + // Thus we could slice the file down to only sniff the first 0x1000 + // bytes (but this makes png_chunks_extract choke on the corrupt file) + const headers = imageFile; //.slice(0, 0x1000); + readFileAsArrayBuffer(headers).then(arrayBuffer=>{ + const buffer = new Uint8Array(arrayBuffer); + const chunks = png_chunks_extract(buffer); + for (const chunk of chunks) { + if (chunk.name === 'pHYs') { + if (chunk.data.byteLength !== PHYS_HIDPI.length) return; + hidpi = chunk.data.every((val, i) => val === PHYS_HIDPI[i]); + return; + } + } + }); + } + // Once ready, create a thumbnail img.onload = function() { URL.revokeObjectURL(objectUrl); - deferred.resolve(img); + let width = hidpi ? (img.width >> 1) : img.width; + let height = hidpi ? (img.height >> 1) : img.height; + deferred.resolve({ img, width, height }); }; img.onerror = function(e) { deferred.reject(e); @@ -129,8 +157,8 @@ function infoForImageFile(matrixClient, roomId, imageFile) { } let imageInfo; - return loadImageElement(imageFile).then(function(img) { - return createThumbnail(img, img.width, img.height, thumbnailType); + return loadImageElement(imageFile).then(function(r) { + return createThumbnail(r.img, r.width, r.height, thumbnailType); }).then(function(result) { imageInfo = result.info; return uploadFile(matrixClient, roomId, result.thumbnail); diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index dc891b86ff..c0e751431f 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -179,10 +179,16 @@ export default class MImageBody extends React.Component { // given we deliberately don't thumbnail them serverside to prevent // billion lol attacks and similar return this.context.matrixClient.mxcUrlToHttp( - content.info.thumbnail_url, 800, 600, + content.info.thumbnail_url, + 800 * window.devicePixelRatio, + 600 * window.devicePixelRatio, ); } else { - return this.context.matrixClient.mxcUrlToHttp(content.url, 800, 600); + return this.context.matrixClient.mxcUrlToHttp( + content.url, + 800 * window.devicePixelRatio, + 600 * window.devicePixelRatio + ); } } From 8511bc27cc4e11479cc0203437536d6e2f430407 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 20 Jan 2019 15:35:16 +0000 Subject: [PATCH 002/481] only request thumbs on retina if the original image is too big to be used as a thumbnail --- src/components/views/messages/MImageBody.js | 67 +++++++++++++++++++-- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index c0e751431f..14c8c94f30 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -151,6 +151,18 @@ export default class MImageBody extends React.Component { if (this.refs.image) { const { naturalWidth, naturalHeight } = this.refs.image; + // XXX: if this is a retina image, the naturalWidth/Height + // are going to be off by a factor of 2. However, we don't know + // this at this point - so until we include a resolution param + // in info, this might cause scroll jumps for retina images? + // + // Something like: + // + // if (content.info && content.info.devicePixelRatio) { + // naturalWidth /= content.info.devicePixelRatio; + // naturalHeight /= content.info.devicePixelRatio; + // } + loadedImageDimensions = { naturalWidth, naturalHeight }; } @@ -167,6 +179,11 @@ export default class MImageBody extends React.Component { } _getThumbUrl() { + // FIXME: the dharma skin lets images grow as wide as you like, rather than capped to 800x600. + // So either we need to support custom timeline widths here, or reimpose the cap, otherwise the + // thumbnail resolution will be unnecessarily reduced. + // custom timeline widths seems preferable. + const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { // Don't use the thumbnail for clients wishing to autoplay gifs. @@ -175,7 +192,7 @@ export default class MImageBody extends React.Component { } return this.state.decryptedUrl; } else if (content.info && content.info.mimetype === "image/svg+xml" && content.info.thumbnail_url) { - // special case to return client-generated thumbnails for SVGs, if any, + // special case to return clientside sender-generated thumbnails for SVGs, if any, // given we deliberately don't thumbnail them serverside to prevent // billion lol attacks and similar return this.context.matrixClient.mxcUrlToHttp( @@ -184,11 +201,49 @@ export default class MImageBody extends React.Component { 600 * window.devicePixelRatio, ); } else { - return this.context.matrixClient.mxcUrlToHttp( - content.url, - 800 * window.devicePixelRatio, - 600 * window.devicePixelRatio - ); + if (window.devicePixelRatio === 1.0 || + (!content.info || !content.info.w || + !content.info.h || !content.info.size)) + { + // always thumbnail. it may look a bit worse, but it'll save bandwidth. + // which is probably desirable on a lo-dpi device anyway. + return this.context.matrixClient.mxcUrlToHttp( + content.url, + 800 * window.devicePixelRatio, + 600 * window.devicePixelRatio + ); + } + else { + // we should only request thumbnails if the image is bigger than 800x600 + // (or 1600x1200 on retina) otherwise the image in the timeline will just + // end up resampled and de-retina'd for no good reason. + // Ideally the server would pregen 1600x1200 thumbnails in order to provide retina + // thumbnails, but we don't do this currently in synapse for fear of disk space. + // As a compromise, let's switch to non-retina thumbnails only if the original + // image is both physically too large and going to be massive to load in the + // timeline (e.g. >1MB). + + if ((content.info.w > 800 * window.devicePixelRatio || + content.info.h > 600 * window.devicePixelRatio) && + content.info.size > 1*1024*1024) + { + // image is too large physically and bytewise to clutter our timeline so + // we ask for a thumbnail, despite knowing that it will be max 800x600 + // despite us being retina (as synapse doesn't do 1600x1200 thumbs yet). + + return this.context.matrixClient.mxcUrlToHttp( + content.url, + 800 * window.devicePixelRatio, + 600 * window.devicePixelRatio + ); + } + else { + // no width/height means we want the original image. + return this.context.matrixClient.mxcUrlToHttp( + content.url, + }; + } + } } } From 8cf2607415ad7bdb837fa0de15dc9c28a353bae8 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:30:06 +0100 Subject: [PATCH 003/481] use AutoHideScrollbar in ScrollPanel --- res/css/structures/_RoomView.scss | 2 + .../structures/AutoHideScrollbar.js | 1 + src/components/structures/ScrollPanel.js | 40 +++++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index f15552e484..1b639928e0 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -84,6 +84,7 @@ limitations under the License. display: flex; flex-direction: column; flex: 1; + min-width: 0; } .mx_RoomView_body .mx_RoomView_timeline { @@ -111,6 +112,7 @@ limitations under the License. .mx_RoomView_messagePanel { width: 100%; overflow-y: auto; + flex: 1 1 0; } .mx_RoomView_messagePanelSearchSpinner { diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js index 0f93f20407..72d48a2084 100644 --- a/src/components/structures/AutoHideScrollbar.js +++ b/src/components/structures/AutoHideScrollbar.js @@ -121,6 +121,7 @@ export default class AutoHideScrollbar extends React.Component { render() { return (
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index ee4045c91e..cdb79686ad 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -15,14 +15,13 @@ limitations under the License. */ const React = require("react"); -const ReactDOM = require("react-dom"); import PropTypes from 'prop-types'; import Promise from 'bluebird'; import { KeyCode } from '../../Keyboard'; -import sdk from '../../index.js'; +import AutoHideScrollbar from "./AutoHideScrollbar"; const DEBUG_SCROLL = false; -// var DEBUG_SCROLL = true; +// const DEBUG_SCROLL = true; // The amount of extra scroll distance to allow prior to unfilling. // See _getExcessHeight. @@ -129,11 +128,6 @@ module.exports = React.createClass({ */ onScroll: PropTypes.func, - /* onResize: a callback which is called whenever the Gemini scroll - * panel is resized - */ - onResize: PropTypes.func, - /* className: classnames to add to the top-level div */ className: PropTypes.string, @@ -150,7 +144,6 @@ module.exports = React.createClass({ onFillRequest: function(backwards) { return Promise.resolve(false); }, onUnfillRequest: function(backwards, scrollToken) {}, onScroll: function() {}, - onResize: function() {}, }; }, @@ -185,6 +178,16 @@ module.exports = React.createClass({ debuglog("Scroll event: offset now:", sn.scrollTop, "_lastSetScroll:", this._lastSetScroll); + // ignore scroll events where scrollTop hasn't changed, + // appears to happen when the layout changes outside + // of the scroll container, like resizing the right panel. + if (sn.scrollTop === this._lastEventScroll) { + debuglog("ignore scroll event with same scrollTop as before"); + return; + } + + this._lastEventScroll = sn.scrollTop; + // Sometimes we see attempts to write to scrollTop essentially being // ignored. (Or rather, it is successfully written, but on the next // scroll event, it's been reset again). @@ -225,9 +228,7 @@ module.exports = React.createClass({ onResize: function() { this.clearBlockShrinking(); - this.props.onResize(); this.checkScroll(); - if (this._gemScroll) this._gemScroll.forceUpdate(); }, // after an update to the contents of the panel, check that the scroll is @@ -672,17 +673,17 @@ module.exports = React.createClass({ throw new Error("ScrollPanel._getScrollNode called when unmounted"); } - if (!this._gemScroll) { + if (!this._divScroll) { // Likewise, we should have the ref by this point, but if not // turn the NPE into something meaningful. throw new Error("ScrollPanel._getScrollNode called before gemini ref collected"); } - return this._gemScroll.scrollbar.getViewElement(); + return this._divScroll; }, - _collectGeminiScroll: function(gemScroll) { - this._gemScroll = gemScroll; + _collectScroll: function(divScroll) { + this._divScroll = divScroll; }, /** @@ -724,19 +725,18 @@ module.exports = React.createClass({ }, render: function() { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); // 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. - return (
    { this.props.children }
-
- ); + + ); }, }); From 27070b314960ed3cfc0e4415e96534accff821a3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:33:05 +0100 Subject: [PATCH 004/481] remove onChildResize in RoomView as it's unused --- src/components/structures/RoomView.js | 15 ++------------- src/components/views/rooms/MessageComposer.js | 5 ----- .../views/rooms/MessageComposerInput.js | 4 ---- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 2a1c7fe79e..d7488a2558 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1355,8 +1355,7 @@ module.exports = React.createClass({ const showBar = this.refs.messagePanel.canJumpToReadMarker(); if (this.state.showTopUnreadMessagesBar != showBar) { - this.setState({showTopUnreadMessagesBar: showBar}, - this.onChildResize); + this.setState({showTopUnreadMessagesBar: showBar}); } }, @@ -1399,7 +1398,7 @@ module.exports = React.createClass({ }; }, - onResize: function(e) { + onResize: function() { // 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 @@ -1417,9 +1416,6 @@ module.exports = React.createClass({ if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50; this.setState({auxPanelMaxHeight: auxPanelMaxHeight}); - - // changing the maxHeight on the auxpanel will trigger a callback go - // onChildResize, so no need to worry about that here. }, onFullscreenClick: function() { @@ -1449,10 +1445,6 @@ module.exports = React.createClass({ this.forceUpdate(); // TODO: just update the voip buttons }, - onChildResize: function() { - // no longer anything to do here - }, - onStatusBarVisible: function() { if (this.unmounted) return; this.setState({ @@ -1645,7 +1637,6 @@ module.exports = React.createClass({ isPeeking={myMembership !== "join"} onInviteClick={this.onInviteButtonClick} onStopWarningClick={this.onStopAloneWarningClick} - onResize={this.onChildResize} onVisible={this.onStatusBarVisible} onHidden={this.onStatusBarHidden} />; @@ -1714,7 +1705,6 @@ module.exports = React.createClass({ draggingFile={this.state.draggingFile} displayConfCallNotification={this.state.displayConfCallNotification} maxHeight={this.state.auxPanelMaxHeight} - onResize={this.onChildResize} showApps={this.state.showApps} hideAppsDrawer={false} > { aux } @@ -1730,7 +1720,6 @@ module.exports = React.createClass({ messageComposer = this.messageComposerInput = c} key="controls_input" - onResize={this.props.onResize} room={this.props.room} placeholder={placeholderText} onFilesPasted={this.uploadFiles} @@ -505,10 +504,6 @@ export default class MessageComposer extends React.Component { } MessageComposer.propTypes = { - // a callback which is called when the height of the composer is - // changed due to a change in content. - onResize: PropTypes.func, - // js-sdk Room object room: PropTypes.object.isRequired, diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 6b80902c8f..cbea2bccb9 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -135,10 +135,6 @@ function rangeEquals(a: Range, b: Range): boolean { */ export default class MessageComposerInput extends React.Component { static propTypes = { - // a callback which is called when the height of the composer is - // changed due to a change in content. - onResize: PropTypes.func, - // js-sdk Room object room: PropTypes.object.isRequired, From 735b4f6fcfbff30e0064568282f17e4dc8b765bc Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:36:12 +0100 Subject: [PATCH 005/481] create ResizeNotifier to derive which areas of the app resize and emit --- src/components/structures/FilePanel.js | 1 + src/components/structures/LoggedInView.js | 2 + src/components/structures/MainSplit.js | 1 + src/components/structures/MatrixChat.js | 3 ++ src/components/structures/MessagePanel.js | 3 +- src/components/structures/RightPanel.js | 2 +- src/components/structures/RoomView.js | 13 ++++-- src/components/structures/ScrollPanel.js | 3 ++ src/components/structures/TimelinePanel.js | 1 + src/utils/ResizeNotifier.js | 52 ++++++++++++++++++++++ 10 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/utils/ResizeNotifier.js diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js index 927449750c..e35a39a107 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.js @@ -123,6 +123,7 @@ const FilePanel = React.createClass({ timelineSet={this.state.timelineSet} showUrlPreview = {false} tileShape="file_grid" + resizeNotifier={this.props.resizeNotifier} empty={_t('There are no visible files in this room')} /> ); diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index c6c1be67ec..5267dba715 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -173,6 +173,7 @@ const LoggedInView = React.createClass({ }, onResized: (size) => { window.localStorage.setItem("mx_lhs_size", '' + size); + this.props.resizeNotifier.notifyLeftHandleResized(); }, }; const resizer = new Resizer( @@ -448,6 +449,7 @@ const LoggedInView = React.createClass({ disabled={this.props.middleDisabled} collapsedRhs={this.props.collapsedRhs} ConferenceHandler={this.props.ConferenceHandler} + resizeNotifier={this.props.resizeNotifier} />; break; diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 0427130eea..c0bf74d02c 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -27,6 +27,7 @@ export default class MainSplit extends React.Component { _onResized(size) { window.localStorage.setItem("mx_rhs_size", size); + this.props.resizeNotifier.notifyRightHandleResized(); } _createResizer() { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2622a6bf93..a9b34c9058 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -48,6 +48,7 @@ import { _t, getCurrentLanguage } from '../../languageHandler'; import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import { startAnyRegistrationFlow } from "../../Registration.js"; import { messageForSyncError } from '../../utils/ErrorUtils'; +import ResizeNotifier from "../../utils/ResizeNotifier"; const AutoDiscovery = Matrix.AutoDiscovery; @@ -194,6 +195,7 @@ export default React.createClass({ hideToSRUsers: false, syncError: null, // If the current syncing status is ERROR, the error object, otherwise null. + resizeNotifier: new ResizeNotifier(), }; return s; }, @@ -1661,6 +1663,7 @@ export default React.createClass({ dis.dispatch({ action: 'show_right_panel' }); } + this.state.resizeNotifier.notifyWindowResized(); this._windowWidth = window.innerWidth; }, diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index b1f88a6221..aec2f8cbe1 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -703,7 +703,8 @@ module.exports = React.createClass({ onFillRequest={this.props.onFillRequest} onUnfillRequest={this.props.onUnfillRequest} style={style} - stickyBottom={this.props.stickyBottom}> + stickyBottom={this.props.stickyBottom} + resizeNotifier={this.props.resizeNotifier}> { topSpinner } { this._getEventTiles() } { whoIsTyping } diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 5c745b04cc..93cbff3233 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -193,7 +193,7 @@ export default class RightPanel extends React.Component { } else if (this.state.phase === RightPanel.Phase.NotificationPanel) { panel = ; } else if (this.state.phase === RightPanel.Phase.FilePanel) { - panel = ; + panel = ; } const classes = classNames("mx_RightPanel", "mx_fadable", { diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index d7488a2558..5a914cbd1c 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -392,7 +392,7 @@ module.exports = React.createClass({ this._updateConfCallNotification(); window.addEventListener('beforeunload', this.onPageUnload); - window.addEventListener('resize', this.onResize); + this.props.resizeNotifier.on("middlePanelResized", this.onResize); this.onResize(); document.addEventListener("keydown", this.onKeyDown); @@ -472,7 +472,7 @@ module.exports = React.createClass({ } window.removeEventListener('beforeunload', this.onPageUnload); - window.removeEventListener('resize', this.onResize); + this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); document.removeEventListener("keydown", this.onKeyDown); @@ -1829,6 +1829,7 @@ module.exports = React.createClass({ className="mx_RoomView_messagePanel" membersLoaded={this.state.membersLoaded} permalinkCreator={this.state.permalinkCreator} + resizeNotifier={this.props.resizeNotifier} />); let topUnreadMessagesBar = null; @@ -1861,7 +1862,7 @@ module.exports = React.createClass({ }, ); - const rightPanel = this.state.room ? : undefined; + const rightPanel = this.state.room ? : undefined; return (
@@ -1877,7 +1878,11 @@ module.exports = React.createClass({ onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null} e2eStatus={this.state.e2eStatus} /> - +
{ auxPanel }
diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index cdb79686ad..799c88140e 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -149,6 +149,8 @@ module.exports = React.createClass({ componentWillMount: function() { this._pendingFillRequests = {b: null, f: null}; + this.props.resizeNotifier.on("middlePanelResized", this.onResize); + this.resetScrollState(); }, @@ -171,6 +173,7 @@ module.exports = React.createClass({ // // (We could use isMounted(), but facebook have deprecated that.) this.unmounted = true; + this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); }, onScroll: function(ev) { diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 911499e314..537862ab1e 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -1227,6 +1227,7 @@ var TimelinePanel = React.createClass({ alwaysShowTimestamps={this.state.alwaysShowTimestamps} className={this.props.className} tileShape={this.props.tileShape} + resizeNotifier={this.props.resizeNotifier} /> ); }, diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js new file mode 100644 index 0000000000..43578ebcaa --- /dev/null +++ b/src/utils/ResizeNotifier.js @@ -0,0 +1,52 @@ +/* +Copyright 2019 New Vector 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. +*/ + +/** + * Fires when the middle panel has been resized. + * @event module:utils~ResizeNotifier#"middlePanelResized" + */ +import { EventEmitter } from "events"; +import { throttle } from "lodash"; + +export default class ResizeNotifier extends EventEmitter { + + constructor() { + super(); + // with default options, will call fn once at first call, and then every x ms + // if there was another call in that timespan + this._throttledMiddlePanel = throttle(() => this.emit("middlePanelResized"), 200); + } + + notifyBannersChanged() { + this.emit("middlePanelResized"); + } + + // can be called in quick succession + notifyLeftHandleResized() { + this._throttledMiddlePanel(); + } + + // can be called in quick succession + notifyRightHandleResized() { + this._throttledMiddlePanel(); + } + + // can be called in quick succession + notifyWindowResized() { + this._throttledMiddlePanel(); + } +} + From 56aeb5194a5e584c30b28e25abff3ab7b4fce33c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:37:20 +0100 Subject: [PATCH 006/481] emit timeline_resize in MatrixChat based on ResizeNotifier as it's used in PersistentElement which could be used at various places --- src/components/structures/MatrixChat.js | 8 ++++++++ src/components/structures/MessagePanel.js | 5 ----- src/components/structures/RoomView.js | 5 ----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index a9b34c9058..6e05138e2d 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -318,6 +318,9 @@ export default React.createClass({ // N.B. we don't call the whole of setTheme() here as we may be // racing with the theme CSS download finishing from index.js Tinter.tint(); + + // For PersistentElement + this.state.resizeNotifier.on("middlePanelResized", this._dispatchTimelineResize); }, componentDidMount: function() { @@ -400,6 +403,7 @@ export default React.createClass({ dis.unregister(this.dispatcherRef); window.removeEventListener("focus", this.onFocus); window.removeEventListener('resize', this.handleResize); + this.state.resizeNotifier.removeListener("middlePanelResized", this._dispatchTimelineResize); }, componentWillUpdate: function(props, state) { @@ -1667,6 +1671,10 @@ export default React.createClass({ this._windowWidth = window.innerWidth; }, + _dispatchTimelineResize() { + dis.dispatch({ action: 'timeline_resize' }, true); + }, + onRoomCreated: function(roomId) { dis.dispatch({ action: "view_room", diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index aec2f8cbe1..fecf5f1ad7 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -21,7 +21,6 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import shouldHideEvent from '../../shouldHideEvent'; import {wantsDateSeparator} from '../../DateUtils'; -import dis from "../../dispatcher"; import sdk from '../../index'; import MatrixClientPeg from '../../MatrixClientPeg'; @@ -665,10 +664,6 @@ module.exports = React.createClass({ } }, - onResize: function() { - dis.dispatch({ action: 'timeline_resize' }, true); - }, - render: function() { const ScrollPanel = sdk.getComponent("structures.ScrollPanel"); const WhoIsTypingTile = sdk.getComponent("rooms.WhoIsTypingTile"); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 5a914cbd1c..507fbf6979 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -856,10 +856,6 @@ module.exports = React.createClass({ } }, - onSearchResultsResize: function() { - dis.dispatch({ action: 'timeline_resize' }, true); - }, - onSearchResultsFillRequest: function(backwards) { if (!backwards) { return Promise.resolve(false); @@ -1794,7 +1790,6 @@ module.exports = React.createClass({
  • { this.getSearchResultTiles() } From c8123ec66536c0e10e07c607b7a116d4a444ab6d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:38:30 +0100 Subject: [PATCH 007/481] use AutoHideScrollbar in memberlist --- res/css/views/rooms/_MemberList.scss | 5 +++++ src/components/views/rooms/MemberList.js | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 9f2b5da930..cac97cb60d 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -20,6 +20,7 @@ limitations under the License. flex: 1; display: flex; flex-direction: column; + min-height: 0; .mx_Spinner { flex: 1 0 auto; @@ -35,6 +36,10 @@ limitations under the License. margin-top: 8px; margin-bottom: 4px; } + + .mx_AutoHideScrollbar { + flex: 1 1 0; + } } .mx_MemberList_chevron { diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index f9ce672c16..29f49f1691 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -20,6 +20,8 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher'; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; + const MatrixClientPeg = require("../../../MatrixClientPeg"); const sdk = require('../../../index'); const rate_limited_func = require('../../../ratelimitedfunc'); @@ -439,7 +441,6 @@ module.exports = React.createClass({ const SearchBox = sdk.getComponent('structures.SearchBox'); const TruncatedList = sdk.getComponent("elements.TruncatedList"); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const cli = MatrixClientPeg.get(); const room = cli.getRoom(this.props.roomId); @@ -466,7 +467,7 @@ module.exports = React.createClass({ return (
    { inviteButton } - +
    - + Date: Tue, 12 Mar 2019 16:38:42 +0100 Subject: [PATCH 008/481] use AutoHideScrollbar in member info panel --- src/components/views/rooms/MemberInfo.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 3ada730ec8..35161dedf7 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -44,6 +44,7 @@ import SdkConfig from '../../../SdkConfig'; import MultiInviter from "../../../utils/MultiInviter"; import SettingsStore from "../../../settings/SettingsStore"; import E2EIcon from "./E2EIcon"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; module.exports = withMatrixClient(React.createClass({ displayName: 'MemberInfo', @@ -1003,7 +1004,7 @@ module.exports = withMatrixClient(React.createClass({ { roomMemberDetails }
    - +
    { this._renderUserOptions() } @@ -1015,7 +1016,7 @@ module.exports = withMatrixClient(React.createClass({ { spinner }
    -
    +
    ); }, From 58f26ee9b070b1eca2943bdca5e14a96ca390a84 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 17:29:16 +0100 Subject: [PATCH 009/481] emit resize event when banners are shown/hidden to restore scroll pos --- src/Notifier.js | 12 +++++++++++- src/components/structures/LoggedInView.js | 19 +++++++++++++------ src/components/structures/MatrixChat.js | 13 ++++++++++--- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/Notifier.js b/src/Notifier.js index 80e8be1084..ab8009c457 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -220,7 +220,17 @@ const Notifier = { } }, - isToolbarHidden: function() { + shouldShowToolbar: function() { + const client = MatrixClientPeg.get(); + if (!client) { + return false; + } + const isGuest = client.isGuest(); + return !isGuest && Notifier.supportsDesktopNotifications() && + !Notifier.isEnabled() && !Notifier._isToolbarHidden(); + }, + + _isToolbarHidden: function() { // Check localStorage for any such meta data if (global.localStorage) { return global.localStorage.getItem("notifications_hidden") === "true"; diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 5267dba715..c22c217e5f 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -22,7 +22,6 @@ import PropTypes from 'prop-types'; import { DragDropContext } from 'react-beautiful-dnd'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard'; -import Notifier from '../../Notifier'; import PageTypes from '../../PageTypes'; import CallMediaHandler from '../../CallMediaHandler'; import sdk from '../../index'; @@ -121,6 +120,18 @@ const LoggedInView = React.createClass({ this._matrixClient.on("RoomState.events", this.onRoomStateEvents); }, + componentDidUpdate(prevProps) { + // attempt to guess when a banner was opened or closed + if ( + (prevProps.showCookieBar !== this.props.showCookieBar) || + (prevProps.hasNewVersion !== this.props.hasNewVersion) || + (prevProps.userHasGeneratedPassword !== this.props.userHasGeneratedPassword) || + (prevProps.showNotifierToolbar !== this.props.showNotifierToolbar) + ) { + this.props.resizeNotifier.notifyBannersChanged(); + } + }, + componentWillUnmount: function() { document.removeEventListener('keydown', this._onKeyDown); this._matrixClient.removeListener("accountData", this.onAccountData); @@ -491,7 +502,6 @@ const LoggedInView = React.createClass({ }); let topBar; - const isGuest = this.props.matrixClient.isGuest(); if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') { topBar = ; } else if (this.state.userHasGeneratedPassword) { topBar = ; - } else if ( - !isGuest && Notifier.supportsDesktopNotifications() && - !Notifier.isEnabled() && !Notifier.isToolbarHidden() - ) { + } else if (this.props.showNotifierToolbar) { topBar = ; } diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 6e05138e2d..a7192b96cb 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -29,6 +29,7 @@ import PlatformPeg from "../../PlatformPeg"; import SdkConfig from "../../SdkConfig"; import * as RoomListSorter from "../../RoomListSorter"; import dis from "../../dispatcher"; +import Notifier from '../../Notifier'; import Modal from "../../Modal"; import Tinter from "../../Tinter"; @@ -196,6 +197,7 @@ export default React.createClass({ syncError: null, // If the current syncing status is ERROR, the error object, otherwise null. resizeNotifier: new ResizeNotifier(), + showNotifierToolbar: Notifier.shouldShowToolbar(), }; return s; }, @@ -644,8 +646,9 @@ export default React.createClass({ case 'view_invite': showRoomInviteDialog(payload.roomId); break; - case 'notifier_enabled': - this.forceUpdate(); + case 'notifier_enabled': { + this.setState({showNotifierToolbar: Notifier.shouldShowToolbar()}); + } break; case 'hide_left_panel': this.setState({ @@ -1180,6 +1183,7 @@ export default React.createClass({ */ _onLoggedIn: async function() { this.setStateForNewView({view: VIEWS.LOGGED_IN}); + this.setState({showNotifierToolbar: Notifier.shouldShowToolbar()}); if (this._is_registered) { this._is_registered = false; @@ -1672,7 +1676,10 @@ export default React.createClass({ }, _dispatchTimelineResize() { - dis.dispatch({ action: 'timeline_resize' }, true); + // prevent dispatch from within dispatch error + setTimeout(() => { + dis.dispatch({ action: 'timeline_resize' }, true); + }, 0); }, onRoomCreated: function(roomId) { From 9541cc175f357fc0cdeab5299239eac199d58b9a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 18:00:05 +0100 Subject: [PATCH 010/481] use ResizeNotifier as well to relayout room list --- src/components/structures/LeftPanel.js | 2 +- src/components/structures/LoggedInView.js | 2 +- src/components/views/rooms/RoomList.js | 10 ++++++---- src/utils/ResizeNotifier.js | 8 ++++++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index 21438c597c..95b57a0ca5 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -234,7 +234,7 @@ const LeftPanel = React.createClass({ diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index c22c217e5f..4771c6f487 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -543,7 +543,7 @@ const LoggedInView = React.createClass({
    diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 227dd318ed..2de9918e6e 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -212,7 +212,7 @@ module.exports = React.createClass({ this._checkSubListsOverflow(); this.resizer.attach(); - window.addEventListener("resize", this.onWindowResize); + this.props.resizeNotifier.on("leftPanelResized", this.onResize); this.mounted = true; }, @@ -260,7 +260,6 @@ module.exports = React.createClass({ componentWillUnmount: function() { this.mounted = false; - window.removeEventListener("resize", this.onWindowResize); dis.unregister(this.dispatcherRef); if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Room", this.onRoom); @@ -272,6 +271,8 @@ module.exports = React.createClass({ MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); } + this.props.resizeNotifier.removeListener("leftPanelResized", this.onResize); + if (this._tagStoreToken) { this._tagStoreToken.remove(); @@ -293,13 +294,14 @@ module.exports = React.createClass({ this._delayedRefreshRoomList.cancelPendingCall(); }, - onWindowResize: function() { + + onResize: function() { if (this.mounted && this._layout && this.resizeContainer && Array.isArray(this._layoutSections) ) { this._layout.update( this._layoutSections, - this.resizeContainer.offsetHeight + this.resizeContainer.offsetHeight, ); } }, diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js index 43578ebcaa..ff4b79091b 100644 --- a/src/utils/ResizeNotifier.js +++ b/src/utils/ResizeNotifier.js @@ -31,11 +31,13 @@ export default class ResizeNotifier extends EventEmitter { } notifyBannersChanged() { + this.emit("leftPanelResized"); this.emit("middlePanelResized"); } // can be called in quick succession notifyLeftHandleResized() { + // don't emit event for own region this._throttledMiddlePanel(); } @@ -46,6 +48,12 @@ export default class ResizeNotifier extends EventEmitter { // can be called in quick succession notifyWindowResized() { + // no need to throttle this one, + // also it could make scrollbars appear for + // a split second when the room list manual layout is now + // taller than the available space + this.emit("leftPanelResized"); + this._throttledMiddlePanel(); } } From d63c5e7134070a4cd44f36dfb30f94f161370c4f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 13 Mar 2019 00:34:34 -0600 Subject: [PATCH 011/481] Basic widget OpenID reauth implementation Covers the minimum of https://github.com/vector-im/riot-web/issues/7153 This does not handling automatically accepting/blocking widgets yet, however. This could lead to dialog irritation. --- src/FromWidgetPostMessageApi.js | 42 ++++++++++++++++++++++++++++-- src/WidgetMessaging.js | 45 +++++++++++++++++++++++++++++++++ src/i18n/strings/en_EN.json | 4 ++- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/FromWidgetPostMessageApi.js b/src/FromWidgetPostMessageApi.js index ea7eeba756..577eabf5ec 100644 --- a/src/FromWidgetPostMessageApi.js +++ b/src/FromWidgetPostMessageApi.js @@ -1,5 +1,6 @@ /* Copyright 2018 New Vector Ltd +Copyright 2019 Travis Ralston Licensed under the Apache License, Version 2.0 (the 'License'); you may not use this file except in compliance with the License. @@ -20,17 +21,19 @@ import IntegrationManager from './IntegrationManager'; import WidgetMessagingEndpoint from './WidgetMessagingEndpoint'; import ActiveWidgetStore from './stores/ActiveWidgetStore'; -const WIDGET_API_VERSION = '0.0.1'; // Current API version +const WIDGET_API_VERSION = '0.0.2'; // Current API version const SUPPORTED_WIDGET_API_VERSIONS = [ '0.0.1', + '0.0.2', ]; const INBOUND_API_NAME = 'fromWidget'; -// Listen for and handle incomming requests using the 'fromWidget' postMessage +// Listen for and handle incoming requests using the 'fromWidget' postMessage // API and initiate responses export default class FromWidgetPostMessageApi { constructor() { this.widgetMessagingEndpoints = []; + this.widgetListeners = {}; // {action: func[]} this.start = this.start.bind(this); this.stop = this.stop.bind(this); @@ -45,6 +48,32 @@ export default class FromWidgetPostMessageApi { window.removeEventListener('message', this.onPostMessage); } + /** + * Adds a listener for a given action + * @param {string} action The action to listen for. + * @param {Function} callbackFn A callback function to be called when the action is + * encountered. Called with two parameters: the interesting request information and + * the raw event received from the postMessage API. The raw event is meant to be used + * for sendResponse and similar functions. + */ + addListener(action, callbackFn) { + if (!this.widgetListeners[action]) this.widgetListeners[action] = []; + this.widgetListeners[action].push(callbackFn); + } + + /** + * Removes a listener for a given action. + * @param {string} action The action that was subscribed to. + * @param {Function} callbackFn The original callback function that was used to subscribe + * to updates. + */ + removeListener(action, callbackFn) { + if (!this.widgetListeners[action]) return; + + const idx = this.widgetListeners.indexOf(callbackFn); + if (idx !== -1) this.widgetListeners.splice(idx, 1); + } + /** * Register a widget endpoint for trusted postMessage communication * @param {string} widgetId Unique widget identifier @@ -117,6 +146,13 @@ export default class FromWidgetPostMessageApi { return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise } + // Call any listeners we have registered + if (this.widgetListeners[event.data.action]) { + for (const fn of this.widgetListeners[event.data.action]) { + fn(event.data, event); + } + } + // Although the requestId is required, we don't use it. We'll be nice and process the message // if the property is missing, but with a warning for widget developers. if (!event.data.requestId) { @@ -164,6 +200,8 @@ export default class FromWidgetPostMessageApi { if (ActiveWidgetStore.widgetHasCapability(widgetId, 'm.always_on_screen')) { ActiveWidgetStore.setWidgetPersistence(widgetId, val); } + } else if (action === 'get_openid') { + // Handled by caller } else { console.warn('Widget postMessage event unhandled'); this.sendError(event, {message: 'The postMessage was unhandled'}); diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index 5b722df65f..17ce9360b7 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -1,5 +1,6 @@ /* Copyright 2017 New Vector Ltd +Copyright 2019 Travis Ralston Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,6 +22,10 @@ limitations under the License. import FromWidgetPostMessageApi from './FromWidgetPostMessageApi'; import ToWidgetPostMessageApi from './ToWidgetPostMessageApi'; +import Modal from "./Modal"; +import QuestionDialog from "./components/views/dialogs/QuestionDialog"; +import {_t} from "./languageHandler"; +import MatrixClientPeg from "./MatrixClientPeg"; if (!global.mxFromWidgetMessaging) { global.mxFromWidgetMessaging = new FromWidgetPostMessageApi(); @@ -40,6 +45,7 @@ export default class WidgetMessaging { this.target = target; this.fromWidget = global.mxFromWidgetMessaging; this.toWidget = global.mxToWidgetMessaging; + this._openIdHandlerRef = this._onOpenIdRequest.bind(this); this.start(); } @@ -109,9 +115,48 @@ export default class WidgetMessaging { start() { this.fromWidget.addEndpoint(this.widgetId, this.widgetUrl); + this.fromWidget.addListener("get_openid", this._openIdHandlerRef); } stop() { this.fromWidget.removeEndpoint(this.widgetId, this.widgetUrl); + this.fromWidget.removeListener("get_openid", this._openIdHandlerRef); + } + + _onOpenIdRequest(ev, rawEv) { + if (ev.widgetId !== this.widgetId) return; // not interesting + + // Confirm that we received the request + this.fromWidget.sendResponse(rawEv, {state: "request"}); + + // TODO: Support blacklisting widgets + // TODO: Support whitelisting widgets + + // Actually ask for permission to send the user's data + Modal.createTrackedDialog("OpenID widget permissions", '', QuestionDialog, { + title: _t("A widget would like to verify your identity"), + description: _t( + "A widget located at %(widgetUrl)s would like to verify your identity. " + + "By allowing this, the widget will be able to verify your user ID, but not " + + "perform actions as you.", { + widgetUrl: this.widgetUrl, + }, + ), + button: _t("Allow"), + onFinished: async (confirm) => { + const responseBody = {success: confirm}; + if (confirm) { + const credentials = await MatrixClientPeg.get().getOpenIdToken(); + Object.assign(responseBody, credentials); + } + this.messageToWidget({ + api: OUTBOUND_API_NAME, + action: "openid_credentials", + data: responseBody, + }).catch((error) => { + console.error("Failed to send OpenID credentials: ", error); + }); + }, + }); } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8cc85b6036..e13390e226 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -230,6 +230,9 @@ "%(names)s and %(count)s others are typing …|other": "%(names)s and %(count)s others are typing …", "%(names)s and %(count)s others are typing …|one": "%(names)s and one other is typing …", "%(names)s and %(lastPerson)s are typing …": "%(names)s and %(lastPerson)s are typing …", + "A widget would like to verify your identity": "A widget would like to verify your identity", + "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.": "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.", + "Allow": "Allow", "This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.", "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.", "Please contact your service administrator to continue using the service.": "Please contact your service administrator to continue using the service.", @@ -924,7 +927,6 @@ "NOTE: Apps are not end-to-end encrypted": "NOTE: Apps are not end-to-end encrypted", "Warning: This widget might use cookies.": "Warning: This widget might use cookies.", "Do you want to load widget from URL:": "Do you want to load widget from URL:", - "Allow": "Allow", "Delete Widget": "Delete Widget", "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?", "Delete widget": "Delete widget", From 955ec14db98816dba3fe8a53de769cf11848df1e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 14 Mar 2019 15:04:09 +0100 Subject: [PATCH 012/481] chrome apparently anchors the scroll position, which fights against our restore position logic. Disable it like this. --- res/css/structures/_RoomView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 1b639928e0..ced0b9eab3 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -113,6 +113,7 @@ limitations under the License. width: 100%; overflow-y: auto; flex: 1 1 0; + overflow-anchor: none; } .mx_RoomView_messagePanelSearchSpinner { From 5ded646db0126f03f2d0db9f498bbd39caeff25d Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 14 Mar 2019 17:03:32 -0600 Subject: [PATCH 013/481] Warn that members won't be autojoined to upgraded rooms Fixes https://github.com/vector-im/riot-web/issues/8173 Wording is questionable though. --- src/components/views/rooms/RoomUpgradeWarningBar.js | 6 ++++++ src/i18n/strings/en_EN.json | 1 + 2 files changed, 7 insertions(+) diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.js b/src/components/views/rooms/RoomUpgradeWarningBar.js index 3a11f46e51..32969cdd3d 100644 --- a/src/components/views/rooms/RoomUpgradeWarningBar.js +++ b/src/components/views/rooms/RoomUpgradeWarningBar.js @@ -72,6 +72,12 @@ module.exports = React.createClass({ return (
    {upgradeText} +
    + {_t( + "Members of the room will be required to click a link to join the " + + "new room. No one will be automatically joined or invited to the new room.", + )} +
    {_t("Only room administrators will see this warning")}
    diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2bda11a1dd..bfb8828fd3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -581,6 +581,7 @@ "Camera": "Camera", "Voice & Video": "Voice & Video", "This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers", + "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.": "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.", "Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s", "Room information": "Room information", "Internal room ID:": "Internal room ID:", From 788041a774b02d20f4c0001db1d15ce2e1975f89 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 14 Mar 2019 17:11:44 -0600 Subject: [PATCH 014/481] Warn that members won't be invited to the new room in room settings --- res/css/views/settings/tabs/_SettingsTab.scss | 4 ++++ .../settings/tabs/room/AdvancedRoomSettingsTab.js | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index 7fd8bceb50..88735f99b2 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -14,6 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_SettingsTab_warningText { + color: $warning-color; +} + .mx_SettingsTab_heading { font-size: 20px; font-weight: 600; diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js index 3c6a7addc3..13ee39ccd7 100644 --- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js @@ -67,9 +67,17 @@ export default class AdvancedRoomSettingsTab extends React.Component { let roomUpgradeButton; if (this.state.upgradeRecommendation && this.state.upgradeRecommendation.needsUpgrade) { roomUpgradeButton = ( - - {_t("Upgrade room to version %(ver)s", {ver: this.state.upgradeRecommendation.version})} - +
    +

    + {_t( + "Members of the room will be required to click a link to join the new room. No " + + "one will be automatically joined or invited to the new room.", + )} +

    + + {_t("Upgrade room to version %(ver)s", {ver: this.state.upgradeRecommendation.version})} + +
    ); } From fba4b7235f4766d8f5a08abfd7dc82c0953a3006 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 14 Mar 2019 17:24:22 -0600 Subject: [PATCH 015/481] Add a confirmation prompt when upgrading the room via slashcommand Wording is questionable here, but the idea is to discourage non-power-users from accidentally upgrading their room. They should already be receiving a bunch of warnings if they should consider upgrading in the first place. --- src/SlashCommands.js | 39 ++++++++++++++++++++++++++++++++++++- src/i18n/strings/en_EN.json | 6 +++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 711346c4a7..11018df081 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -28,6 +28,7 @@ import {MATRIXTO_URL_PATTERN} from "./linkify-matrix"; import * as querystring from "querystring"; import MultiInviter from './utils/MultiInviter'; import { linkifyAndSanitizeHtml } from './HtmlUtils'; +import QuestionDialog from "./components/views/dialogs/QuestionDialog"; class Command { constructor({name, args='', description, runFn, hideCompletionAfterSpace=false}) { @@ -105,7 +106,43 @@ export const CommandMap = { description: _td('Upgrades a room to a new version'), runFn: function(roomId, args) { if (args) { - return success(MatrixClientPeg.get().upgradeRoom(roomId, args)); + const room = MatrixClientPeg.get().getRoom(roomId); + Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation', + QuestionDialog, { + title: _t('Room upgrade confirmation'), + description: ( +
    + { _t( + "Upgrading your room in this way can be dangerous or unnecessary. Room upgrades " + + "are usually done to change the server's behaviour in a given room and not so much " + + "anything to do with client (Riot) behaviour.", + ) } +
    +
    + { _t( + "Members of the room will be required to click a link to join the new room. No " + + "one will be automatically joined or invited to the new room.", + ) } +
    +
    + { _t( + "Please confirm that you'd like to go forward with upgrading this room from " + + "%(oldVersion)s to %(newVersion)s", + { + oldVersion: room ? room.getVersion() : "1", + newVersion: args, + }, + ) } +
    + ), + button: _t("Upgrade Room"), + onFinished: (confirm) => { + if (!confirm) return; + + MatrixClientPeg.get().upgradeRoom(roomId, args); + }, + }); + return success(); } return reject(this.getUsage()); }, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index bfb8828fd3..26113d3d4f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -132,6 +132,11 @@ "/ddg is not a command": "/ddg is not a command", "To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.", "Upgrades a room to a new version": "Upgrades a room to a new version", + "Room upgrade confirmation": "Room upgrade confirmation", + "Upgrading your room in this way can be dangerous or unnecessary. Room upgrades are usually done to change the server's behaviour in a given room and not so much anything to do with client (Riot) behaviour.": "Upgrading your room in this way can be dangerous or unnecessary. Room upgrades are usually done to change the server's behaviour in a given room and not so much anything to do with client (Riot) behaviour.", + "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.": "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.", + "Please confirm that you'd like to go forward with upgrading this room from %(oldVersion)s to %(newVersion)s": "Please confirm that you'd like to go forward with upgrading this room from %(oldVersion)s to %(newVersion)s", + "Upgrade Room": "Upgrade Room", "Changes your display nickname": "Changes your display nickname", "Changes your display nickname in the current room only": "Changes your display nickname in the current room only", "Changes colour scheme of current room": "Changes colour scheme of current room", @@ -581,7 +586,6 @@ "Camera": "Camera", "Voice & Video": "Voice & Video", "This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers", - "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.": "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.", "Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s", "Room information": "Room information", "Internal room ID:": "Internal room ID:", From 0b8196343f008d9fd2e22cd54c2c3be85f7c5c8c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 15 Mar 2019 09:57:26 +0100 Subject: [PATCH 016/481] fix some tests --- test/components/structures/MessagePanel-test.js | 9 ++++++++- test/components/structures/ScrollPanel-test.js | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 0a51cb8918..c7287f1523 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -21,6 +21,7 @@ const ReactDOM = require("react-dom"); const TestUtils = require('react-addons-test-utils'); const expect = require('expect'); import sinon from 'sinon'; +import { EventEmitter } from "events"; const sdk = require('matrix-react-sdk'); @@ -46,8 +47,14 @@ const WrappedMessagePanel = React.createClass({ }; }, + getInitialState: function() { + return { + resizeNotifier: new EventEmitter(), + }; + }, + render: function() { - return ; + return ; }, }); diff --git a/test/components/structures/ScrollPanel-test.js b/test/components/structures/ScrollPanel-test.js index 0e091cdddf..41d0f4469b 100644 --- a/test/components/structures/ScrollPanel-test.js +++ b/test/components/structures/ScrollPanel-test.js @@ -19,6 +19,7 @@ const ReactDOM = require("react-dom"); const ReactTestUtils = require('react-addons-test-utils'); const expect = require('expect'); import Promise from 'bluebird'; +import { EventEmitter } from "events"; const sdk = require('matrix-react-sdk'); @@ -29,6 +30,7 @@ const Tester = React.createClass({ getInitialState: function() { return { tileKeys: [], + resizeNotifier: new EventEmitter(), }; }, @@ -130,7 +132,8 @@ const Tester = React.createClass({ return ( + onFillRequest={this._onFillRequest} + resizeNotifier={this.state.resizeNotifier}> { tiles } ); From 30d848b86e514066888f865fff049a266aa60e0d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:30:06 +0100 Subject: [PATCH 017/481] use AutoHideScrollbar in ScrollPanel --- res/css/structures/_RoomView.scss | 2 + .../structures/AutoHideScrollbar.js | 1 + src/components/structures/ScrollPanel.js | 40 +++++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index f15552e484..1b639928e0 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -84,6 +84,7 @@ limitations under the License. display: flex; flex-direction: column; flex: 1; + min-width: 0; } .mx_RoomView_body .mx_RoomView_timeline { @@ -111,6 +112,7 @@ limitations under the License. .mx_RoomView_messagePanel { width: 100%; overflow-y: auto; + flex: 1 1 0; } .mx_RoomView_messagePanelSearchSpinner { diff --git a/src/components/structures/AutoHideScrollbar.js b/src/components/structures/AutoHideScrollbar.js index 0f93f20407..72d48a2084 100644 --- a/src/components/structures/AutoHideScrollbar.js +++ b/src/components/structures/AutoHideScrollbar.js @@ -121,6 +121,7 @@ export default class AutoHideScrollbar extends React.Component { render() { return (
    diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index ee4045c91e..cdb79686ad 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -15,14 +15,13 @@ limitations under the License. */ const React = require("react"); -const ReactDOM = require("react-dom"); import PropTypes from 'prop-types'; import Promise from 'bluebird'; import { KeyCode } from '../../Keyboard'; -import sdk from '../../index.js'; +import AutoHideScrollbar from "./AutoHideScrollbar"; const DEBUG_SCROLL = false; -// var DEBUG_SCROLL = true; +// const DEBUG_SCROLL = true; // The amount of extra scroll distance to allow prior to unfilling. // See _getExcessHeight. @@ -129,11 +128,6 @@ module.exports = React.createClass({ */ onScroll: PropTypes.func, - /* onResize: a callback which is called whenever the Gemini scroll - * panel is resized - */ - onResize: PropTypes.func, - /* className: classnames to add to the top-level div */ className: PropTypes.string, @@ -150,7 +144,6 @@ module.exports = React.createClass({ onFillRequest: function(backwards) { return Promise.resolve(false); }, onUnfillRequest: function(backwards, scrollToken) {}, onScroll: function() {}, - onResize: function() {}, }; }, @@ -185,6 +178,16 @@ module.exports = React.createClass({ debuglog("Scroll event: offset now:", sn.scrollTop, "_lastSetScroll:", this._lastSetScroll); + // ignore scroll events where scrollTop hasn't changed, + // appears to happen when the layout changes outside + // of the scroll container, like resizing the right panel. + if (sn.scrollTop === this._lastEventScroll) { + debuglog("ignore scroll event with same scrollTop as before"); + return; + } + + this._lastEventScroll = sn.scrollTop; + // Sometimes we see attempts to write to scrollTop essentially being // ignored. (Or rather, it is successfully written, but on the next // scroll event, it's been reset again). @@ -225,9 +228,7 @@ module.exports = React.createClass({ onResize: function() { this.clearBlockShrinking(); - this.props.onResize(); this.checkScroll(); - if (this._gemScroll) this._gemScroll.forceUpdate(); }, // after an update to the contents of the panel, check that the scroll is @@ -672,17 +673,17 @@ module.exports = React.createClass({ throw new Error("ScrollPanel._getScrollNode called when unmounted"); } - if (!this._gemScroll) { + if (!this._divScroll) { // Likewise, we should have the ref by this point, but if not // turn the NPE into something meaningful. throw new Error("ScrollPanel._getScrollNode called before gemini ref collected"); } - return this._gemScroll.scrollbar.getViewElement(); + return this._divScroll; }, - _collectGeminiScroll: function(gemScroll) { - this._gemScroll = gemScroll; + _collectScroll: function(divScroll) { + this._divScroll = divScroll; }, /** @@ -724,19 +725,18 @@ module.exports = React.createClass({ }, render: function() { - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); // 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. - return (
      { this.props.children }
    -
    - ); + + ); }, }); From f71a9f10dd7f7420c1f5d3fd3100057139772ba0 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:33:05 +0100 Subject: [PATCH 018/481] remove onChildResize in RoomView as it's unused --- src/components/structures/RoomView.js | 15 ++------------- src/components/views/rooms/MessageComposer.js | 5 ----- .../views/rooms/MessageComposerInput.js | 4 ---- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 34c711ee6f..ae3a4b2bac 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1364,8 +1364,7 @@ module.exports = React.createClass({ const showBar = this.refs.messagePanel.canJumpToReadMarker(); if (this.state.showTopUnreadMessagesBar != showBar) { - this.setState({showTopUnreadMessagesBar: showBar}, - this.onChildResize); + this.setState({showTopUnreadMessagesBar: showBar}); } }, @@ -1408,7 +1407,7 @@ module.exports = React.createClass({ }; }, - onResize: function(e) { + onResize: function() { // 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 @@ -1426,9 +1425,6 @@ module.exports = React.createClass({ if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50; this.setState({auxPanelMaxHeight: auxPanelMaxHeight}); - - // changing the maxHeight on the auxpanel will trigger a callback go - // onChildResize, so no need to worry about that here. }, onFullscreenClick: function() { @@ -1458,10 +1454,6 @@ module.exports = React.createClass({ this.forceUpdate(); // TODO: just update the voip buttons }, - onChildResize: function() { - // no longer anything to do here - }, - onStatusBarVisible: function() { if (this.unmounted) return; this.setState({ @@ -1654,7 +1646,6 @@ module.exports = React.createClass({ isPeeking={myMembership !== "join"} onInviteClick={this.onInviteButtonClick} onStopWarningClick={this.onStopAloneWarningClick} - onResize={this.onChildResize} onVisible={this.onStatusBarVisible} onHidden={this.onStatusBarHidden} />; @@ -1723,7 +1714,6 @@ module.exports = React.createClass({ draggingFile={this.state.draggingFile} displayConfCallNotification={this.state.displayConfCallNotification} maxHeight={this.state.auxPanelMaxHeight} - onResize={this.onChildResize} showApps={this.state.showApps} hideAppsDrawer={false} > { aux } @@ -1739,7 +1729,6 @@ module.exports = React.createClass({ messageComposer = this.messageComposerInput = c} key="controls_input" - onResize={this.props.onResize} room={this.props.room} placeholder={placeholderText} onFilesPasted={this.uploadFiles} @@ -505,10 +504,6 @@ export default class MessageComposer extends React.Component { } MessageComposer.propTypes = { - // a callback which is called when the height of the composer is - // changed due to a change in content. - onResize: PropTypes.func, - // js-sdk Room object room: PropTypes.object.isRequired, diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 6b80902c8f..cbea2bccb9 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -135,10 +135,6 @@ function rangeEquals(a: Range, b: Range): boolean { */ export default class MessageComposerInput extends React.Component { static propTypes = { - // a callback which is called when the height of the composer is - // changed due to a change in content. - onResize: PropTypes.func, - // js-sdk Room object room: PropTypes.object.isRequired, From 891e343df624be7e1b22f858a6894110cb7e7525 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:36:12 +0100 Subject: [PATCH 019/481] create ResizeNotifier to derive which areas of the app resize and emit --- src/components/structures/FilePanel.js | 1 + src/components/structures/LoggedInView.js | 2 + src/components/structures/MainSplit.js | 1 + src/components/structures/MatrixChat.js | 3 ++ src/components/structures/MessagePanel.js | 3 +- src/components/structures/RightPanel.js | 2 +- src/components/structures/RoomView.js | 13 ++++-- src/components/structures/ScrollPanel.js | 3 ++ src/components/structures/TimelinePanel.js | 1 + src/utils/ResizeNotifier.js | 52 ++++++++++++++++++++++ 10 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/utils/ResizeNotifier.js diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js index 927449750c..e35a39a107 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.js @@ -123,6 +123,7 @@ const FilePanel = React.createClass({ timelineSet={this.state.timelineSet} showUrlPreview = {false} tileShape="file_grid" + resizeNotifier={this.props.resizeNotifier} empty={_t('There are no visible files in this room')} /> ); diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index c6c1be67ec..5267dba715 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -173,6 +173,7 @@ const LoggedInView = React.createClass({ }, onResized: (size) => { window.localStorage.setItem("mx_lhs_size", '' + size); + this.props.resizeNotifier.notifyLeftHandleResized(); }, }; const resizer = new Resizer( @@ -448,6 +449,7 @@ const LoggedInView = React.createClass({ disabled={this.props.middleDisabled} collapsedRhs={this.props.collapsedRhs} ConferenceHandler={this.props.ConferenceHandler} + resizeNotifier={this.props.resizeNotifier} />; break; diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 0427130eea..c0bf74d02c 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -27,6 +27,7 @@ export default class MainSplit extends React.Component { _onResized(size) { window.localStorage.setItem("mx_rhs_size", size); + this.props.resizeNotifier.notifyRightHandleResized(); } _createResizer() { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2622a6bf93..a9b34c9058 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -48,6 +48,7 @@ import { _t, getCurrentLanguage } from '../../languageHandler'; import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import { startAnyRegistrationFlow } from "../../Registration.js"; import { messageForSyncError } from '../../utils/ErrorUtils'; +import ResizeNotifier from "../../utils/ResizeNotifier"; const AutoDiscovery = Matrix.AutoDiscovery; @@ -194,6 +195,7 @@ export default React.createClass({ hideToSRUsers: false, syncError: null, // If the current syncing status is ERROR, the error object, otherwise null. + resizeNotifier: new ResizeNotifier(), }; return s; }, @@ -1661,6 +1663,7 @@ export default React.createClass({ dis.dispatch({ action: 'show_right_panel' }); } + this.state.resizeNotifier.notifyWindowResized(); this._windowWidth = window.innerWidth; }, diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index b1f88a6221..aec2f8cbe1 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -703,7 +703,8 @@ module.exports = React.createClass({ onFillRequest={this.props.onFillRequest} onUnfillRequest={this.props.onUnfillRequest} style={style} - stickyBottom={this.props.stickyBottom}> + stickyBottom={this.props.stickyBottom} + resizeNotifier={this.props.resizeNotifier}> { topSpinner } { this._getEventTiles() } { whoIsTyping } diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 5c745b04cc..93cbff3233 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -193,7 +193,7 @@ export default class RightPanel extends React.Component { } else if (this.state.phase === RightPanel.Phase.NotificationPanel) { panel = ; } else if (this.state.phase === RightPanel.Phase.FilePanel) { - panel = ; + panel = ; } const classes = classNames("mx_RightPanel", "mx_fadable", { diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index ae3a4b2bac..bb2c322b0a 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -392,7 +392,7 @@ module.exports = React.createClass({ this._updateConfCallNotification(); window.addEventListener('beforeunload', this.onPageUnload); - window.addEventListener('resize', this.onResize); + this.props.resizeNotifier.on("middlePanelResized", this.onResize); this.onResize(); document.addEventListener("keydown", this.onKeyDown); @@ -472,7 +472,7 @@ module.exports = React.createClass({ } window.removeEventListener('beforeunload', this.onPageUnload); - window.removeEventListener('resize', this.onResize); + this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); document.removeEventListener("keydown", this.onKeyDown); @@ -1838,6 +1838,7 @@ module.exports = React.createClass({ className="mx_RoomView_messagePanel" membersLoaded={this.state.membersLoaded} permalinkCreator={this.state.permalinkCreator} + resizeNotifier={this.props.resizeNotifier} />); let topUnreadMessagesBar = null; @@ -1870,7 +1871,7 @@ module.exports = React.createClass({ }, ); - const rightPanel = this.state.room ? : undefined; + const rightPanel = this.state.room ? : undefined; return (
    @@ -1886,7 +1887,11 @@ module.exports = React.createClass({ onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null} e2eStatus={this.state.e2eStatus} /> - +
    { auxPanel }
    diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index cdb79686ad..799c88140e 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -149,6 +149,8 @@ module.exports = React.createClass({ componentWillMount: function() { this._pendingFillRequests = {b: null, f: null}; + this.props.resizeNotifier.on("middlePanelResized", this.onResize); + this.resetScrollState(); }, @@ -171,6 +173,7 @@ module.exports = React.createClass({ // // (We could use isMounted(), but facebook have deprecated that.) this.unmounted = true; + this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); }, onScroll: function(ev) { diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index f0feaf94c5..c983f904a0 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -1228,6 +1228,7 @@ var TimelinePanel = React.createClass({ alwaysShowTimestamps={this.state.alwaysShowTimestamps} className={this.props.className} tileShape={this.props.tileShape} + resizeNotifier={this.props.resizeNotifier} /> ); }, diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js new file mode 100644 index 0000000000..43578ebcaa --- /dev/null +++ b/src/utils/ResizeNotifier.js @@ -0,0 +1,52 @@ +/* +Copyright 2019 New Vector 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. +*/ + +/** + * Fires when the middle panel has been resized. + * @event module:utils~ResizeNotifier#"middlePanelResized" + */ +import { EventEmitter } from "events"; +import { throttle } from "lodash"; + +export default class ResizeNotifier extends EventEmitter { + + constructor() { + super(); + // with default options, will call fn once at first call, and then every x ms + // if there was another call in that timespan + this._throttledMiddlePanel = throttle(() => this.emit("middlePanelResized"), 200); + } + + notifyBannersChanged() { + this.emit("middlePanelResized"); + } + + // can be called in quick succession + notifyLeftHandleResized() { + this._throttledMiddlePanel(); + } + + // can be called in quick succession + notifyRightHandleResized() { + this._throttledMiddlePanel(); + } + + // can be called in quick succession + notifyWindowResized() { + this._throttledMiddlePanel(); + } +} + From 1bdbf3086f04579d7ec860e8f95605168c3e7bf7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:37:20 +0100 Subject: [PATCH 020/481] emit timeline_resize in MatrixChat based on ResizeNotifier as it's used in PersistentElement which could be used at various places --- src/components/structures/MatrixChat.js | 8 ++++++++ src/components/structures/MessagePanel.js | 5 ----- src/components/structures/RoomView.js | 5 ----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index a9b34c9058..6e05138e2d 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -318,6 +318,9 @@ export default React.createClass({ // N.B. we don't call the whole of setTheme() here as we may be // racing with the theme CSS download finishing from index.js Tinter.tint(); + + // For PersistentElement + this.state.resizeNotifier.on("middlePanelResized", this._dispatchTimelineResize); }, componentDidMount: function() { @@ -400,6 +403,7 @@ export default React.createClass({ dis.unregister(this.dispatcherRef); window.removeEventListener("focus", this.onFocus); window.removeEventListener('resize', this.handleResize); + this.state.resizeNotifier.removeListener("middlePanelResized", this._dispatchTimelineResize); }, componentWillUpdate: function(props, state) { @@ -1667,6 +1671,10 @@ export default React.createClass({ this._windowWidth = window.innerWidth; }, + _dispatchTimelineResize() { + dis.dispatch({ action: 'timeline_resize' }, true); + }, + onRoomCreated: function(roomId) { dis.dispatch({ action: "view_room", diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index aec2f8cbe1..fecf5f1ad7 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -21,7 +21,6 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import shouldHideEvent from '../../shouldHideEvent'; import {wantsDateSeparator} from '../../DateUtils'; -import dis from "../../dispatcher"; import sdk from '../../index'; import MatrixClientPeg from '../../MatrixClientPeg'; @@ -665,10 +664,6 @@ module.exports = React.createClass({ } }, - onResize: function() { - dis.dispatch({ action: 'timeline_resize' }, true); - }, - render: function() { const ScrollPanel = sdk.getComponent("structures.ScrollPanel"); const WhoIsTypingTile = sdk.getComponent("rooms.WhoIsTypingTile"); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index bb2c322b0a..d8b4fbb0f1 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -865,10 +865,6 @@ module.exports = React.createClass({ } }, - onSearchResultsResize: function() { - dis.dispatch({ action: 'timeline_resize' }, true); - }, - onSearchResultsFillRequest: function(backwards) { if (!backwards) { return Promise.resolve(false); @@ -1803,7 +1799,6 @@ module.exports = React.createClass({
  • { this.getSearchResultTiles() } From dad382a4b750bedd1ba6349f23aa701909348f85 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 16:38:30 +0100 Subject: [PATCH 021/481] use AutoHideScrollbar in memberlist --- res/css/views/rooms/_MemberList.scss | 5 +++++ src/components/views/rooms/MemberList.js | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_MemberList.scss b/res/css/views/rooms/_MemberList.scss index 9f2b5da930..cac97cb60d 100644 --- a/res/css/views/rooms/_MemberList.scss +++ b/res/css/views/rooms/_MemberList.scss @@ -20,6 +20,7 @@ limitations under the License. flex: 1; display: flex; flex-direction: column; + min-height: 0; .mx_Spinner { flex: 1 0 auto; @@ -35,6 +36,10 @@ limitations under the License. margin-top: 8px; margin-bottom: 4px; } + + .mx_AutoHideScrollbar { + flex: 1 1 0; + } } .mx_MemberList_chevron { diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index f9ce672c16..29f49f1691 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -20,6 +20,8 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher'; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; + const MatrixClientPeg = require("../../../MatrixClientPeg"); const sdk = require('../../../index'); const rate_limited_func = require('../../../ratelimitedfunc'); @@ -439,7 +441,6 @@ module.exports = React.createClass({ const SearchBox = sdk.getComponent('structures.SearchBox'); const TruncatedList = sdk.getComponent("elements.TruncatedList"); - const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper"); const cli = MatrixClientPeg.get(); const room = cli.getRoom(this.props.roomId); @@ -466,7 +467,7 @@ module.exports = React.createClass({ return (
    { inviteButton } - +
    - + Date: Tue, 12 Mar 2019 16:38:42 +0100 Subject: [PATCH 022/481] use AutoHideScrollbar in member info panel --- src/components/views/rooms/MemberInfo.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 3ada730ec8..35161dedf7 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -44,6 +44,7 @@ import SdkConfig from '../../../SdkConfig'; import MultiInviter from "../../../utils/MultiInviter"; import SettingsStore from "../../../settings/SettingsStore"; import E2EIcon from "./E2EIcon"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; module.exports = withMatrixClient(React.createClass({ displayName: 'MemberInfo', @@ -1003,7 +1004,7 @@ module.exports = withMatrixClient(React.createClass({ { roomMemberDetails }
    - +
    { this._renderUserOptions() } @@ -1015,7 +1016,7 @@ module.exports = withMatrixClient(React.createClass({ { spinner }
    -
    +
    ); }, From 4795625cee23c73864efc7bb32b93548a551529f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 17:29:16 +0100 Subject: [PATCH 023/481] emit resize event when banners are shown/hidden to restore scroll pos --- src/Notifier.js | 12 +++++++++++- src/components/structures/LoggedInView.js | 19 +++++++++++++------ src/components/structures/MatrixChat.js | 13 ++++++++++--- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/Notifier.js b/src/Notifier.js index 80e8be1084..ab8009c457 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -220,7 +220,17 @@ const Notifier = { } }, - isToolbarHidden: function() { + shouldShowToolbar: function() { + const client = MatrixClientPeg.get(); + if (!client) { + return false; + } + const isGuest = client.isGuest(); + return !isGuest && Notifier.supportsDesktopNotifications() && + !Notifier.isEnabled() && !Notifier._isToolbarHidden(); + }, + + _isToolbarHidden: function() { // Check localStorage for any such meta data if (global.localStorage) { return global.localStorage.getItem("notifications_hidden") === "true"; diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index 5267dba715..c22c217e5f 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -22,7 +22,6 @@ import PropTypes from 'prop-types'; import { DragDropContext } from 'react-beautiful-dnd'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard'; -import Notifier from '../../Notifier'; import PageTypes from '../../PageTypes'; import CallMediaHandler from '../../CallMediaHandler'; import sdk from '../../index'; @@ -121,6 +120,18 @@ const LoggedInView = React.createClass({ this._matrixClient.on("RoomState.events", this.onRoomStateEvents); }, + componentDidUpdate(prevProps) { + // attempt to guess when a banner was opened or closed + if ( + (prevProps.showCookieBar !== this.props.showCookieBar) || + (prevProps.hasNewVersion !== this.props.hasNewVersion) || + (prevProps.userHasGeneratedPassword !== this.props.userHasGeneratedPassword) || + (prevProps.showNotifierToolbar !== this.props.showNotifierToolbar) + ) { + this.props.resizeNotifier.notifyBannersChanged(); + } + }, + componentWillUnmount: function() { document.removeEventListener('keydown', this._onKeyDown); this._matrixClient.removeListener("accountData", this.onAccountData); @@ -491,7 +502,6 @@ const LoggedInView = React.createClass({ }); let topBar; - const isGuest = this.props.matrixClient.isGuest(); if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') { topBar = ; } else if (this.state.userHasGeneratedPassword) { topBar = ; - } else if ( - !isGuest && Notifier.supportsDesktopNotifications() && - !Notifier.isEnabled() && !Notifier.isToolbarHidden() - ) { + } else if (this.props.showNotifierToolbar) { topBar = ; } diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 6e05138e2d..a7192b96cb 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -29,6 +29,7 @@ import PlatformPeg from "../../PlatformPeg"; import SdkConfig from "../../SdkConfig"; import * as RoomListSorter from "../../RoomListSorter"; import dis from "../../dispatcher"; +import Notifier from '../../Notifier'; import Modal from "../../Modal"; import Tinter from "../../Tinter"; @@ -196,6 +197,7 @@ export default React.createClass({ syncError: null, // If the current syncing status is ERROR, the error object, otherwise null. resizeNotifier: new ResizeNotifier(), + showNotifierToolbar: Notifier.shouldShowToolbar(), }; return s; }, @@ -644,8 +646,9 @@ export default React.createClass({ case 'view_invite': showRoomInviteDialog(payload.roomId); break; - case 'notifier_enabled': - this.forceUpdate(); + case 'notifier_enabled': { + this.setState({showNotifierToolbar: Notifier.shouldShowToolbar()}); + } break; case 'hide_left_panel': this.setState({ @@ -1180,6 +1183,7 @@ export default React.createClass({ */ _onLoggedIn: async function() { this.setStateForNewView({view: VIEWS.LOGGED_IN}); + this.setState({showNotifierToolbar: Notifier.shouldShowToolbar()}); if (this._is_registered) { this._is_registered = false; @@ -1672,7 +1676,10 @@ export default React.createClass({ }, _dispatchTimelineResize() { - dis.dispatch({ action: 'timeline_resize' }, true); + // prevent dispatch from within dispatch error + setTimeout(() => { + dis.dispatch({ action: 'timeline_resize' }, true); + }, 0); }, onRoomCreated: function(roomId) { From bab2730d405b3fdde49891c2843c7810514a89de Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 12 Mar 2019 18:00:05 +0100 Subject: [PATCH 024/481] use ResizeNotifier as well to relayout room list --- src/components/structures/LeftPanel.js | 2 +- src/components/structures/LoggedInView.js | 2 +- src/components/views/rooms/RoomList.js | 10 ++++++---- src/utils/ResizeNotifier.js | 8 ++++++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index 21438c597c..95b57a0ca5 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -234,7 +234,7 @@ const LeftPanel = React.createClass({ diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index c22c217e5f..4771c6f487 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -543,7 +543,7 @@ const LoggedInView = React.createClass({
    diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 227dd318ed..2de9918e6e 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -212,7 +212,7 @@ module.exports = React.createClass({ this._checkSubListsOverflow(); this.resizer.attach(); - window.addEventListener("resize", this.onWindowResize); + this.props.resizeNotifier.on("leftPanelResized", this.onResize); this.mounted = true; }, @@ -260,7 +260,6 @@ module.exports = React.createClass({ componentWillUnmount: function() { this.mounted = false; - window.removeEventListener("resize", this.onWindowResize); dis.unregister(this.dispatcherRef); if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Room", this.onRoom); @@ -272,6 +271,8 @@ module.exports = React.createClass({ MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); } + this.props.resizeNotifier.removeListener("leftPanelResized", this.onResize); + if (this._tagStoreToken) { this._tagStoreToken.remove(); @@ -293,13 +294,14 @@ module.exports = React.createClass({ this._delayedRefreshRoomList.cancelPendingCall(); }, - onWindowResize: function() { + + onResize: function() { if (this.mounted && this._layout && this.resizeContainer && Array.isArray(this._layoutSections) ) { this._layout.update( this._layoutSections, - this.resizeContainer.offsetHeight + this.resizeContainer.offsetHeight, ); } }, diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js index 43578ebcaa..ff4b79091b 100644 --- a/src/utils/ResizeNotifier.js +++ b/src/utils/ResizeNotifier.js @@ -31,11 +31,13 @@ export default class ResizeNotifier extends EventEmitter { } notifyBannersChanged() { + this.emit("leftPanelResized"); this.emit("middlePanelResized"); } // can be called in quick succession notifyLeftHandleResized() { + // don't emit event for own region this._throttledMiddlePanel(); } @@ -46,6 +48,12 @@ export default class ResizeNotifier extends EventEmitter { // can be called in quick succession notifyWindowResized() { + // no need to throttle this one, + // also it could make scrollbars appear for + // a split second when the room list manual layout is now + // taller than the available space + this.emit("leftPanelResized"); + this._throttledMiddlePanel(); } } From 987a1a00b38d3895e62c7efbcde2d9b505571bdb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 14 Mar 2019 15:04:09 +0100 Subject: [PATCH 025/481] chrome apparently anchors the scroll position, which fights against our restore position logic. Disable it like this. --- res/css/structures/_RoomView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 1b639928e0..ced0b9eab3 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -113,6 +113,7 @@ limitations under the License. width: 100%; overflow-y: auto; flex: 1 1 0; + overflow-anchor: none; } .mx_RoomView_messagePanelSearchSpinner { From 95e61a57bc6a8a49e7e9e27b86bf45ada629b05c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 15 Mar 2019 09:57:26 +0100 Subject: [PATCH 026/481] fix some tests --- test/components/structures/MessagePanel-test.js | 9 ++++++++- test/components/structures/ScrollPanel-test.js | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 0a51cb8918..c7287f1523 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -21,6 +21,7 @@ const ReactDOM = require("react-dom"); const TestUtils = require('react-addons-test-utils'); const expect = require('expect'); import sinon from 'sinon'; +import { EventEmitter } from "events"; const sdk = require('matrix-react-sdk'); @@ -46,8 +47,14 @@ const WrappedMessagePanel = React.createClass({ }; }, + getInitialState: function() { + return { + resizeNotifier: new EventEmitter(), + }; + }, + render: function() { - return ; + return ; }, }); diff --git a/test/components/structures/ScrollPanel-test.js b/test/components/structures/ScrollPanel-test.js index 0e091cdddf..41d0f4469b 100644 --- a/test/components/structures/ScrollPanel-test.js +++ b/test/components/structures/ScrollPanel-test.js @@ -19,6 +19,7 @@ const ReactDOM = require("react-dom"); const ReactTestUtils = require('react-addons-test-utils'); const expect = require('expect'); import Promise from 'bluebird'; +import { EventEmitter } from "events"; const sdk = require('matrix-react-sdk'); @@ -29,6 +30,7 @@ const Tester = React.createClass({ getInitialState: function() { return { tileKeys: [], + resizeNotifier: new EventEmitter(), }; }, @@ -130,7 +132,8 @@ const Tester = React.createClass({ return ( + onFillRequest={this._onFillRequest} + resizeNotifier={this.state.resizeNotifier}> { tiles } ); From 8d8445429c97da0e7306cb318549a7576ab1fbf0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 14:13:15 -0600 Subject: [PATCH 027/481] Show options for .m.rule.tombstone push rules Part of vector-im/riot-web#8447 --- src/components/views/settings/Notifications.js | 2 ++ src/i18n/strings/en_EN.json | 1 + src/notifications/VectorPushRulesDefinitions.js | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index b8f8279bb0..4520f5c9a1 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -507,6 +507,7 @@ module.exports = React.createClass({ //'.m.rule.member_event': 'vector', '.m.rule.call': 'vector', '.m.rule.suppress_notices': 'vector', + '.m.rule.tombstone': 'vector', // Others go to others }; @@ -562,6 +563,7 @@ module.exports = React.createClass({ //'im.vector.rule.member_event', '.m.rule.call', '.m.rule.suppress_notices', + '.m.rule.tombstone', ]; for (const i in vectorRuleIds) { const vectorRuleId = vectorRuleIds[i]; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e23be021e8..7b26ed5cf2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -325,6 +325,7 @@ "When I'm invited to a room": "When I'm invited to a room", "Call invitation": "Call invitation", "Messages sent by bot": "Messages sent by bot", + "When rooms are upgraded": "When rooms are upgraded", "Active call (%(roomName)s)": "Active call (%(roomName)s)", "unknown caller": "unknown caller", "Incoming voice call from %(name)s": "Incoming voice call from %(name)s", diff --git a/src/notifications/VectorPushRulesDefinitions.js b/src/notifications/VectorPushRulesDefinitions.js index 402a69e7a6..b15fb4ccd7 100644 --- a/src/notifications/VectorPushRulesDefinitions.js +++ b/src/notifications/VectorPushRulesDefinitions.js @@ -183,4 +183,15 @@ module.exports = { off: StandardActions.ACTION_DONT_NOTIFY, }, }), + + // Room upgrades (tombstones) + ".m.rule.tombstone": new VectorPushRuleDefinition({ + kind: "override", + description: _td("When rooms are upgraded"), // passed through _t() translation in src/components/views/settings/Notifications.js + vectorStateToActions: { // The actions for each vector state, or null to disable the rule. + on: StandardActions.ACTION_NOTIFY, + loud: StandardActions.ACTION_HIGHLIGHT, + off: StandardActions.ACTION_DISABLED, + }, + }), }; From e5059fdf0f82b120c50ad2c9447726b7f9885ce2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 14:14:00 -0600 Subject: [PATCH 028/481] Don't show Matrix-namespaced push rules which the server doesn't declare So that users can't change push rules they don't have. Similar to the behaviour in https://github.com/matrix-org/matrix-js-sdk/pull/860 --- src/components/views/settings/Notifications.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index 4520f5c9a1..23f7cd484a 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -704,6 +704,10 @@ module.exports = React.createClass({ const rows = []; for (const i in this.state.vectorPushRules) { const rule = this.state.vectorPushRules[i]; + if (rule.rule === undefined && rule.vectorRuleId.startsWith(".m.")) { + console.warn(`Skipping render of rule ${rule.vectorRuleId} due to no underlying rule`); + continue; + } //console.log("rendering: " + rule.description + ", " + rule.vectorRuleId + ", " + rule.vectorState); rows.push(this.renderNotifRulesTableRow(rule.description, rule.vectorRuleId, rule.vectorState)); } From 92b851b26c4b397cbdd66b615a8a36ae60b31603 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 15:49:18 -0600 Subject: [PATCH 029/481] Update text for room version upgrades in settings --- .../settings/tabs/room/AdvancedRoomSettingsTab.js | 11 ++++++++--- src/i18n/strings/en_EN.json | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js index 13ee39ccd7..8c56e17a13 100644 --- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js @@ -70,12 +70,17 @@ export default class AdvancedRoomSettingsTab extends React.Component {

    {_t( - "Members of the room will be required to click a link to join the new room. No " + - "one will be automatically joined or invited to the new room.", + "Warning: Upgrading a room will not automatically migrate room members " + + "to the new version of the room. We'll post a link to the new room in the old version " + + "of the room - room members will have to click this link to join the new room.", + {}, { + "b": (sub) => {sub}, + "i": (sub) => {sub}, + }, )}

    - {_t("Upgrade room to version %(ver)s", {ver: this.state.upgradeRecommendation.version})} + {_t("Upgrade this room to the recommended room version")}
    ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d450e92d71..a49fc485fe 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -586,7 +586,8 @@ "Camera": "Camera", "Voice & Video": "Voice & Video", "This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers", - "Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s", + "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.", + "Upgrade this room to the recommended room version": "Upgrade this room to the recommended room version", "Room information": "Room information", "Internal room ID:": "Internal room ID:", "Room version": "Room version", From f6e3437944d781e4cb9bd0d3934568c5c026c281 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 16:00:34 -0600 Subject: [PATCH 030/481] Update text in RoomUpgradeWarningBar to match suggestions --- .../views/rooms/_RoomUpgradeWarningBar.scss | 2 +- .../views/rooms/RoomUpgradeWarningBar.js | 66 +++++++++---------- src/i18n/strings/en_EN.json | 3 +- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/res/css/views/rooms/_RoomUpgradeWarningBar.scss b/res/css/views/rooms/_RoomUpgradeWarningBar.scss index 82785b82d2..fe81d3801a 100644 --- a/res/css/views/rooms/_RoomUpgradeWarningBar.scss +++ b/res/css/views/rooms/_RoomUpgradeWarningBar.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_RoomUpgradeWarningBar { text-align: center; - height: 176px; + height: 235px; background-color: $event-selected-color; align-items: center; flex-direction: column; diff --git a/src/components/views/rooms/RoomUpgradeWarningBar.js b/src/components/views/rooms/RoomUpgradeWarningBar.js index 32969cdd3d..589608dcfa 100644 --- a/src/components/views/rooms/RoomUpgradeWarningBar.js +++ b/src/components/views/rooms/RoomUpgradeWarningBar.js @@ -37,47 +37,43 @@ module.exports = React.createClass({ render: function() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - let upgradeText = ( -
    + return ( +
    +
    + {_t( + "This room is running room version , which this homeserver has " + + "marked as unstable.", + {}, + { + "roomVersion": () => {this.props.room.getVersion()}, + "i": (sub) => {sub}, + }, + )} +
    - {_t("This room is using an unstable room version. If you aren't expecting " + - "this, please upgrade the room.")} +

    + {_t( + "Upgrading this room will shut down the current instance of the room and create " + + "an upgraded room with the same name.", + )} +

    +

    + {_t( + "Warning: Upgrading a room will not automatically migrate room members " + + "to the new version of the room. We'll post a link to the new room in the old " + + "version of the room - room members will have to click this link to join the new room.", + {}, { + "b": (sub) => {sub}, + "i": (sub) => {sub}, + }, + )} +

    - {_t("Click here to upgrade to the latest room version.")} + {_t("Upgrade this room to the recommended room version")}

    -
    - ); - if (this.props.recommendation.urgent) { - upgradeText = ( -
    -
    - {_t("There is a known vulnerability affecting this room.")} -
    -
    - {_t("This room version is vulnerable to malicious modification of room state.")} -
    -

    - - {_t("Click here to upgrade to the latest room version and ensure room integrity " + - "is protected.")} - -

    -
    - ); - } - - return ( -
    - {upgradeText} -
    - {_t( - "Members of the room will be required to click a link to join the " + - "new room. No one will be automatically joined or invited to the new room.", - )} -
    {_t("Only room administrators will see this warning")}
    diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a49fc485fe..976f902f27 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -812,7 +812,8 @@ "Click here to upgrade to the latest room version.": "Click here to upgrade to the latest room version.", "There is a known vulnerability affecting this room.": "There is a known vulnerability affecting this room.", "This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.", - "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Click here to upgrade to the latest room version and ensure room integrity is protected.", + "This room is running room version , which this homeserver has marked as unstable.": "This room is running room version , which this homeserver has marked as unstable.", + "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.", "Only room administrators will see this warning": "Only room administrators will see this warning", "This Room": "This Room", "All Rooms": "All Rooms", From 4777f851f8e282bd4cfa56203e5a44223141bca4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 16:08:48 -0600 Subject: [PATCH 031/481] Update text for /upgraderoom to match suggestions --- src/SlashCommands.js | 73 ++++++++++++++++++++++++++----------- src/i18n/strings/en_EN.json | 17 ++++----- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 11018df081..dc653b45ab 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -112,30 +112,59 @@ export const CommandMap = { title: _t('Room upgrade confirmation'), description: (
    - { _t( - "Upgrading your room in this way can be dangerous or unnecessary. Room upgrades " + - "are usually done to change the server's behaviour in a given room and not so much " + - "anything to do with client (Riot) behaviour.", - ) } -
    -
    - { _t( - "Members of the room will be required to click a link to join the new room. No " + - "one will be automatically joined or invited to the new room.", - ) } -
    -
    - { _t( - "Please confirm that you'd like to go forward with upgrading this room from " + - "%(oldVersion)s to %(newVersion)s", - { - oldVersion: room ? room.getVersion() : "1", - newVersion: args, - }, - ) } +

    {_t("Upgrading a room can be destructive and isn't always necessary.")}

    +

    + {_t( + "Room upgrades are usually recommended when a room version is considered " + + "unstable. Unstable room versions might have bugs, missing features, or " + + "security vulnerabilities.", + {}, { + "i": (sub) => {sub}, + }, + )} +

    +

    + {_t( + "Room upgrades usually only affect server-side processing of the " + + "room. If you're having problems with your Riot client, please file an issue " + + "with .", + {}, { + "i": (sub) => {sub}, + "issueLink": () => { + return + https://github.com/vector-im/riot-web/issues/new/choose + ; + }, + } + )} +

    +

    + {_t( + "Warning: Upgrading a room will not automatically migrate room " + + "members to the new version of the room. We'll post a link to the new room " + + "in the old version of the room - room members will have to click this link to " + + "join the new room.", + {}, { + "b": (sub) => {sub}, + "i": (sub) => {sub}, + }, + )} +

    +

    + {_t( + "Please confirm that you'd like to go forward with upgrading this room " + + "from to ", + {}, + { + oldVersion: () => {room ? room.getVersion() : "1"}, + newVersion: () => {args}, + }, + )} +

    ), - button: _t("Upgrade Room"), + button: _t("Upgrade"), onFinished: (confirm) => { if (!confirm) return; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 976f902f27..ef4bc75d27 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -133,10 +133,12 @@ "To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.", "Upgrades a room to a new version": "Upgrades a room to a new version", "Room upgrade confirmation": "Room upgrade confirmation", - "Upgrading your room in this way can be dangerous or unnecessary. Room upgrades are usually done to change the server's behaviour in a given room and not so much anything to do with client (Riot) behaviour.": "Upgrading your room in this way can be dangerous or unnecessary. Room upgrades are usually done to change the server's behaviour in a given room and not so much anything to do with client (Riot) behaviour.", - "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.": "Members of the room will be required to click a link to join the new room. No one will be automatically joined or invited to the new room.", - "Please confirm that you'd like to go forward with upgrading this room from %(oldVersion)s to %(newVersion)s": "Please confirm that you'd like to go forward with upgrading this room from %(oldVersion)s to %(newVersion)s", - "Upgrade Room": "Upgrade Room", + "Upgrading a room can be destructive and isn't always necessary.": "Upgrading a room can be destructive and isn't always necessary.", + "Room upgrades are usually recommended when a room version is considered unstable. Unstable room versions might have bugs, missing features, or security vulnerabilities.": "Room upgrades are usually recommended when a room version is considered unstable. Unstable room versions might have bugs, missing features, or security vulnerabilities.", + "Room upgrades usually only affect server-side processing of the room. If you're having problems with your Riot client, please file an issue with .": "Room upgrades usually only affect server-side processing of the room. If you're having problems with your Riot client, please file an issue with .", + "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.", + "Please confirm that you'd like to go forward with upgrading this room from to ": "Please confirm that you'd like to go forward with upgrading this room from to ", + "Upgrade": "Upgrade", "Changes your display nickname": "Changes your display nickname", "Changes your display nickname in the current room only": "Changes your display nickname in the current room only", "Changes colour scheme of current room": "Changes colour scheme of current room", @@ -586,7 +588,6 @@ "Camera": "Camera", "Voice & Video": "Voice & Video", "This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers", - "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.", "Upgrade this room to the recommended room version": "Upgrade this room to the recommended room version", "Room information": "Room information", "Internal room ID:": "Internal room ID:", @@ -808,11 +809,7 @@ "Not now": "Not now", "Don't ask me again": "Don't ask me again", "Add a topic": "Add a topic", - "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.", - "Click here to upgrade to the latest room version.": "Click here to upgrade to the latest room version.", - "There is a known vulnerability affecting this room.": "There is a known vulnerability affecting this room.", - "This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.", - "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.", + "This room is running room version , which this homeserver has marked as unstable.": "This room is running room version , which this homeserver has marked as unstable.", "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.", "Only room administrators will see this warning": "Only room administrators will see this warning", "This Room": "This Room", From 7504927ed9303f98cce59cab52330c64ce5053ba Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 16:37:32 -0600 Subject: [PATCH 032/481] Appease the linter --- src/SlashCommands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index dc653b45ab..039ccb928f 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -136,7 +136,7 @@ export const CommandMap = { https://github.com/vector-im/riot-web/issues/new/choose ; }, - } + }, )}

    From 27c9b24cab605c599fba046447b2d4c15697b087 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 16:44:27 -0600 Subject: [PATCH 033/481] Appease more of the linter --- .../views/settings/tabs/room/AdvancedRoomSettingsTab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js index 8c56e17a13..cabc196e40 100644 --- a/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/AdvancedRoomSettingsTab.js @@ -71,8 +71,8 @@ export default class AdvancedRoomSettingsTab extends React.Component {

    {_t( "Warning: Upgrading a room will not automatically migrate room members " + - "to the new version of the room. We'll post a link to the new room in the old version " + - "of the room - room members will have to click this link to join the new room.", + "to the new version of the room. We'll post a link to the new room in the old " + + "version of the room - room members will have to click this link to join the new room.", {}, { "b": (sub) => {sub}, "i": (sub) => {sub}, From f045beafc37ea62c176ccbd7a69c98481b6a352a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 21:33:31 -0600 Subject: [PATCH 034/481] Support whitelisting/blacklisting widgets for OpenID --- res/css/_components.scss | 1 + .../_WidgetOpenIDPermissionsDialog.scss | 28 +++++ src/WidgetMessaging.js | 62 +++++----- .../dialogs/WidgetOpenIDPermissionsDialog.js | 106 ++++++++++++++++++ .../views/elements/LabelledToggleSwitch.js | 20 +++- src/i18n/strings/en_EN.json | 8 +- src/settings/Settings.js | 7 ++ 7 files changed, 199 insertions(+), 33 deletions(-) create mode 100644 res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss create mode 100644 src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 4fb0eed4af..f29e30dcb4 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -70,6 +70,7 @@ @import "./views/dialogs/_ShareDialog.scss"; @import "./views/dialogs/_UnknownDeviceDialog.scss"; @import "./views/dialogs/_UserSettingsDialog.scss"; +@import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss"; @import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss"; @import "./views/dialogs/keybackup/_KeyBackupFailedDialog.scss"; @import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss"; diff --git a/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss b/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss new file mode 100644 index 0000000000..a419c105a9 --- /dev/null +++ b/res/css/views/dialogs/_WidgetOpenIDPermissionsDialog.scss @@ -0,0 +1,28 @@ +/* +Copyright 2019 Travis Ralston + +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. +*/ + +.mx_WidgetOpenIDPermissionsDialog .mx_SettingsFlag { + .mx_ToggleSwitch { + display: inline-block; + vertical-align: middle; + margin-right: 8px; + } + + .mx_SettingsFlag_label { + display: inline-block; + vertical-align: middle; + } +} diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index 17ce9360b7..dba703ffb8 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -26,6 +26,8 @@ import Modal from "./Modal"; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; import {_t} from "./languageHandler"; import MatrixClientPeg from "./MatrixClientPeg"; +import SettingsStore from "./settings/SettingsStore"; +import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog"; if (!global.mxFromWidgetMessaging) { global.mxFromWidgetMessaging = new FromWidgetPostMessageApi(); @@ -123,40 +125,46 @@ export default class WidgetMessaging { this.fromWidget.removeListener("get_openid", this._openIdHandlerRef); } - _onOpenIdRequest(ev, rawEv) { + async _onOpenIdRequest(ev, rawEv) { if (ev.widgetId !== this.widgetId) return; // not interesting + const settings = SettingsStore.getValue("widgetOpenIDPermissions"); + if (settings.blacklist && settings.blacklist.includes(this.widgetId)) { + this.fromWidget.sendResponse(rawEv, {state: "blocked"}); + return; + } + if (settings.whitelist && settings.whitelist.includes(this.widgetId)) { + const responseBody = {state: "allowed"}; + const credentials = await MatrixClientPeg.get().getOpenIdToken(); + Object.assign(responseBody, credentials); + this.fromWidget.sendResponse(rawEv, responseBody); + return; + } + // Confirm that we received the request this.fromWidget.sendResponse(rawEv, {state: "request"}); - // TODO: Support blacklisting widgets - // TODO: Support whitelisting widgets - // Actually ask for permission to send the user's data - Modal.createTrackedDialog("OpenID widget permissions", '', QuestionDialog, { - title: _t("A widget would like to verify your identity"), - description: _t( - "A widget located at %(widgetUrl)s would like to verify your identity. " + - "By allowing this, the widget will be able to verify your user ID, but not " + - "perform actions as you.", { - widgetUrl: this.widgetUrl, + Modal.createTrackedDialog("OpenID widget permissions", '', + WidgetOpenIDPermissionsDialog, { + widgetUrl: this.widgetUrl, + widgetId: this.widgetId, + + onFinished: async (confirm) => { + const responseBody = {success: confirm}; + if (confirm) { + const credentials = await MatrixClientPeg.get().getOpenIdToken(); + Object.assign(responseBody, credentials); + } + this.messageToWidget({ + api: OUTBOUND_API_NAME, + action: "openid_credentials", + data: responseBody, + }).catch((error) => { + console.error("Failed to send OpenID credentials: ", error); + }); }, - ), - button: _t("Allow"), - onFinished: async (confirm) => { - const responseBody = {success: confirm}; - if (confirm) { - const credentials = await MatrixClientPeg.get().getOpenIdToken(); - Object.assign(responseBody, credentials); - } - this.messageToWidget({ - api: OUTBOUND_API_NAME, - action: "openid_credentials", - data: responseBody, - }).catch((error) => { - console.error("Failed to send OpenID credentials: ", error); - }); }, - }); + ); } } diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js new file mode 100644 index 0000000000..bec71e49a3 --- /dev/null +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -0,0 +1,106 @@ +/* +Copyright 2019 Travis Ralston + +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 {Tab, TabbedView} from "../../structures/TabbedView"; +import {_t, _td} from "../../../languageHandler"; +import GeneralUserSettingsTab from "../settings/tabs/user/GeneralUserSettingsTab"; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import LabsUserSettingsTab from "../settings/tabs/user/LabsUserSettingsTab"; +import SecurityUserSettingsTab from "../settings/tabs/user/SecurityUserSettingsTab"; +import NotificationUserSettingsTab from "../settings/tabs/user/NotificationUserSettingsTab"; +import PreferencesUserSettingsTab from "../settings/tabs/user/PreferencesUserSettingsTab"; +import VoiceUserSettingsTab from "../settings/tabs/user/VoiceUserSettingsTab"; +import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab"; +import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab"; +import sdk from "../../../index"; +import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; + +export default class WidgetOpenIDPermissionsDialog extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + widgetUrl: PropTypes.string.isRequired, + widgetId: PropTypes.string.isRequired, + }; + + constructor() { + super(); + + this.state = { + rememberSelection: false, + }; + } + + _onAllow = () => { + this._onPermissionSelection(true); + }; + + _onDeny = () => { + this._onPermissionSelection(false); + }; + + _onPermissionSelection(allowed) { + if (this.state.rememberSelection) { + console.log(`Remembering ${this.props.widgetId} as allowed=${allowed} for OpenID`); + + const currentValues = SettingsStore.getValue("widgetOpenIDPermissions"); + if (!currentValues.whitelist) currentValues.whitelist = []; + if (!currentValues.blacklist) currentValues.blacklist = []; + + (allowed ? currentValues.whitelist : currentValues.blacklist).push(this.props.widgetId); + SettingsStore.setValue("widgetOpenIDPermissions", null, SettingLevel.DEVICE, currentValues); + } + + this.props.onFinished(allowed); + } + + _onRememberSelectionChange = (newVal) => { + this.setState({rememberSelection: newVal}); + }; + + render() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( + +

    +

    + {_t( + "A widget located at %(widgetUrl)s would like to verify your identity. " + + "By allowing this, the widget will be able to verify your user ID, but not " + + "perform actions as you.", { + widgetUrl: this.props.widgetUrl, + }, + )} +

    + +
    + + + ); + } +} diff --git a/src/components/views/elements/LabelledToggleSwitch.js b/src/components/views/elements/LabelledToggleSwitch.js index 292c978e88..0cb9b224cf 100644 --- a/src/components/views/elements/LabelledToggleSwitch.js +++ b/src/components/views/elements/LabelledToggleSwitch.js @@ -31,15 +31,29 @@ export default class LabelledToggleSwitch extends React.Component { // Whether or not to disable the toggle switch disabled: PropTypes.bool, + + // True to put the toggle in front of the label + // Default false. + toggleInFront: PropTypes.bool, }; render() { // This is a minimal version of a SettingsFlag + + let firstPart = {this.props.label}; + let secondPart = ; + + if (this.props.toggleInFront) { + const temp = firstPart; + firstPart = secondPart; + secondPart = temp; + } + return (
    - {this.props.label} - + {firstPart} + {secondPart}
    ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 21ad35a44c..4322d6cf7b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -230,9 +230,6 @@ "%(names)s and %(count)s others are typing …|other": "%(names)s and %(count)s others are typing …", "%(names)s and %(count)s others are typing …|one": "%(names)s and one other is typing …", "%(names)s and %(lastPerson)s are typing …": "%(names)s and %(lastPerson)s are typing …", - "A widget would like to verify your identity": "A widget would like to verify your identity", - "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.": "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.", - "Allow": "Allow", "This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.", "This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.", "Please contact your service administrator to continue using the service.": "Please contact your service administrator to continue using the service.", @@ -927,6 +924,7 @@ "NOTE: Apps are not end-to-end encrypted": "NOTE: Apps are not end-to-end encrypted", "Warning: This widget might use cookies.": "Warning: This widget might use cookies.", "Do you want to load widget from URL:": "Do you want to load widget from URL:", + "Allow": "Allow", "Delete Widget": "Delete Widget", "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?", "Delete widget": "Delete widget", @@ -1176,6 +1174,10 @@ "Room contains unknown devices": "Room contains unknown devices", "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.", "Unknown devices": "Unknown devices", + "A widget would like to verify your identity": "A widget would like to verify your identity", + "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.": "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.", + "Remember my selection for this widget": "Remember my selection for this widget", + "Deny": "Deny", "Unable to load backup status": "Unable to load backup status", "Recovery Key Mismatch": "Recovery Key Mismatch", "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 4fe53633ff..fcf70b4df7 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -340,6 +340,13 @@ export const SETTINGS = { displayName: _td('Show developer tools'), default: false, }, + "widgetOpenIDPermissions": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + default: { + whitelisted: [], + blacklisted: [], + }, + }, "RoomList.orderByImportance": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Order rooms in the room list by most important first instead of most recent'), From b48842e070e089872795c107955eea3b536cc6b8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 21:51:19 -0600 Subject: [PATCH 035/481] Fix imports for linter --- src/WidgetMessaging.js | 2 -- .../views/dialogs/WidgetOpenIDPermissionsDialog.js | 11 +---------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index dba703ffb8..501fc34c7a 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -23,8 +23,6 @@ limitations under the License. import FromWidgetPostMessageApi from './FromWidgetPostMessageApi'; import ToWidgetPostMessageApi from './ToWidgetPostMessageApi'; import Modal from "./Modal"; -import QuestionDialog from "./components/views/dialogs/QuestionDialog"; -import {_t} from "./languageHandler"; import MatrixClientPeg from "./MatrixClientPeg"; import SettingsStore from "./settings/SettingsStore"; import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog"; diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index bec71e49a3..e6e97a3305 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -16,17 +16,8 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {Tab, TabbedView} from "../../structures/TabbedView"; -import {_t, _td} from "../../../languageHandler"; -import GeneralUserSettingsTab from "../settings/tabs/user/GeneralUserSettingsTab"; +import {_t} from "../../../languageHandler"; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; -import LabsUserSettingsTab from "../settings/tabs/user/LabsUserSettingsTab"; -import SecurityUserSettingsTab from "../settings/tabs/user/SecurityUserSettingsTab"; -import NotificationUserSettingsTab from "../settings/tabs/user/NotificationUserSettingsTab"; -import PreferencesUserSettingsTab from "../settings/tabs/user/PreferencesUserSettingsTab"; -import VoiceUserSettingsTab from "../settings/tabs/user/VoiceUserSettingsTab"; -import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab"; -import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab"; import sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; From b68960ad261b299d5cf1b991b196922a81919da9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 15 Mar 2019 22:24:27 -0600 Subject: [PATCH 036/481] Reload widget messaging when widgets reload Fixes a bug for some widgets where they cannot do their startup routine (capabilities negotiation, etc) when someone maximizes the widget. By reloading the widget messaging, we ensure the widget is kept in the loop. --- src/components/views/elements/AppTile.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index fe0141dde0..8ed408ffbe 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -336,9 +336,14 @@ export default class AppTile extends React.Component { * Called when widget iframe has finished loading */ _onLoaded() { - if (!ActiveWidgetStore.getWidgetMessaging(this.props.id)) { - this._setupWidgetMessaging(); + // Destroy the old widget messaging before starting it back up again. Some widgets + // have startup routines that run when they are loaded, so we just need to reinitialize + // the messaging for them. + if (ActiveWidgetStore.getWidgetMessaging(this.props.id)) { + ActiveWidgetStore.delWidgetMessaging(this.props.id); } + this._setupWidgetMessaging(); + ActiveWidgetStore.setRoomId(this.props.id, this.props.room.roomId); this.setState({loading: false}); } From a397f333d7374ecadc16005999509743219af5a6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 16 Mar 2019 16:02:38 -0600 Subject: [PATCH 037/481] Discard old sticker picker when the URL changes Fixes https://github.com/vector-im/riot-web/issues/7547 --- src/components/views/rooms/Stickerpicker.js | 23 ++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 2970a296ba..9d8912954c 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -25,6 +25,7 @@ import dis from '../../../dispatcher'; import AccessibleButton from '../elements/AccessibleButton'; import WidgetUtils from '../../../utils/WidgetUtils'; import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; +import PersistedElement from "../elements/PersistedElement"; const widgetType = 'm.stickerpicker'; @@ -32,6 +33,9 @@ const widgetType = 'm.stickerpicker'; // above it, so it needs a greater z-index than the ContextMenu const STICKERPICKER_Z_INDEX = 5000; +// Key to store the widget's AppTile under in PersistedElement +const PERSISTED_ELEMENT_KEY = "stickerPicker"; + export default class Stickerpicker extends React.Component { constructor(props) { super(props); @@ -126,6 +130,23 @@ export default class Stickerpicker extends React.Component { _updateWidget() { const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets()[0]; + + const currentWidget = this.state.stickerpickerWidget; + let currentUrl = null; + if (currentWidget && currentWidget.content && currentWidget.content.url) { + currentUrl = currentWidget.content.url; + } + + let newUrl = null; + if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) { + newUrl = stickerpickerWidget.content.url; + } + + if (newUrl !== currentUrl) { + // Destroy the existing frame so a new one can be created + PersistedElement.destroyElement(PERSISTED_ELEMENT_KEY); + } + this.setState({ stickerpickerWidget, widgetId: stickerpickerWidget ? stickerpickerWidget.id : null, @@ -211,7 +232,7 @@ export default class Stickerpicker extends React.Component { width: this.popoverWidth, }} > - + Date: Mon, 18 Mar 2019 14:05:56 +0100 Subject: [PATCH 038/481] dont break room directory and search --- src/components/structures/RoomDirectory.js | 1 - src/components/structures/RoomView.js | 1 + src/components/structures/ScrollPanel.js | 13 +++++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index e13eab8eb3..59b4cbe2e6 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -551,7 +551,6 @@ module.exports = React.createClass({ onFillRequest={ this.onFillRequest } stickyBottom={false} startAtBottom={false} - onResize={function() {}} > { scrollpanel_content } ; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index d8b4fbb0f1..ba6b54bdbc 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1799,6 +1799,7 @@ module.exports = React.createClass({
  • { this.getSearchResultTiles() } diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 799c88140e..b4325a173a 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -135,6 +135,9 @@ module.exports = React.createClass({ /* 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, }, getDefaultProps: function() { @@ -149,7 +152,10 @@ module.exports = React.createClass({ componentWillMount: function() { this._pendingFillRequests = {b: null, f: null}; - this.props.resizeNotifier.on("middlePanelResized", this.onResize); + + if (this.props.resizeNotifier) { + this.props.resizeNotifier.on("middlePanelResized", this.onResize); + } this.resetScrollState(); }, @@ -173,7 +179,10 @@ module.exports = React.createClass({ // // (We could use isMounted(), but facebook have deprecated that.) this.unmounted = true; - this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); + + if (this.props.resizeNotifier) { + this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); + } }, onScroll: function(ev) { From 620590bd905ef60ed4e80528ecb7f877d7de3370 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 18 Mar 2019 16:24:56 +0000 Subject: [PATCH 039/481] Update yarn.lock Which wasn't updated at release time --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index d1da66b82b..bca7997c18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4371,10 +4371,10 @@ math-random@^1.0.1: resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== -matrix-js-sdk@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-1.0.1.tgz#783efc501e2521997869cfe8e719134d9e10a45c" - integrity sha512-+ErnXHfkxOoRHUYbY/R+2ZHvPKdPCx/eoYjb2Oy7L9pBqCNllI0WRVsro6oqRJQs0krVP8blyIjWOJynWSw96g== +matrix-js-sdk@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-1.0.2.tgz#482d8d2076c7565cf7354722e96c9971e372182a" + integrity sha512-4WCBJFSoOLelHi7IUAcVxPQF+gTc/i9NUKZ77qwUfcZVED8VKTIyWZnwpeLgocK5gAOJV9fkAyO5mny9SkZaGg== dependencies: another-json "^0.2.0" babel-runtime "^6.26.0" From a5d12a134d49fe32c5f849a4e6bb2e1bc77f9e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Mon, 18 Mar 2019 14:48:25 +0000 Subject: [PATCH 040/481] Translated using Weblate (Slovak) Currently translated at 89.8% (1401 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 9569e436e8..7fe66304ff 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -1644,5 +1644,17 @@ "Send %(eventType)s events": "Poslať udalosti %(eventType)s", "Roles & Permissions": "Role & Povolenia", "Select the roles required to change various parts of the room": "Vyberte role potrebné na zmenu rôznych častí miestnosti", - "Enable encryption?": "Povoliť šifrovanie?" + "Enable encryption?": "Povoliť šifrovanie?", + "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.": "Po povolení šifrovania miestnosti nie je možné šifrovanie zakázať. Správy poslané v šifrovanej miestnosti nie sú viditeľné na servery, prečítať ich môžu len členovia miestnosti. Mnohí Boti, premostenia do iných sietí a integrácie nemusia po zapnutí šifrovania fungovať správne. Dozvedieť sa viac o šifrovaní.", + "To link to this room, please add an alias.": "Ak chcete získať odkaz do tejto miestnosti, musíte pridať alias.", + "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Zmena viditeľnosti histórie sa prejaví len na budúcich správach v tejto miestnosti. Viditeľnosť existujúcich správ ostane bez zmeny.", + "Encryption": "Šifrovanie", + "Once enabled, encryption cannot be disabled.": "Po aktivovaní šifrovanie nie je možné deaktivovať.", + "Encrypted": "Zašifrované", + "Some devices for this user are not trusted": "Niektoré zariadenia tohoto používateľa nie sú dôverihodné", + "Some devices in this encrypted room are not trusted": "Niektoré zariadenia v tejto šifrovanej miestnosti nie sú dôverihodné", + "All devices for this user are trusted": "Všetky zariadenia tohoto používateľa sú dôverihodné", + "All devices in this encrypted room are trusted": "Všetky zariadenia v tejto šifrovanej miestnosti sú dôverihodné", + "Use Key Backup": "Použiť zálohovanie kľúčov", + "Never lose encrypted messages": "Nikdy neprídete o zašifrované správy" } From 9a6dcc3e6321ef060bd3639bd208ef660ef2826f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Mon, 18 Mar 2019 17:40:35 +0000 Subject: [PATCH 041/481] Translated using Weblate (Slovak) Currently translated at 89.8% (1401 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 7fe66304ff..35aed8b445 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -5,11 +5,11 @@ "Call Timeout": "Časový limit hovoru", "The remote side failed to pick up": "Vzdialenej strane sa nepodarilo prijať hovor", "Unable to capture screen": "Nie je možné zachytiť obrazovku", - "Existing Call": "Existujúci hovor", + "Existing Call": "Prebiehajúci hovor", "You are already in a call.": "Už ste súčasťou iného hovoru.", "VoIP is unsupported": "VoIP nie je podporovaný", "You cannot place VoIP calls in this browser.": "Pomocou tohoto webového prehliadača nemôžete uskutočňovať VoIP hovory.", - "You cannot place a call with yourself.": "Nemôžete uskutočniť hovor so samým sebou.", + "You cannot place a call with yourself.": "Nemôžete zavolať samému sebe.", "Conference calls are not supported in this client": "Tento klient nepodporuje konferenčné hovory", "Conference calls are not supported in encrypted rooms": "Konferenčné hovory nie sú podporované v šifrovaných miestnostiach", "Warning!": "Upozornenie!", @@ -57,7 +57,7 @@ "Failed to invite users to %(groupId)s": "Do komunity %(groupId)s sa nepodarilo pozvať používateľov", "Failed to add the following rooms to %(groupId)s:": "Do komunity %(groupId)s sa nepodarilo pridať nasledujúce miestnosti:", "Riot does not have permission to send you notifications - please check your browser settings": "Riot nemá udelené povolenie, aby vám mohol posielať oznámenia - Prosím, skontrolujte nastavenia vašeho prehliadača", - "Riot was not given permission to send notifications - please try again": "Aplikácii Riot neboli udelené oprávnenia potrebné pre posielanie oznámení - prosím, skúste to znovu", + "Riot was not given permission to send notifications - please try again": "Aplikácii Riot nebolo udelené povolenie potrebné pre posielanie oznámení - prosím, skúste to znovu", "Unable to enable Notifications": "Nie je možné povoliť oznámenia", "This email address was not found": "Túto emailovú adresu sa nepodarilo nájsť", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Zdá sa, že vaša emailová adresa nie je priradená k žiadnemu Matrix ID na tomto domovskom serveri.", @@ -82,7 +82,7 @@ "This room is not recognised.": "Nie je možné rozpoznať takúto miestnosť.", "Power level must be positive integer.": "Úroveň moci musí byť kladné celé číslo.", "You are not in this room.": "Nenachádzate sa v tejto miestnosti.", - "You do not have permission to do that in this room.": "V tejto miestnosti nemáte oprávnenie na vykonanie takejto akcie.", + "You do not have permission to do that in this room.": "V tejto miestnosti na toto nemáte udelené povolenie.", "Missing room_id in request": "V požiadavke chýba room_id", "Room %(roomId)s not visible": "Miestnosť %(roomId)s nie je viditeľná", "Missing user_id in request": "V požiadavke chýba user_id", @@ -204,7 +204,7 @@ "Drop file here to upload": "Pretiahnutím sem nahráte súbor", " (unsupported)": " (nepodporované)", "Join as voice or video.": "Pripojte sa ako audio alebo video.", - "Ongoing conference call%(supportedText)s.": "Prebiehajúci%(supportedText)s hovor.", + "Ongoing conference call%(supportedText)s.": "Práve prebieha %(supportedText)s konferenčný hovor.", "%(senderName)s sent an image": "%(senderName)s poslal obrázok", "%(senderName)s sent a video": "%(senderName)s poslal video", "%(senderName)s uploaded a file": "%(senderName)s nahral súbor", @@ -263,7 +263,7 @@ "Video call": "Video hovor", "Upload file": "Nahrať súbor", "Show Text Formatting Toolbar": "Zobraziť lištu formátovania textu", - "You do not have permission to post to this room": "Nemáte udelené právo posielať do tejto miestnosti", + "You do not have permission to post to this room": "Nemáte povolenie posielať do tejto miestnosti", "Turn Markdown on": "Povoliť Markdown", "Turn Markdown off": "Zakázať Markdown", "Hide Text Formatting Toolbar": "Skryť lištu formátovania textu", @@ -382,7 +382,7 @@ "Members only (since they were invited)": "Len členovia (odkedy boli pozvaní)", "Members only (since they joined)": "Len členovia (odkedy vstúpili)", "Room Colour": "Farba miestnosti", - "Permissions": "Oprávnenia", + "Permissions": "Povolenia", "The default role for new room members is": "Predvolený status pre nových členov je", "To send messages, you must be a": "Aby ste mohli posielať správy, musíte byť", "To invite users into the room, you must be a": "Aby ste mohli pozývať používateľov do miestnosti, musíte byť", @@ -714,7 +714,7 @@ "Click to mute video": "Kliknutím stlmíte video", "Click to unmute audio": "Kliknutím zrušíte stlmenie zvuku", "Click to mute audio": "Kliknutím stlmíte zvuk", - "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Pri pokuse načítať konkrétny bod v histórii tejto miestnosti sa vyskytla chyba, nemáte oprávnenie na zobrazenie zodpovedajúcej správy.", + "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Pri pokuse načítať konkrétny bod v histórii tejto miestnosti sa vyskytla chyba, nemáte povolenie na zobrazenie zodpovedajúcej správy.", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Pri pokuse načítať konkrétny bod v histórii tejto miestnosti sa vyskytla chyba, Správu nie je možné nájsť.", "Failed to load timeline position": "Nepodarilo sa načítať pozíciu na časovej osi", "Uploading %(filename)s and %(count)s others|other": "Nahrávanie %(filename)s a %(count)s ďalších súborov", @@ -772,7 +772,7 @@ "Bulk Options": "Hromadné možnosti", "Desktop specific": "Špecifické pre pracovnú plochu", "Start automatically after system login": "Spustiť automaticky po prihlásení do systému", - "No media permissions": "Žiadne oprávnenia k médiám", + "No media permissions": "Nepovolený prístup k médiám", "You may need to manually permit Riot to access your microphone/webcam": "Mali by ste aplikácii Riot ručne udeliť právo pristupovať k mikrofónu a kamere", "Missing Media Permissions, click here to request.": "Kliknutím sem vyžiadate chýbajúce oprávnenia na prístup k mediálnym zariadeniam.", "No Microphones detected": "Neboli rozpoznané žiadne mikrofóny", @@ -1150,7 +1150,7 @@ "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Zatiaľ nie je možné k odpovedi pridať súbor. Súbor teda nebude odoslaný ako odpoveď.", "Unable to reply": "Nie je možné odpovedať", "At this time it is not possible to reply with an emote.": "V odpovedi zatiaľ nie je možné vijadriť pocit.", - "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Nie je možné načítať udalosť odkazovanú v odpovedi. Takáto udalosť buď neexistuje alebo nemáte oprávnenie na jej zobrazenie.", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Nie je možné načítať udalosť odkazovanú v odpovedi. Takáto udalosť buď neexistuje alebo nemáte povolenie na jej zobrazenie.", "Riot bugs are tracked on GitHub: create a GitHub issue.": "Požiadavky projektu Riot sledujeme na Github: vytvoriť github požiadavku.", "Log out and remove encryption keys?": "Odhlásiť sa a odstrániť šifrovacie kľúče?", "Send Logs": "Odoslať záznamy", @@ -1208,8 +1208,8 @@ "You have no historical rooms": "Nemáte žiadne historické miestnosti", "A conference call could not be started because the intgrations server is not available": "Nie je možné uskutočniť konferenčný hovor, integračný server nie je k dispozícii", "A call is currently being placed!": "Práve prebieha iný hovor!", - "Permission Required": "Vyžaduje sa oprávnenie", - "You do not have permission to start a conference call in this room": "V tejto miestnosti nemáte oprávnenie začať konferenčný hovor", + "Permission Required": "Vyžaduje sa povolenie", + "You do not have permission to start a conference call in this room": "V tejto miestnosti nemáte povolenie začať konferenčný hovor", "Show empty room list headings": "Zobrazovať nadpisy prázdnych zoznamov miestností", "This event could not be displayed": "Nie je možné zobraziť túto udalosť", "Demote yourself?": "Znížiť vlastnú úroveň moci?", @@ -1282,7 +1282,7 @@ "Unable to load! Check your network connectivity and try again.": "Nie je možné načítať! Skontrolujte prístup na internet a skúste neskôr.", "Failed to invite users to the room:": "Používateľov sa nepodarilo pozvať do miestnosti:", "Unrecognised address": "Nerozpoznaná adresa", - "You do not have permission to invite people to this room.": "Nemáte pridelené oprávnenie pozývať ľudí do tejto miestnosti.", + "You do not have permission to invite people to this room.": "Nemáte povolenie pozývať ľudí do tejto miestnosti.", "User %(user_id)s does not exist": "Používateľ %(user_id)s neexistuje", "User %(user_id)s may or may not exist": "Nie je možné určiť, či používateľ %(user_id)s existuje", "Unknown server error": "Neznáma chyba servera", @@ -1618,7 +1618,7 @@ "Key backup": "Zálohovanie kľúčov", "Security & Privacy": "Bezpečnosť & Súkromie", "Missing media permissions, click the button below to request.": "Chýbajú povolenia na médiá, vyžiadate klepnutím na tlačidlo nižšie.", - "Request media permissions": "Požiadať povolenia pristupovať k médiám", + "Request media permissions": "Požiadať o povolenia pristupovať k médiám", "Voice & Video": "Hlas & Video", "Room information": "Informácie o miestnosti", "Internal room ID:": "Interné ID miestnosti:", @@ -1633,7 +1633,7 @@ "Change permissions": "Zmeniť povolenia", "Change topic": "Zmeniť tému", "Modify widgets": "Upraviť widgety", - "Default role": "Predvolená úloha", + "Default role": "Predvolená rola", "Send messages": "Odoslať správy", "Invite users": "Pozvať používateľov", "Change settings": "Zmeniť nastavenia", From d6f31bef8ec9aaeebb28e38fd5cb3eb8b7bd9adb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 18 Mar 2019 23:25:11 +0000 Subject: [PATCH 042/481] Disable big emoji for m.emote messages as it looks weird Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/messages/TextualBody.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 1b6c9418a9..404a0f0889 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -431,7 +431,7 @@ module.exports = React.createClass({ const stripReply = ReplyThread.getParentEventId(mxEvent); let body = HtmlUtils.bodyToHtml(content, this.props.highlights, { - disableBigEmoji: !SettingsStore.getValue('TextualBody.enableBigEmoji'), + disableBigEmoji: content.msgtype === "m.emote" || !SettingsStore.getValue('TextualBody.enableBigEmoji'), // Part of Replies fallback support stripReplyFallback: stripReply, }); From cadf36e1c9dede95a23af433206edc03b2d8cc54 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 18 Mar 2019 23:33:24 +0000 Subject: [PATCH 043/481] Don't show calculated room name in room settings name input field Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/room_settings/RoomProfileSettings.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/views/room_settings/RoomProfileSettings.js b/src/components/views/room_settings/RoomProfileSettings.js index 8205ee3f6e..1c36328c00 100644 --- a/src/components/views/room_settings/RoomProfileSettings.js +++ b/src/components/views/room_settings/RoomProfileSettings.js @@ -34,14 +34,20 @@ export default class RoomProfileSettings extends React.Component { const client = MatrixClientPeg.get(); const room = client.getRoom(props.roomId); if (!room) throw new Error("Expected a room for ID: ", props.roomId); + const avatarEvent = room.currentState.getStateEvents("m.room.avatar", ""); let avatarUrl = avatarEvent && avatarEvent.getContent() ? avatarEvent.getContent()["url"] : null; if (avatarUrl) avatarUrl = client.mxcUrlToHttp(avatarUrl, 96, 96, 'crop', false); + const topicEvent = room.currentState.getStateEvents("m.room.topic", ""); const topic = topicEvent && topicEvent.getContent() ? topicEvent.getContent()['topic'] : ''; + + const nameEvent = room.currentState.getStateEvents('m.room.name', ''); + const name = nameEvent && nameEvent.getContent() ? nameEvent.getContent()['name'] : ''; + this.state = { - originalDisplayName: room.name, - displayName: room.name, + originalDisplayName: name, + displayName: name, originalAvatarUrl: avatarUrl, avatarUrl: avatarUrl, avatarFile: null, From 71f6b08b265697a716b0cef3a5b1d9d974e84325 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 19 Mar 2019 13:42:22 +0100 Subject: [PATCH 044/481] first impl of new scrolling, still a bit broken --- res/css/_components.scss | 1 + res/css/structures/_ScrollPanel.scss | 26 +++ src/components/structures/ScrollPanel.js | 283 ++++++++++++----------- 3 files changed, 174 insertions(+), 136 deletions(-) create mode 100644 res/css/structures/_ScrollPanel.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index 4fb0eed4af..69f4730d85 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -19,6 +19,7 @@ @import "./structures/_RoomStatusBar.scss"; @import "./structures/_RoomSubList.scss"; @import "./structures/_RoomView.scss"; +@import "./structures/_ScrollPanel.scss"; @import "./structures/_SearchBox.scss"; @import "./structures/_TabbedView.scss"; @import "./structures/_TagPanel.scss"; diff --git a/res/css/structures/_ScrollPanel.scss b/res/css/structures/_ScrollPanel.scss new file mode 100644 index 0000000000..699224949b --- /dev/null +++ b/res/css/structures/_ScrollPanel.scss @@ -0,0 +1,26 @@ +/* +Copyright 2019 New Vector 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. +*/ + +.mx_ScrollPanel { + + .mx_RoomView_MessageList { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + overflow-y: hidden; + } +} diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index b4325a173a..9d0bfce6cb 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -18,6 +18,7 @@ const React = require("react"); import PropTypes from 'prop-types'; import Promise from 'bluebird'; import { KeyCode } from '../../Keyboard'; +import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; const DEBUG_SCROLL = false; @@ -30,11 +31,14 @@ const UNPAGINATION_PADDING = 6000; // many scroll events causing many unfilling requests. const UNFILL_REQUEST_DEBOUNCE_MS = 200; +const PAGE_SIZE = 200; + +let debuglog; if (DEBUG_SCROLL) { // using bind means that we get to keep useful line numbers in the console - var debuglog = console.log.bind(console); + debuglog = console.log.bind(console, "ScrollPanel debuglog:"); } else { - var debuglog = function() {}; + debuglog = function() {}; } /* This component implements an intelligent scrolling list. @@ -186,56 +190,12 @@ module.exports = React.createClass({ }, onScroll: function(ev) { - const sn = this._getScrollNode(); - debuglog("Scroll event: offset now:", sn.scrollTop, - "_lastSetScroll:", this._lastSetScroll); - - // ignore scroll events where scrollTop hasn't changed, - // appears to happen when the layout changes outside - // of the scroll container, like resizing the right panel. - if (sn.scrollTop === this._lastEventScroll) { - debuglog("ignore scroll event with same scrollTop as before"); - return; - } - - this._lastEventScroll = sn.scrollTop; - - // Sometimes we see attempts to write to scrollTop essentially being - // ignored. (Or rather, it is successfully written, but on the next - // scroll event, it's been reset again). - // - // This was observed on Chrome 47, when scrolling using the trackpad in OS - // X Yosemite. Can't reproduce on El Capitan. Our theory is that this is - // due to Chrome not being able to cope with the scroll offset being reset - // while a two-finger drag is in progress. - // - // By way of a workaround, we detect this situation and just keep - // resetting scrollTop until we see the scroll node have the right - // value. - if (this._lastSetScroll !== undefined && sn.scrollTop < this._lastSetScroll-200) { - console.log("Working around vector-im/vector-web#528"); - this._restoreSavedScrollState(); - return; - } - - // If there weren't enough children to fill the viewport, the scroll we - // got might be different to the scroll we wanted; we don't want to - // forget what we wanted, so don't overwrite the saved state unless - // this appears to be a user-initiated scroll. - if (sn.scrollTop != this._lastSetScroll) { - this._saveScrollState(); - } else { - debuglog("Ignoring scroll echo"); - // only ignore the echo once, otherwise we'll get confused when the - // user scrolls away from, and back to, the autoscroll point. - this._lastSetScroll = undefined; - } - + this._scrollTimeout.restart(); + this._saveScrollState(); this._checkBlockShrinking(); + this.checkFillState(); this.props.onScroll(ev); - - this.checkFillState(); }, onResize: function() { @@ -258,14 +218,7 @@ module.exports = React.createClass({ // whether it will stay that way when the children update. isAtBottom: function() { const sn = this._getScrollNode(); - - // there seems to be some bug with flexbox/gemini/chrome/richvdh's - // understanding of the box model, wherein the scrollNode ends up 2 - // pixels higher than the available space, even when there are less - // than a screenful of messages. + 3 is a fudge factor to pretend - // that we're at the bottom when we're still a few pixels off. - - return sn.scrollHeight - Math.ceil(sn.scrollTop) <= sn.clientHeight + 3; + return sn.scrollTop === sn.scrollHeight - sn.clientHeight; }, // returns the vertical height in the given direction that can be removed from @@ -301,10 +254,15 @@ module.exports = React.createClass({ // `---------' - _getExcessHeight: function(backwards) { const sn = this._getScrollNode(); + const contentHeight = this._getMessagesHeight(); + const listHeight = this._getListHeight(); + const clippedHeight = contentHeight - listHeight; + const unclippedScrollTop = sn.scrollTop + clippedHeight; + if (backwards) { - return sn.scrollTop - sn.clientHeight - UNPAGINATION_PADDING; + return unclippedScrollTop - sn.clientHeight - UNPAGINATION_PADDING; } else { - return sn.scrollHeight - (sn.scrollTop + 2*sn.clientHeight) - UNPAGINATION_PADDING; + return contentHeight - (unclippedScrollTop + 2*sn.clientHeight) - UNPAGINATION_PADDING; } }, @@ -356,6 +314,9 @@ module.exports = React.createClass({ if (excessHeight <= 0) { return; } + + const origExcessHeight = excessHeight; + const tiles = this.refs.itemlist.children; // The scroll token of the first/last tile to be unpaginated @@ -367,8 +328,9 @@ module.exports = React.createClass({ // pagination. // // If backwards is true, we unpaginate (remove) tiles from the back (top). + let tile; for (let i = 0; i < tiles.length; i++) { - const tile = tiles[backwards ? i : tiles.length - 1 - i]; + tile = tiles[backwards ? i : tiles.length - 1 - i]; // Subtract height of tile as if it were unpaginated excessHeight -= tile.clientHeight; //If removing the tile would lead to future pagination, break before setting scroll token @@ -380,6 +342,7 @@ module.exports = React.createClass({ markerScrollToken = tile.dataset.scrollTokens.split(',')[0]; } } + debuglog("unfilling now", backwards, origExcessHeight, Array.prototype.indexOf.call(tiles, tile)); if (markerScrollToken) { // Use a debouncer to prevent multiple unfill calls in quick succession @@ -439,7 +402,7 @@ module.exports = React.createClass({ * false, the first token in data-scroll-tokens of the child which we are * tracking. * - * number pixelOffset: undefined if stuckAtBottom is true; if it is false, + * number bottomOffset: undefined if stuckAtBottom is true; if it is false, * the number of pixels the bottom of the tracked child is above the * bottom of the scroll panel. */ @@ -460,14 +423,20 @@ module.exports = React.createClass({ * child list.) */ resetScrollState: function() { - this.scrollState = {stuckAtBottom: this.props.startAtBottom}; + this.scrollState = { + stuckAtBottom: this.props.startAtBottom, + }; + this._bottomGrowth = 0; + this._pages = 0; + this._scrollTimeout = new Timer(100); + this._heightUpdateInProgress = false; }, /** * jump to the top of the content. */ scrollToTop: function() { - this._setScrollTop(0); + this._getScrollNode().scrollTop = 0; this._saveScrollState(); }, @@ -479,24 +448,26 @@ module.exports = React.createClass({ // 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 // happening, since there may be no user-visible change here). - this._setScrollTop(Number.MAX_VALUE); + const sn = this._getScrollNode(); + sn.scrollTop = sn.scrollHeight; this._saveScrollState(); }, /** * Page up/down. * - * mult: -1 to page up, +1 to page down + * @param {number} mult: -1 to page up, +1 to page down */ scrollRelative: function(mult) { const scrollNode = this._getScrollNode(); const delta = mult * scrollNode.clientHeight * 0.5; - this._setScrollTop(scrollNode.scrollTop + delta); + scrollNode.scrollTop = scrollNode.scrollTop + delta; this._saveScrollState(); }, /** * Scroll up/down in response to a scroll key + * @param {object} ev the keyboard event */ handleScrollKey: function(ev) { switch (ev.keyCode) { @@ -529,21 +500,21 @@ module.exports = React.createClass({ /* Scroll the panel to bring the DOM node with the scroll token * `scrollToken` into view. * - * offsetBase gives the reference point for the pixelOffset. 0 means the + * offsetBase gives the reference point for the bottomOffset. 0 means the * top of the container, 1 means the bottom, and fractional values mean * somewhere in the middle. If omitted, it defaults to 0. * - * pixelOffset gives the number of pixels *above* the offsetBase that the + * bottomOffset gives the number of pixels *above* the offsetBase that the * node (specifically, the bottom of it) will be positioned. If omitted, it * defaults to 0. */ - scrollToToken: function(scrollToken, pixelOffset, offsetBase) { - pixelOffset = pixelOffset || 0; + scrollToToken: function(scrollToken, bottomOffset, offsetBase) { + bottomOffset = bottomOffset || 0; offsetBase = offsetBase || 0; - // convert pixelOffset so that it is based on the bottom of the + // convert bottomOffset so that it is based on the bottom of the // container. - pixelOffset += this._getScrollNode().clientHeight * (1-offsetBase); + bottomOffset += this._getScrollNode().clientHeight * (1-offsetBase); // save the desired scroll state. It's important we do this here rather // than as a result of the scroll event, because (a) we might not *get* @@ -554,50 +525,13 @@ module.exports = React.createClass({ this.scrollState = { stuckAtBottom: false, trackedScrollToken: scrollToken, - pixelOffset: pixelOffset, + bottomOffset: bottomOffset, }; // ... then make it so. this._restoreSavedScrollState(); }, - // set the scrollTop attribute appropriately to position the given child at the - // given offset in the window. A helper for _restoreSavedScrollState. - _scrollToToken: function(scrollToken, pixelOffset) { - /* find the dom node with the right scrolltoken */ - let node; - const messages = this.refs.itemlist.children; - for (let i = messages.length-1; i >= 0; --i) { - const m = messages[i]; - // 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens - // There might only be one scroll token - if (m.dataset.scrollTokens && - m.dataset.scrollTokens.split(',').indexOf(scrollToken) !== -1) { - node = m; - break; - } - } - - if (!node) { - debuglog("ScrollPanel: No node with scrollToken '"+scrollToken+"'"); - return; - } - - const scrollNode = this._getScrollNode(); - const scrollTop = scrollNode.scrollTop; - const viewportBottom = scrollTop + scrollNode.clientHeight; - const nodeBottom = node.offsetTop + node.clientHeight; - const intendedViewportBottom = nodeBottom + pixelOffset; - const scrollDelta = intendedViewportBottom - viewportBottom; - - debuglog("ScrollPanel: scrolling to token '" + scrollToken + "'+" + - pixelOffset + " (delta: "+scrollDelta+")"); - - if (scrollDelta !== 0) { - this._setScrollTop(scrollTop + scrollDelta); - } - }, - _saveScrollState: function() { if (this.props.stickyBottom && this.isAtBottom()) { this.scrollState = { stuckAtBottom: true }; @@ -606,12 +540,13 @@ module.exports = React.createClass({ } const scrollNode = this._getScrollNode(); - const viewportBottom = scrollNode.scrollTop + scrollNode.clientHeight; + const viewportBottom = scrollNode.scrollHeight - (scrollNode.scrollTop + scrollNode.clientHeight); const itemlist = this.refs.itemlist; const messages = itemlist.children; let node = null; + // TODO: do a binary search here, as items are sorted by offsetTop // loop backwards, from bottom-most message (as that is the most common case) for (let i = messages.length-1; i >= 0; --i) { if (!messages[i].dataset.scrollTokens) { @@ -631,12 +566,12 @@ module.exports = React.createClass({ return; } - const nodeBottom = node.offsetTop + node.clientHeight; - debuglog("ScrollPanel: saved scroll state", this.scrollState); + debuglog("ScrollPanel: replacing scroll state"); this.scrollState = { stuckAtBottom: false, + trackedNode: node, trackedScrollToken: node.dataset.scrollTokens.split(',')[0], - pixelOffset: viewportBottom - nodeBottom, + bottomOffset: this._topFromBottom(node), }; }, @@ -644,35 +579,111 @@ module.exports = React.createClass({ const scrollState = this.scrollState; if (scrollState.stuckAtBottom) { - this._setScrollTop(Number.MAX_VALUE); + const sn = this._getScrollNode(); + sn.scrollTop = sn.scrollHeight; } else if (scrollState.trackedScrollToken) { - this._scrollToToken(scrollState.trackedScrollToken, - scrollState.pixelOffset); + const itemlist = this.refs.itemlist; + const trackedNode = this._getTrackedNode(); + if (trackedNode) { + const newBottomOffset = this._topFromBottom(trackedNode); + const bottomDiff = newBottomOffset - scrollState.bottomOffset; + this._bottomGrowth += bottomDiff; + scrollState.bottomOffset = newBottomOffset; + itemlist.style.height = `${this._getListHeight()}px`; + debuglog("ScrollPanel: balancing height because messages below viewport grew by "+bottomDiff+"px"); + } + } + // TODO: also call _updateHeight if not already in progress + if (!this._heightUpdateInProgress) { + const heightDiff = this._getMessagesHeight() - this._getListHeight(); + if (heightDiff > 0) { + this._updateHeight(); + } + } + }, + // need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content? + async _updateHeight() { + if (this._heightUpdateInProgress) { + return; + } + this._heightUpdateInProgress = true; + try { + // wait until user has stopped scrolling + if (this._scrollTimeout.isRunning()) { + await this._scrollTimeout.finished(); + } + + const sn = this._getScrollNode(); + const itemlist = this.refs.itemlist; + const contentHeight = this._getMessagesHeight(); + const minHeight = sn.clientHeight; + const height = Math.max(minHeight, contentHeight); + this._pages = Math.ceil(height / PAGE_SIZE); + this._bottomGrowth = 0; + const newHeight = this._getListHeight(); + + if (this.scrollState.stuckAtBottom) { + itemlist.style.height = `${newHeight}px`; + sn.scrollTop = sn.scrollHeight; + debuglog("updateHeight to", newHeight); + } else { + const trackedNode = this._getTrackedNode(); + const oldTop = trackedNode.offsetTop; + itemlist.style.height = `${newHeight}px`; + const newTop = trackedNode.offsetTop; + const topDiff = newTop - oldTop; + sn.scrollTop = sn.scrollTop + topDiff; + debuglog("updateHeight to", newHeight, topDiff); + } + } finally { + this._heightUpdateInProgress = false; } }, - _setScrollTop: function(scrollTop) { - const scrollNode = this._getScrollNode(); + _getTrackedNode() { + const scrollState = this.scrollState; + const trackedNode = scrollState.trackedNode; - const prevScroll = scrollNode.scrollTop; + if (!trackedNode || !trackedNode.parentElement) { + let node; + const messages = this.refs.itemlist.children; + const scrollToken = scrollState.trackedScrollToken; - // FF ignores attempts to set scrollTop to very large numbers - scrollNode.scrollTop = Math.min(scrollTop, scrollNode.scrollHeight); - - // If this change generates a scroll event, we should not update the - // saved scroll state on it. See the comments in onScroll. - // - // If we *don't* expect a scroll event, we need to leave _lastSetScroll - // alone, otherwise we'll end up ignoring a future scroll event which is - // nothing to do with this change. - - if (scrollNode.scrollTop != prevScroll) { - this._lastSetScroll = scrollNode.scrollTop; + for (let i = messages.length-1; i >= 0; --i) { + const m = messages[i]; + // 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens + // There might only be one scroll token + if (m.dataset.scrollTokens && + m.dataset.scrollTokens.split(',').indexOf(scrollToken) !== -1) { + node = m; + break; + } + } + debuglog("had to find tracked node again for " + scrollState.trackedScrollToken); + scrollState.trackedNode = node; } - debuglog("ScrollPanel: set scrollTop:", scrollNode.scrollTop, - "requested:", scrollTop, - "_lastSetScroll:", this._lastSetScroll); + if (!scrollState.trackedNode) { + debuglog("ScrollPanel: No node with ; '"+scrollState.trackedScrollToken+"'"); + return; + } + + return scrollState.trackedNode; + }, + + _getListHeight() { + return this._bottomGrowth + (this._pages * PAGE_SIZE); + }, + + _getMessagesHeight() { + const itemlist = this.refs.itemlist; + const lastNode = itemlist.lastElementChild; + // 18 is itemlist padding + return (lastNode.offsetTop + lastNode.clientHeight) - itemlist.firstElementChild.offsetTop + (18 * 2); + }, + + _topFromBottom(node) { + return this.refs.itemlist.clientHeight - node.offsetTop; }, /* get the DOM node which has the scrollTop property we care about for our @@ -742,7 +753,7 @@ module.exports = React.createClass({ // it's not obvious why we have a separate div and ol anyway. return ( + className={`mx_ScrollPanel ${this.props.className}`} style={this.props.style}>
      { this.props.children } From 469511aa4433d41aa8895f91db9a90babb98bd89 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 19 Mar 2019 16:50:55 +0100 Subject: [PATCH 045/481] correctly calculate last node in viewport these variables are now relative to bottom of timeline, before it was the top --- src/components/structures/ScrollPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 9d0bfce6cb..5ddc0e0028 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -555,7 +555,7 @@ module.exports = React.createClass({ node = messages[i]; // break at the first message (coming from the bottom) // that has it's offsetTop above the bottom of the viewport. - if (node.offsetTop < viewportBottom) { + if (this._topFromBottom(node) > viewportBottom) { // Use this node as the scrollToken break; } From 2bcced72ad0bc91b429d25bde5639f7ab501b0a9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 19 Mar 2019 16:51:39 +0100 Subject: [PATCH 046/481] take (potentially clipped) content height into account for filling --- src/components/structures/ScrollPanel.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 5ddc0e0028..601caf78d6 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -298,11 +298,14 @@ module.exports = React.createClass({ // `---------' - // - if (sn.scrollTop < sn.clientHeight) { + const contentHeight = this._getMessagesHeight(); + const contentTop = contentHeight - this._getListHeight(); + const contentScrollTop = sn.scrollTop + contentTop; + if (contentScrollTop < sn.clientHeight) { // need to back-fill this._maybeFill(true); } - if (sn.scrollTop > sn.scrollHeight - sn.clientHeight * 2) { + if (contentScrollTop > contentHeight - sn.clientHeight * 2) { // need to forward-fill this._maybeFill(false); } From 02569fca4bd71a245d427042db55befa1f49bf02 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 19 Mar 2019 16:19:56 +0000 Subject: [PATCH 047/481] Support CI for matching branches on forks Currently, people with push access to the main Riot repos can push matching branch names to Riot and the SDKs, and CI will test all the branches together. This change allows contributors to access the same ability when submitting several matching PRs from their fork of each repo. Part of https://github.com/vector-im/riot-web/issues/9041 --- scripts/fetchdep.sh | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 6fb50e7cea..1f9695778b 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -1,28 +1,40 @@ -#!/bin/sh +#!/bin/bash -org="$1" -repo="$2" +set -x + +deforg="$1" +defrepo="$2" defbranch="$3" [ -z "$defbranch" ] && defbranch="develop" -rm -r "$repo" || true +rm -r "$defrepo" || true clone() { - branch=$1 + org=$1 + repo=$2 + branch=$3 if [ -n "$branch" ] then - echo "Trying to use the branch $branch" + echo "Trying to use $org/$repo#$branch" git clone https://github.com/$org/$repo.git $repo --branch "$branch" && exit 0 fi } - # Try the PR author's branch in case it exists on the deps as well. -clone $BUILDKITE_BRANCH +# If BUILDKITE_BRANCH is set, it will contain either: +# * "branch" when the author's branch and target branch are in the same repo +# * "author:branch" when the author's branch is in their fork +# We can split on `:` into an array to check. +BUILDKITE_BRANCH_ARRAY=(${BUILDKITE_BRANCH//:/ }) +if [[ "${#BUILDKITE_BRANCH_ARRAY[@]}" == "1" ]]; then + clone $deforg $defrepo $BUILDKITE_BRANCH +elif [[ "${#BUILDKITE_BRANCH_ARRAY[@]}" == "2" ]]; then + clone ${BUILDKITE_BRANCH_ARRAY[0]} $defrepo ${BUILDKITE_BRANCH_ARRAY[1]} +fi # Try the target branch of the push or PR. -clone $BUILDKITE_PULL_REQUEST_BASE_BRANCH +clone $deforg $defrepo $BUILDKITE_PULL_REQUEST_BASE_BRANCH # Try the current branch from Jenkins. -clone `"echo $GIT_BRANCH" | sed -e 's/^origin\///'` +clone $deforg $defrepo `"echo $GIT_BRANCH" | sed -e 's/^origin\///'` # Use the default branch as the last resort. -clone $defbranch +clone $deforg $defrepo $defbranch From 88f039fe44c175c4970690e21b313524bd64ddc4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 19 Mar 2019 16:53:23 +0100 Subject: [PATCH 048/481] keep track of current updateHeight request outside of method it's only called from one place --- src/components/structures/ScrollPanel.js | 66 +++++++++++------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 601caf78d6..1cc78655cb 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -578,7 +578,7 @@ module.exports = React.createClass({ }; }, - _restoreSavedScrollState: function() { + _restoreSavedScrollState: async function() { const scrollState = this.scrollState; if (scrollState.stuckAtBottom) { @@ -598,48 +598,44 @@ module.exports = React.createClass({ } // TODO: also call _updateHeight if not already in progress if (!this._heightUpdateInProgress) { - const heightDiff = this._getMessagesHeight() - this._getListHeight(); - if (heightDiff > 0) { - this._updateHeight(); + this._heightUpdateInProgress = true; + try { + await this._updateHeight(); + } finally { + this._heightUpdateInProgress = false; } } }, // need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content? async _updateHeight() { - if (this._heightUpdateInProgress) { - return; + const startTs = Date.now(); + // wait until user has stopped scrolling + if (this._scrollTimeout.isRunning()) { + debuglog("xxx updateHeight waiting for scrolling to end ... "); + await this._scrollTimeout.finished(); } - this._heightUpdateInProgress = true; - try { - // wait until user has stopped scrolling - if (this._scrollTimeout.isRunning()) { - await this._scrollTimeout.finished(); - } - const sn = this._getScrollNode(); - const itemlist = this.refs.itemlist; - const contentHeight = this._getMessagesHeight(); - const minHeight = sn.clientHeight; - const height = Math.max(minHeight, contentHeight); - this._pages = Math.ceil(height / PAGE_SIZE); - this._bottomGrowth = 0; - const newHeight = this._getListHeight(); + const sn = this._getScrollNode(); + const itemlist = this.refs.itemlist; + const contentHeight = this._getMessagesHeight(); + const minHeight = sn.clientHeight; + const height = Math.max(minHeight, contentHeight); + this._pages = Math.ceil(height / PAGE_SIZE); + this._bottomGrowth = 0; + const newHeight = this._getListHeight(); - if (this.scrollState.stuckAtBottom) { - itemlist.style.height = `${newHeight}px`; - sn.scrollTop = sn.scrollHeight; - debuglog("updateHeight to", newHeight); - } else { - const trackedNode = this._getTrackedNode(); - const oldTop = trackedNode.offsetTop; - itemlist.style.height = `${newHeight}px`; - const newTop = trackedNode.offsetTop; - const topDiff = newTop - oldTop; - sn.scrollTop = sn.scrollTop + topDiff; - debuglog("updateHeight to", newHeight, topDiff); - } - } finally { - this._heightUpdateInProgress = false; + if (this.scrollState.stuckAtBottom) { + itemlist.style.height = `${newHeight}px`; + sn.scrollTop = sn.scrollHeight; + debuglog("xxx updateHeight to", newHeight); + } else { + const trackedNode = this._getTrackedNode(); + const oldTop = trackedNode.offsetTop; + itemlist.style.height = `${newHeight}px`; + const newTop = trackedNode.offsetTop; + const topDiff = newTop - oldTop; + sn.scrollTop = sn.scrollTop + topDiff; + debuglog("xxx updateHeight to", newHeight, topDiff, Date.now() - startTs); } }, From c306181fcd7f008ffcfd95523a2a0e0cf7dce355 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 11:00:27 +0100 Subject: [PATCH 049/481] take into account that node might not be in DOM while updating height --- src/components/structures/ScrollPanel.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 1cc78655cb..1867a5abb0 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -624,18 +624,25 @@ module.exports = React.createClass({ this._bottomGrowth = 0; const newHeight = this._getListHeight(); - if (this.scrollState.stuckAtBottom) { + const scrollState = this.scrollState; + if (scrollState.stuckAtBottom) { itemlist.style.height = `${newHeight}px`; sn.scrollTop = sn.scrollHeight; debuglog("xxx updateHeight to", newHeight); - } else { + } else if (scrollState.trackedScrollToken) { const trackedNode = this._getTrackedNode(); - const oldTop = trackedNode.offsetTop; - itemlist.style.height = `${newHeight}px`; - const newTop = trackedNode.offsetTop; - const topDiff = newTop - oldTop; - sn.scrollTop = sn.scrollTop + topDiff; - debuglog("xxx updateHeight to", newHeight, topDiff, Date.now() - startTs); + // if the timeline has been reloaded + // this can be called before scrollToBottom or whatever has been called + // so don't do anything of the node has disappeared from + // the currently filled piece of the timeline + if (trackedNode) { + const oldTop = trackedNode.offsetTop; + itemlist.style.height = `${newHeight}px`; + const newTop = trackedNode.offsetTop; + const topDiff = newTop - oldTop; + sn.scrollTop = sn.scrollTop + topDiff; + debuglog("xxx updateHeight to", newHeight, topDiff, Date.now() - startTs); + } } }, From 1e372aad47711332554ac9f7572b1c60f1cc8cbb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 11:10:04 +0100 Subject: [PATCH 050/481] only log when node was found --- src/components/structures/ScrollPanel.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 1867a5abb0..36cf4dc018 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -665,7 +665,9 @@ module.exports = React.createClass({ break; } } - debuglog("had to find tracked node again for " + scrollState.trackedScrollToken); + if (node) { + debuglog("had to find tracked node again for " + scrollState.trackedScrollToken); + } scrollState.trackedNode = node; } From 1a8fe4dd430080427a5386b8c0669f2b5be4c09e Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 20 Mar 2019 10:54:06 +0000 Subject: [PATCH 051/481] Go back to using mainine velocity We moved off to our own fork of velocity many moons ago to fix a memory leak bug when velocity was being barely maintained. They have now merged the bugfix, so go back to mainline. --- package.json | 2 +- src/Velociraptor.js | 2 +- src/VelocityBounce.js | 2 +- src/components/structures/BottomLeftMenu.js | 4 ++-- .../views/dialogs/DeactivateAccountDialog.js | 2 +- yarn.lock | 11 +++++------ 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index ad48555fc7..3144eb7fa6 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "slate-react": "^0.18.10", "text-encoding-utf-8": "^1.0.1", "url": "^0.11.0", - "velocity-vector": "github:vector-im/velocity#059e3b2", + "velocity-animate": "^1.5.2", "whatwg-fetch": "^1.1.1", "zxcvbn": "^4.4.2" }, diff --git a/src/Velociraptor.js b/src/Velociraptor.js index ad51f66ae3..d2cae5c2a7 100644 --- a/src/Velociraptor.js +++ b/src/Velociraptor.js @@ -1,7 +1,7 @@ const React = require('react'); const ReactDom = require('react-dom'); import PropTypes from 'prop-types'; -const Velocity = require('velocity-vector'); +const Velocity = require('velocity-animate'); /** * The Velociraptor contains components and animates transitions with velocity. diff --git a/src/VelocityBounce.js b/src/VelocityBounce.js index b9513249b8..db216f81fb 100644 --- a/src/VelocityBounce.js +++ b/src/VelocityBounce.js @@ -1,4 +1,4 @@ -const Velocity = require('velocity-vector'); +const Velocity = require('velocity-animate'); // courtesy of https://github.com/julianshapiro/velocity/issues/283 // We only use easeOutBounce (easeInBounce is just sort of nonsensical) diff --git a/src/components/structures/BottomLeftMenu.js b/src/components/structures/BottomLeftMenu.js index 2f48bd0299..5f2b954300 100644 --- a/src/components/structures/BottomLeftMenu.js +++ b/src/components/structures/BottomLeftMenu.js @@ -19,8 +19,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; import sdk from '../../index'; import dis from '../../dispatcher'; -import Velocity from 'velocity-vector'; -import 'velocity-vector/velocity.ui'; +import Velocity from 'velocity-animate'; +import 'velocity-animate/velocity.ui'; import SettingsStore from '../../settings/SettingsStore'; const CALLOUT_ANIM_DURATION = 1000; diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js index 6e87a816bb..53cec93d03 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.js +++ b/src/components/views/dialogs/DeactivateAccountDialog.js @@ -21,7 +21,7 @@ import sdk from '../../../index'; import Analytics from '../../../Analytics'; import MatrixClientPeg from '../../../MatrixClientPeg'; import * as Lifecycle from '../../../Lifecycle'; -import Velocity from 'velocity-vector'; +import Velocity from 'velocity-animate'; import { _t } from '../../../languageHandler'; export default class DeactivateAccountDialog extends React.Component { diff --git a/yarn.lock b/yarn.lock index 58e3f6df52..454c0c8a47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3956,7 +3956,7 @@ jest-regex-util@^24.3.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.3.0.tgz#d5a65f60be1ae3e310d5214a0307581995227b36" integrity sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg== -"jquery@>= 1.4.3", jquery@^3.3.1: +jquery@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== @@ -6851,11 +6851,10 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -"velocity-vector@github:vector-im/velocity#059e3b2": - version "1.2.3" - resolved "https://codeload.github.com/vector-im/velocity/tar.gz/059e3b2348f1110888d033974d3109fd5a3af00f" - dependencies: - jquery ">= 1.4.3" +velocity-animate@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/velocity-animate/-/velocity-animate-1.5.2.tgz#5a351d75fca2a92756f5c3867548b873f6c32105" + integrity sha512-m6EXlCAMetKztO1ppBhGU1/1MR3IiEevO6ESq6rcrSQ3Q77xYSW13jkfXW88o4xMrkXJhy/U7j4wFR/twMB0Eg== verror@1.10.0: version "1.10.0" From f164a78eaaebb4987302afd39c13a38f63719518 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:02:53 +0100 Subject: [PATCH 052/481] reimplement typing notif timeline shrinking prevention instead of setting a min-height on the whole timeline, track how much height we need to add to prevent shrinking and set paddingBottom on the container element of the timeline. --- src/components/structures/MessagePanel.js | 31 +++-- src/components/structures/ScrollPanel.js | 111 +++++++++++++----- src/components/structures/TimelinePanel.js | 2 +- src/components/views/rooms/WhoIsTypingTile.js | 21 ++-- 4 files changed, 117 insertions(+), 48 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index fecf5f1ad7..805749b1cd 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -631,12 +631,22 @@ module.exports = React.createClass({ } }, - _onTypingVisible: function() { + _onTypingShown: function() { const scrollPanel = this.refs.scrollPanel; + // this will make the timeline grow, so checkScroll + scrollPanel.checkScroll(); if (scrollPanel && scrollPanel.getScrollState().stuckAtBottom) { - // scroll down if at bottom - scrollPanel.checkScroll(); - scrollPanel.blockShrinking(); + scrollPanel.preventShrinking(); + } + }, + + _onTypingHidden: function() { + const scrollPanel = this.refs.scrollPanel; + if (scrollPanel) { + // as hiding the typing notifications doesn't + // update the scrollPanel, we tell it to apply + // the shrinking prevention once the typing notifs are hidden + scrollPanel.updatePreventShrinking(); } }, @@ -652,15 +662,15 @@ module.exports = React.createClass({ // update the min-height, so once the last // person stops typing, no jumping occurs if (isAtBottom && isTypingVisible) { - scrollPanel.blockShrinking(); + scrollPanel.preventShrinking(); } } }, - clearTimelineHeight: function() { + onTimelineReset: function() { const scrollPanel = this.refs.scrollPanel; if (scrollPanel) { - scrollPanel.clearBlockShrinking(); + scrollPanel.clearPreventShrinking(); } }, @@ -688,7 +698,12 @@ module.exports = React.createClass({ let whoIsTyping; if (this.props.room) { - whoIsTyping = (); + whoIsTyping = ( + ); } return ( diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 36cf4dc018..b1add8235f 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -175,6 +175,7 @@ module.exports = React.createClass({ // // This will also re-check the fill state, in case the paginate was inadequate this.checkScroll(); + this.updatePreventShrinking(); }, componentWillUnmount: function() { @@ -192,22 +193,23 @@ module.exports = React.createClass({ onScroll: function(ev) { this._scrollTimeout.restart(); this._saveScrollState(); - this._checkBlockShrinking(); this.checkFillState(); - + this.updatePreventShrinking(); this.props.onScroll(ev); }, onResize: function() { - this.clearBlockShrinking(); 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() { this._restoreSavedScrollState(); - this._checkBlockShrinking(); this.checkFillState(); }, @@ -718,39 +720,84 @@ module.exports = React.createClass({ }, /** - * Set the current height as the min height for the message list - * so the timeline cannot shrink. This is used to avoid - * jumping when the typing indicator gets replaced by a smaller message. - */ - blockShrinking: function() { + 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() { const messageList = this.refs.itemlist; - if (messageList) { - const currentHeight = messageList.clientHeight; - messageList.style.minHeight = `${currentHeight}px`; + const tiles = messageList && messageList.children; + if (!messageList) { + return; } + let lastTileNode; + for (let i = tiles.length - 1; i >= 0; i--) { + const node = tiles[i]; + if (node.dataset.scrollTokens) { + lastTileNode = node; + break; + } + } + if (!lastTileNode) { + return; + } + this.clearPreventShrinking(); + const offsetFromBottom = messageList.clientHeight - (lastTileNode.offsetTop + lastTileNode.clientHeight); + this.preventShrinkingState = { + offsetFromBottom: offsetFromBottom, + offsetNode: lastTileNode, + }; + debuglog("prevent shrinking, last tile ", offsetFromBottom, "px from bottom"); + }, + + /** Clear shrinking prevention. Used internally, and when the timeline is reloaded. */ + clearPreventShrinking: function() { + const messageList = this.refs.itemlist; + const balanceElement = messageList && messageList.parentElement; + if (balanceElement) balanceElement.style.paddingBottom = null; + this.preventShrinkingState = null; + debuglog("prevent shrinking cleared"); }, /** - * Clear the previously set min height - */ - clearBlockShrinking: function() { - const messageList = this.refs.itemlist; - if (messageList) { - messageList.style.minHeight = null; - } - }, - - _checkBlockShrinking: function() { - const sn = this._getScrollNode(); - const scrollState = this.scrollState; - if (!scrollState.stuckAtBottom) { - const spaceBelowViewport = sn.scrollHeight - (sn.scrollTop + sn.clientHeight); - // only if we've scrolled up 200px from the bottom - // should we clear the min-height used by the typing notifications, - // otherwise we might still see it jump as the whitespace disappears - // when scrolling up from the bottom - if (spaceBelowViewport >= 200) { - this.clearBlockShrinking(); + update the container padding to balance + the bottom offset of the last tile since + preventShrinking was called. + Clears the prevent-shrinking state ones the offset + from the bottom of the marked tile grows larger than + what it was when marking. + */ + updatePreventShrinking: function() { + if (this.preventShrinkingState) { + const sn = this._getScrollNode(); + const scrollState = this.scrollState; + const messageList = this.refs.itemlist; + const {offsetNode, offsetFromBottom} = this.preventShrinkingState; + // element used to set paddingBottom to balance the typing notifs disappearing + const balanceElement = messageList.parentElement; + // if the offsetNode got unmounted, clear + let shouldClear = !offsetNode.parentElement; + // also if 200px from bottom + if (!shouldClear && !scrollState.stuckAtBottom) { + const spaceBelowViewport = sn.scrollHeight - (sn.scrollTop + sn.clientHeight); + shouldClear = spaceBelowViewport >= 200; + } + // try updating if not clearing + if (!shouldClear) { + const currentOffset = messageList.clientHeight - (offsetNode.offsetTop + offsetNode.clientHeight); + const offsetDiff = offsetFromBottom - currentOffset; + if (offsetDiff > 0) { + balanceElement.style.paddingBottom = `${offsetDiff}px`; + if (this.scrollState.stuckAtBottom) { + sn.scrollTop = sn.scrollHeight; + } + debuglog("update prevent shrinking ", offsetDiff, "px from bottom"); + } else if (offsetDiff < 0) { + shouldClear = true; + } + } + if (shouldClear) { + this.clearPreventShrinking(); } } }, diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index c983f904a0..aba7964a15 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -939,7 +939,7 @@ var TimelinePanel = React.createClass({ // clear the timeline min-height when // (re)loading the timeline if (this.refs.messagePanel) { - this.refs.messagePanel.clearTimelineHeight(); + this.refs.messagePanel.onTimelineReset(); } this._reloadEvents(); diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 9dd690f6e5..95cf0717c7 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -29,7 +29,8 @@ module.exports = React.createClass({ propTypes: { // the room this statusbar is representing. room: PropTypes.object.isRequired, - onVisible: PropTypes.func, + onShown: PropTypes.func, + onHidden: PropTypes.func, // Number of names to display in typing indication. E.g. set to 3, will // result in "X, Y, Z and 100 others are typing." whoIsTypingLimit: PropTypes.number, @@ -59,11 +60,13 @@ module.exports = React.createClass({ }, componentDidUpdate: function(_, prevState) { - if (this.props.onVisible && - !prevState.usersTyping.length && - this.state.usersTyping.length - ) { - this.props.onVisible(); + const wasVisible = this._isVisible(prevState); + const isVisible = this._isVisible(this.state); + if (this.props.onShown && !wasVisible && isVisible) { + this.props.onShown(); + } + else if (this.props.onHidden && wasVisible && !isVisible) { + this.props.onHidden(); } }, @@ -77,8 +80,12 @@ module.exports = React.createClass({ Object.values(this.state.delayedStopTypingTimers).forEach((t) => t.abort()); }, + _isVisible: function(state) { + return state.usersTyping.length !== 0 || Object.keys(state.delayedStopTypingTimers).length !== 0; + }, + isVisible: function() { - return this.state.usersTyping.length !== 0 || Object.keys(this.state.delayedStopTypingTimers).length !== 0; + return this._isVisible(this.state); }, onRoomTimeline: function(event, room) { From 460f9a5959312a621b1828f920dabba160c09436 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:10:38 +0100 Subject: [PATCH 053/481] comment typo --- src/components/structures/ScrollPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index b1add8235f..4e17cff320 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -216,7 +216,7 @@ module.exports = React.createClass({ // 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 the content is scrolled down right now, irrespective of + // about whether the content is scrolled down right now, irrespective of // whether it will stay that way when the children update. isAtBottom: function() { const sn = this._getScrollNode(); From a8b149cfbbcf0df35ab0cf7310fcc77af38fdfb9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:12:49 +0100 Subject: [PATCH 054/481] cleanup scrollpanel logging --- src/components/structures/ScrollPanel.js | 30 +++++++++++++----------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 4e17cff320..7d9ac0fb6a 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -22,7 +22,6 @@ import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; const DEBUG_SCROLL = false; -// const DEBUG_SCROLL = true; // The amount of extra scroll distance to allow prior to unfilling. // See _getExcessHeight. @@ -347,7 +346,6 @@ module.exports = React.createClass({ markerScrollToken = tile.dataset.scrollTokens.split(',')[0]; } } - debuglog("unfilling now", backwards, origExcessHeight, Array.prototype.indexOf.call(tiles, tile)); if (markerScrollToken) { // Use a debouncer to prevent multiple unfill calls in quick succession @@ -357,6 +355,7 @@ module.exports = React.createClass({ } this._unfillDebouncer = setTimeout(() => { this._unfillDebouncer = null; + debuglog("unfilling now", backwards, origExcessHeight); this.props.onUnfillRequest(backwards, markerScrollToken); }, UNFILL_REQUEST_DEBOUNCE_MS); } @@ -366,11 +365,11 @@ module.exports = React.createClass({ _maybeFill: function(backwards) { const dir = backwards ? 'b' : 'f'; if (this._pendingFillRequests[dir]) { - debuglog("ScrollPanel: Already a "+dir+" fill in progress - not starting another"); + debuglog("Already a "+dir+" fill in progress - not starting another"); return; } - debuglog("ScrollPanel: starting "+dir+" fill"); + debuglog("starting "+dir+" fill"); // onFillRequest can end up calling us recursively (via onScroll // events) so make sure we set this before firing off the call. @@ -387,7 +386,7 @@ module.exports = React.createClass({ // Unpaginate once filling is complete this._checkUnfillState(!backwards); - debuglog("ScrollPanel: "+dir+" fill complete; hasMoreResults:"+hasMoreResults); + debuglog(""+dir+" fill complete; hasMoreResults:"+hasMoreResults); if (hasMoreResults) { // further pagination requests have been disabled until now, so // it's time to check the fill state again in case the pagination @@ -540,7 +539,7 @@ module.exports = React.createClass({ _saveScrollState: function() { if (this.props.stickyBottom && this.isAtBottom()) { this.scrollState = { stuckAtBottom: true }; - debuglog("ScrollPanel: Saved scroll state", this.scrollState); + debuglog("saved stuckAtBottom state"); return; } @@ -567,11 +566,11 @@ module.exports = React.createClass({ } if (!node) { - debuglog("ScrollPanel: unable to save scroll state: found no children in the viewport"); + debuglog("unable to save scroll state: found no children in the viewport"); return; } - debuglog("ScrollPanel: replacing scroll state"); + debuglog("saving anchored scroll state to message", node && node.innerText); this.scrollState = { stuckAtBottom: false, trackedNode: node, @@ -595,7 +594,7 @@ module.exports = React.createClass({ this._bottomGrowth += bottomDiff; scrollState.bottomOffset = newBottomOffset; itemlist.style.height = `${this._getListHeight()}px`; - debuglog("ScrollPanel: balancing height because messages below viewport grew by "+bottomDiff+"px"); + debuglog("balancing height because messages below viewport grew by "+bottomDiff+"px"); } } // TODO: also call _updateHeight if not already in progress @@ -606,15 +605,18 @@ module.exports = React.createClass({ } finally { this._heightUpdateInProgress = false; } + } 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() { - const startTs = Date.now(); // wait until user has stopped scrolling if (this._scrollTimeout.isRunning()) { - debuglog("xxx updateHeight waiting for scrolling to end ... "); + debuglog("updateHeight waiting for scrolling to end ... "); await this._scrollTimeout.finished(); + } else { + debuglog("updateHeight getting straight to business, no scrolling going on."); } const sn = this._getScrollNode(); @@ -630,7 +632,7 @@ module.exports = React.createClass({ if (scrollState.stuckAtBottom) { itemlist.style.height = `${newHeight}px`; sn.scrollTop = sn.scrollHeight; - debuglog("xxx updateHeight to", newHeight); + debuglog("updateHeight to", newHeight); } else if (scrollState.trackedScrollToken) { const trackedNode = this._getTrackedNode(); // if the timeline has been reloaded @@ -643,7 +645,7 @@ module.exports = React.createClass({ const newTop = trackedNode.offsetTop; const topDiff = newTop - oldTop; sn.scrollTop = sn.scrollTop + topDiff; - debuglog("xxx updateHeight to", newHeight, topDiff, Date.now() - startTs); + debuglog("updateHeight to", newHeight, topDiff); } } }, @@ -674,7 +676,7 @@ module.exports = React.createClass({ } if (!scrollState.trackedNode) { - debuglog("ScrollPanel: No node with ; '"+scrollState.trackedScrollToken+"'"); + debuglog("No node with ; '"+scrollState.trackedScrollToken+"'"); return; } From 9da13fe430eff77ac765c00f091215659c047efd Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:13:09 +0100 Subject: [PATCH 055/481] small cleanup --- src/components/structures/ScrollPanel.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 7d9ac0fb6a..b6dd17e8b6 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -569,7 +569,6 @@ module.exports = React.createClass({ debuglog("unable to save scroll state: found no children in the viewport"); return; } - debuglog("saving anchored scroll state to message", node && node.innerText); this.scrollState = { stuckAtBottom: false, @@ -597,7 +596,6 @@ module.exports = React.createClass({ debuglog("balancing height because messages below viewport grew by "+bottomDiff+"px"); } } - // TODO: also call _updateHeight if not already in progress if (!this._heightUpdateInProgress) { this._heightUpdateInProgress = true; try { From 02a5aa3b1f698d178bb5ee6ebd41abf909d9276b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:15:43 +0100 Subject: [PATCH 056/481] more logging cleanup --- src/components/structures/ScrollPanel.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index b6dd17e8b6..d322a83225 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -569,11 +569,12 @@ module.exports = React.createClass({ debuglog("unable to save scroll state: found no children in the viewport"); return; } - debuglog("saving anchored scroll state to message", node && node.innerText); + const scrollToken = node.dataset.scrollTokens.split(',')[0]; + debuglog("saving anchored scroll state to message", node && node.innerText, scrollToken); this.scrollState = { stuckAtBottom: false, trackedNode: node, - trackedScrollToken: node.dataset.scrollTokens.split(',')[0], + trackedScrollToken: scrollToken, bottomOffset: this._topFromBottom(node), }; }, From 85d305430f92fe6f38298e42feaeefa2b0bebc63 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:37:34 +0100 Subject: [PATCH 057/481] no need for forceUpdate here --- src/components/structures/MessagePanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 805749b1cd..51fee851f3 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -627,7 +627,7 @@ module.exports = React.createClass({ _onHeightChanged: function() { const scrollPanel = this.refs.scrollPanel; if (scrollPanel) { - scrollPanel.forceUpdate(); + scrollPanel.checkScroll(); } }, From 3e13a11372b2194f3ea97689193be8f8d04f9cc5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 20 Mar 2019 17:38:05 +0100 Subject: [PATCH 058/481] restore scroll position after hiding typing notifs with checkScroll --- src/components/structures/MessagePanel.js | 3 +++ src/components/structures/ScrollPanel.js | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 51fee851f3..b57b659136 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -647,6 +647,9 @@ module.exports = React.createClass({ // update the scrollPanel, we tell it to apply // the shrinking prevention once the typing notifs are hidden scrollPanel.updatePreventShrinking(); + // order is important here as checkScroll will scroll down to + // reveal added padding to balance the notifs disappearing. + scrollPanel.checkScroll(); } }, diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index d322a83225..f33fec9d8a 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -789,9 +789,6 @@ module.exports = React.createClass({ const offsetDiff = offsetFromBottom - currentOffset; if (offsetDiff > 0) { balanceElement.style.paddingBottom = `${offsetDiff}px`; - if (this.scrollState.stuckAtBottom) { - sn.scrollTop = sn.scrollHeight; - } debuglog("update prevent shrinking ", offsetDiff, "px from bottom"); } else if (offsetDiff < 0) { shouldClear = true; From 58b2068fbf0cd54fabf3644964ca64ee4862ea00 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 20 Mar 2019 17:43:19 +0000 Subject: [PATCH 059/481] Set velocity's mock option in the unit test --- test/components/structures/MessagePanel-test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 0a51cb8918..38f97dd8f9 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -31,6 +31,8 @@ import Matrix from 'matrix-js-sdk'; const test_utils = require('test-utils'); const mockclock = require('mock-clock'); +import Velocity from 'velocity-animate'; + let client; const room = new Matrix.Room(); @@ -65,9 +67,17 @@ describe('MessagePanel', function() { // HACK: We assume all settings want to be disabled SettingsStore.getValue = sinon.stub().returns(false); + + // This option clobbers the duratrion of all animations to be 1ms + // which makes unit testing a lot simpler (the animation doesn't + // complete without this even if we mock the clock and tick it + // what should be the correct amount of time). + Velocity.mock = true; }); afterEach(function() { + delete Velocity.mock; + clock.uninstall(); sandbox.restore(); }); From 6f79e8503a1923bd225ee93e98157cb650b36237 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 20 Mar 2019 17:57:51 +0000 Subject: [PATCH 060/481] Switch to `git` protocol for CI dependencies If you try to clone a repo that doesn't exist via `https`, `git` will prompt for auth credentials and hang forever. Using `git` avoids this and fails immediately instead, which is what we want for a missing repo. Part of https://github.com/vector-im/riot-web/issues/9221 --- scripts/fetchdep.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 1f9695778b..f82752bfc5 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -17,7 +17,7 @@ clone() { if [ -n "$branch" ] then echo "Trying to use $org/$repo#$branch" - git clone https://github.com/$org/$repo.git $repo --branch "$branch" && exit 0 + git clone git://github.com/$org/$repo.git $repo --branch "$branch" && exit 0 fi } From 99369a54fec25dc5022ead8f1e59f35ce96eecd0 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 20 Mar 2019 18:11:42 +0000 Subject: [PATCH 061/481] Typo Co-Authored-By: dbkr --- test/components/structures/MessagePanel-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 38f97dd8f9..96d898972d 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -68,7 +68,7 @@ describe('MessagePanel', function() { // HACK: We assume all settings want to be disabled SettingsStore.getValue = sinon.stub().returns(false); - // This option clobbers the duratrion of all animations to be 1ms + // This option clobbers the duration of all animations to be 1ms // which makes unit testing a lot simpler (the animation doesn't // complete without this even if we mock the clock and tick it // what should be the correct amount of time). From 8b1e05542d15e01df61c8f9f1b40a84e85d725d6 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 20 Mar 2019 19:10:47 +0000 Subject: [PATCH 062/481] Add log grouping to buildkite --- .buildkite/pipeline.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml index 04b047436b..4fc8254514 100644 --- a/.buildkite/pipeline.yaml +++ b/.buildkite/pipeline.yaml @@ -22,6 +22,7 @@ steps: - label: ":karma: Tests" command: # Install chrome + - "echo '--- Installing Chrome'" - "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -" - "sh -c 'echo \"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google.list'" - "apt-get update" @@ -30,7 +31,9 @@ steps: # TODO: Remove hacky chmod for BuildKite - "chmod +x ./scripts/ci/*.sh" - "chmod +x ./scripts/*" + - "echo '--- Installing Dependencies'" - "./scripts/ci/install-deps.sh" + - "echo '+++ Running Tests'" - "./scripts/ci/unit-tests.sh" env: CHROME_BIN: "/usr/bin/google-chrome-stable" @@ -42,6 +45,7 @@ steps: - label: "🔧 Riot Tests" command: # Install chrome + - "echo '--- Installing Chrome'" - "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -" - "sh -c 'echo \"deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main\" >> /etc/apt/sources.list.d/google.list'" - "apt-get update" @@ -50,7 +54,9 @@ steps: # TODO: Remove hacky chmod for BuildKite - "chmod +x ./scripts/ci/*.sh" - "chmod +x ./scripts/*" + - "echo '--- Installing Dependencies'" - "./scripts/ci/install-deps.sh" + - "echo '+++ Running Tests'" - "./scripts/ci/riot-unit-tests.sh" env: CHROME_BIN: "/usr/bin/google-chrome-stable" From 1ed2e6dcc1def5c3dd8d9684d34d4eaeb733e297 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 20 Mar 2019 15:03:02 -0600 Subject: [PATCH 063/481] Remove the correct widget listener --- src/FromWidgetPostMessageApi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FromWidgetPostMessageApi.js b/src/FromWidgetPostMessageApi.js index 577eabf5ec..4dd3ea6e6d 100644 --- a/src/FromWidgetPostMessageApi.js +++ b/src/FromWidgetPostMessageApi.js @@ -70,8 +70,8 @@ export default class FromWidgetPostMessageApi { removeListener(action, callbackFn) { if (!this.widgetListeners[action]) return; - const idx = this.widgetListeners.indexOf(callbackFn); - if (idx !== -1) this.widgetListeners.splice(idx, 1); + const idx = this.widgetListeners[action].indexOf(callbackFn); + if (idx !== -1) this.widgetListeners[action].splice(idx, 1); } /** From 817fe1a520d90a778d196c34257bcd3d38a24dc2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 21 Mar 2019 11:01:47 +0100 Subject: [PATCH 064/481] disable typing notifs jumping prevention for now --- src/components/structures/ScrollPanel.js | 29 ++---------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index ee4045c91e..b88bd6d98e 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -216,8 +216,6 @@ module.exports = React.createClass({ this._lastSetScroll = undefined; } - this._checkBlockShrinking(); - this.props.onScroll(ev); this.checkFillState(); @@ -234,7 +232,6 @@ module.exports = React.createClass({ // where it ought to be, and set off pagination requests if necessary. checkScroll: function() { this._restoreSavedScrollState(); - this._checkBlockShrinking(); this.checkFillState(); }, @@ -691,36 +688,14 @@ module.exports = React.createClass({ * jumping when the typing indicator gets replaced by a smaller message. */ blockShrinking: function() { - const messageList = this.refs.itemlist; - if (messageList) { - const currentHeight = messageList.clientHeight; - messageList.style.minHeight = `${currentHeight}px`; - } + // Disabled for now because of https://github.com/vector-im/riot-web/issues/9205 }, /** * Clear the previously set min height */ clearBlockShrinking: function() { - const messageList = this.refs.itemlist; - if (messageList) { - messageList.style.minHeight = null; - } - }, - - _checkBlockShrinking: function() { - const sn = this._getScrollNode(); - const scrollState = this.scrollState; - if (!scrollState.stuckAtBottom) { - const spaceBelowViewport = sn.scrollHeight - (sn.scrollTop + sn.clientHeight); - // only if we've scrolled up 200px from the bottom - // should we clear the min-height used by the typing notifications, - // otherwise we might still see it jump as the whitespace disappears - // when scrolling up from the bottom - if (spaceBelowViewport >= 200) { - this.clearBlockShrinking(); - } - } + // Disabled for now because of https://github.com/vector-im/riot-web/issues/9205 }, render: function() { From 3ab205b64d38be88d7e632acfac469c085a68e37 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 21 Mar 2019 11:24:01 +0100 Subject: [PATCH 065/481] Prepare changelog for v1.0.5 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76852d6575..b3313abacc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +Changes in [1.0.5](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.5) (2019-03-21) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.4...v1.0.5) + + * Hotfix: disable typing notifs jumping prevention for now + [\#2811](https://github.com/matrix-org/matrix-react-sdk/pull/2811) + Changes in [1.0.4](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.4) (2019-03-18) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.4-rc.1...v1.0.4) From a483352798c2d3b0b4a48ce548d593658b5aadf4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 21 Mar 2019 11:27:29 +0100 Subject: [PATCH 066/481] v1.0.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee423d80d3..506802e458 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "1.0.4", + "version": "1.0.5", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 680afc5ce0966a121bcdade742560a6562679880 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 21 Mar 2019 15:37:06 +0100 Subject: [PATCH 067/481] fix scrollToToken alignment --- src/components/structures/ScrollPanel.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index f33fec9d8a..c92d74e283 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -518,7 +518,9 @@ module.exports = React.createClass({ // convert bottomOffset so that it is based on the bottom of the // container. - bottomOffset += this._getScrollNode().clientHeight * (1-offsetBase); + const scrollNode = this._getScrollNode(); + const viewportBottom = scrollNode.scrollHeight - (scrollNode.scrollTop + scrollNode.clientHeight); + bottomOffset += viewportBottom + scrollNode.clientHeight * (1-offsetBase); // save the desired scroll state. It's important we do this here rather // than as a result of the scroll event, because (a) we might not *get* From ab49bc4fcf94ce8bebc51bdc5820c6c98431501e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 21 Mar 2019 15:37:35 +0100 Subject: [PATCH 068/481] fix comment typo --- src/components/structures/ScrollPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index c92d74e283..a04e4ef171 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -638,7 +638,7 @@ module.exports = React.createClass({ const trackedNode = this._getTrackedNode(); // if the timeline has been reloaded // this can be called before scrollToBottom or whatever has been called - // so don't do anything of the node has disappeared from + // so don't do anything if the node has disappeared from // the currently filled piece of the timeline if (trackedNode) { const oldTop = trackedNode.offsetTop; From 1c677d35810a8226375f1855b3658a838b5e01a6 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 19 Mar 2019 15:33:28 +0000 Subject: [PATCH 069/481] Change to new consistent name for `MemoryStore` --- src/MatrixClientPeg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 1cf29c3e82..ad20988d9e 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -103,7 +103,7 @@ class MatrixClientPeg { } catch (err) { if (dbType === 'indexeddb') { console.error('Error starting matrixclient store - falling back to memory store', err); - this.matrixClient.store = new Matrix.MatrixInMemoryStore({ + this.matrixClient.store = new Matrix.MemoryStore({ localStorage: global.localStorage, }); } else { From 8a0d6562dc5bcac9afe1dc2723500c442233ebc7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 21 Mar 2019 10:32:22 -0600 Subject: [PATCH 070/481] Use medium agents for the more resource intensive builds --- .buildkite/pipeline.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml index 4fc8254514..6a347ec002 100644 --- a/.buildkite/pipeline.yaml +++ b/.buildkite/pipeline.yaml @@ -20,6 +20,10 @@ steps: # image: "node:10" - label: ":karma: Tests" + agents: + # We use a medium sized instance instead of the normal small ones because + # webpack loves to gorge itself on resources. + queue: "medium" command: # Install chrome - "echo '--- Installing Chrome'" @@ -43,6 +47,10 @@ steps: propagate-environment: true - label: "🔧 Riot Tests" + agents: + # We use a medium sized instance instead of the normal small ones because + # webpack loves to gorge itself on resources. + queue: "medium" command: # Install chrome - "echo '--- Installing Chrome'" From 4bfdbe3094832c5491edf15c1923a5d6c7616d25 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 22 Mar 2019 15:23:21 +0100 Subject: [PATCH 071/481] fix jumping when unfilling the top while scrolling down --- src/components/structures/ScrollPanel.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index a04e4ef171..7f992097bf 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -642,11 +642,17 @@ module.exports = React.createClass({ // the currently filled piece of the timeline if (trackedNode) { const oldTop = trackedNode.offsetTop; + // changing the height might change the scrollTop + // if the new height is smaller than the scrollTop. + // We calculate the diff that needs to be applied + // ourselves, so be sure to measure the + // scrollTop before changing the height. + const preexistingScrollTop = sn.scrollTop; itemlist.style.height = `${newHeight}px`; const newTop = trackedNode.offsetTop; const topDiff = newTop - oldTop; - sn.scrollTop = sn.scrollTop + topDiff; - debuglog("updateHeight to", newHeight, topDiff); + sn.scrollTop = preexistingScrollTop + topDiff; + debuglog("updateHeight to", {newHeight, topDiff, preexistingScrollTop}); } } }, From c9c251924069ef9a641c78856010f2b8ea79c48e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 22 Mar 2019 15:47:04 +0100 Subject: [PATCH 072/481] log scroll events --- src/components/structures/ScrollPanel.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 7f992097bf..f00ff40155 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -190,6 +190,7 @@ module.exports = React.createClass({ }, onScroll: function(ev) { + debuglog("onScroll", this._getScrollNode().scrollTop); this._scrollTimeout.restart(); this._saveScrollState(); this.checkFillState(); From 2ac7dd4ca3da3593cbdedc48981ecb728411418e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 21 Mar 2019 15:02:26 +0000 Subject: [PATCH 073/481] Explicitly create `cryptoStore` in React SDK The React SDK has a client creation path that starts 2 out of 3 stores, but then leaves the other one for the JS SDK's default value handling. We'll soon be adding additional code to check the health of stores, so it would be simpler to follow and think about if we create them all in one place. --- src/utils/createMatrixClient.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/utils/createMatrixClient.js b/src/utils/createMatrixClient.js index 2acd1fae28..040f1e96cb 100644 --- a/src/utils/createMatrixClient.js +++ b/src/utils/createMatrixClient.js @@ -48,10 +48,6 @@ export default function createMatrixClient(opts, useIndexedDb) { useAuthorizationHeader: true, }; - if (localStorage) { - storeOpts.sessionStore = new Matrix.WebStorageSessionStore(localStorage); - } - if (indexedDB && localStorage && useIndexedDb) { storeOpts.store = new Matrix.IndexedDBStore({ indexedDB: indexedDB, @@ -61,6 +57,16 @@ export default function createMatrixClient(opts, useIndexedDb) { }); } + if (localStorage) { + storeOpts.sessionStore = new Matrix.WebStorageSessionStore(localStorage); + } + + if (indexedDB && useIndexedDb) { + storeOpts.cryptoStore = new Matrix.IndexedDBCryptoStore( + indexedDB, "matrix-js-sdk:crypto", + ); + } + opts = Object.assign(storeOpts, opts); return Matrix.createClient(opts); From c17f7a29492ab8a435ef3945ca363f8b4c6e8e18 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 22 Mar 2019 18:50:08 +0000 Subject: [PATCH 074/481] Trim the logging for URL previews It should be sufficient to have the error stack and general log message for URL preview failure. --- src/components/views/rooms/LinkPreviewWidget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index 5f32a6a613..8b6f295080 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -52,7 +52,7 @@ module.exports = React.createClass({ this.props.onHeightChanged, ); }, (error)=>{ - console.error("Failed to get preview for " + this.props.link + " " + error); + console.error("Failed to get URL preview: " + error); }).done(); }, From 50ffdc2f1290b471c91e14442407a2a96532ae4d Mon Sep 17 00:00:00 2001 From: Tee Mak Date: Fri, 22 Mar 2019 14:50:13 -0400 Subject: [PATCH 075/481] Fixed drop shadow for tooltip. The box-shadow color value is from $menu-box-shadow-color. The shadow now looks consistent on light or dark theme. --- res/css/views/elements/_Tooltip.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/elements/_Tooltip.scss b/res/css/views/elements/_Tooltip.scss index 78604b1564..2f35bd338e 100644 --- a/res/css/views/elements/_Tooltip.scss +++ b/res/css/views/elements/_Tooltip.scss @@ -54,7 +54,7 @@ limitations under the License. position: fixed; border: 1px solid $menu-border-color; border-radius: 4px; - box-shadow: 4px 4px 12px 0 rgba(118, 131, 156, 0.6); + box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; background-color: $menu-bg-color; z-index: 2000; padding: 10px; From 50614fa7fb95364247de39ddfc7e6f5bfc14c35f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 22 Mar 2019 14:22:20 -0600 Subject: [PATCH 076/481] Attach an onChange listener to the room's blacklist devices option Fixes https://github.com/vector-im/riot-web/issues/9235 The global option in user settings is unaffected by this bug. Users who have previously set the per-room flag without success can simply refresh the page and the change will be picked up. The bug here is that the current session would not update accordingly, however. Introduced in https://github.com/matrix-org/matrix-react-sdk/pull/2523 --- .../views/settings/tabs/room/SecurityRoomSettingsTab.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js index f4293a60dc..b44d7b019d 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js @@ -197,6 +197,10 @@ export default class SecurityRoomSettingsTab extends React.Component { }); }; + _updateBlacklistDevicesFlag = (checked) => { + MatrixClientPeg.get().getRoom(this.props.roomId).setBlacklistUnverifiedDevices(checked); + }; + _renderRoomAccess() { const client = MatrixClientPeg.get(); const room = client.getRoom(this.props.roomId); @@ -318,6 +322,7 @@ export default class SecurityRoomSettingsTab extends React.Component { let encryptionSettings = null; if (isEncrypted) { encryptionSettings = ; } From 798e68b4ab666938c42578e5d80b94fbfeaf6b06 Mon Sep 17 00:00:00 2001 From: Samu Voutilainen Date: Mon, 18 Mar 2019 13:55:14 +0000 Subject: [PATCH 077/481] Translated using Weblate (Finnish) Currently translated at 95.2% (1485 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fi/ --- src/i18n/strings/fi.json | 74 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index ec22932237..363e04d21f 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -1580,5 +1580,77 @@ "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Varmenna tämä käyttäjä merkitsemällä hänet luotetuksi. Käyttäjiin luottaminen antaa sinulle ylimääräistä mielenrauhaa käyttäessäsi osapuolten välistä salausta.", "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Tämän käyttäjän varmentaminen merkitsee heidän laitteensa luotetuiksi, sekä merkitsee sinun laitteesi luotetuiksi tälle käyttäjälle.", "Waiting for partner to confirm...": "Odotetaan, että toinen osapuoli varmistaa...", - "Incoming Verification Request": "Saapuva varmennuspyyntö" + "Incoming Verification Request": "Saapuva varmennuspyyntö", + "You've previously used Riot 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, Riot needs to resync your account.": "Olet aikaisemmin käytttänyt Riotia laitteella %(host)s, jossa oli jäsenten laiska lataus käytössä. Tässä versiossa laiska lataus on pois käytöstä. Koska paikallinen välimuisti ei ole yhteensopiva näiden kahden asetuksen välillä, Riotin täytyy hakea tunnuksesi tiedot uudelleen.", + "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Jos sinulla on toinen Riotin versio edelleen auki toisessa välilehdessä, suljethan sen, koska Riotin käyttäminen samalla laitteella niin, että laiska lataus on toisessa tabissa käytössä ja toisessa ei, aiheuttaa ongelmia.", + "Incompatible local cache": "Yhteensopimaton paikallinen välimuisti", + "Clear cache and resync": "Tyhjennä välimuisti ja hae tiedot uudelleen", + "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot käyttää nyt 3-5 kertaa vähemmän muistia, koska se lataa tietoa muista käyttäjistä vain tarvittaessa. Odotathan, kun haemme tarvittavat tiedot palvelimelta!", + "I don't want my encrypted messages": "En halua salattuja viestejäni", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Välttääksesi duplikaatin luomista, katsothan olemassaolevat tapahtumat ensin (ja lisää +1, mikäli löydät tapahtuman joka koskee sinuakin) tai luo uusi tapahtuma mikäli et löydä ongelmaasi.", + "Room Settings - %(roomName)s": "Huoneen asetukset — %(roomName)s", + "Clear Storage and Sign Out": "Tyhjennä varasto ja kirjaudu ulos", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Selaimen varaston tyhjentäminen saattaa korjata ongelman, mutta kirjaudut samalla ulos ja estää sinua lukemasta salattuja keskusteluita.", + "A username can only contain lower case letters, numbers and '=_-./'": "Käyttäjätunnus voi sisältää vain pieniä kirjaimia, numeroita ja merkkejä ”=_-./”", + "COPY": "Kopioi", + "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Estät tällä hetkellä varmentamattomia laitteita; jotta voit lähettää viestejä näihin laitteisiin, sinun täytyy varmentaa ne.", + "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "Suosittelemme, että menet varmennusprosessin läpi jokaisella laitteella, varmistaaksesi, että ne kuuluvat oikeille omistajilleen, mutta voit lähettää viestin uudelleen varmentamatta, jos niin haluat.", + "Unable to load backup status": "Varmuuskopioinnin tilan lataaminen epäonnistui", + "Recovery Key Mismatch": "Palautusavaimet eivät täsmää", + "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Varmuuskopiota ei voitu purkaa tällä avaimella. Tarkastathan, että syötit oikean palautusavaimen.", + "Incorrect Recovery Passphrase": "Väärä palautuksen salalause", + "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Varmuuskopiota ei voitu purkaa tällä salalauseella. Tarkastathan, että syötit oikean palautuksen salalauseen.", + "Failed to decrypt %(failedCount)s sessions!": "%(failedCount)s istunnon purkaminen epäonnistui!", + "Restored %(sessionCount)s session keys": "%(sessionCount)s istunnon avainta palautettu", + "Enter Recovery Passphrase": "Syötä palautuksen salalause", + "Warning: you should only set up key backup from a trusted computer.": "Varoitus: sinun pitäisi ottaa avainvarmuuskopio käyttöön vain luotetulta tietokoneelta.", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Pääse käsiksi turvattuun viestihistoriaasi ja ota käyttöön turvallinen viestintä syöttämällä palautuksen salalauseesi.", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Jos olet unohtanut palautuksen salalauseesi, voit käyttää palautusavaintasi tai ottaa käyttöön uuden palautustavan", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Pääse käsiksi turvattuun viestihistoriaasi ja ota käyttöön turvallinen viestintä syöttämällä palautusavaimesi.", + "If you've forgotten your recovery passphrase you can ": "Jos olet unohtanut palautuksen salalauseesi, voit ", + "Share Permalink": "Jaa ikilinkki", + "Collapse Reply Thread": "Supista vastaussäie", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "Voit käyttää mukautettuja palvelinasetuksia kirjautuaksesi toiselle Matrix-palvelimelle. Tämä sallii tämän sovelluksen käytön toisella kotipalvelimella olevalla Matrix-tunnuksella.", + "Please review and accept all of the homeserver's policies": "Tarkistathan tämän kotipalvelimen käytännöt", + "Please review and accept the policies of this homeserver:": "Tarkistathan tämän kotipalvelimen käytännöt:", + "Code": "Koodi", + "Your Modular server": "Modular-palvelimesi", + "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Syötä Modular-kotipalvelimesi sijainti. Se voi käyttää omaa domainiasi tai olla osoitteen modular.im alidomain.", + "The username field must not be blank.": "Käyttäjätunnus ei voi olla tyhjä.", + "Username": "Käyttäjätunnus", + "Sign in to your Matrix account": "Kirjaudu sisään Matrix-tunnukseesi", + "Sign in to your Matrix account on %(serverName)s": "Kirjaudu sisään Matrix-tunnukseesi palvelimella %(serverName)s", + "Change": "Muuta", + "Create your Matrix account": "Luo Matrix-tunnus", + "Create your Matrix account on %(serverName)s": "Luo Matrix-tunnus palvelimelle %(serverName)s", + "Confirm": "Varmista", + "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Käytä sähköpostia tunnuksesi palauttamiseen. Muut käyttäjät voivat kutsua sinut huoneisiin yhteystiedoillasi.", + "Other servers": "Muut palvelimet", + "Enter custom server URLs What does this mean?": "Syötä mukautettujen palvelinten osoitteet. Mitä tämä tarkoittaa?", + "Free": "Vapaa", + "Join millions for free on the largest public server": "Liity ilmaiseksi miljoonien joukkoon suurimmalla julkisella palvelimella", + "Premium": "Premium", + "Premium hosting for organisations Learn more": "Premium-ylläpitoa organisaatioille. Lue lisää", + "Other": "Muut", + "Find other public servers or use a custom server": "Etsi muita julkisia palvelimia tai käytä mukautettua palvelinta", + "Please install Chrome, Firefox, or Safari for the best experience.": "Parhaan käyttökokemuksen saa Chromella, Firefoxilla tai Safarilla.", + "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      Yhteisösivusi HTML

      \n

      \n Käytä pitkää kuvausta tutustuttaaksesi uudet yhteisösi jäsenet, tai jaa \n yhteisölle tärkeitä a href=\"foo\">linkkejä\n

      \n

      \n Voit jopa käyttää ”img”-tageja\n

      \n", + "Unable to join community": "Yhteisöön liittyminen epäonnistui", + "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Olet tämän yhteisön ylläpitäjä. Et voi liittyä uudelleen ilman kutsua toiselta ylläpitäjältä.", + "Unable to leave community": "Yhteisön jättäminen ei onnistunut", + "Want more than a community? Get your own server": "Haluatko enemmän kuin yhteisön? Hanki oma palvelin", + "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "Muutokset, jotka on tehty yhteisösi nimeenja kuvaan eivät välttämättä ole näkyvissä muille käyttäjille 30 minuuttiin.", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Nämä huoneet näytetään yhteisön jäsenille yhteisösivulle. Yhteisön jäsenet voivat liittyä näihin huoneisiin klikkaamalla niitä.", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Epäkelpo asetus: ei voitu toimittaa oletuksena olevaa kotipalvelimen osoitetta ja oletuksena olevaa palvelimen nimeä", + "Can't leave Server Notices room": "Palvelinilmoitushuonetta ei voitu jättää", + "This room is used for important messages from the Homeserver, so you cannot leave it.": "Tämä huone on kotipalvelimen tärkeille viesteille, joten ei voi poistua siitä.", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Jatkaaksesi kotipalvelimen %(homeserverDomain)s päyttöä, sinun täytyy tarkastaa ja hyväksyä käyttöehtomme.", + "Review terms and conditions": "Tarkasta käyttöehdot", + "You are logged in to another account": "Olet kirjautuneena sisään toisella tunnuksella", + "Unknown error discovering homeserver": "Tuntematon virhe kotipalvelimen etsinnässä", + "Did you know: you can use communities to filter your Riot.im experience!": "Tiesitkö: voit käyttää yhteisöjä suodattaaksesi Riot.im-kokemustasi!", + "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.": "Asettaaksesi suodattimen, raahaa yhteisön kuva vasemmalla olevan suodatinpaneelin päälle. Voit klikata suodatinpaneelissa olevaa yhteisön kuvaa, jotta näät vain huoneet ja henkilöt, jotka liittyvät kyseiseen yhteisöön.", + "Failed to get protocol list from homeserver": "Protokollalistan hakeminen kotipalvelimelta epäonnistui", + "The homeserver may be too old to support third party networks": "Tämä kotipalvelin saattaa olla liian vanha tukeakseen kolmannen osapuolen verkkoja", + "Search for a room like #example": "Etsi huoneita tyyliin #esimerkki" } From 36dee9b4dd9d0ddb1637e34c772c6d4e155ccb3e Mon Sep 17 00:00:00 2001 From: Tuomas Hietala Date: Fri, 22 Mar 2019 19:26:56 +0000 Subject: [PATCH 078/481] Translated using Weblate (Finnish) Currently translated at 95.2% (1485 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fi/ --- src/i18n/strings/fi.json | 158 +++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index 363e04d21f..e47b9498d0 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -47,7 +47,7 @@ "%(names)s and %(lastPerson)s are typing": "%(names)s ja %(lastPerson)s kirjoittavat", "A new password must be entered.": "Sinun täytyy syöttää uusi salasana.", "%(senderName)s answered the call.": "%(senderName)s vastasi puheluun.", - "An error has occurred.": "Virhe.", + "An error has occurred.": "Tapahtui virhe.", "Anyone": "Kaikki", "Anyone who knows the room's link, apart from guests": "Kaikki jotka tietävät huoneen osoitteen, paitsi vieraat", "Anyone who knows the room's link, including guests": "Kaikki jotka tietävät huoneen osoitteen, mukaanlukien vieraat", @@ -66,15 +66,15 @@ "%(targetName)s accepted an invitation.": "%(targetName)s hyväksyi kutsun.", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s hyväksyi kutsun käyttäjän %(displayName)s puolesta.", "Account": "Tili", - "and %(count)s others...|other": "ja %(count)s lisää...", - "and %(count)s others...|one": "ja yksi lisää...", + "and %(count)s others...|other": "ja %(count)s muuta...", + "and %(count)s others...|one": "ja yksi muu...", "Ban": "Anna porttikielto", "Banned users": "Porttikiellon saanneet käyttäjät", "Bans user with given id": "Antaa porttikiellon käyttäjälle jolla on annettu tunniste", "Bulk Options": "Bulkkiasetukset", "Changes your display nickname": "Muuttaa näyttönimesi", "Changes colour scheme of current room": "Muuttaa tamänhetkisen huoneen väritystä", - "Clear Cache and Reload": "Puhdista välimuisti ja lataa uudelleen", + "Clear Cache and Reload": "Tyhjennä välimuisti ja lataa uudelleen", "Clear Cache": "Puhdista välimuisti", "Click here to fix": "Paina tästä korjataksesi", "Click to mute audio": "Paina mykistääksesi äänet", @@ -134,7 +134,7 @@ "End-to-end encryption information": "Osapuolten välisen salauksen tiedot", "Enter Code": "Syötä koodi", "Enter passphrase": "Syötä salasana", - "Error decrypting attachment": "Liitteen salauksen purku epäonnistui", + "Error decrypting attachment": "Virhe purettaessa liitteen salausta", "Event information": "Tapahtumatiedot", "Export": "Vie", "Export E2E room keys": "Tallenna osapuolten välisen salauksen huoneavaimet", @@ -184,7 +184,7 @@ "Invalid Email Address": "Virheellinen sähköpostiosoite", "Invite new room members": "Kutsu lisää jäseniä huoneeseen", "Invited": "Kutsuttu", - "Invites": "Kutsuu", + "Invites": "Kutsut", "Invites user with given id to current room": "Kutsuu annetun käyttäjätunnisteen mukaisen käyttäjän huoneeseen", "Sign in with": "Tunnistus", "Join Room": "Liity huoneeseen", @@ -200,10 +200,10 @@ "Logged in as:": "Kirjautunut käyttäjänä:", "Logout": "Kirjaudu ulos", "Low priority": "Alhainen prioriteetti", - "Manage Integrations": "Hallinoi integraatioita", + "Manage Integrations": "Hallinnoi integraatioita", "Markdown is disabled": "Markdown on pois päältä", "Markdown is enabled": "Markdown on päällä", - "matrix-react-sdk version:": "Matrix-react-sdk versio:", + "matrix-react-sdk version:": "Matrix-react-sdk:n versio:", "Message not sent due to unknown devices being present": "Viestiä ei lähetetty koska paikalla on tuntemattomia laitteita", "Mobile phone number": "Puhelinnumero", "Mobile phone number (optional)": "Puhelinnumero (valinnainen)", @@ -225,7 +225,7 @@ "No more results": "Ei enempää tuloksia", "No results": "Ei tuloksia", "OK": "OK", - "olm version:": "olm versio:", + "olm version:": "olmin versio:", "Once encryption is enabled for a room it cannot be turned off again (for now)": "Kun salaus on kytketty päälle sitä ei enää voi kytkeä pois (toistaiseksi)", "Only people who have been invited": "Vain kutsun saanneet käyttäjät", "Password": "Salasana", @@ -246,7 +246,7 @@ "Remove Contact Information?": "Poista yhteystiedot?", "Results from DuckDuckGo": "DuckDuckGo:n tulokset", "Return to login screen": "Palaa kirjautumissivulle", - "riot-web version:": "Riot-web versio:", + "riot-web version:": "Riot-webin versio:", "Room Colour": "Huoneen väri", "Room contains unknown devices": "Huone sisältää tuntemattomia laitteita", "Room name (optional)": "Huoneen nimi (valinnainen)", @@ -296,7 +296,7 @@ "Blacklisted": "Estetyt", "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s muuti huoneen nimeksi %(roomName)s.", "Drop here to tag %(section)s": "Pudota tähän tägätäksesi %(section)s", - "Enable automatic language detection for syntax highlighting": "Ota automaattinen kielentunnistus käyttöön koodin väritystä varten", + "Enable automatic language detection for syntax highlighting": "Ota automaattinen kielentunnistus käyttöön syntaksikorostusta varten", "Encrypted messages will not be visible on clients that do not yet implement encryption": "Salatut viestit eivät näy ohjelmissa joissa salaus ei ole vielä implementoitu", "%(senderName)s ended the call.": "%(senderName)s lopetti puhelun.", "Guest access is disabled on this Home Server.": "Vierailijat on estetty tällä kotipalvelimella.", @@ -313,7 +313,7 @@ "No users have specific privileges in this room": "Kellään käyttäjällä ei ole erityisiä oikeuksia", "%(senderName)s placed a %(callType)s call.": "%(senderName)s soitti %(callType)spuhelun.", "Remove %(threePid)s?": "Poista %(threePid)s?", - "%(senderName)s requested a VoIP conference.": "%(senderName)s pyysi VoIP konferenssia.", + "%(senderName)s requested a VoIP conference.": "%(senderName)s pyysi VoIP-konferenssia.", "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s asetti näyttönimekseen %(displayName)s.", "The file '%(fileName)s' exceeds this home server's size limit for uploads": "Tiedosto ‘%(fileName)s’ ylittää tämän kotipalvelimen maksimitiedostokoon", "The file '%(fileName)s' failed to upload": "Tiedoston ‘%(fileName)s’ lataaminen epäonnistui", @@ -321,8 +321,8 @@ "This invitation was sent to an email address which is not associated with this account:": "Kutsu lähetettiin sähköpostiosoitteeseen jota ei ole liitetty tähän tiliin:", "This room is not recognised.": "Huonetta ei tunnistettu.", "These are experimental features that may break in unexpected ways": "Nämä ovat kokeellisia ominaisuuksia jotka saattavat toimia ennakoimattomilla tavoilla", - "This doesn't appear to be a valid email address": "Olemassa olevan historian näkyvyys ei muutu", - "This is a preview of this room. Room interactions have been disabled": "Tämä on huoneen ennakokatselu. Vuorovaikutus ei ole mahdollista", + "This doesn't appear to be a valid email address": "Tämä ei vaikuta olevan kelvollinen sähköpostiosoite", + "This is a preview of this room. Room interactions have been disabled": "Tämä on huoneen esikatselu. Vuorovaikutus ei ole mahdollista", "This phone number is already in use": "Puhelinnumero on jo käytössä", "To link to a room it must have an address.": "Linkittääksesi tähän huoneseen sillä on oltava osoite.", "Turn Markdown off": "Ota Markdown pois käytöstä", @@ -333,11 +333,11 @@ "Verification": "Varmennus", "verified": "varmennettu", "Verified": "Varmennettu", - "Verified key": "Varmennusavain", + "Verified key": "Varmennettu avain", "Video call": "Videopuhelu", "Voice call": "Äänipuhelu", - "VoIP conference finished.": "VoIP konferenssi loppui.", - "VoIP conference started.": "VoIP konferenssi alkoi.", + "VoIP conference finished.": "VoIP-konferenssi loppui.", + "VoIP conference started.": "VoIP-konferenssi alkoi.", "VoIP is unsupported": "VoIP ei ole tuettu", "(no answer)": "(ei vastausta)", "(unknown failure: %(reason)s)": "(tuntematon virhe: %(reason)s)", @@ -354,7 +354,7 @@ "You do not have permission to do that in this room.": "Sinulla ei ole oikeutta tehdä tuota tässä huoneessa.", "You are trying to access %(roomName)s.": "Yrität liittyä huoneeseen %(roomName)s.", "You cannot place a call with yourself.": "Et voi soittaa itsellesi.", - "You cannot place VoIP calls in this browser.": "Et voi soittaa VoIP puheluita tällä selaimella.", + "You cannot place VoIP calls in this browser.": "Et voi soittaa VoIP-puheluita tällä selaimella.", "You do not have permission to post to this room": "Sinulla ei ole oikeutta kirjoittaa tässä huoneessa", "You have been banned from %(roomName)s by %(userName)s.": "Käyttäjä %(userName)s on antanut sinulle porttikiellon huoneeseen %(roomName)s.", "You have been invited to join this room by %(inviterName)s": "Käyttäjä %(inviterName)s on kutsunut sinut tähän huoneeseen", @@ -366,7 +366,7 @@ "You need to be able to invite users to do that.": "Sinun pitää pystyä kutsua käyttäjiä voidaksesi tehdä tuon.", "You need to be logged in.": "Sinun pitää olla kirjautunut.", "You need to enter a user name.": "Sinun pitää syöttää käyttäjänimi.", - "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Sinun sähköpostiosoitteesi ei vaikuta olevan liitetty mihinkään Matrixtunnisteeseen tällä kotipalvelimella.", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Sähköpostiosoitteesi ei vaikuta olevan liitetty mihinkään Matrix-tunnukseen tällä kotipalvelimella.", "Your password has been reset": "Salasanasi on palautettu", "You should not yet trust it to secure data": "Sinun ei vielä kannata luottaa siihen turvataksesi dataa", "Your home server does not support device management.": "Kotipalvelimesi ei tue laitteiden hallintaa.", @@ -457,7 +457,7 @@ "Publish this room to the public in %(domain)s's room directory?": "Julkaise tämä huone domainin %(domain)s huoneluettelossa?", "Missing room_id in request": "room_id puuttuu kyselystä", "Missing user_id in request": "user_id puuttuu kyselystä", - "Never send encrypted messages to unverified devices from this device": "Älä koskaa lähetä salattuja viestejä varmentamattomiin laitteisiin tältä laitteelta", + "Never send encrypted messages to unverified devices from this device": "Älä koskaan lähetä salattuja viestejä varmentamattomiin laitteisiin tältä laitteelta", "Never send encrypted messages to unverified devices in this room from this device": "Älä koskaa lähetä salattuja viestejä varmentamattomiin laitteisiin tässä huoneessa tältä laitteelta", "New address (e.g. #foo:%(localDomain)s)": "Uusi osoite (esim. #foo:%(localDomain)s)", "Press to start a chat with someone": "Paina ", @@ -467,20 +467,20 @@ "Remote addresses for this room:": "Tämän huoneen etäosoitteet:", "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s poisti näyttönimensä (%(oldDisplayName)s).", "Riot does not have permission to send you notifications - please check your browser settings": "Riotilla ei ole oikeuksia lähettää sinulle ilmoituksia. Ole hyvä ja tarkista selaimen asetukset", - "Riot was not given permission to send notifications - please try again": "Riotilla ei saannut oikeuksia lähettää ilmoituksia. Ole hyvä ja yritä uudelleen", + "Riot was not given permission to send notifications - please try again": "Riot ei saannut lupaa lähettää ilmoituksia. Ole hyvä ja yritä uudelleen", "Room %(roomId)s not visible": "Huone %(roomId)s ei ole näkyvissä", "%(roomName)s does not exist.": "%(roomName)s ei ole olemassa.", "%(roomName)s is not accessible at this time.": "%(roomName)s ei ole saatavilla tällä hetkellä.", "Seen by %(userName)s at %(dateTime)s": "Käyttäjän %(userName)s näkemä %(dateTime)s", "Send Reset Email": "Lähetä salasanan palautusviesti", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s lähetti kuvan.", - "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s lähetti kutsun käyttäjälle %(targetDisplayName)s liittyäkseen huoneeseen.", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s kutsui käyttäjän %(targetDisplayName)s liittymään huoneeseen.", "Server may be unavailable or overloaded": "Palvelin saattaa olla saavuttamattomissa tai ylikuormitettu", "Show Text Formatting Toolbar": "Näytä tekstinmuotoilupalkki", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Näytä aikaleimat 12h muodossa (esim. 2:30pm)", "Signed Out": "Uloskirjautunut", "Start authentication": "Aloita tunnistus", - "Success": "Onnistuminen", + "Success": "Onnistui", "Tagged as: ": "Tägit: ", "The default role for new room members is": "Huoneen uusien jäsenten oletusrooli on", "The main address for this room is": "Tämän huoneen pääosoite on", @@ -510,14 +510,14 @@ "Define the power level of a user": "Määritä käyttäjän oikeustaso", "Failed to change power level": "Oikeustason muuttaminen epäonnistui", "'%(alias)s' is not a valid format for an address": "'%(alias)s' ei ole oikean muotoinen osoitteelle", - "'%(alias)s' is not a valid format for an alias": "'%(alias)s' ei ole oikean muotoinen aliakselle", + "'%(alias)s' is not a valid format for an alias": "'%(alias)s' ei ole kelvollinen muoto aliakselle", "Please check your email and click on the link it contains. Once this is done, click continue.": "Ole hyvä ja tarkista sähköpostisi ja seuraa sen sisältämää linkkiä. Kun olet valmis, paina jatka.", "Power level must be positive integer.": "Oikeustason pitää olla positiivinen kokonaisluku.", "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Salasanan palautus nollaa myös osapuolten välisen salauksen avaimet kaikilla laitteilla. Tällöin vanhojen viestien lukeminen ei ole enää mahdollista, ellet ensin tallenna huoneavaimia ja tuo niitä takaisin jälkeenpäin. Tähän tulee parannusta tulevaisuudessa.", "Server may be unavailable, overloaded, or search timed out :(": "Palvelin saattaa olla saavuttamattomissa, ylikuormitettu tai haku kesti liian kauan :(", "Server may be unavailable, overloaded, or the file too big": "Palvelin saattaa olla saavuttamattomissa, ylikuormitettu, tai tiedosto on liian suuri", "Server may be unavailable, overloaded, or you hit a bug.": "Palvelin saattaa olla saavuttamattomissa, ylikuormitettu tai olet törmännyt virheeseen.", - "Server unavailable, overloaded, or something else went wrong.": "Palvelin on saavuttamattomissa, ylikuormitettu tai jokin muu meni vikaan.", + "Server unavailable, overloaded, or something else went wrong.": "Palvelin on saavuttamattomissa, ylikuormitettu tai jotain muuta meni vikaan.", "The email address linked to your account must be entered.": "Sinun pitää syöttää tiliisi liitetty sähköpostiosoite.", "The visibility of existing history will be unchanged": "Olemassaolevan viestihistorian näkyvyys ei muutu", "To get started, please pick a username!": "Valitse käyttäjänimi aloittaaksesi!", @@ -525,7 +525,7 @@ "To reset your password, enter the email address linked to your account": "Syötä tiliisi liitetty sähköpostiosoite uudelleenalustaaksesi salasanasi", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Aikajanan tietty hetki yritettiin ladata, mutta sinulla ei ole oikeutta nähdä kyseistä viestiä.", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Aikajanan tietty hetki yritettiin ladata, mutta se ei löytynyt.", - "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Ei ole mahdollista varmistaa että sähköposti johon tämä kutsu lähetettiin vastaa sinun tiliisi liittettyä osoitetta.", + "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Ei voida varmistaa että osoite, johon tämä kutsu lähetettiin vastaa tiliisi liittettyä osoitetta.", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (oikeustaso %(powerLevelNumber)s)", "Verification Pending": "Varmennus on vireillä", "(could not connect media)": "(mediaa ei voitu yhdistää)", @@ -534,8 +534,8 @@ "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s veti takaisin käyttäjän %(targetName)s kutsun.", "You're not in any rooms yet! Press to make a room or to browse the directory": "Et ole vielä missään huoneessa! Paina luodaksesi huoneen tai selatakseski hakemistoa", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Sinut on kirjattu ulos kaikista laitteista etkä enää saa Push-ilmoituksia. Jotta saisit jälleen ilmoituksia pitää sinun jälleen kirjautua sisään jokaisella laitteella", - "You may wish to login with a different account, or add this email to this account.": "Haluat ehkä kirjautua toiseen tiliin tai lisätä tämä sähköpostiosoite tähän tiliin.", - "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Salasanan muuttaminen onnistui. Et saa enää push-ilmoituksia muilla laitteilla kunnes olet uudelleen kirjautunut sisään niillä", + "You may wish to login with a different account, or add this email to this account.": "Haluat ehkä kirjautua toiseen tiliin tai lisätä tämän sähköpostiosoitteen tähän tiliin.", + "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Salasanan muuttaminen onnistui. Et saa push-ilmoituksia muilla laitteilla ennen kuin kirjaudut niihin sisään", "You seem to be in a call, are you sure you want to quit?": "Sinulla näyttää olevan puhelu kesken. Haluatko varmasti lopettaa?", "You seem to be uploading files, are you sure you want to quit?": "Näytät lataavan tiedostoja. Oletko varma että haluat lopettaa?", "Jan": "tammikuu", @@ -567,9 +567,9 @@ "Home server URL": "Kotipalvelimen URL", "Identity server URL": "Identiteettipalvelimen URL", "What does this mean?": "Mitä tämä tarkoittaa?", - "Error decrypting audio": "Äänen salauksen purku epäonnistui", - "Error decrypting image": "Kuvan salauksen purku epäonnistui", - "Error decrypting video": "Videon salauksen purku epäonnistui", + "Error decrypting audio": "Virhe purettaessa äänen salausta", + "Error decrypting image": "Virhe purettaessa kuvan salausta", + "Error decrypting video": "Virhe purettaessa videon salausta", "Add an Integration": "Lisää integraatio", "Removed or unknown message type": "Poistettu tai tuntematon viestityyppi", "URL Previews": "URL-esikatselut", @@ -586,7 +586,7 @@ "This will be your account name on the homeserver, or you can pick a different server.": "Tämä on tilisi -kotipalvelimella, tai voit valita toisen palvelimen.", "If you already have a Matrix account you can log in instead.": "Jos sinulla on jo Matrix-tili voit kirjautua.", "Your browser does not support the required cryptography extensions": "Selaimesi ei tue vaadittuja kryptografisia laajennuksia", - "Not a valid Riot keyfile": "Virheellinen Riot avaintiedosto", + "Not a valid Riot keyfile": "Ei kelvollinen Riot-avaintiedosto", "Authentication check failed: incorrect password?": "Autentikointi epäonnistui: virheellinen salasana?", "Do you want to set an email address?": "Haluatko asettaa sähköpostiosoitteen?", "This will allow you to reset your password and receive notifications.": "Tämä sallii sinun uudelleenalustaa salasanasi ja vastaanottaa ilmoituksia.", @@ -604,7 +604,7 @@ "Failed to upload image": "Kuvan lataaminen epäonnistui", "Robot check is currently unavailable on desktop - please use a web browser": "Robottitarkistus ei tällä hetkellä toimi työpöytäversiossa. Ole hyvä ja käytä nettiselainta", "Add a widget": "Lisää sovelma", - "Cannot add any more widgets": "Lisää sovelmia ei voida enää lisätä", + "Cannot add any more widgets": "Enempää sovelmia ei voida lisätä", "Delete widget": "Poista sovelma", "Do you want to load widget from URL:": "Haluatko ladata sovelman URL-osoitteesta:", "The maximum permitted number of widgets have already been added to this room.": "Maksimimäärä sovelmia on jo lisätty tähän huoneeseen.", @@ -621,12 +621,12 @@ "Which rooms would you like to add to this community?": "Mitkä huoneet haluaisit listätä tähän yhteisöön?", "Show these rooms to non-members on the community page and room list?": "Näytetäänkö nämä huoneet ei-jäsenille yhteisön sivulla ja huonelistassa?", "Add rooms to the community": "Lisää huoneita tähän yhteisöön", - "Room name or alias": "Huoneen nimi taj alias", + "Room name or alias": "Huoneen nimi tai alias", "Add to community": "Lisää yhteisöön", "Failed to invite the following users to %(groupId)s:": "Seuraavien käyttäjien kutsuminen ryhmään %(groupId)s epäonnistui:", "Failed to invite users to community": "Käyttäjien kutsuminen yhteisöön epäonnostui", "Failed to invite users to %(groupId)s": "Käyttäjien kutsuminen yhteisöön %(groupId)s epäonnistui", - "Failed to add the following rooms to %(groupId)s:": "Seiraavien huoneiden lisääminen yhteisöön %(groupId)s epäonnistui:", + "Failed to add the following rooms to %(groupId)s:": "Seuraavien huoneiden lisääminen yhteisöön %(groupId)s epäonnistui:", "Restricted": "Rajoitettu", "You are now ignoring %(userId)s": "Et enää huomioi käyttäjää %(userId)s", "You are no longer ignoring %(userId)s": "Huomioit jälleen käyttäjän %(userId)s", @@ -730,7 +730,7 @@ "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Huoneen '%(roomName)s' näkyvyys yhteisössä %(groupId)s ei voitu päivittää.", "Visibility in Room List": "Näkyvyys huoneluettelossa", "Visible to everyone": "Näkyy kaikille", - "Only visible to community members": "Vain näkyvä yhteisön jäsenille", + "Only visible to community members": "Näkyy vain yhteisön jäsenille", "Filter community rooms": "Suodata yhteisön huoneet", "Communities": "Yhteisöt", "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", @@ -742,8 +742,8 @@ "Try using one of the following valid address types: %(validTypesList)s.": "Kokeile käyttää yhtä näistä valideista osoitetyypeistä: %(validTypesList)s.", "You have entered an invalid address.": "Olet syöttänyt virheellisen sähköpostiosoitteen.", "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.": "Oletko varma että haluat poistaa tämän tapahtuman? Huomaa että jos poistat huoneen nimen tai aiheen muutoksen, saattaa muutos kumoutua.", - "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Yhteisötunnisteet voivat sisältää vain merkit a-z, 0-9 tai '=_-/'", - "Something went wrong whilst creating your community": "Jokin epäonnistui yhteisön luomisessa", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Yhteisötunnisteet voivat sisältää vain merkkejä a-z, 0-9 tai '=_-/'", + "Something went wrong whilst creating your community": "Jokin meni pieleen yhteisön luomisessa", "Create Community": "Luo yhteisö", "Community Name": "Yhteisön nimi", "Community ID": "Yhteisötunniste", @@ -787,7 +787,7 @@ "You're not currently a member of any communities.": "Et ole minkään yhteisön jäsen tällä hetkellä.", "Error whilst fetching joined communities": "Virhe ladatessa listaa yhteistöistä joihin olet liittynyt", "Create a new community": "Luo uusi yhteisö", - "Light theme": "Vaalea ulkoasu", + "Light theme": "Vaalea teema", "Dark theme": "Tumma teema", "Status.im theme": "Status.im ulkoasu", "Autocomplete Delay (ms):": "Automaattitäydennyksen viive (ms):", @@ -797,8 +797,8 @@ "Sign in to get started": "Kirjaudu aloittaksesi", "Upload an avatar:": "Lataa profiilikuva:", "Deops user with given id": "Poistaa annetun tunnisteen omaavalta käyttäjältä ylläpito-oikeudet", - "Ignores a user, hiding their messages from you": "Jättää käyttäjän huomioimatta jolloin heidän viestejä ei näytetä sinulle", - "Stops ignoring a user, showing their messages going forward": "Lopettaa käyttäjän huomiotta jättämisen jolloin heidän tulevat viestit näytetään sinulle", + "Ignores a user, hiding their messages from you": "Jättää käyttäjän huomioimatta, jotta hänen viestejään ei näytetä sinulle", + "Stops ignoring a user, showing their messages going forward": "Lopettaa käyttäjän huomiotta jättämisen, jotta hänen viestinsä näytetään sinulle", "Notify the whole room": "Hälytä koko huone", "Room Notification": "Huonehälytys", "Call Failed": "Puhelu epäonnistui", @@ -824,10 +824,10 @@ "Delete %(count)s devices|one": "Poista laite", "Select devices": "Valitse laitteet", "Ongoing conference call%(supportedText)s.": "Menossa oleva ryhmäpuhelu %(supportedText)s.", - "%(duration)ss": "%(duration)s", + "%(duration)ss": "%(duration)ss", "%(duration)sm": "%(duration)sm", "%(duration)sh": "%(duration)sh", - "%(duration)sd": "%(duration)s päivä", + "%(duration)sd": "%(duration)s pv", "Online for %(duration)s": "Läsnä %(duration)s", "Idle for %(duration)s": "Toimettomana %(duration)s", "Offline for %(duration)s": "Poissa %(duration)s", @@ -844,7 +844,7 @@ "To change the topic, you must be a": "Vaihtaaksesi huoneen aihetta, sinun tulee olla", "To modify widgets in the room, you must be a": "Vaihtaaksesi huoneen pienoisohjelmia, sinun tulee olla", "Addresses": "Osoitteet", - "Flair": "Tyyppi", + "Flair": "Tyyli", "Showing flair for these communities:": "Yhteisöjen tyypit:", "This room is not showing flair for any communities": "Tälle huoneelle ei ole määritelty minkään yhteisön tyyppiä", "URL previews are enabled by default for participants in this room.": "URL-esikatselut on päällä oletusarvoisesti tämän huoneen jäsenillä.", @@ -852,7 +852,7 @@ "Token incorrect": "Väärä tunniste", "Flair will appear if enabled in room settings": "Tyyppi näkyy jos määritelty tämän huoneen asetuksissa", "Flair will not appear": "Tyyppi ei näkyvissä", - "Something went wrong when trying to get your communities.": "Jokin meni pieleen haettaessa yhteisöjäsi.", + "Something went wrong when trying to get your communities.": "Jokin meni pieleen yhteisöjäsi haettaessa.", "Delete Widget": "Poista pienoisohjelma", "Revoke widget access": "Poista pienoisohjelman oikeudet", "Unblacklist": "Poista estolistalta", @@ -873,8 +873,8 @@ "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)s poistui ja liittyi uudelleen", "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)s poistui ja liittyi uudelleen %(count)s kertaa", "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s poistui ja liittyi uudelleen", - "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s hylkäsi kutsun %(count)s kertaa", - "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s hylkäsi kutsun", + "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s hylkäsivät kutsunsa %(count)s kertaa", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s hylkäsivät kutsunsa", "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s hylkäsi kutsun %(count)s kertaa", "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s hylkäsi kutsun", "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)s kutsu peruttiin %(count)s kertaa", @@ -886,12 +886,12 @@ "was invited %(count)s times|other": "kutsuttiin %(count)s kertaa", "was invited %(count)s times|one": "kutsuttiin", "were banned %(count)s times|other": "estettiin %(count)s kertaa", - "were banned %(count)s times|one": "estettiin", - "was banned %(count)s times|other": "estettiin %(count)s kertaa", - "was banned %(count)s times|one": "estettiin", - "were unbanned %(count)s times|one": "estoi poistettiin", - "was unbanned %(count)s times|other": "esto poistettiin %(count)s kertaa", - "was unbanned %(count)s times|one": "esto poistettiin", + "were banned %(count)s times|one": "saivat porttikiellon", + "was banned %(count)s times|other": "saivat porttikiellon %(count)s kertaa", + "was banned %(count)s times|one": "sai porttikiellon", + "were unbanned %(count)s times|one": "porttikiellot poistettiin", + "was unbanned %(count)s times|other": "porttikielto poistettiin %(count)s kertaa", + "was unbanned %(count)s times|one": "porttikielto poistettiin", "were kicked %(count)s times|other": "poistettiin %(count)s kertaa", "were kicked %(count)s times|one": "poistettiin", "was kicked %(count)s times|other": "poistettiin %(count)s kertaa", @@ -932,7 +932,7 @@ "You are not receiving desktop notifications": "Et vastaanota työpöytäilmoituksia", "Friday": "Perjantai", "Update": "Päivitä", - "What's New": "Mikä on uutta", + "What's New": "Mitä uutta", "Add an email address above to configure email notifications": "Lisää sähköpostiosoite yllä saadaksesi ilmoituksia sähköpostiisi", "Expand panel": "Avaa paneeli", "On": "Päällä", @@ -982,12 +982,12 @@ "Messages containing keywords": "Avainsanoja sisältävät viestit", "View Source": "Näytä lähde", "Tuesday": "Tiistai", - "Enter keywords separated by a comma:": "Anna avainsanat eroteltuna pilkuin:", + "Enter keywords separated by a comma:": "Anna avainsanat pilkuin eroteltuna:", "Search…": "Haku…", "You have successfully set a password and an email address!": "Olet onnistuneesti asettanut salasanan ja sähköpostiosoitteen!", "Remove %(name)s from the directory?": "Poista %(name)s hakemistosta?", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot käyttää monia selainominaisuuksia, joista osa selaimesi ei tue tai ne ovat kokeellisia.", - "Developer Tools": "Kehitystila", + "Developer Tools": "Kehittäjätyökalut", "Enable desktop notifications": "Ota käyttöön työpöytäilmoitukset", "Explore Account Data": "Tilitiedot", "All messages (noisy)": "Kaikki viestit (äänekkäästi)", @@ -1017,7 +1017,7 @@ "Messages containing my display name": "Viestit, jotka sisältävät näyttönimeni", "State Key": "Tila-avain", "Failed to send custom event.": "Kustomoidun tapahtuman lähettäminen epäonnistui.", - "What's new?": "Mikä on uutta?", + "What's new?": "Mitä uutta?", "Notify me for anything else": "Ilmoita minulle kaikesta muusta", "When I'm invited to a room": "Kun minut kutsutaan huoneeseen", "Can't update user notification settings": "Käyttäjän ilmoitusasetusten päivittäminen epäonnistui", @@ -1033,7 +1033,7 @@ "Show message in desktop notification": "Näytä viestit ilmoituskeskuksessa", "Unhide Preview": "Näytä ennakkokatselu", "Unable to join network": "Verkkoon liittyminen epäonnistui", - "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Olet saattanut muuttaa niitä toisessa asiakasohjelmassa kuin Riot. Et voi muuttaa niitä Riotissa mutta ne pätevät kuitenkin", + "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Olet saattanut muuttaa niitä muussa asiakasohjelmassa kuin Riotissa. Et voi muuttaa niitä Riotissa mutta ne pätevät silti", "Sorry, your browser is not able to run Riot.": "Valitettavasti Riot ei toimi selaimessasi.", "Uploaded on %(date)s by %(user)s": "Ladattu %(date)s käyttäjän %(user)s toimesta", "Messages in group chats": "Viestit ryhmäkeskusteluissa", @@ -1065,7 +1065,7 @@ "Collapse panel": "Piilota paneeli", "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!": "Nykyisellä selaimellasi ohjelman ulkonäkö voi olla aivan virheellinen, ja jotkut ominaisuudet eivät saata toimia. Voit jatkaa jos haluat kokeilla mutta et voi odottaa saavasi apua mahdollisesti ilmeneviin ongelmiin!", "Checking for an update...": "Tarkistetaan päivityksen saatavuutta...", - "There are advanced notifications which are not shown here": "On kehittyneitä ilmoituksia joita ei näytetä tässä", + "There are advanced notifications which are not shown here": "Tässä ei näytetä edistyneitä ilmoituksia", "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Voit myös määrittää toisen identiteettipalvelimen, mutta et voi kutsua muita käyttäjiä sähköpostin perusteella, eivätkä se voi kutsua sinua.", "Your language of choice": "Valitsemasi kieli", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Yksityisyydensuoja on meille tärkeää, joten emme kerää mitään henkilökohtaista tai yksilöivää tietoa analytiikkaamme varten.", @@ -1115,7 +1115,7 @@ "Encrypted messages in group chats": "Salatut viestit ryhmäkeskusteluissa", "The other party cancelled the verification.": "Toinen osapuoli perui varmennuksen.", "Verified!": "Varmennettu!", - "You've successfully verified this user.": "Olet onnistuneesti varmentanut tämän käyttäjän.", + "You've successfully verified this user.": "Olet varmentanut tämän käyttäjän.", "Verify this user by confirming the following emoji appear on their screen.": "Varmenna tämä käyttäjä varmistamalla, että seuraava emoji ilmestyy heidän ruudulleen.", "Verify this user by confirming the following number appears on their screen.": "Varmenna tämä käyttäjä varmistamalla, että seuraava luku ilmestyy heidän ruudulleen.", "Unable to find a supported verification method.": "Tuetun varmennustavan löytäminen ei onnistunut.", @@ -1180,7 +1180,7 @@ "Anchor": "Ankkuri", "Headphones": "Kuulokkeet", "Folder": "Kansio", - "Pin": "Pinssi", + "Pin": "Nuppineula", "Call in Progress": "Puhelu meneillään", "General": "Yleiset", "Security & Privacy": "Turvallisuus ja yksityisyys", @@ -1365,9 +1365,9 @@ "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s vaihtoi vieraiden pääsyn tilaan %(rule)s", "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s lisäsi osoitteet %(addedAddresses)s ja poisti osoitteet %(removedAddresses)s tältä huoneelta.", "%(displayName)s is typing …": "%(displayName)s kirjoittaa…", - "%(names)s and %(count)s others are typing …|other": "%(names)s ja %(count)s muuta ovat kirjoittamassa…", - "%(names)s and %(count)s others are typing …|one": "%(names)s ja yksi muu ovat kirjoittamassa…", - "%(names)s and %(lastPerson)s are typing …": "%(names)s ja %(lastPerson)s ovat kirjoittamassa…", + "%(names)s and %(count)s others are typing …|other": "%(names)s ja %(count)s muuta kirjoittavat…", + "%(names)s and %(count)s others are typing …|one": "%(names)s ja yksi muu kirjoittavat…", + "%(names)s and %(lastPerson)s are typing …": "%(names)s ja %(lastPerson)s kirjoittavat…", "This homeserver has hit its Monthly Active User limit.": "Tämän kotipalvelimen kuukausittaisten aktiivisten käyttäjien raja on täynnä.", "This homeserver has exceeded one of its resource limits.": "Tämä kotipalvelin on ylittänyt yhden rajoistaan.", "Unrecognised address": "Osoitetta ei tunnistettu", @@ -1382,11 +1382,11 @@ "Avoid dates and years that are associated with you": "Vältä päivämääriä ja vuosia, jotka liittyvät sinuun", "Capitalization doesn't help very much": "Isolla alkukirjaimella aloittaminen ei erityisesti hyödytä", "All-uppercase is almost as easy to guess as all-lowercase": "Pelkästään isoilla kirjaimilla kirjoitettu on melkein yhtä helppo arvata kuin kokonaan pienellä kirjoitettu", - "Reversed words aren't much harder to guess": "Varatut sanat eivät ole paljoakaan vaikeampia arvata", + "Reversed words aren't much harder to guess": "Takaperin kirjoitetut sanat eivät ole paljoakaan vaikeampia arvata", "Predictable substitutions like '@' instead of 'a' don't help very much": "Arvattavat vaihdot, kuten ”@” ”a”:n sijaan ei auta paljoakaan", "Add another word or two. Uncommon words are better.": "Lisää sana tai kaksi. Epätavalliset sanat ovat parempia.", "Sequences like abc or 6543 are easy to guess": "Sarjat, kuten ”abc” tai ”6543” ovat helppoja arvata", - "Recent years are easy to guess": "Viimeaikaiset vuodet ovat helppoja arvata", + "Recent years are easy to guess": "Viime vuodet ovat helppoja arvata", "Dates are often easy to guess": "Päivämäärät ovat usein helppoja arvata", "This is a top-10 common password": "Tämä on kymmenen yleisimmän salasanan joukossa", "This is a top-100 common password": "Tämä on sadan yleisimmän salasanan joukossa", @@ -1404,13 +1404,13 @@ "Show read receipts": "Näytä lukukuittaukset", "Enable big emoji in chat": "Ota käyttöön suuret emojit keskusteluissa", "Enable Community Filter Panel": "Ota käyttöön yhteisön suodatinpaneeli", - "Allow Peer-to-Peer for 1:1 calls": "Salli vertaisten välinen yhteydenpito kahdenkeskisissä puheluissa", + "Allow Peer-to-Peer for 1:1 calls": "Salli vertaisten väliset yhteydet kahdenkeskisissä puheluissa", "Prompt before sending invites to potentially invalid matrix IDs": "Kysy varmistus ennen kutsujen lähettämistä mahdollisesti epäkelpoihin Matrix ID:hin", "Messages containing my username": "Viestit, jotka sisältävät käyttäjänimeni", "Messages containing @room": "Viestit, jotka sisältävät sanan ”@room”", - "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Turvalliset viestit tämän käyttäjän kanssa ovat salattuja, eikä niitä voi lukea kolmannen osapuolen toimesta.", + "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Turvalliset viestit tämän käyttäjän kanssa ovat salattuja päästä päähän, eivätkä kolmannet osapuolet voi lukea niitä.", "Thumbs up": "Peukut ylös", - "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Lähetimme sinulle viestin sähköpostiosoitteesi varmentamiseksi. Seuraathan sähköpostissa olevia ohjeita, ja sen jälkeen klikkaa alapuolella olevaa painiketta.", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Lähetimme sinulle viestin sähköpostiosoitteesi varmentamiseksi. Noudata sähköpostissa olevia ohjeita, ja klikkaa sen jälkeen alla olevaa painiketta.", "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Oletko varma? Et voi lukea salattuja viestejäsi, mikäli avaimesi eivät ole kunnolla varmuuskopioituna.", "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Salatut viestit turvataan kahdenkeskisellä salauksella. Vain sinä ja viestien vastaanottajat omistavat avaimet näiden viestien lukemiseen.", "Unable to load key backup status": "Avainten varmuuskopionnin tilan lukeminen epäonnistui", @@ -1418,14 +1418,14 @@ "Back up your keys before signing out to avoid losing them.": "Varmuuskopioi avaimesi ennen kuin kirjaudut ulos välttääksesi avainten menetyksen.", "Use key backup": "Käytä avainten varmuuskopiointia", "Backing up %(sessionsRemaining)s keys...": "Varmuuskopioidaan %(sessionsRemaining)s avainta…", - "All keys backed up": "Kaikki avaimet ovat varmuuskopioitu", + "All keys backed up": "Kaikki avaimet on varmuuskopioitu", "Backup has a signature from unknown device with ID %(deviceId)s.": "Varmuuskopiossa on allekirjoitus tuntemattomasta laitteesta ID:llä %(deviceId)s.", "Backup has a valid signature from this device": "Varmuuskopiossa on pätevä allekirjoitus tästä laitteesta", "Backup has a valid signature from verified device ": "Varmuuskopiossa on pätevä allekirjoitus varmennetusta laitteesta ", "Backup has a valid signature from unverified device ": "Varmuuskopiossa on pätevä allekirjoitus varmentamattomasta laitteesta ", "Backup has an invalid signature from verified device ": "Varmuuskopiossa on epäkelpo allekirjoitus varmennetusta laitteesta ", "Backup has an invalid signature from unverified device ": "Varmuuskopiossa on epäkelpo allekirjoitus varmentamattomasta laitteesta ", - "Backup is not signed by any of your devices": "Varmuuskopiota ei ole allekirjoitettu yhdenkään laitteesi toimesta", + "Backup is not signed by any of your devices": "Yksikään laitteistasi ei ole allekirjoittanut varmuuskopiota", "This backup is trusted because it has been restored on this device": "Tämä varmuuskopio on luotettu, koska se on palautettu tähän laitteeseen", "Backup version: ": "Varmuuskopion versio: ", "Algorithm: ": "Algoritmi: ", @@ -1440,7 +1440,7 @@ "Bug reporting": "Virheiden raportointi", "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.": "Jos olet ilmoittanut virheestä Githubin kautta, debug-lokit voivat auttaa meitä ongelman jäljittämisessä. Debug-lokit sisältävät ohjelman käyttödataa sisältäen käyttäjätunnuksen, vierailemiesi huoneiden tai ryhmien ID:t tai aliakset ja muiden käyttäjien käyttäjätunnukset. Debug-lokit eivät sisällä viestejä.", "Autocomplete delay (ms)": "Automaattisen täydennyksen viive (ms)", - "To link to this room, please add an alias.": "Joudut lisäämään aliaksen linkataksesi tähän huoneeseen.", + "To link to this room, please add an alias.": "Lisää alias linkittääksesi tähän huoneeseen.", "Ignored users": "Hiljennetyt käyttäjät", "Bulk options": "Massatoimintoasetukset", "Key backup": "Avainvarmuuskopio", @@ -1458,7 +1458,7 @@ "Show a placeholder for removed messages": "Näytä paikanpitäjä poistetuille viesteille", "Show avatar changes": "Näytä profiilikuvien muutokset", "Show read receipts sent by other users": "Näytä muiden käyttäjien lukukuittaukset", - "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Näytä muistutus Suojatun Viestien Palautuksen käyttöönotosta salatuissa huoneissa", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Näytä muistutus suojatun viestien palautuksen käyttöönotosta salatuissa huoneissa", "Show avatars in user and room mentions": "Näytä profiilikuvat käyttäjä- ja huonemaininnoissa", "Order rooms in the room list by most important first instead of most recent": "Järjestä huonelista tärkein ensin viimeisimmän sijasta", "Got It": "Ymmärretty", @@ -1505,11 +1505,11 @@ "Use Key Backup": "Käytä avainvarmuuskopiointia", "Never lose encrypted messages": "Älä hukkaa salattuja viestejäsi", "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Viestit tässä huoneessa on turvattu osapuolten välisellä salauksella. Vain sinä ja viestien vastaanottajat omistavat avaimet näiden viestien lukemiseen.", - "Securely back up your keys to avoid losing them. Learn more.": "Varmuuskopioi avaimesi, jotta et menetä niitä. Opi lisää.", + "Securely back up your keys to avoid losing them. Learn more.": "Varmuuskopioi avaimesi, jotta et menetä niitä. Lue lisää.", "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "Tämä huone käyttää epävakaata huoneen versiota. Jos et odottanut tätä, päivitä huoneesi.", "There is a known vulnerability affecting this room.": "Tunnettu haavoittuvuus vaikuttaa tähän huoneesen.", "This room version is vulnerable to malicious modification of room state.": "Tämä huone on haavoittuvainen pahantahtoisille huoneen tilan muokkauksille.", - "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Klikkaa tästä päivittääksesi uusimpaan huoneen versioon ja varmistaaksesi, että huoneen integriteetti on suojattu.", + "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Klikkaa tästä päivittääksesi uusimpaan huoneen versioon ja varmistaaksesi, että huoneen eheys on suojattu.", "Only room administrators will see this warning": "Vain huoneen ylläpitäjät näkevät tämän varoituksen", "Add some now": "Lisää muutamia", "Error updating main address": "Pääosoitteen päivityksessä tapahtui virhe", @@ -1524,7 +1524,7 @@ "Please contact your service administrator to get this limit increased.": "Ota yhteyttä ylläpitäjääsi tämän rajan kasvattamiseksi.", "This homeserver has hit its Monthly Active User limit so some users will not be able to log in.": "Tämä kotipalvelin on saavuttanut kuukausittaisten aktiivisten käyttäjien rajansa, joten osa käyttäjistä ei pysty kirjautumaan sisään.", "This homeserver has exceeded one of its resource limits so some users will not be able to log in.": "Tämä kotipalvelin on ylittänyt yhden resurssirajoistaan, joten osa käyttäjistä ei pysty kirjautumaan sisään.", - "Warning: This widget might use cookies.": "Varoitus: tämä sovelma saattaa käyttää keksejä.", + "Warning: This widget might use cookies.": "Varoitus: tämä sovelma saattaa käyttää evästeitä.", "Failed to remove widget": "Sovelman poisto epäonnistui", "An error ocurred whilst trying to remove the widget from the room": "Sovelman poistossa huoneesta tapahtui virhe", "Minimize apps": "Pienennä sovellukset", @@ -1560,7 +1560,7 @@ "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Alla luetelluille Matrix ID:ille ei löytynyt profiileja. Haluaisitko kutsua ne siitä huolimatta?", "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.": "Debug-lokit sisältävät ohjelman käyttödataa, kuten käyttäjätunnuksesi, huoneiden ja ryhmien ID:t tai aliakset, joissa olet vieraillut sekä muiden käyttäjien käyttäjätunnukset. Ne eivät sisällä viestejä.", "Before submitting logs, you must create a GitHub issue to describe your problem.": "Ennen lokien lähettämistä sinun täytyy luoda tapahtuma Githubiin, joka sisältää kuvauksen ongelmastasi.", - "What GitHub issue are these logs for?": "Mihin Github-tapahtumaan nämä lokit liittyvät?", + "What GitHub issue are these logs for?": "Mihin Github-issueen nämä lokit liittyvät?", "Notes:": "Huomiot:", "Unable to load commit detail: %(msg)s": "Commitin tietojen hakeminen epäonnistui: %(msg)s", "Community IDs cannot be empty.": "Yhteisön ID:t eivät voi olla tyhjänä.", @@ -1568,10 +1568,10 @@ "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Olet aikaisemmin käyttänyt uudempaa Riotin versiota koneella %(host)s. Jotta voit käyttää tätä versiota osapuolten välisellä salauksella, sinun täytyy kirjautua ulos ja kirjautua takaisin sisään. ", "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Tämä tekee tunnuksestasi lopullisesti käyttökelvottoman. Et voi kirjautua sisään, eikä kukaan voi rekisteröidä tunnusta samalla käyttäjä-ID:llä. Tunnuksesi tulee lähtemään kaikista huoneista, joihin se on liittynyt, ja tietosi tullaan poistamaan identiteettipalvelimelta. Tämä toimenpide on lopullinen eikä sitä voi kumota.", "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.": "Tunnuksesi poistaminen käytöstä ei oletuksena saa meitä unohtamaan lähettämiäsi viestejä. Jos haluaisit meidän unohtavan viestisi, klikkaa alapuolella olevasta laatikosta.", - "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.": "Viestien näkyvyys Matrixissa on samanlainen kuin sähköpostissa. Vaikka se, et unohdamme viestisi, tarkoittaa, ettei viestejäsi jaeta enää uusille tai rekisteröitymättömille käyttäjille, käyttäjät, jotka ovat jo saaneet viestisi pystyvät lukemaan jatkossakin omaa kopioonsa viesteistäsi.", + "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.": "Viestien näkyvyys Matrixissa on samantapainen kuin sähköpostissa. Vaikka se, että unohdamme viestisi, tarkoittaa, ettei viestejäsi jaeta enää uusille tai rekisteröitymättömille käyttäjille, käyttäjät, jotka ovat jo saaneet viestisi pystyvät lukemaan jatkossakin omaa kopiotaan viesteistäsi.", "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)": "Unohda kaikki viestit, jotka olen lähettänyt, kun tunnukseni on otettu pois käytöstä (b>Warning: tämä aiheuttaa tulevien käyttäjien näkevän epätäydellisen version keskusteluista)", "Use Legacy Verification (for older clients)": "Käytä vanhentunutta varmennustapaa (vanhemmille asiakasohjelmille)", - "Verify by comparing a short text string.": "Varmenna vertaamalla lyhyttä tekstijonoa.", + "Verify by comparing a short text string.": "Varmenna vertaamalla lyhyttä merkkijonoa.", "Begin Verifying": "Aloita varmentaminen", "Waiting for partner to accept...": "Odotetaan, että toinen osapuoli hyväksyy...", "Nothing appearing? Not all clients support interactive verification yet. .": "Näytölle ei ilmesty mitään? Kaikki asiakasohjelmat eivät vielä tue interaktiivista varmentamista. .", From a34a8bb425452a7854df29bf340b8b51b8a47d6e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 22 Mar 2019 17:36:54 -0600 Subject: [PATCH 079/481] Use leaveRoomChain when leaving a room Requires https://github.com/matrix-org/matrix-js-sdk/pull/868 Fixes https://github.com/vector-im/riot-web/issues/8539 We don't need to use leaveRoomChain when rejecting invites because we won't have the references needed. This leaves the couple spots where we do actually leave a room, and use the new function for that. --- src/SlashCommands.js | 2 +- src/components/structures/MatrixChat.js | 41 ++++++++++++++++--------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 039ccb928f..b5f2ed8ba2 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -431,7 +431,7 @@ export const CommandMap = { if (!targetRoomId) targetRoomId = roomId; return success( - cli.leave(targetRoomId).then(function() { + cli.leaveRoomChain(targetRoomId).then(function() { dis.dispatch({action: 'view_next_room'}); }), ); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2622a6bf93..17ce6e0e73 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1058,34 +1058,47 @@ export default React.createClass({ button: _t("Leave"), onFinished: (shouldLeave) => { if (shouldLeave) { - const d = MatrixClientPeg.get().leave(roomId); + const d = MatrixClientPeg.get().leaveRoomChain(roomId); // FIXME: controller shouldn't be loading a view :( const Loader = sdk.getComponent("elements.Spinner"); const modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner'); - d.then(() => { + d.then((errors) => { modal.close(); + + if (errors[roomId]) { + // Something went wrong + const err = errors[roomId]; + console.error("Failed to leave room " + roomId + " " + err); + let title = _t("Failed to leave room"); + let message = _t("Server may be unavailable, overloaded, or you hit a bug."); + if (err.errcode === 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') { + title = _t("Can't leave Server Notices room"); + message = _t( + "This room is used for important messages from the Homeserver, " + + "so you cannot leave it.", + ); + } else if (err && err.message) { + message = err.message; + } + Modal.createTrackedDialog('Failed to leave room', '', ErrorDialog, { + title: title, + description: message, + }); + return; + } + if (this.state.currentRoomId === roomId) { dis.dispatch({action: 'view_next_room'}); } }, (err) => { + // This should only happen if something went seriously wrong with leaving the chain. modal.close(); console.error("Failed to leave room " + roomId + " " + err); - let title = _t("Failed to leave room"); - let message = _t("Server may be unavailable, overloaded, or you hit a bug."); - if (err.errcode == 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') { - title = _t("Can't leave Server Notices room"); - message = _t( - "This room is used for important messages from the Homeserver, " + - "so you cannot leave it.", - ); - } else if (err && err.message) { - message = err.message; - } Modal.createTrackedDialog('Failed to leave room', '', ErrorDialog, { title: title, - description: message, + description: _t("Unknown error"), }); }); } From 4fd48988e96683df1dd3c543c700bc1afd0166a2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 22 Mar 2019 17:39:42 -0600 Subject: [PATCH 080/481] Check for any errors leaving the room, not just the top level --- src/components/structures/MatrixChat.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 17ce6e0e73..26956858be 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1067,10 +1067,11 @@ export default React.createClass({ d.then((errors) => { modal.close(); - if (errors[roomId]) { - // Something went wrong - const err = errors[roomId]; - console.error("Failed to leave room " + roomId + " " + err); + for (const leftRoomId of Object.keys(errors)) { + const err = errors[leftRoomId]; + if (!err) continue; + + console.error("Failed to leave room " + leftRoomId + " " + err); let title = _t("Failed to leave room"); let message = _t("Server may be unavailable, overloaded, or you hit a bug."); if (err.errcode === 'M_CANNOT_LEAVE_SERVER_NOTICE_ROOM') { From 389abed5745590e1d78b65c5ffc2c48a42bb162e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 22 Mar 2019 19:03:43 -0600 Subject: [PATCH 081/481] Define a title for generic error --- src/components/structures/MatrixChat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 26956858be..9d8a4adb6f 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1098,7 +1098,7 @@ export default React.createClass({ modal.close(); console.error("Failed to leave room " + roomId + " " + err); Modal.createTrackedDialog('Failed to leave room', '', ErrorDialog, { - title: title, + title: _t("Failed to leave room"), description: _t("Unknown error"), }); }); From e5f7563decc2124209b51bd8980c3c96a1af33a8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 22 Mar 2019 20:22:13 -0600 Subject: [PATCH 082/481] Ask the user for debug logs when the timeline explodes Fixes https://github.com/vector-im/riot-web/issues/9260 Workaround for https://github.com/vector-im/riot-web/issues/8593 Requires https://github.com/matrix-org/matrix-js-sdk/pull/869 We check if any dialogs are open before moving forward because we don't want to risk showing so many dialogs that the user is unable to click a button. We're also not overly concerned if the dialog being shown is irrelevant because whatever the user is doing will likely be unaffected, and we can scream in pain when they're finished. --- src/Modal.js | 4 + src/components/structures/MatrixChat.js | 12 ++ .../views/dialogs/TimelineExplosionDialog.js | 130 ++++++++++++++++++ src/i18n/strings/en_EN.json | 4 + 4 files changed, 150 insertions(+) create mode 100644 src/components/views/dialogs/TimelineExplosionDialog.js diff --git a/src/Modal.js b/src/Modal.js index 4d90e313ce..96dbd49324 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -124,6 +124,10 @@ class ModalManager { this.closeAll = this.closeAll.bind(this); } + hasDialogs() { + return this._priorityModal || this._staticModal || this._modals.length > 0; + } + getOrCreateContainer() { let container = document.getElementById(DIALOG_CONTAINER_ID); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2622a6bf93..b617e4ca02 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -48,6 +48,7 @@ import { _t, getCurrentLanguage } from '../../languageHandler'; import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import { startAnyRegistrationFlow } from "../../Registration.js"; import { messageForSyncError } from '../../utils/ErrorUtils'; +import TimelineExplosionDialog from "../views/dialogs/TimelineExplosionDialog"; const AutoDiscovery = Matrix.AutoDiscovery; @@ -1278,6 +1279,17 @@ export default React.createClass({ return self._loggedInView.child.canResetTimelineInRoom(roomId); }); + cli.on('sync.unexpectedError', function(err) { + if (err.message && err.message.includes("live timeline ") && err.message.includes(" is no longer live ")) { + console.error("Caught timeline explosion - trying to ask user for more information"); + if (Modal.hasDialogs()) { + console.warn("User has another dialog open - skipping prompt"); + return; + } + Modal.createTrackedDialog('Timeline exploded', '', TimelineExplosionDialog, {}); + } + }); + cli.on('sync', function(state, prevState, data) { // LifecycleStore and others cannot directly subscribe to matrix client for // events because flux only allows store state changes during flux dispatches. diff --git a/src/components/views/dialogs/TimelineExplosionDialog.js b/src/components/views/dialogs/TimelineExplosionDialog.js new file mode 100644 index 0000000000..5c8fba8f9c --- /dev/null +++ b/src/components/views/dialogs/TimelineExplosionDialog.js @@ -0,0 +1,130 @@ +/* +Copyright 2019 New Vector 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 sdk from '../../../index'; +import SdkConfig from '../../../SdkConfig'; +import { _t } from '../../../languageHandler'; + +// Dev note: this should be a temporary dialog while we work out what is +// actually going on. See https://github.com/vector-im/riot-web/issues/8593 +// for more details. This dialog is almost entirely a copy/paste job of +// BugReportDialog. +export default class TimelineExplosionDialog extends React.Component { + static propTypes = { + onFinished: React.PropTypes.func.isRequired, + }; + + constructor(props, context) { + super(props, context); + this.state = { + busy: false, + progress: null, + }; + } + + _onCancel() { + console.log("Reloading without sending logs for timeline explosion"); + window.location.reload(); + } + + _onSubmit = () => { + const userText = "Caught timeline explosion\n\nhttps://github.com/vector-im/riot-web/issues/8593"; + + this.setState({busy: true, progress: null}); + this._sendProgressCallback(_t("Preparing to send logs")); + + require(['../../../rageshake/submit-rageshake'], (s) => { + s(SdkConfig.get().bug_report_endpoint_url, { + userText, + sendLogs: true, + progressCallback: this._sendProgressCallback, + }).then(() => { + console.log("logs sent for timeline explosion - reloading riot"); + window.location.reload(); + }, (err) => { + console.error("Error sending logs for timeline explosion - reloading anyways. ", err); + window.location.reload(); + }); + }); + }; + + _sendProgressCallback = (progress) => { + this.setState({progress: progress}); + }; + + render() { + const Loader = sdk.getComponent("elements.Spinner"); + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + let progress = null; + if (this.state.busy) { + progress = ( +
      + {this.state.progress} ... + +
      + ); + } + + return ( + +
      +

      + {_t( + "Riot has run into a problem which makes it difficult to show you " + + "your messages right now. Nothing has been lost, and reloading the app " + + "should fix this for you. In order to assist us in troubleshooting the " + + "problem, we'd like to take a look at your debug logs. You do not need " + + "to send your logs unless you want to, but we would really appreciate " + + "it if you did. We'd also like to apologize for having to show this " + + "message to you - we hope your debug logs are the key to solving the " + + "issue once and for all. If you'd like more information on the bug you've " + + "accidentally run into, please visit the issue.", + {}, + { + 'a': (sub) => { + return {sub}; + }, + }, + )} +

      +

      + {_t( + "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.", + )} +

      + {progress} +
      + +
      + ); + } +} + diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef4bc75d27..0d0dad74ba 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1173,6 +1173,10 @@ "Share Room Message": "Share Room Message", "Link to selected message": "Link to selected message", "COPY": "COPY", + "Error showing you your room": "Error showing you your room", + "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost, and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.": "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost, and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.", + "Send debug logs and reload Riot": "Send debug logs and reload Riot", + "Reload Riot without sending logs": "Reload Riot without sending logs", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.", "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.", "Room contains unknown devices": "Room contains unknown devices", From 00335e246274d1bfd4bcd6f3a340598d5ba3592a Mon Sep 17 00:00:00 2001 From: YaoiFangirl420 <48789208+YaoiFangirl420@users.noreply.github.com> Date: Sat, 23 Mar 2019 20:53:09 -0700 Subject: [PATCH 083/481] Fix bug with NetworkList dropdown The NetworkDropdown component was incorrectly guarding against a null check when retrieving the list of networks Signed-off-by: YaoiFangirl420 <48789208+YaoiFangirl420@users.noreply.github.com> --- src/components/views/directory/NetworkDropdown.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index ebfff5ae8c..722fe21c1b 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -131,10 +131,11 @@ export default class NetworkDropdown extends React.Component { _getMenuOptions() { const options = []; + const roomDirectory = this.props.config.roomDirectory || {}; let servers = []; - if (this.props.config.roomDirectory.servers) { - servers = servers.concat(this.props.config.roomDirectory.servers); + if (roomDirectory.servers) { + servers = servers.concat(roomDirectory.servers); } if (!servers.includes(MatrixClientPeg.getHomeServerName())) { From 21d52a83113eab3654c36cff431660124961535a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 23 Mar 2019 22:50:26 -0600 Subject: [PATCH 084/481] Use the same function name to bind the OpenID request handler --- src/WidgetMessaging.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index 501fc34c7a..bbecdfa086 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -45,7 +45,7 @@ export default class WidgetMessaging { this.target = target; this.fromWidget = global.mxFromWidgetMessaging; this.toWidget = global.mxToWidgetMessaging; - this._openIdHandlerRef = this._onOpenIdRequest.bind(this); + this._onOpenIdRequest = this._onOpenIdRequest.bind(this); this.start(); } @@ -115,12 +115,12 @@ export default class WidgetMessaging { start() { this.fromWidget.addEndpoint(this.widgetId, this.widgetUrl); - this.fromWidget.addListener("get_openid", this._openIdHandlerRef); + this.fromWidget.addListener("get_openid", this._onOpenIdRequest); } stop() { this.fromWidget.removeEndpoint(this.widgetId, this.widgetUrl); - this.fromWidget.removeListener("get_openid", this._openIdHandlerRef); + this.fromWidget.removeListener("get_openid", this._onOpenIdRequest); } async _onOpenIdRequest(ev, rawEv) { From 2dcb40f1be6a90b628a84581f838a012821547f6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 23 Mar 2019 23:25:31 -0600 Subject: [PATCH 085/481] Track OpenID automatic permissions by (widgetLocation, widgetUrl) --- src/WidgetMessaging.js | 11 ++++++--- .../dialogs/WidgetOpenIDPermissionsDialog.js | 8 ++++++- src/components/views/elements/AppTile.js | 2 +- src/settings/Settings.js | 4 ++-- src/utils/WidgetUtils.js | 23 +++++++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index bbecdfa086..8d419ba6eb 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -26,6 +26,7 @@ import Modal from "./Modal"; import MatrixClientPeg from "./MatrixClientPeg"; import SettingsStore from "./settings/SettingsStore"; import WidgetOpenIDPermissionsDialog from "./components/views/dialogs/WidgetOpenIDPermissionsDialog"; +import WidgetUtils from "./utils/WidgetUtils"; if (!global.mxFromWidgetMessaging) { global.mxFromWidgetMessaging = new FromWidgetPostMessageApi(); @@ -39,9 +40,10 @@ if (!global.mxToWidgetMessaging) { const OUTBOUND_API_NAME = 'toWidget'; export default class WidgetMessaging { - constructor(widgetId, widgetUrl, target) { + constructor(widgetId, widgetUrl, isUserWidget, target) { this.widgetId = widgetId; this.widgetUrl = widgetUrl; + this.isUserWidget = isUserWidget; this.target = target; this.fromWidget = global.mxFromWidgetMessaging; this.toWidget = global.mxToWidgetMessaging; @@ -126,12 +128,14 @@ export default class WidgetMessaging { async _onOpenIdRequest(ev, rawEv) { if (ev.widgetId !== this.widgetId) return; // not interesting + const widgetSecurityKey = WidgetUtils.getWidgetSecurityKey(this.widgetId, this.widgetUrl, this.isUserWidget); + const settings = SettingsStore.getValue("widgetOpenIDPermissions"); - if (settings.blacklist && settings.blacklist.includes(this.widgetId)) { + if (settings.blacklist && settings.blacklist.includes(widgetSecurityKey)) { this.fromWidget.sendResponse(rawEv, {state: "blocked"}); return; } - if (settings.whitelist && settings.whitelist.includes(this.widgetId)) { + if (settings.whitelist && settings.whitelist.includes(widgetSecurityKey)) { const responseBody = {state: "allowed"}; const credentials = await MatrixClientPeg.get().getOpenIdToken(); Object.assign(responseBody, credentials); @@ -147,6 +151,7 @@ export default class WidgetMessaging { WidgetOpenIDPermissionsDialog, { widgetUrl: this.widgetUrl, widgetId: this.widgetId, + isUserWidget: this.isUserWidget, onFinished: async (confirm) => { const responseBody = {success: confirm}; diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index e6e97a3305..5f341261f8 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -20,12 +20,14 @@ import {_t} from "../../../languageHandler"; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; +import WidgetUtils from "../../../utils/WidgetUtils"; export default class WidgetOpenIDPermissionsDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, widgetUrl: PropTypes.string.isRequired, widgetId: PropTypes.string.isRequired, + isUserWidget: PropTypes.bool.isRequired, }; constructor() { @@ -52,7 +54,11 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component { if (!currentValues.whitelist) currentValues.whitelist = []; if (!currentValues.blacklist) currentValues.blacklist = []; - (allowed ? currentValues.whitelist : currentValues.blacklist).push(this.props.widgetId); + const securityKey = WidgetUtils.getWidgetSecurityKey( + this.props.widgetId, + this.props.widgetUrl, + this.props.isUserWidget); + (allowed ? currentValues.whitelist : currentValues.blacklist).push(securityKey); SettingsStore.setValue("widgetOpenIDPermissions", null, SettingLevel.DEVICE, currentValues); } diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 8ed408ffbe..955c2d5480 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -351,7 +351,7 @@ export default class AppTile extends React.Component { _setupWidgetMessaging() { // FIXME: There's probably no reason to do this here: it should probably be done entirely // in ActiveWidgetStore. - const widgetMessaging = new WidgetMessaging(this.props.id, this.props.url, this.refs.appFrame.contentWindow); + const widgetMessaging = new WidgetMessaging(this.props.id, this.props.url, this.props.userWidget, this.refs.appFrame.contentWindow); ActiveWidgetStore.setWidgetMessaging(this.props.id, widgetMessaging); widgetMessaging.getCapabilities().then((requestedCapabilities) => { console.log(`Widget ${this.props.id} requested capabilities: ` + requestedCapabilities); diff --git a/src/settings/Settings.js b/src/settings/Settings.js index fcf70b4df7..765b2f85c6 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -343,8 +343,8 @@ export const SETTINGS = { "widgetOpenIDPermissions": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, default: { - whitelisted: [], - blacklisted: [], + whitelist: [], + blacklist: [], }, }, "RoomList.orderByImportance": { diff --git a/src/utils/WidgetUtils.js b/src/utils/WidgetUtils.js index b5a2ae31fb..41a241c905 100644 --- a/src/utils/WidgetUtils.js +++ b/src/utils/WidgetUtils.js @@ -1,6 +1,7 @@ /* Copyright 2017 Vector Creations Ltd Copyright 2018 New Vector Ltd +Copyright 2019 Travis Ralston Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,6 +26,7 @@ import WidgetEchoStore from '../stores/WidgetEchoStore'; // before waitFor[Room/User]Widget rejects its promise const WIDGET_WAIT_TIME = 20000; import SettingsStore from "../settings/SettingsStore"; +import ActiveWidgetStore from "../stores/ActiveWidgetStore"; /** * Encodes a URI according to a set of template variables. Variables will be @@ -396,4 +398,25 @@ export default class WidgetUtils { return capWhitelist; } + + static getWidgetSecurityKey(widgetId, widgetUrl, isUserWidget) { + let widgetLocation = ActiveWidgetStore.getRoomId(widgetId); + + if (isUserWidget) { + const userWidget = WidgetUtils.getUserWidgetsArray() + .find((w) => w.id === widgetId && w.content && w.content.url === widgetUrl); + + if (!userWidget) { + throw new Error("No matching user widget to form security key"); + } + + widgetLocation = userWidget.sender; + } + + if (!widgetLocation) { + throw new Error("Failed to locate where the widget resides"); + } + + return encodeURIComponent(`${widgetLocation}::${widgetUrl}`); + } } From 3654c895ebf75dca452bc7f955e09d470a670662 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 23 Mar 2019 23:31:19 -0600 Subject: [PATCH 086/481] Appease the linter --- src/components/views/elements/AppTile.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 955c2d5480..c410b31799 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -351,7 +351,8 @@ export default class AppTile extends React.Component { _setupWidgetMessaging() { // FIXME: There's probably no reason to do this here: it should probably be done entirely // in ActiveWidgetStore. - const widgetMessaging = new WidgetMessaging(this.props.id, this.props.url, this.props.userWidget, this.refs.appFrame.contentWindow); + const widgetMessaging = new WidgetMessaging( + this.props.id, this.props.url, this.props.userWidget, this.refs.appFrame.contentWindow); ActiveWidgetStore.setWidgetMessaging(this.props.id, widgetMessaging); widgetMessaging.getCapabilities().then((requestedCapabilities) => { console.log(`Widget ${this.props.id} requested capabilities: ` + requestedCapabilities); From a8ae63bb06759b9ae019e0f6d16ec35348535dcb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 23 Mar 2019 23:50:06 -0600 Subject: [PATCH 087/481] Minimize stickerpicker when the title is clicked Fixes https://github.com/vector-im/riot-web/issues/6437 This also fixes a bug where if the room had apps open and you clicked the sticker picker's title, you'd end up closing the apps and not the picker. --- src/components/views/elements/AppTile.js | 14 +++++++++----- src/i18n/strings/en_EN.json | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 8ed408ffbe..466715dc3c 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -447,10 +447,14 @@ export default class AppTile extends React.Component { } // Toggle the view state of the apps drawer - dis.dispatch({ - action: 'appsDrawer', - show: !this.props.show, - }); + if (this.props.userWidget) { + this._onMinimiseClick(); + } else { + dis.dispatch({ + action: 'appsDrawer', + show: !this.props.show, + }); + } } _getSafeUrl() { @@ -626,7 +630,7 @@ export default class AppTile extends React.Component { { /* Maximise widget */ } { showMaximiseButton && } { /* Title */ } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef4bc75d27..1bb1c8e98c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -935,6 +935,7 @@ "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", "Reload widget": "Reload widget", "Popout widget": "Popout widget", "Picture": "Picture", From 1ba23d6833e41fa9b3d0d49df75be4ba078687f8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sat, 23 Mar 2019 23:53:21 -0600 Subject: [PATCH 088/481] Fix typo preventing users from adding more widgets easily Fixes https://github.com/vector-im/riot-web/issues/9266 --- src/components/views/rooms/AppsDrawer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index 449ca5f83d..e0e7a48b8c 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -144,7 +144,7 @@ module.exports = React.createClass({ _launchManageIntegrations: function() { const IntegrationsManager = sdk.getComponent('views.settings.IntegrationsManager'); - this._scalarClient.connect().done(() => { + this.scalarClient.connect().done(() => { const src = (this.scalarClient !== null && this.scalarClient.hasCredentials()) ? this.scalarClient.getScalarInterfaceUrlForRoom(this.props.room, 'add_integ') : null; From 8cca1bef23a4b6d3c036fb9ac74133dee2fac96a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sun, 24 Mar 2019 00:07:00 -0600 Subject: [PATCH 089/481] Add a command for creating custom widgets without an integration manager Fixes https://github.com/vector-im/riot-web/issues/4882 --- src/SlashCommands.js | 21 +++++++++++++++++++++ src/i18n/strings/en_EN.json | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 039ccb928f..fbacaef7c2 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -29,6 +29,7 @@ import * as querystring from "querystring"; import MultiInviter from './utils/MultiInviter'; import { linkifyAndSanitizeHtml } from './HtmlUtils'; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; +import WidgetUtils from "./utils/WidgetUtils"; class Command { constructor({name, args='', description, runFn, hideCompletionAfterSpace=false}) { @@ -606,6 +607,26 @@ export const CommandMap = { }, }), + addwidget: new Command({ + name: 'addwidget', + args: '', + description: _td('Adds a custom widget by URL to the room'), + runFn: function(roomId, args) { + if (!args || (!args.startsWith("https://") && !args.startsWith("http://"))) { + return reject(_t("Please supply a https:// or http:// widget URL")); + } + if (WidgetUtils.canUserModifyWidgets(roomId)) { + const userId = MatrixClientPeg.get().getUserId(); + const nowMs = (new Date()).getTime(); + const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`); + return success(WidgetUtils.setRoomWidget( + roomId, widgetId, "customwidget", args, "Custom Widget", {})); + } else { + return reject(_t("You cannot modify widgets in this room.")); + } + }, + }), + // Verify a user, device, and pubkey tuple verify: new Command({ name: 'verify', diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef4bc75d27..8adbf1a8d8 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -161,6 +161,9 @@ "Define the power level of a user": "Define the power level of a user", "Deops user with given id": "Deops user with given id", "Opens the Developer Tools dialog": "Opens the Developer Tools dialog", + "Adds a custom widget by URL to the room": "Adds a custom widget by URL to the room", + "Please supply a https:// or http:// widget URL": "Please supply a https:// or http:// widget URL", + "You cannot modify widgets in this room.": "You cannot modify widgets in this room.", "Verifies a user, device, and pubkey tuple": "Verifies a user, device, and pubkey tuple", "Unknown (user, device) pair:": "Unknown (user, device) pair:", "Device already verified!": "Device already verified!", From f2b64a8e7fe3c3b9614bb99789c1efa616d99a31 Mon Sep 17 00:00:00 2001 From: YaoiFangirl420 <48789208+YaoiFangirl420@users.noreply.github.com> Date: Sun, 24 Mar 2019 02:05:04 -0700 Subject: [PATCH 090/481] Add blocks around homeserver and identity server urls To make the urls visually distinct from the surrounding non-url text Signed-off-by: YaoiFangirl420 <48789208+YaoiFangirl420@users.noreply.github.com> --- .../views/settings/tabs/user/HelpUserSettingsTab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js index d001a3f2e6..e45b0d0389 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.js @@ -235,8 +235,8 @@ export default class HelpUserSettingsTab extends React.Component {
      {_t("Advanced")}
      - {_t("Homeserver is")} {MatrixClientPeg.get().getHomeserverUrl()}
      - {_t("Identity Server is")} {MatrixClientPeg.get().getIdentityServerUrl()}
      + {_t("Homeserver is")} {MatrixClientPeg.get().getHomeserverUrl()}
      + {_t("Identity Server is")} {MatrixClientPeg.get().getIdentityServerUrl()}
      {_t("Access Token:") + ' '} From 8f7170a4a161012ee3f84d6214836a8fc31cf1e6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 25 Mar 2019 12:45:51 +0100 Subject: [PATCH 091/481] add timeline profiling markers when updateheight and onscroll run --- src/components/structures/ScrollPanel.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index f00ff40155..ccf2e06f9f 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -195,6 +195,7 @@ module.exports = React.createClass({ this._saveScrollState(); this.checkFillState(); this.updatePreventShrinking(); + console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()})); this.props.onScroll(ev); }, @@ -596,6 +597,7 @@ module.exports = React.createClass({ const bottomDiff = newBottomOffset - scrollState.bottomOffset; this._bottomGrowth += bottomDiff; scrollState.bottomOffset = newBottomOffset; + console.timeStamp("restoreSavedScrollState:" + JSON.stringify({bd: bottomDiff, lh: this._getListHeight()})); itemlist.style.height = `${this._getListHeight()}px`; debuglog("balancing height because messages below viewport grew by "+bottomDiff+"px"); } @@ -635,6 +637,7 @@ module.exports = React.createClass({ itemlist.style.height = `${newHeight}px`; sn.scrollTop = sn.scrollHeight; debuglog("updateHeight to", newHeight); + console.timeStamp("updateHeight: to bottom"); } else if (scrollState.trackedScrollToken) { const trackedNode = this._getTrackedNode(); // if the timeline has been reloaded @@ -654,6 +657,7 @@ module.exports = React.createClass({ const topDiff = newTop - oldTop; sn.scrollTop = preexistingScrollTop + topDiff; debuglog("updateHeight to", {newHeight, topDiff, preexistingScrollTop}); + console.timeStamp("updateHeight:" + JSON.stringify({nh: newHeight, td: topDiff, st: preexistingScrollTop})); } } }, From 3e676454b67a563ad5677e3f1d2f6ba67ec8b561 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 25 Mar 2019 11:33:31 -0600 Subject: [PATCH 092/481] Update src/components/views/dialogs/TimelineExplosionDialog.js Co-Authored-By: turt2live --- src/components/views/dialogs/TimelineExplosionDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/TimelineExplosionDialog.js b/src/components/views/dialogs/TimelineExplosionDialog.js index 5c8fba8f9c..a6c6dc5fb2 100644 --- a/src/components/views/dialogs/TimelineExplosionDialog.js +++ b/src/components/views/dialogs/TimelineExplosionDialog.js @@ -53,7 +53,7 @@ export default class TimelineExplosionDialog extends React.Component { sendLogs: true, progressCallback: this._sendProgressCallback, }).then(() => { - console.log("logs sent for timeline explosion - reloading riot"); + console.log("Logs sent for timeline explosion - reloading Riot"); window.location.reload(); }, (err) => { console.error("Error sending logs for timeline explosion - reloading anyways. ", err); From 1e5c0a871314d3874fa5c820bd3922da4aa7bf48 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 25 Mar 2019 11:56:49 -0600 Subject: [PATCH 093/481] Apply suggestions from code review Co-Authored-By: turt2live --- src/components/views/dialogs/TimelineExplosionDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/TimelineExplosionDialog.js b/src/components/views/dialogs/TimelineExplosionDialog.js index a6c6dc5fb2..6e810d0421 100644 --- a/src/components/views/dialogs/TimelineExplosionDialog.js +++ b/src/components/views/dialogs/TimelineExplosionDialog.js @@ -56,7 +56,7 @@ export default class TimelineExplosionDialog extends React.Component { console.log("Logs sent for timeline explosion - reloading Riot"); window.location.reload(); }, (err) => { - console.error("Error sending logs for timeline explosion - reloading anyways. ", err); + console.error("Error sending logs for timeline explosion - reloading anyways.", err); window.location.reload(); }); }); @@ -89,7 +89,7 @@ export default class TimelineExplosionDialog extends React.Component {

      {_t( "Riot has run into a problem which makes it difficult to show you " + - "your messages right now. Nothing has been lost, and reloading the app " + + "your messages right now. Nothing has been lost and reloading the app " + "should fix this for you. In order to assist us in troubleshooting the " + "problem, we'd like to take a look at your debug logs. You do not need " + "to send your logs unless you want to, but we would really appreciate " + From 43291c708d5677ab8890977c5ecff621c383e32c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 25 Mar 2019 11:58:11 -0600 Subject: [PATCH 094/481] i18n --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0d0dad74ba..f67eda9614 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1174,7 +1174,7 @@ "Link to selected message": "Link to selected message", "COPY": "COPY", "Error showing you your room": "Error showing you your room", - "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost, and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.": "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost, and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.", + "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.": "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.", "Send debug logs and reload Riot": "Send debug logs and reload Riot", "Reload Riot without sending logs": "Reload Riot without sending logs", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.", From 69fcebf045863a9196eea2d9ed18948b3a876212 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 25 Mar 2019 21:14:21 -0600 Subject: [PATCH 095/481] Use allow/deny instead of whitelist/blacklist for terminology --- src/WidgetMessaging.js | 4 ++-- .../views/dialogs/WidgetOpenIDPermissionsDialog.js | 6 +++--- src/settings/Settings.js | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/WidgetMessaging.js b/src/WidgetMessaging.js index 8d419ba6eb..1d8e1b9cd3 100644 --- a/src/WidgetMessaging.js +++ b/src/WidgetMessaging.js @@ -131,11 +131,11 @@ export default class WidgetMessaging { const widgetSecurityKey = WidgetUtils.getWidgetSecurityKey(this.widgetId, this.widgetUrl, this.isUserWidget); const settings = SettingsStore.getValue("widgetOpenIDPermissions"); - if (settings.blacklist && settings.blacklist.includes(widgetSecurityKey)) { + if (settings.deny && settings.deny.includes(widgetSecurityKey)) { this.fromWidget.sendResponse(rawEv, {state: "blocked"}); return; } - if (settings.whitelist && settings.whitelist.includes(widgetSecurityKey)) { + if (settings.allow && settings.allow.includes(widgetSecurityKey)) { const responseBody = {state: "allowed"}; const credentials = await MatrixClientPeg.get().getOpenIdToken(); Object.assign(responseBody, credentials); diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index 5f341261f8..62bd1d2521 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -51,14 +51,14 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component { console.log(`Remembering ${this.props.widgetId} as allowed=${allowed} for OpenID`); const currentValues = SettingsStore.getValue("widgetOpenIDPermissions"); - if (!currentValues.whitelist) currentValues.whitelist = []; - if (!currentValues.blacklist) currentValues.blacklist = []; + if (!currentValues.allow) currentValues.allow = []; + if (!currentValues.deny) currentValues.deny = []; const securityKey = WidgetUtils.getWidgetSecurityKey( this.props.widgetId, this.props.widgetUrl, this.props.isUserWidget); - (allowed ? currentValues.whitelist : currentValues.blacklist).push(securityKey); + (allowed ? currentValues.allow : currentValues.deny).push(securityKey); SettingsStore.setValue("widgetOpenIDPermissions", null, SettingLevel.DEVICE, currentValues); } diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 765b2f85c6..6e17ffbbd7 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -343,8 +343,8 @@ export const SETTINGS = { "widgetOpenIDPermissions": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, default: { - whitelist: [], - blacklist: [], + allow: [], + deny: [], }, }, "RoomList.orderByImportance": { From d8edf2e3fbf74da3c135f034516d27acfacbc296 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 25 Mar 2019 23:02:25 -0600 Subject: [PATCH 096/481] Handle all the segments of a v3 event ID They may contain slashes, so it is not suitable to just pull the first segment after the room ID. Instead, we just recompile the event ID from known source, assuming everything afterwards is an event ID. Fixes https://github.com/vector-im/riot-web/issues/8315 This will need adapting to support https://github.com/vector-im/riot-web/issues/9149 --- src/components/structures/MatrixChat.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index df4d0075e6..e810a01928 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1561,7 +1561,16 @@ export default React.createClass({ } else if (screen.indexOf('room/') == 0) { const segments = screen.substring(5).split('/'); const roomString = segments[0]; - const eventId = segments[1]; // undefined if no event id given + let eventId = segments.splice(1).join("/"); // empty string if no event id given + + // Previously we pulled the eventID from the segments in such a way + // where if there was no eventId then we'd get undefined. However, we + // now do a splice and join to handle v3 event IDs which results in + // an empty string. To maintain our potential contract with the rest + // of the app, we coerce the eventId to be undefined where applicable. + if (!eventId) eventId = undefined; + + // TODO: Handle encoded room/event IDs: https://github.com/vector-im/riot-web/issues/9149 // FIXME: sort_out caseConsistency const thirdPartyInvite = { From bc0f13154c49c90767418b3579426859bb42f6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Mon, 18 Mar 2019 18:10:57 +0000 Subject: [PATCH 097/481] Translated using Weblate (Slovak) Currently translated at 96.6% (1506 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 152 +++++++++++++++++++++++++++++++++++---- 1 file changed, 139 insertions(+), 13 deletions(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 35aed8b445..1c7d00fd68 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -1352,13 +1352,13 @@ "Add some now": "Pridajte si nejaké teraz", "Please review and accept all of the homeserver's policies": "Prosím, prečítajte si a odsúhlaste všetky podmienky tohoto domovského servera", "Please review and accept the policies of this homeserver:": "Prosím, prečítajte si a odsúhlaste podmienky používania tohoto domovského servera:", - "Failed to load group members": "Nepodarilo sa načítať zoznam členov skupiny", - "That doesn't look like a valid email address": "Toto nevyzerá byť platná emailová adresa", + "Failed to load group members": "Nepodarilo sa načítať členov skupiny", + "That doesn't look like a valid email address": "Zdá sa, že toto nie je platná emailová adresa", "The following users may not exist": "Nasledujúci používatelia pravdepodobne neexistujú", "The following users may not exist - would you like to invite them anyways?": "Nie je možné určiť, či nasledujúci používatelia skutočne existujú - chcete ich napriek tomu pozvať?", "Invite anyways and never warn me again": "Napriek tomu pozvať a v budúcnosti ma viac neupozorňovať", "Invite anyways": "Napriek tomu pozvať", - "Unable to load commit detail: %(msg)s": "Nie je možné načítať podrobnosti commit: %(msg)s", + "Unable to load commit detail: %(msg)s": "Nie je možné načítať podrobnosti pre commit: %(msg)s", "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Aby ste po odhlásení neprišli o možnosť čítať históriu šifrovaných konverzácií, mali by ste si ešte pred odhlásením exportovať šifrovacie kľúče miestností. Prosím vráťte sa k novšej verzii Riot a exportujte si kľúče", "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Už ste použili novšiu verziu Riot na adrese %(host)s. Ak chcete znovu používať túto verziu aj s E2E šifrovaním, musíte sa odhlásiť a potom zas znovu prihlásiť. ", "Incompatible Database": "Nekompatibilná databáza", @@ -1376,7 +1376,7 @@ "Failed to decrypt %(failedCount)s sessions!": "Nepodarilo sa dešifrovať %(failedCount)s relácií!", "Restored %(sessionCount)s session keys": "Obnovených %(sessionCount)s kľúčov relácií", "Enter Recovery Passphrase": "Zadajte heslo bezpečného obnovenia", - "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Vložením vlastného hesla pre bezpečné obnovenie správ, si nastavíte Bezpečnú obnovu správ, aby ste mali neustále prístup k zašifrovaným konverzáciám.", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Zabezpečte svoju komunikáciu a prístup k šifrovanej histórii konverzácií zadaním hesla obnovenia.", "Waiting for %(userId)s to accept...": "Čakanie na prijatie od používateľa %(userId)s…", "Waiting for %(userId)s to confirm...": "Čakanie na potvrdenie od používateľa %(userId)s…", "Prompt before sending invites to potentially invalid matrix IDs": "Upozorniť pred odoslaním pozvaní na potenciálne neexistujúce Matrix ID", @@ -1384,9 +1384,9 @@ "Invite anyway and never warn me again": "Napriek tomu pozvať a viac neupozorňovať", "Invite anyway": "Napriek tomu pozvať", "Next": "Ďalej", - "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Ak ste zabudli heslo bezpečného obnovenia, môžete použiť kľúč alebo nastaviť obnovenie znovu", - "Enter Recovery Key": "Zadajte kľúč bezpečného obnovenia", - "This looks like a valid recovery key!": "Toto vyzerá ako platný kľúč obnovenia!", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Ak ste zabudli heslo obnovenia, môžete použiť kľúč obnovenia alebo nastaviť bezpečné obnovenie znovu", + "Enter Recovery Key": "Zadajte kľúč obnovenia", + "This looks like a valid recovery key!": "Zdá sa, že toto je platný kľúč obnovenia!", "Not a valid recovery key": "Neplatný kľúč obnovenia", "Access your secure message history and set up secure messaging by entering your recovery key.": "Zabezpečte svoju komunikáciu a prístup k šifrovanej histórii konverzácií zadaním kľúča obnovenia.", "If you've forgotten your recovery passphrase you can ": "Ak ste zabudli heslo obnovenia, ", @@ -1395,7 +1395,7 @@ "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Ste správcom tejto komunity. Nebudete môcť znovu vstúpiť bez pozvania od iného správcu.", "You are currently using Riot anonymously as a guest.": "Momentálne používate Riot anonymne ako hosť.", "If you would like to create a Matrix account you can register now.": "Ak si chcete vytvoriť účet Matrix, môžete sa zaregistrovať teraz.", - "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Neplatná konfigurácia: nie je možné poskytnúť predvolenú URL adresu ani názov domovského servera", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Neplatná konfigurácia: nie je možné zistiť predvolenú URL adresu ani názov domovského servera", "Unknown error discovering homeserver": "Neznáma chyba pri zisťovaní domovského servera", "%(count)s Notifications|other": "%(count)s oznámení", "%(count)s Notifications|one": "%(count)s oznámenie", @@ -1405,7 +1405,7 @@ "Invalid identity server discovery response": "Neplatná odpoveď pri zisťovaní servera totožností", "General failure": "Všeobecná chyba", "Failed to perform homeserver discovery": "Nepodarilo sa zistiť adresu domovského servera", - "Unknown failure discovering homeserver": "Neznáma chyba pri zisťovaní domovského servera", + "Unknown failure discovering homeserver": "Neznáma chyba pri zisťovaní vlastností domovského servera", "Sign in with single sign-on": "Prihlásiť sa pomocou jediného prihlasovania", "Great! This passphrase looks strong enough.": "Výborne! Toto je dostatočne silné heslo.", "Secure your encrypted message history with a Recovery Passphrase.": "Zabezpečte si históriu šifrovaných konverzácií zadaním hesla.", @@ -1448,7 +1448,7 @@ "New Recovery Method": "Nový spôsob obnovi", "A new recovery passphrase and key for Secure Messages has been detected.": "Bolo nájdené nové heslo a kľúč Bezpečného obnovenia správ.", "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Nastavením Bezpečného obnovenia správ na tomto zariadení znovu zašifrujete históriu šifrovaných konverzácií novou metódov obnovenia.", - "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.": "Ak ste si nenastavili nový spôsob obnovenia útočníci sa môžu pokúsiť dostať k vášmu účtu. Ihneď si v nastaveniach zmente heslo a nastavte nový spôsob obnovi.", + "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.": "Ak ste si nenastavili nový spôsob obnovenia útočníci sa môžu pokúsiť dostať k vášmu účtu. Ihneď si v nastaveniach zmeňte heslo a znovu si nastavte možnosti obnovenia.", "Set up Secure Messages": "Nastaviť bezpečné obnovenie správ", "Go to Settings": "Otvoriť nastavenia", "Whether or not you're logged in (we don't record your username)": "Či ste alebo nie ste prihlásení (nezaznamenávame vaše meno používateľa)", @@ -1464,7 +1464,7 @@ "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s nastavil vstup do miestnosti len pre pozvaných.", "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s zmenil podmienku vstupu na %(rule)s", "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s umožnil hosťom vstúpiť do miestnosti.", - "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s zamedzil hosťom vstúpiť do miestnosti", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s zamedzil hosťom vstúpiť do miestnosti.", "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s zmenil prístup hostí na %(rule)s", "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s aktivoval zobrazenie členstva v komunite %(groups)s pre túto miestnosť.", "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s deaktivoval zobrazenie členstva v komunite %(groups)s pre túto miestnosť.", @@ -1570,7 +1570,7 @@ "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Poslali sme vám email, aby sme mohli overiť vašu adresu. Postupujte podľa odoslaných inštrukcií a potom klepnite na nižšie zobrazené tlačidlo.", "Email Address": "Emailová adresa", "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Ste si istí? Ak nemáte správne zálohované šifrovacie kľúče, prídete o históriu šifrovaných konverzácií.", - "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Šifrované správy sú zabezpečené E2E šifrov. Ku kľúčom určeným na čítanie týchto správ máte prístup len vy a adresát(i) týchto správ.", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Šifrované správy sú zabezpečené E2E šifrov. Ku kľúčom potrebných na ich čítanie máte prístup len vy a ich adresát(i).", "Restore from Backup": "Obnoviť zo zálohy", "This device is backing up your keys. ": "Kľúče z tohoto zariadenia sú zálohované. ", "This device is not backing up your keys.": "Kľúče z tohoto zariadenia nie sú zálohované.", @@ -1656,5 +1656,131 @@ "All devices for this user are trusted": "Všetky zariadenia tohoto používateľa sú dôverihodné", "All devices in this encrypted room are trusted": "Všetky zariadenia v tejto šifrovanej miestnosti sú dôverihodné", "Use Key Backup": "Použiť zálohovanie kľúčov", - "Never lose encrypted messages": "Nikdy neprídete o zašifrované správy" + "Never lose encrypted messages": "Nikdy neprídete o zašifrované správy", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Správy v tejto miestnosti sú zabezpečené E2E šifrov. Ku kľúčom potrebných na ich čítanie máte prístup len vy a ich adresát(i).", + "Securely back up your keys to avoid losing them. Learn more.": "Bezpečne si zálohujte šifrovacie kľúče, aby ste o ne neprišli. Zistiť viac.", + "Not now": "Teraz nie", + "Don't ask me again": "Viac sa nepýtať", + "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "Táto miestnosť používa nestabilnú verziu. Ak tento stav neočakávate, aktualizujte miestnosť prosím.", + "Click here to upgrade to the latest room version.": "Kliknutím aktualizujete na najnovšiu verziu miestnosti.", + "Error updating main address": "Chyba pri aktualizácii hlavnej adresy", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Pri aktualizácii hlavnej adresy miestnosti nastala chyba. Nie je to povolené na servery, alebo sa jedná o dočasný problém.", + "Error creating alias": "Chyba pri pridávaní aliasu", + "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "Pri pridávaní tohoto aliasu nastala chyba. Nie je to povolené na servery, alebo sa jedná o dočasný problém.", + "Error removing alias": "Chyba pri odstraňovaní aliasu", + "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Pri odstraňovaní tohoto aliasu nastala chyba. Alias už neexistuje, alebo sa jedná o dočasný problém.", + "Main address": "Hlavná adresa", + "Error updating flair": "Chyba pri aktualizácii zobrazenia členstva", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Pri aktualizácii zobrazenia členstva v skupinách v tejto miestnosti nastala chyba. Nie je to povolené na servery, alebo sa jedná o dočasný problém.", + "Room avatar": "Obrázok miestnosti", + "Upload room avatar": "Nahrať obrázok miestnosti", + "No room avatar": "Žiadny obrázok miestnosti", + "Room Name": "Názov miestnosti", + "Room Topic": "Téma miestnosti", + "Join": "Vstúpiť", + "Power level": "Úroveň moci", + "Use Legacy Verification (for older clients)": "Použiť pôvodný spôsob overenia (kompatibilný so staršími aplikáciami)", + "Verify by comparing a short text string.": "Overiť porovnaním krátkeho textového reťazca.", + "Begin Verifying": "Začať overenie", + "Waiting for partner to accept...": "Čakanie na prijatie od partnera…", + "Nothing appearing? Not all clients support interactive verification yet. .": "Nič sa nezobrazuje? Ešte nie všetky aplikácie podporujú interaktívne overenie. .", + "Use two-way text verification": "Použiť obojsmerné textové overenie", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Overte tohoto používateľa a označte ho ako dôveryhodného. Dôverovanie používateľov pridáva pokoj na duši pri posielaní E2E šifrovaných správ.", + "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Overením tohoto používateľa označíte jeho zariadenia ako dôverihodné pre vás a vaše zariadenia ako dôverihodné pre neho.", + "Waiting for partner to confirm...": "Čakanie na potvrdenie od partnera…", + "Incoming Verification Request": "Prichádzajúca žiadosť o overenie", + "I don't want my encrypted messages": "Nezáleží mi na zašifrovaných správach", + "Manually export keys": "Ručne exportovať kľúče", + "You'll lose access to your encrypted messages": "Stratíte prístup ku zašifrovaným správam", + "Are you sure you want to sign out?": "Naozaj sa chcete odhlásiť?", + "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Ak spozorujete chyby, alebo sa s nami chcete podeliť o spätnú väzbu, dajte nám vedieť cez Github.", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Prosím nezakladajte duplicity. Pozrite si najprv existujúce hlásenia, pridajte k nim +1 alebo svoje komentáre a až ak neviete nájsť hlásenie svojho problému, vytvorte nové hlásenie.", + "Report bugs & give feedback": "Nahlasovanie chýb & spätná väzba", + "Go back": "Naspäť", + "Room Settings - %(roomName)s": "Nastavenia miestnosti - %(roomName)s", + "A username can only contain lower case letters, numbers and '=_-./'": "Meno používateľa môže obsahovať len malé písmená, číslice a znaky „=_-./“", + "Recovery Key Mismatch": "Kľúče obnovenia sa nezhodujú", + "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Zálohu nie je možné dešifrovať zadaným kľúčom. Prosím, uistite sa, že ste zadali správny kľúč obnovenia.\nBackup could not be decrypted with this key: please verify that you entered the correct recovery key.", + "Incorrect Recovery Passphrase": "Nesprávne heslo obnovenia", + "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Zálohu nie je možné dešifrovať zadaným heslom. Prosím, uistite sa, že ste zadali správne heslo obnovenia.", + "Warning: you should only set up key backup from a trusted computer.": "Pozor: Zálohovanie šifrovacích kľúčov by ste mali nastavovať na dôverihodnom počítači.", + "Share Permalink": "Zdieľať trvalý odkaz", + "Update status": "Aktualizovať stav", + "Set status": "Nastaviť stav", + "Hide": "Skryť", + "This homeserver would like to make sure you are not a robot.": "Tento domovský server by sa rád uistil, že nie ste robot.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "Vlastné nastavenia servera môžete použiť na pripojenie k inému domovskému serveru Matrix zadaním URL adresy. Umožní vám to prihlásiť sa cez túto aplikáciu k existujúcemu Matrix účtu na inom domovskom servery.", + "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Môžete tiež nastaviť vlastnú adresu servera totožností, potom ale nebudete môcť pozývať používateľov zadaním ich emailovej adresy a ani oni nebudú môcť pozývať vás zadaním vašej emailovej adresy.", + "Your Modular server": "Váš server Modular", + "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Zadajte umiestnenie vášho domovského servera modular. Môže to byť buď vaša doména alebo subdoména modular.im.", + "Server Name": "Názov servera", + "The username field must not be blank.": "Pole meno používateľa nesmie ostať prázdne.", + "Username": "Meno používateľa", + "Not sure of your password? Set a new one": "Nie ste si istí vašim heslom? Nastavte si nové", + "Sign in to your Matrix account": "Prihláste sa k svojmu Matrix účtu", + "Sign in to your Matrix account on %(serverName)s": "Prihláste sa k svojmu Matrix účtu na servery %(serverName)s", + "Change": "Zmeniť", + "Create your Matrix account": "Vytvorte si účet Matrix", + "Create your Matrix account on %(serverName)s": "Vytvorte si Matrix účet na servery %(serverName)s", + "Email (optional)": "Email (nepovinné)", + "Phone (optional)": "Telefón (nepovinné)", + "Confirm": "Potvrdiť", + "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Ak zadáte emailovú adresu, budete ju môcť použiť na obnovenie účtu. Ostatní používatelia vás môžu pozývať do miestností zadaním vašich kontaktných údajov.", + "Other servers": "Ostatné servery", + "Enter custom server URLs What does this mean?": "Zadajte vlastné URL adresy serverov Čo to znamená?", + "Homeserver URL": "URL adresa domovského servera", + "Identity Server URL": "URL adresa servera totožností", + "Free": "Zdarma", + "Join millions for free on the largest public server": "Pripojte sa k mnohým používateľom najväčšieho verejného domovského servera zdarma", + "Premium": "Premium", + "Premium hosting for organisations Learn more": "Platený hosting pre organizácie Zistiť viac", + "Other": "Ďalšie", + "Find other public servers or use a custom server": "Nájdite ďalšie verejné domovské servery alebo nastavte pripojenie k serveru ručne", + "Please install Chrome, Firefox, or Safari for the best experience.": "Pre najlepší zážitok si prosím nainštalujte Chrome, Firefox alebo Safari.", + "Couldn't load page": "Nie je možné načítať stránku", + "Want more than a community? Get your own server": "Chceli by ste viac než komunitu? Získajte vlastný server", + "This homeserver does not support communities": "Tento domovský server nepodporuje komunity", + "You are logged in to another account": "Ste prihlásení k inému účtu", + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Ďakujeme za overenie vašej emailovej adresy! Práve ste prihlásený ako používateľ (%(sessionUserId)s) nie ako používateľ, ktorému ste práve overili emailovú adresu (%(verifiedUserId)s). Ak sa chcete prihlásiť ako %(verifiedUserId2)s, prosím, najprv sa odhláste.", + "Failed to get protocol list from homeserver": "Nepodarilo sa získať zoznam protokolov z domovského servera", + "The homeserver may be too old to support third party networks": "Tento domovský server je pravdepodobne zastaralý a preto nemusí podporovať siete tretích strán.", + "Search for a room like #example": "Hľadať miestnosť ako je #priklad", + "Guest": "Hosť", + "Could not load user profile": "Nie je možné načítať profil používateľa", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Zmena hesla spôsobí obnovenie E2E šifrovacích kľúčov na všetkých vašich zariadeniach a história šifrovaných konverzácií sa tak pre vás môže stať nečitateľná. Pred obnovením hesla si prosím nastavte zálohovanie šifrovacích kľúčov alebo si E2E kľúče exportujte na inom zariadení.", + "Your Matrix account": "Váš Matrix účet", + "Your Matrix account on %(serverName)s": "Váš Matrix účet na serveri %(serverName)s", + "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.": "Zdá sa, že zadaná adresa domovského servera %(hsUrl)s nie je platná. Prosím, zadajte platnú URL adresu začínajúcu prefixom protokolu (napr. https://).", + "A verification email will be sent to your inbox to confirm setting your new password.": "Na emailovú adresu vám odošleme overovaciu správu, aby bolo možné potvrdiť nastavenie vašeho nového hesla.", + "Sign in instead": "Radšej sa prihlásiť", + "Your password has been reset.": "Vaše heslo bolo obnovené.", + "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Boli ste odhlásení zo všetkých zariadení a nebudú sa vám viac zobrazovať okamžité oznámenia. Ak chcete zobrazovať oznámenia, musíte sa na každom zariadení znovu prihlásiť.", + "Set a new password": "Nastaviť nové heslo", + "This homeserver does not support login using email address.": "Tento domovský server nepodporuje prihlásenie sa zadaním emailovej adresy.", + "Guest access is disabled on this homeserver.": "Na tomto domovskom servery nie je povolený prístup pre hostí.", + "Create account": "Vytvoriť účet", + "Registration has been disabled on this homeserver.": "Na tomto domovskom servery nie je povolená registrácia.", + "Unable to query for supported registration methods.": "Nie je možné požiadať o podporované metódy registrácie.", + "You need to enter a username.": "Musíte zadať meno používateľa.", + "Create your account": "Vytvoriť váš účet", + "Keep going...": "Pokračujte…", + "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.": "Zašifrovanú kópiu vašich šifrovacích kľúčov uchováme na domovskom servery. Zabezpečte si zálohovanie zadaním hesla obnovenia, čo posilní ochranu vašich údajov.", + "For maximum security, this should be different from your account password.": "Aby ste zachovali maximálnu mieru zabezpečenia, heslo obnovenia by malo byť odlišné ako heslo, ktorým sa prihlasujete do Matrix účtu.", + "Set up with a Recovery Key": "Nastaviť použitím kľúča obnovenia", + "Please enter your passphrase a second time to confirm.": "Prosím zadajte heslo obnovenia ešte raz pre potvrdenie.", + "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.": "Kľúč obnovenia je bezpečnostný mechanizmus - môžete ho použiť na prístup k šifrovacím kľúčom v prípade, ak zabudnete vaše heslo obnovenia.", + "Keep your recovery key somewhere very secure, like a password manager (or a safe)": "Kľúč obnovenia si bezpečne uchovajte, použite napr. správcu hesiel (alebo ho schovajte v trezore)", + "Your keys are being backed up (the first backup could take a few minutes).": "Zálohovanie kľúčov (prvé zálohovanie môže trvať niekoľko minút).", + "Okay": "OK", + "Secure your backup with a passphrase": "Zabezpečte si zálohu zadaním hesla obnovenia", + "Confirm your passphrase": "Potvrdiť heslo obnovenia", + "Recovery key": "Kľúč obnovenia", + "Starting backup...": "Začína sa zálohovanie…", + "Success!": "Hotovo!", + "A new recovery passphrase and key for Secure Messages have been detected.": "Boli zistené nový kľúč a nové heslo obnovenia zálohovania šifrovacích kľúčov.", + "This device is encrypting history using the new recovery method.": "Toto zariadenie šifruje históriu použitím novej metódy obnovenia.", + "Recovery Method Removed": "Odstránený spôsob obnovenia", + "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "Na tomto zariadení bolo zistené, že heslo a kľúč obnovenia šifrovacích kľúčov zo zálohy boli odstránené.", + "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "Ak ste ich odstránili omylom, môžete si obnovenie nastaviť znovu, čo zašifruje zálohy použitím novej metódy.", + "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.": "Ak ste spôsob obnovenia neodstránili vy, útočník sa pravdepodobne usiluje dostať k vašemu účtu. Zmente si prosím heslo na prihlásenie do Matrix účtu a znovu si ihneď nastavte možnosti obnovenia." } From 18b5041ed21cb99d54e44c3aca3f664277842b06 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 26 Mar 2019 12:19:30 +0100 Subject: [PATCH 098/481] try filling async instead of sync in scroll handler see if that avoids jumps --- src/components/structures/ScrollPanel.js | 49 +++++++++++++++++++----- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index ccf2e06f9f..eaf3e26db7 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -21,7 +21,7 @@ import { KeyCode } from '../../Keyboard'; import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; -const DEBUG_SCROLL = false; +const DEBUG_SCROLL = true; // The amount of extra scroll distance to allow prior to unfilling. // See _getExcessHeight. @@ -193,10 +193,10 @@ module.exports = React.createClass({ debuglog("onScroll", this._getScrollNode().scrollTop); this._scrollTimeout.restart(); this._saveScrollState(); - this.checkFillState(); this.updatePreventShrinking(); console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()})); this.props.onScroll(ev); + this.checkFillState(); }, onResize: function() { @@ -270,11 +270,12 @@ module.exports = React.createClass({ }, // check the scroll state and send out backfill requests if necessary. - checkFillState: function() { + checkFillState: async function(depth=0) { if (this.unmounted) { return; } + const isFirstCall = depth === 0; const sn = this._getScrollNode(); // if there is less than a screenful of messages above or below the @@ -301,16 +302,46 @@ module.exports = React.createClass({ // `---------' - // + if (isFirstCall) { + if (this._isFilling) { + debuglog("_isFilling: not entering while request is ongoing, marking for a subsequent request"); + this._fillRequestWhileRunning = true; + return; + } + debuglog("_isFilling: setting"); + this._isFilling = true; + } + + const contentHeight = this._getMessagesHeight(); const contentTop = contentHeight - this._getListHeight(); const contentScrollTop = sn.scrollTop + contentTop; + const fillPromises = []; + if (contentScrollTop < sn.clientHeight) { // need to back-fill - this._maybeFill(true); + fillPromises.push(this._maybeFill(depth, true)); } if (contentScrollTop > contentHeight - sn.clientHeight * 2) { // need to forward-fill - this._maybeFill(false); + fillPromises.push(this._maybeFill(depth, false)); + } + + if (fillPromises.length) { + try { + await Promise.all(fillPromises); + } catch (err) { + console.error(err); + } + } + if (isFirstCall) { + debuglog("_isFilling: clearing"); + this._isFilling = false; + } + + if (this._fillRequestWhileRunning) { + this._fillRequestWhileRunning = false; + this.checkFillState(); } }, @@ -364,7 +395,7 @@ module.exports = React.createClass({ }, // check if there is already a pending fill request. If not, set one off. - _maybeFill: function(backwards) { + _maybeFill: function(depth, backwards) { const dir = backwards ? 'b' : 'f'; if (this._pendingFillRequests[dir]) { debuglog("Already a "+dir+" fill in progress - not starting another"); @@ -377,7 +408,7 @@ module.exports = React.createClass({ // events) so make sure we set this before firing off the call. this._pendingFillRequests[dir] = true; - Promise.try(() => { + return new Promise(resolve => setTimeout(resolve, 1)).then(() => { return this.props.onFillRequest(backwards); }).finally(() => { this._pendingFillRequests[dir] = false; @@ -393,9 +424,9 @@ module.exports = React.createClass({ // further pagination requests have been disabled until now, so // it's time to check the fill state again in case the pagination // was insufficient. - this.checkFillState(); + return this.checkFillState(depth + 1); } - }).done(); + }); }, /* get the current scroll state. This returns an object with the following From 82a9b348c05d42f6148229aa4498b4aa0508458c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 26 Mar 2019 13:34:55 +0100 Subject: [PATCH 099/481] add some comments and initialization for async filling --- src/components/structures/ScrollPanel.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index eaf3e26db7..7ae102eb4b 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -154,6 +154,8 @@ module.exports = React.createClass({ }, componentWillMount: function() { + this._fillRequestWhileRunning = false; + this._isFilling = false; this._pendingFillRequests = {b: null, f: null}; if (this.props.resizeNotifier) { @@ -302,6 +304,10 @@ module.exports = React.createClass({ // `---------' - // + // as filling is async and recursive, + // don't allow more than 1 chain of calls concurrently + // do make a note when a new request comes in while already running one, + // so we can trigger a new chain of calls once done. if (isFirstCall) { if (this._isFilling) { debuglog("_isFilling: not entering while request is ongoing, marking for a subsequent request"); @@ -408,6 +414,10 @@ module.exports = React.createClass({ // events) so make sure we set this before firing off the call. this._pendingFillRequests[dir] = true; + // wait 1ms before paginating, because otherwise + // this will block the scroll event handler for +700ms + // if messages are already cached in memory, + // This would cause jumping to happen on Chrome/macOS. return new Promise(resolve => setTimeout(resolve, 1)).then(() => { return this.props.onFillRequest(backwards); }).finally(() => { From 805539fdc740bcdd98852348c56b68e41e3c3040 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 26 Mar 2019 13:44:39 +0100 Subject: [PATCH 100/481] remove timestamp logging in profiler --- src/components/structures/ScrollPanel.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 7ae102eb4b..ba67468fbb 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -196,7 +196,6 @@ module.exports = React.createClass({ this._scrollTimeout.restart(); this._saveScrollState(); this.updatePreventShrinking(); - console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()})); this.props.onScroll(ev); this.checkFillState(); }, @@ -638,9 +637,8 @@ module.exports = React.createClass({ const bottomDiff = newBottomOffset - scrollState.bottomOffset; this._bottomGrowth += bottomDiff; scrollState.bottomOffset = newBottomOffset; - console.timeStamp("restoreSavedScrollState:" + JSON.stringify({bd: bottomDiff, lh: this._getListHeight()})); itemlist.style.height = `${this._getListHeight()}px`; - debuglog("balancing height because messages below viewport grew by "+bottomDiff+"px"); + debuglog("balancing height because messages below viewport grew by", bottomDiff); } } if (!this._heightUpdateInProgress) { @@ -678,7 +676,6 @@ module.exports = React.createClass({ itemlist.style.height = `${newHeight}px`; sn.scrollTop = sn.scrollHeight; debuglog("updateHeight to", newHeight); - console.timeStamp("updateHeight: to bottom"); } else if (scrollState.trackedScrollToken) { const trackedNode = this._getTrackedNode(); // if the timeline has been reloaded @@ -698,7 +695,6 @@ module.exports = React.createClass({ const topDiff = newTop - oldTop; sn.scrollTop = preexistingScrollTop + topDiff; debuglog("updateHeight to", {newHeight, topDiff, preexistingScrollTop}); - console.timeStamp("updateHeight:" + JSON.stringify({nh: newHeight, td: topDiff, st: preexistingScrollTop})); } } }, From 90dbeefcfbc108499b31323244e805d6846b5b2b Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 25 Mar 2019 16:22:53 +0000 Subject: [PATCH 101/481] Remove unused option for disabling IndexedDB `createMatrixClient` and surrounding paths support an argument to disable IndexedDB, but it is never actually used. This removes the option to simplify the code. --- src/MatrixClientPeg.js | 4 ++-- src/utils/createMatrixClient.js | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index ad20988d9e..f5994921de 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -171,7 +171,7 @@ class MatrixClientPeg { return matches[1]; } - _createClient(creds: MatrixClientCreds, useIndexedDb) { + _createClient(creds: MatrixClientCreds) { const opts = { baseUrl: creds.homeserverUrl, idBaseUrl: creds.identityServerUrl, @@ -183,7 +183,7 @@ class MatrixClientPeg { verificationMethods: [verificationMethods.SAS] }; - this.matrixClient = createMatrixClient(opts, useIndexedDb); + this.matrixClient = createMatrixClient(opts); // we're going to add eventlisteners for each matrix event tile, so the // potential number of event listeners is quite high. diff --git a/src/utils/createMatrixClient.js b/src/utils/createMatrixClient.js index 040f1e96cb..dee9324460 100644 --- a/src/utils/createMatrixClient.js +++ b/src/utils/createMatrixClient.js @@ -32,23 +32,18 @@ try { * @param {Object} opts options to pass to Matrix.createClient. This will be * extended with `sessionStore` and `store` members. * - * @param {bool} useIndexedDb True to attempt to use indexeddb, or false to force - * use of the memory store. Default: true. - * * @property {string} indexedDbWorkerScript Optional URL for a web worker script * for IndexedDB store operations. By default, indexeddb ops are done on * the main thread. * * @returns {MatrixClient} the newly-created MatrixClient */ -export default function createMatrixClient(opts, useIndexedDb) { - if (useIndexedDb === undefined) useIndexedDb = true; - +export default function createMatrixClient(opts) { const storeOpts = { useAuthorizationHeader: true, }; - if (indexedDB && localStorage && useIndexedDb) { + if (indexedDB && localStorage) { storeOpts.store = new Matrix.IndexedDBStore({ indexedDB: indexedDB, dbName: "riot-web-sync", @@ -61,7 +56,7 @@ export default function createMatrixClient(opts, useIndexedDb) { storeOpts.sessionStore = new Matrix.WebStorageSessionStore(localStorage); } - if (indexedDB && useIndexedDb) { + if (indexedDB) { storeOpts.cryptoStore = new Matrix.IndexedDBCryptoStore( indexedDB, "matrix-js-sdk:crypto", ); From 46f5f872c4b12fa0c44e2e14e4d1762803f21456 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 26 Mar 2019 15:51:02 +0100 Subject: [PATCH 102/481] implement scrolling to a token (best effort) --- src/components/structures/ScrollPanel.js | 41 ++++++++++++------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index ba67468fbb..57185b08b0 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -546,38 +546,35 @@ module.exports = React.createClass({ /* Scroll the panel to bring the DOM node with the scroll token * `scrollToken` into view. * - * offsetBase gives the reference point for the bottomOffset. 0 means the + * offsetBase gives the reference point for the pixelOffset. 0 means the * top of the container, 1 means the bottom, and fractional values mean * somewhere in the middle. If omitted, it defaults to 0. * - * bottomOffset gives the number of pixels *above* the offsetBase that the + * pixelOffset gives the number of pixels *above* the offsetBase that the * node (specifically, the bottom of it) will be positioned. If omitted, it * defaults to 0. */ - scrollToToken: function(scrollToken, bottomOffset, offsetBase) { - bottomOffset = bottomOffset || 0; + scrollToToken: function(scrollToken, pixelOffset, offsetBase) { + pixelOffset = pixelOffset || 0; offsetBase = offsetBase || 0; - // convert bottomOffset so that it is based on the bottom of the - // container. - const scrollNode = this._getScrollNode(); - const viewportBottom = scrollNode.scrollHeight - (scrollNode.scrollTop + scrollNode.clientHeight); - bottomOffset += viewportBottom + scrollNode.clientHeight * (1-offsetBase); - - // save the desired scroll state. It's important we do this here rather - // than as a result of the scroll event, because (a) we might not *get* - // a scroll event, and (b) it might not currently be possible to set - // the requested scroll state (eg, because we hit the end of the - // timeline and need to do more pagination); we want to save the - // *desired* scroll state rather than what we end up achieving. + // set the trackedScrollToken so we can get the node through _getTrackedNode this.scrollState = { stuckAtBottom: false, trackedScrollToken: scrollToken, - bottomOffset: bottomOffset, }; - - // ... then make it so. - this._restoreSavedScrollState(); + const trackedNode = this._getTrackedNode(); + const scrollNode = this._getScrollNode(); + if (trackedNode) { + // set the scrollTop to the position we want. + // note though, that this might not succeed if the combination of offsetBase and pixelOffset + // would position the trackedNode towards the top of the viewport. + // This because when setting the scrollTop only 10 or so events might be loaded, + // not giving enough content below the trackedNode to scroll downwards + // enough so it ends up in the top of the viewport. + scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset; + this._saveScrollState(); + } }, _saveScrollState: function() { @@ -615,11 +612,13 @@ module.exports = React.createClass({ } const scrollToken = node.dataset.scrollTokens.split(',')[0]; debuglog("saving anchored scroll state to message", node && node.innerText, scrollToken); + const bottomOffset = this._topFromBottom(node); this.scrollState = { stuckAtBottom: false, trackedNode: node, trackedScrollToken: scrollToken, - bottomOffset: this._topFromBottom(node), + bottomOffset: bottomOffset, + pixelOffset: bottomOffset - viewportBottom, //needed for restoring the scroll position when coming back to the room }; }, From 40c210ad0ea0cd498f3bcec8c33baa5b5ab8444b Mon Sep 17 00:00:00 2001 From: Eden Tyler-Moss Date: Tue, 26 Mar 2019 15:06:04 +0000 Subject: [PATCH 103/481] Added translation using Weblate (English (United Kingdom)) --- src/i18n/strings/en_GB.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/i18n/strings/en_GB.json diff --git a/src/i18n/strings/en_GB.json b/src/i18n/strings/en_GB.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/src/i18n/strings/en_GB.json @@ -0,0 +1 @@ +{} From f61a6104b557b268995ea55f227b2c55cb2789ad Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Mar 2019 09:23:17 -0600 Subject: [PATCH 104/481] Use m.custom for widget type As per https://github.com/matrix-org/matrix-doc/issues/1236 --- src/SlashCommands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index fbacaef7c2..1c64e15cc8 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -620,7 +620,7 @@ export const CommandMap = { const nowMs = (new Date()).getTime(); const widgetId = encodeURIComponent(`${roomId}_${userId}_${nowMs}`); return success(WidgetUtils.setRoomWidget( - roomId, widgetId, "customwidget", args, "Custom Widget", {})); + roomId, widgetId, "m.custom", args, "Custom Widget", {})); } else { return reject(_t("You cannot modify widgets in this room.")); } From 7e56a9a80eeb09bdd462498a2fcf707d6b650326 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 26 Mar 2019 17:13:02 +0100 Subject: [PATCH 105/481] prevent resize handle hit area overlapping with (native) scrollbar --- res/css/structures/_MainSplit.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 28c89fe7ca..4d73953cd7 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -19,3 +19,9 @@ limitations under the License. flex-direction: row; min-width: 0; } + +// move hit area 5px to the right so it doesn't overlap with the timeline scrollbar +.mx_MainSplit > .mx_ResizeHandle.mx_ResizeHandle_horizontal { + margin: 0 -10px 0 0; + padding: 0 10px 0 0; +} From 4c0f459995787e8e7310ef7437c3020b477b7eb9 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 25 Mar 2019 17:43:53 +0000 Subject: [PATCH 106/481] Add basic storage consistency check This adds a storage consistency check just before creating a client on login. Each data store we use is checked for data and any problems are logged to the console. Fixes https://github.com/vector-im/riot-web/issues/9271 --- src/Lifecycle.js | 5 ++- src/utils/StorageManager.js | 90 +++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/utils/StorageManager.js diff --git a/src/Lifecycle.js b/src/Lifecycle.js index f7579cf3c0..fbb68481ad 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -31,7 +31,8 @@ import Modal from './Modal'; import sdk from './index'; import ActiveWidgetStore from './stores/ActiveWidgetStore'; import PlatformPeg from "./PlatformPeg"; -import {sendLoginRequest} from "./Login"; +import { sendLoginRequest } from "./Login"; +import * as StorageManager from './utils/StorageManager'; /** * Called at startup, to attempt to build a logged-in Matrix session. It tries @@ -353,6 +354,8 @@ async function _doSetLoggedIn(credentials, clearStorage) { await _clearStorage(); } + await StorageManager.checkConsistency(); + Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl, credentials.identityServerUrl); if (localStorage) { diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js new file mode 100644 index 0000000000..4774d3b7e1 --- /dev/null +++ b/src/utils/StorageManager.js @@ -0,0 +1,90 @@ +/* +Copyright 2019 New Vector 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 Matrix from 'matrix-js-sdk'; + +const localStorage = window.localStorage; + +// just *accessing* indexedDB throws an exception in firefox with +// indexeddb disabled. +let indexedDB; +try { + indexedDB = window.indexedDB; +} catch (e) {} + +// The JS SDK will add a prefix of "matrix-js-sdk:" to the sync store name. +const SYNC_STORE_NAME = "riot-web-sync"; +const CRYPTO_STORE_NAME = "matrix-js-sdk:crypto"; + +function log(msg) { + console.log(`StorageManager: ${msg}`); +} + +function error(msg) { + console.error(`StorageManager: ${msg}`); +} + +export async function checkConsistency() { + log("Checking storage consistency"); + log(`Local storage supported? ${!!localStorage}`); + log(`IndexedDB supported? ${!!indexedDB}`); + + let dataInLocalStorage = false; + let dataInCryptoStore = false; + let healthy = true; + + if (localStorage) { + dataInLocalStorage = localStorage.length > 0; + log(`Local storage contains data? ${dataInLocalStorage}`); + } else { + healthy = false; + error("Local storage cannot be used on this browser"); + } + + if (indexedDB && localStorage) { + const dataInSyncStore = await Matrix.IndexedDBStore.exists( + indexedDB, SYNC_STORE_NAME, + ); + log(`Sync store contains data? ${dataInSyncStore}`); + } else { + healthy = false; + error("Sync store cannot be used on this browser"); + } + + if (indexedDB) { + dataInCryptoStore = await Matrix.IndexedDBCryptoStore.exists( + indexedDB, CRYPTO_STORE_NAME, + ); + log(`Crypto store contains data? ${dataInCryptoStore}`); + } else { + healthy = false; + error("Crypto store cannot be used on this browser"); + } + + if (dataInLocalStorage && !dataInCryptoStore) { + healthy = false; + error( + "Data exists in local storage but not in crypto store. " + + "IndexedDB storage has likely been evicted by the browser!", + ); + } + + if (healthy) { + log("Storage consistency checks passed"); + } else { + error("Storage consistency checks failed"); + } +} From f2f3661b7e56ece752e003fffa50f955de675d8e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 26 Mar 2019 17:40:24 +0100 Subject: [PATCH 107/481] more debug logging --- src/components/structures/ScrollPanel.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 57185b08b0..99c2df1b14 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -572,6 +572,7 @@ module.exports = React.createClass({ // This because when setting the scrollTop only 10 or so events might be loaded, // not giving enough content below the trackedNode to scroll downwards // enough so it ends up in the top of the viewport. + debuglog("scrollToken: setting scrollTop", {offsetBase, pixelOffset, offsetTop: trackedNode.offsetTop}); scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset; this._saveScrollState(); } From f8dce875f233321f3208a541544f420c079fce21 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 26 Mar 2019 10:09:04 +0000 Subject: [PATCH 108/481] Clarify devices affected by notification settings This clarifies that the notification settings only apply to the current device. This also tries to apply the spirit of https://github.com/matrix-org/matrix-react-sdk/pull/1995 (authored by @aidalgol) which wanted to remove "web" from the label, since there's also a desktop client. --- src/components/views/settings/Notifications.js | 4 ++-- src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index b8f8279bb0..f344f2c897 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -837,7 +837,7 @@ module.exports = React.createClass({ + label={_t('Enable desktop notifications for this device')} /> + label={_t('Enable audible notifications for this device')} /> { emailNotificationsRows } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ef4bc75d27..1f4d97e408 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -497,9 +497,9 @@ "Advanced notification settings": "Advanced notification settings", "There are advanced notifications which are not shown here": "There are advanced notifications which are not shown here", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply", - "Enable desktop notifications": "Enable desktop notifications", + "Enable desktop notifications for this device": "Enable desktop notifications for this device", "Show message in desktop notification": "Show message in desktop notification", - "Enable audible notifications in web client": "Enable audible notifications in web client", + "Enable audible notifications for this device": "Enable audible notifications for this device", "Off": "Off", "On": "On", "Noisy": "Noisy", From 4eb9fa6922e949bb01a29e6c0e2064be19e4e114 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Mar 2019 14:22:48 -0600 Subject: [PATCH 109/481] Check if the message panel is at the end of the timeline on init Fixes https://github.com/vector-im/riot-web/issues/8503 componentDidUpdate is called a lot, and we don't really want to keep checking the messagePanel, so this introduces a new flag to check if the init is even needed. --- src/components/structures/RoomView.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 34c711ee6f..23d5b2f127 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -144,6 +144,7 @@ module.exports = React.createClass({ // 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 showTopUnreadMessagesBar: false, @@ -428,6 +429,12 @@ module.exports = React.createClass({ roomView.addEventListener('dragend', this.onDragLeaveOrEnd); } } + if (this.refs.messagePanel && !this.state.atEndOfLiveTimelineInit) { + this.setState({ + atEndOfLiveTimelineInit: true, + atEndOfLiveTimeline: this.refs.messagePanel.isAtEndOfLiveTimeline(), + }); + } }, componentWillUnmount: function() { From 340c24cfa71757c1fe5c09d50296cb40fb225c18 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Mar 2019 15:13:20 -0600 Subject: [PATCH 110/481] Filter out upgraded rooms from autocomplete results Fixes https://github.com/vector-im/riot-web/issues/9289 Theory is that this shouldn't happen in the first place (aliases should be transferred), but there's evidently some cases where this doesn't work, or gets state reset. --- src/autocomplete/RoomProvider.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js index 483506557f..ab5c3a259f 100644 --- a/src/autocomplete/RoomProvider.js +++ b/src/autocomplete/RoomProvider.js @@ -56,7 +56,7 @@ export default class RoomProvider extends AutocompleteProvider { const {command, range} = this.getCurrentCommand(query, selection, force); if (command) { // the only reason we need to do this is because Fuse only matches on properties - this.matcher.setObjects(client.getRooms().filter( + let matcherObjects = client.getRooms().filter( (room) => !!room && !!getDisplayAliasForRoom(room), ).map((room) => { return { @@ -64,7 +64,23 @@ export default class RoomProvider extends AutocompleteProvider { name: room.name, displayedAlias: getDisplayAliasForRoom(room), }; - })); + }); + + // Filter out any matches where the user will have also autocompleted new rooms + matcherObjects = matcherObjects.filter((r) => { + const tombstone = r.room.currentState.getStateEvents("m.room.tombstone", ""); + if (tombstone && tombstone.getContent() && tombstone.getContent()['replacement_room']) { + console.log(r.displayedAlias); + const hasReplacementRoom = matcherObjects.some( + (r2) => r2.room.roomId === tombstone.getContent()['replacement_room'], + ); + console.log(hasReplacementRoom); + return !hasReplacementRoom; + } + return true; + }); + + this.matcher.setObjects(matcherObjects); const matchedString = command[0]; completions = this.matcher.match(matchedString); completions = _sortBy(completions, [ From 04a9038a05127cc66d1eeafa6f875d6ab2b416f8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Mar 2019 19:22:24 -0600 Subject: [PATCH 111/481] Alert the user to unread notifications in prior versions of rooms Fixes https://github.com/vector-im/riot-web/issues/8161 --- res/css/structures/_RoomView.scss | 7 ++++++ src/components/structures/RoomSubList.js | 27 +++++++++++++++++++-- src/components/structures/RoomView.js | 30 ++++++++++++++++++++++++ src/i18n/strings/en_EN.json | 2 ++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index f15552e484..b958d934d1 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -70,6 +70,13 @@ limitations under the License. background-color: $primary-bg-color; } +.mx_RoomView_auxPanel_hiddenHighlights { + border-bottom: 1px solid $primary-hairline-color; + padding: 10px; + color: $warning-color; + cursor: pointer; +} + .mx_RoomView_auxPanel_apps { max-width: 1920px ! important; } diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 78cc5bd58f..825a80b844 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -29,6 +29,7 @@ import { Group } from 'matrix-js-sdk'; import PropTypes from 'prop-types'; import RoomTile from "../views/rooms/RoomTile"; import LazyRenderList from "../views/elements/LazyRenderList"; +import MatrixClientPeg from "../../MatrixClientPeg"; // turn this on for drop & drag console debugging galore const debug = false; @@ -138,6 +139,28 @@ const RoomSubList = React.createClass({ this.setState(this.state); }, + getUnreadNotificationCount: function(room, type=null) { + let notificationCount = room.getUnreadNotificationCount(type); + + // Check notification counts in the old room just in case there's some lost + // there. We only go one level down to avoid performance issues, and theory + // is that 1st generation rooms will have already been read by the 3rd generation. + const createEvent = room.currentState.getStateEvents("m.room.create", ""); + if (createEvent && createEvent.getContent()['predecessor']) { + const oldRoomId = createEvent.getContent()['predecessor']['room_id']; + const oldRoom = MatrixClientPeg.get().getRoom(oldRoomId); + if (oldRoom) { + // We only ever care if there's highlights in the old room. No point in + // notifying the user for unread messages because they would have extreme + // difficulty changing their notification preferences away from "All Messages" + // and "Noisy". + notificationCount += oldRoom.getUnreadNotificationCount("highlight"); + } + } + + return notificationCount; + }, + makeRoomTile: function(room) { return 0 || this.props.isInvite} - notificationCount={room.getUnreadNotificationCount()} + highlight={this.props.isInvite || this.getUnreadNotificationCount(room, 'highlight') > 0} + notificationCount={this.getUnreadNotificationCount(room)} isInvite={this.props.isInvite} refreshSubList={this._updateSubListCount} incomingCall={null} diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 34c711ee6f..740e2dba7b 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1515,6 +1515,25 @@ module.exports = React.createClass({ } }, + _getOldRoom: function() { + const createEvent = this.state.room.currentState.getStateEvents("m.room.create", ""); + if (!createEvent || !createEvent.getContent()['predecessor']) return null; + + return MatrixClientPeg.get().getRoom(createEvent.getContent()['predecessor']['room_id']); + }, + + _getHiddenHighlightCount: function() { + const oldRoom = this._getOldRoom(); + if (!oldRoom) return 0; + return oldRoom.getUnreadNotificationCount('highlight'); + }, + + _onHiddenHighlightsClick: function() { + 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 MessageComposer = sdk.getComponent('rooms.MessageComposer'); @@ -1673,6 +1692,8 @@ module.exports = React.createClass({ !MatrixClientPeg.get().getKeyBackupEnabled() ); + const hiddenHighlightCount = this._getHiddenHighlightCount(); + let aux = null; let hideCancel = false; if (this.state.forwardingEvent !== null) { @@ -1713,6 +1734,15 @@ module.exports = React.createClass({ room={this.state.room} /> ); + } else if (hiddenHighlightCount > 0) { + aux = ( +

      + {_t( + "You have %(count)s unread notifications in a prior version of this room.", + {count: hiddenHighlightCount}, + )} +
      + ); } const auxPanel = ( diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 18bc876966..56a31e1dcb 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1416,6 +1416,8 @@ "Unknown room %(roomId)s": "Unknown room %(roomId)s", "Room": "Room", "Failed to reject invite": "Failed to reject invite", + "You have %(count)s unread notifications in a prior version of this room.|other": "You have %(count)s unread notifications in a prior version of this room.", + "You have %(count)s unread notifications in a prior version of this room.|one": "You have %(count)s unread notification in a prior version of this room.", "Fill screen": "Fill screen", "Click to unmute video": "Click to unmute video", "Click to mute video": "Click to mute video", From d06fb0d076783369316b1ab8a8fc4215bbccff89 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 26 Mar 2019 16:36:12 +0000 Subject: [PATCH 112/481] Send telemetry about storage consistency This adds telemetry events about basic storage consistency, so we can start to get an idea of how often IndexedDB eviction occurs in the field. Fixes https://github.com/vector-im/riot-web/issues/9272 --- src/utils/StorageManager.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index 4774d3b7e1..5edb43fb0b 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -15,6 +15,7 @@ limitations under the License. */ import Matrix from 'matrix-js-sdk'; +import Analytics from '../Analytics'; const localStorage = window.localStorage; @@ -37,6 +38,10 @@ function error(msg) { console.error(`StorageManager: ${msg}`); } +function track(action) { + Analytics.trackEvent("StorageManager", action); +} + export async function checkConsistency() { log("Checking storage consistency"); log(`Local storage supported? ${!!localStorage}`); @@ -52,6 +57,7 @@ export async function checkConsistency() { } else { healthy = false; error("Local storage cannot be used on this browser"); + track("Local storage disabled"); } if (indexedDB && localStorage) { @@ -62,6 +68,7 @@ export async function checkConsistency() { } else { healthy = false; error("Sync store cannot be used on this browser"); + track("Sync store disabled"); } if (indexedDB) { @@ -72,6 +79,7 @@ export async function checkConsistency() { } else { healthy = false; error("Crypto store cannot be used on this browser"); + track("Crypto store disabled"); } if (dataInLocalStorage && !dataInCryptoStore) { @@ -80,11 +88,14 @@ export async function checkConsistency() { "Data exists in local storage but not in crypto store. " + "IndexedDB storage has likely been evicted by the browser!", ); + track("Crypto store evicted"); } if (healthy) { log("Storage consistency checks passed"); + track("Consistency checks passed"); } else { error("Storage consistency checks failed"); + track("Consistency checks failed"); } } From 5d53913e35c02768d5e2216faf4e5d10d864f826 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 27 Mar 2019 11:35:38 +0100 Subject: [PATCH 113/481] fix filling conditions --- src/components/structures/ScrollPanel.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 99c2df1b14..4043631d39 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -317,17 +317,20 @@ module.exports = React.createClass({ this._isFilling = true; } - - const contentHeight = this._getMessagesHeight(); - const contentTop = contentHeight - this._getListHeight(); - const contentScrollTop = sn.scrollTop + contentTop; + const itemlist = this.refs.itemlist; + const firstTile = itemlist && itemlist.firstElementChild; + const contentTop = firstTile && firstTile.offsetTop; const fillPromises = []; - if (contentScrollTop < sn.clientHeight) { + // if scrollTop gets to 1 screen from the top of the first tile, + // try backward filling + if (!firstTile || (sn.scrollTop - contentTop) < sn.clientHeight) { // need to back-fill fillPromises.push(this._maybeFill(depth, true)); } - if (contentScrollTop > contentHeight - sn.clientHeight * 2) { + // if scrollTop gets to 2 screens from the end (so 1 screen below viewport), + // try forward filling + if ((sn.scrollHeight - sn.scrollTop) < sn.clientHeight * 2) { // need to forward-fill fillPromises.push(this._maybeFill(depth, false)); } From 5ac3905a3768630927eba36c8d477a43c7c4bb00 Mon Sep 17 00:00:00 2001 From: Nad Chishtie Date: Wed, 27 Mar 2019 13:15:03 +0100 Subject: [PATCH 114/481] Use same horizontal padding as room avatar to align to grid --- res/css/structures/_RoomView.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index b958d934d1..e914869fd1 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -72,7 +72,7 @@ limitations under the License. .mx_RoomView_auxPanel_hiddenHighlights { border-bottom: 1px solid $primary-hairline-color; - padding: 10px; + padding: 10px 26px; color: $warning-color; cursor: pointer; } From 1fe830d1c6b5836fc10d76bfe9cd2f26fa1764b2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 27 Mar 2019 13:27:57 +0000 Subject: [PATCH 115/481] Remove noreferrer on widget pop-out Having the referrer allows widgets to do customisation based on what riot instance is embedding it. It gets a referrer when we embed it in the iframe so there's nothing gained by suppressing it here. --- src/components/views/elements/AppTile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 9444da5be4..708eb39bd3 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -495,9 +495,9 @@ export default class AppTile extends React.Component { _onPopoutWidgetClick(e) { // Using Object.assign workaround as the following opens in a new window instead of a new tab. - // window.open(this._getSafeUrl(), '_blank', 'noopener=yes,noreferrer=yes'); + // window.open(this._getSafeUrl(), '_blank', 'noopener=yes'); Object.assign(document.createElement('a'), - { target: '_blank', href: this._getSafeUrl(), rel: 'noopener noreferrer'}).click(); + { target: '_blank', href: this._getSafeUrl(), rel: 'noopener'}).click(); } _onReloadWidgetClick(e) { From 8d27cfde36c8e4f205b1f014b180eaec6c7357ee Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 27 Mar 2019 13:57:48 +0000 Subject: [PATCH 116/481] Remove unused import --- src/components/structures/RoomDirectory.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index e13eab8eb3..b155f514f4 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -511,7 +511,6 @@ module.exports = React.createClass({ }, render: function() { - const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader'); const Loader = sdk.getComponent("elements.Spinner"); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); From 0466e0a3067c31dff975677e131c1d291c7a7201 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 27 Mar 2019 14:17:24 +0000 Subject: [PATCH 117/481] Reorganise room directory code so new room is always available This reorganises the room directory so that the new room buttons is always available no matter what state the overall directory is in. Part of https://github.com/vector-im/riot-web/issues/9046 --- src/components/structures/RoomDirectory.js | 91 ++++++++++------------ 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index b155f514f4..d0c0c32eaa 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -515,20 +515,9 @@ module.exports = React.createClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - // TODO: clean this up - if (this.state.protocolsLoading) { - return ( -
      - -
      - ); - } - let content; - if (this.state.loading) { - content =
      - -
      ; + if (this.state.protocolsLoading || this.state.loading) { + content = ; } else { const rows = this.getRows(); // we still show the scrollpanel, at least for now, because @@ -556,33 +545,48 @@ module.exports = React.createClass({ ; } - const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId); - let instance_expected_field_type; - if ( - protocolName && - this.protocols && - this.protocols[protocolName] && - this.protocols[protocolName].location_fields.length > 0 && - this.protocols[protocolName].field_types - ) { - const last_field = this.protocols[protocolName].location_fields.slice(-1)[0]; - instance_expected_field_type = this.protocols[protocolName].field_types[last_field]; - } + let listHeader; + if (!this.state.protocolsLoading) { + const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown'); + const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox'); - - let placeholder = _t('Search for a room'); - if (!this.state.instanceId) { - placeholder = _t('Search for a room like #example') + ':' + this.state.roomServer; - } else if (instance_expected_field_type) { - placeholder = instance_expected_field_type.placeholder; - } - - let showJoinButton = this._stringLooksLikeId(this.state.filterString, instance_expected_field_type); - if (protocolName) { - const instance = instanceForInstanceId(this.protocols, this.state.instanceId); - if (this._getFieldsForThirdPartyLocation(this.state.filterString, this.protocols[protocolName], instance) === null) { - showJoinButton = false; + const protocolName = protocolNameForInstanceId(this.protocols, this.state.instanceId); + let instance_expected_field_type; + if ( + protocolName && + this.protocols && + this.protocols[protocolName] && + this.protocols[protocolName].location_fields.length > 0 && + this.protocols[protocolName].field_types + ) { + const last_field = this.protocols[protocolName].location_fields.slice(-1)[0]; + instance_expected_field_type = this.protocols[protocolName].field_types[last_field]; } + + + let placeholder = _t('Search for a room'); + if (!this.state.instanceId) { + placeholder = _t('Search for a room like #example') + ':' + this.state.roomServer; + } else if (instance_expected_field_type) { + placeholder = instance_expected_field_type.placeholder; + } + + let showJoinButton = this._stringLooksLikeId(this.state.filterString, instance_expected_field_type); + if (protocolName) { + const instance = instanceForInstanceId(this.protocols, this.state.instanceId); + if (this._getFieldsForThirdPartyLocation(this.state.filterString, this.protocols[protocolName], instance) === null) { + showJoinButton = false; + } + } + + listHeader =
      + + +
      ; } const createRoomButton = ({_t("Create new room")}); - const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown'); - const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox'); return (
      -
      - - -
      + {listHeader} {content}
      From 055f8330425e321fde110a491150c74c09714c81 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 27 Mar 2019 14:54:18 +0000 Subject: [PATCH 118/481] Change loading errors in room directory to inline instead of modal This changes errors that may occur when loading the room directory so that the message appears inline with the overall directory UI instead of in a new modal. This is important so that the new room button remains on screen even if the directory is down. Fixes https://github.com/vector-im/riot-web/issues/9046 --- src/components/structures/RoomDirectory.js | 36 ++++++++++++++-------- src/i18n/strings/en_EN.json | 8 ++--- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index d0c0c32eaa..a7211f6f46 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -26,14 +26,17 @@ const dis = require('../../dispatcher'); import { linkifyAndSanitizeHtml } from '../../HtmlUtils'; import Promise from 'bluebird'; - import { _t } from '../../languageHandler'; - -import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils'; +import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils'; +import Analytics from '../../Analytics'; const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 160; +function track(action) { + Analytics.trackEvent('RoomDirectory', action); +} + module.exports = React.createClass({ displayName: 'RoomDirectory', @@ -53,6 +56,7 @@ module.exports = React.createClass({ publicRooms: [], loading: true, protocolsLoading: true, + error: null, instanceId: null, includeAll: false, roomServer: null, @@ -95,10 +99,12 @@ module.exports = React.createClass({ // thing you see when loading the client! return; } - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to get protocol list from homeserver', '', ErrorDialog, { - title: _t('Failed to get protocol list from homeserver'), - description: _t('The homeserver may be too old to support third party networks'), + track('Failed to get protocol list from homeserver'); + this.setState({ + error: _t( + 'Riot failed to get the protocol list from the homeserver. ' + + 'The homeserver may be too old to support third party networks.', + ), }); }); @@ -187,12 +193,14 @@ module.exports = React.createClass({ return; } - this.setState({ loading: false }); console.error("Failed to get publicRooms: %s", JSON.stringify(err)); - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Failed to get public room list', '', ErrorDialog, { - title: _t('Failed to get public room list'), - description: ((err && err.message) ? err.message : _t('The server may be unavailable or overloaded')), + track('Failed to get public room list'); + this.setState({ + loading: false, + error: + `${_t('Riot failed to get the public room list.')} ` + + `${(err && err.message) ? err.message : _t('The homeserver may be unavailable or overloaded.')}` + , }); }); }, @@ -516,7 +524,9 @@ module.exports = React.createClass({ const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let content; - if (this.state.protocolsLoading || this.state.loading) { + if (this.state.error) { + content = this.state.error; + } else if (this.state.protocolsLoading || this.state.loading) { content = ; } else { const rows = this.getRows(); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e85537ba03..94d524d767 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1379,15 +1379,15 @@ "Create a new community": "Create a new community", "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.", "You have no visible notifications": "You have no visible notifications", - "Failed to get protocol list from homeserver": "Failed to get protocol list from homeserver", - "The homeserver may be too old to support third party networks": "The homeserver may be too old to support third party networks", - "Failed to get public room list": "Failed to get public room list", - "The server may be unavailable or overloaded": "The server may be unavailable or overloaded", + "Riot failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "Riot failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.", + "Riot failed to get the public room list.": "Riot failed to get the public room list.", + "The homeserver may be unavailable or overloaded.": "The homeserver may be unavailable or overloaded.", "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Delete the room alias %(alias)s and remove %(name)s from the directory?", "Remove %(name)s from the directory?": "Remove %(name)s from the directory?", "Remove from Directory": "Remove from Directory", "remove %(name)s from the directory.": "remove %(name)s from the directory.", "delete the alias.": "delete the alias.", + "The server may be unavailable or overloaded": "The server may be unavailable or overloaded", "Unable to join network": "Unable to join network", "Riot does not know how to join a room on this network": "Riot does not know how to join a room on this network", "Room not found": "Room not found", From 86cf83e1781e239780825b70010c02a36bc9ee27 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 27 Mar 2019 15:07:14 +0000 Subject: [PATCH 119/481] Update matrix-mock-request --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3e5388f925..8997d3c2af 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "karma-spec-reporter": "^0.0.31", "karma-summary-reporter": "^1.5.1", "karma-webpack": "^4.0.0-beta.0", - "matrix-mock-request": "^1.2.1", + "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.1.1", "mocha": "^5.0.5", "react-addons-test-utils": "^15.4.0", diff --git a/yarn.lock b/yarn.lock index 454c0c8a47..893ceac0a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4388,10 +4388,10 @@ matrix-js-sdk@1.0.2: request "^2.88.0" unhomoglyph "^1.0.2" -matrix-mock-request@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-1.2.2.tgz#2710bec0e009bb1562d92cdd7f0b77d5946b2ebd" - integrity sha512-9u86m6rOsKekNkqUUkStWXNULrY9G+9ibwolfrmgqTmgR76EGCr9fovM+JPWn4U+TbrewvHMALpPw8OxRg0ExA== +matrix-mock-request@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-1.2.3.tgz#56b15d86e2601a9b48a854844396d18caab649c8" + integrity sha512-Tr7LDHweTW8Ql4C8XhGQFGMzuh+HmPjOcQqrHH1qfSesq0cwdPWanvdnllNjeHoAMcZ43HpMFMzFZfNW1/6HYg== dependencies: bluebird "^3.5.0" expect "^1.20.2" From 82e44249ff57f77ee0b86834db6b19a713e07372 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 27 Mar 2019 16:38:17 +0100 Subject: [PATCH 120/481] make resizeNotifier optional in MainSplit for GroupView --- src/components/structures/MainSplit.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index c0bf74d02c..64f841da97 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -27,7 +27,9 @@ export default class MainSplit extends React.Component { _onResized(size) { window.localStorage.setItem("mx_rhs_size", size); - this.props.resizeNotifier.notifyRightHandleResized(); + if (this.props.resizeNotifier) { + this.props.resizeNotifier.notifyRightHandleResized(); + } } _createResizer() { From 73b2484e0863de3e7ea1e0fc8406a8b1469a5350 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 27 Mar 2019 15:48:38 +0000 Subject: [PATCH 121/481] Catch errors when checking IndexedDB In Firefox private browsing, we may get errors when checking storage consistency. We don't want that to block general Riot operation, so catch those errors and log instead. Fixes https://github.com/vector-im/riot-web/issues/9300 --- src/utils/StorageManager.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index 5edb43fb0b..472e1c93d4 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -61,10 +61,16 @@ export async function checkConsistency() { } if (indexedDB && localStorage) { - const dataInSyncStore = await Matrix.IndexedDBStore.exists( - indexedDB, SYNC_STORE_NAME, - ); - log(`Sync store contains data? ${dataInSyncStore}`); + try { + const dataInSyncStore = await Matrix.IndexedDBStore.exists( + indexedDB, SYNC_STORE_NAME, + ); + log(`Sync store contains data? ${dataInSyncStore}`); + } catch (e) { + healthy = false; + error("Sync store inaccessible", e); + track("Sync store inaccessible"); + } } else { healthy = false; error("Sync store cannot be used on this browser"); @@ -72,10 +78,16 @@ export async function checkConsistency() { } if (indexedDB) { - dataInCryptoStore = await Matrix.IndexedDBCryptoStore.exists( - indexedDB, CRYPTO_STORE_NAME, - ); - log(`Crypto store contains data? ${dataInCryptoStore}`); + try { + dataInCryptoStore = await Matrix.IndexedDBCryptoStore.exists( + indexedDB, CRYPTO_STORE_NAME, + ); + log(`Crypto store contains data? ${dataInCryptoStore}`); + } catch (e) { + healthy = false; + error("Crypto store inaccessible", e); + track("Crypto store inaccessible"); + } } else { healthy = false; error("Crypto store cannot be used on this browser"); From fef36d3e1de101a14ef1a2a85b95d70f28f04258 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 27 Mar 2019 17:35:36 +0000 Subject: [PATCH 122/481] react-sdk rc.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8997d3c2af..5b753da182 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "1.0.2", + "matrix-js-sdk": "^1.0.3-rc.1", "optimist": "^0.6.1", "pako": "^1.0.5", "prop-types": "^15.5.8", diff --git a/yarn.lock b/yarn.lock index 893ceac0a2..5dff5cbae0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4371,10 +4371,10 @@ math-random@^1.0.1: resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== -matrix-js-sdk@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-1.0.2.tgz#482d8d2076c7565cf7354722e96c9971e372182a" - integrity sha512-4WCBJFSoOLelHi7IUAcVxPQF+gTc/i9NUKZ77qwUfcZVED8VKTIyWZnwpeLgocK5gAOJV9fkAyO5mny9SkZaGg== +matrix-js-sdk@^1.0.3-rc.1: + version "1.0.3-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-1.0.3-rc.1.tgz#61dea7fc2efd6f0a23e709443b4ac6a276890e9a" + integrity sha512-31aFwoAR9AIWhqHgJCYplXVFbaykXydm7GBvM/ffCjzN5OgAQEzUqwX18PfWKHVZHqijtj2VZOqnBVsXLX0w6Q== dependencies: another-json "^0.2.0" babel-runtime "^6.26.0" From 8cd9132b379ef360abea9288f868c33f1cb54663 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 27 Mar 2019 17:40:04 +0000 Subject: [PATCH 123/481] Prepare changelog for v1.0.6-rc.1 --- CHANGELOG.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3313abacc..5a683d6e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,94 @@ +Changes in [1.0.6-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.6-rc.1) (2019-03-27) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.5...v1.0.6-rc.1) + + * Catch errors when checking IndexedDB + [\#2836](https://github.com/matrix-org/matrix-react-sdk/pull/2836) + * Remove noreferrer on widget pop-out + [\#2835](https://github.com/matrix-org/matrix-react-sdk/pull/2835) + * Rework room directory so that new room is always available + [\#2834](https://github.com/matrix-org/matrix-react-sdk/pull/2834) + * Send telemetry about storage consistency + [\#2832](https://github.com/matrix-org/matrix-react-sdk/pull/2832) + * Widget OpenID reauth implementation + [\#2781](https://github.com/matrix-org/matrix-react-sdk/pull/2781) + * Log results of basic storage consistency check + [\#2826](https://github.com/matrix-org/matrix-react-sdk/pull/2826) + * Clarify devices affected by notification settings + [\#2828](https://github.com/matrix-org/matrix-react-sdk/pull/2828) + * Add a command for creating custom widgets without an integration manager + [\#2824](https://github.com/matrix-org/matrix-react-sdk/pull/2824) + * Minimize stickerpicker when the title is clicked + [\#2822](https://github.com/matrix-org/matrix-react-sdk/pull/2822) + * Add blocks around homeserver and identity server urls + [\#2825](https://github.com/matrix-org/matrix-react-sdk/pull/2825) + * Fixed drop shadow for tooltip. + [\#2815](https://github.com/matrix-org/matrix-react-sdk/pull/2815) + * Ask the user for debug logs when the timeline explodes + [\#2820](https://github.com/matrix-org/matrix-react-sdk/pull/2820) + * Fix typo preventing users from adding more widgets easily + [\#2823](https://github.com/matrix-org/matrix-react-sdk/pull/2823) + * Attach an onChange listener to the room's blacklist devices option + [\#2817](https://github.com/matrix-org/matrix-react-sdk/pull/2817) + * Use leaveRoomChain when leaving a room + [\#2818](https://github.com/matrix-org/matrix-react-sdk/pull/2818) + * Fix bug with NetworkList dropdown + [\#2821](https://github.com/matrix-org/matrix-react-sdk/pull/2821) + * Trim the logging for URL previews + [\#2816](https://github.com/matrix-org/matrix-react-sdk/pull/2816) + * Explicitly create `cryptoStore` in React SDK + [\#2814](https://github.com/matrix-org/matrix-react-sdk/pull/2814) + * Change to new consistent name for `MemoryStore` + [\#2812](https://github.com/matrix-org/matrix-react-sdk/pull/2812) + * Use medium agents for the more resource intensive builds + [\#2813](https://github.com/matrix-org/matrix-react-sdk/pull/2813) + * Add log grouping to buildkite + [\#2810](https://github.com/matrix-org/matrix-react-sdk/pull/2810) + * Switch to `git` protocol for CI dependencies + [\#2809](https://github.com/matrix-org/matrix-react-sdk/pull/2809) + * Go back to using mainine velocity + [\#2808](https://github.com/matrix-org/matrix-react-sdk/pull/2808) + * Warn that members won't be autojoined to upgraded rooms + [\#2796](https://github.com/matrix-org/matrix-react-sdk/pull/2796) + * Support CI for matching branches on forks + [\#2807](https://github.com/matrix-org/matrix-react-sdk/pull/2807) + * Discard old sticker picker when the URL changes + [\#2801](https://github.com/matrix-org/matrix-react-sdk/pull/2801) + * Reload widget messaging when widgets reload + [\#2799](https://github.com/matrix-org/matrix-react-sdk/pull/2799) + * Don't show calculated room name in room settings name input field + [\#2806](https://github.com/matrix-org/matrix-react-sdk/pull/2806) + * Disable big emoji for m.emote messages as it looks weird + [\#2805](https://github.com/matrix-org/matrix-react-sdk/pull/2805) + * Remove Edge from browser support statements + [\#2803](https://github.com/matrix-org/matrix-react-sdk/pull/2803) + * Update from Weblate + [\#2802](https://github.com/matrix-org/matrix-react-sdk/pull/2802) + * Really fix tag panel + [\#2800](https://github.com/matrix-org/matrix-react-sdk/pull/2800) + * Update CompatibilityPage to match officially supported browsers + [\#2793](https://github.com/matrix-org/matrix-react-sdk/pull/2793) + * Use Buildkite for CI + [\#2788](https://github.com/matrix-org/matrix-react-sdk/pull/2788) + * Fix CSS syntax errors preventing offline member opacity from working + [\#2794](https://github.com/matrix-org/matrix-react-sdk/pull/2794) + * Make the EntityTile chevron a masked SVG for theming + [\#2795](https://github.com/matrix-org/matrix-react-sdk/pull/2795) + * Remove refs from `RegistrationForm` + [\#2791](https://github.com/matrix-org/matrix-react-sdk/pull/2791) + * Fix initial letter avatar vertical offset in Firefox + [\#2792](https://github.com/matrix-org/matrix-react-sdk/pull/2792) + * Fix the custom tag panel + [\#2797](https://github.com/matrix-org/matrix-react-sdk/pull/2797) + * Ensure freshly invited members don't count towards the alone warning + [\#2786](https://github.com/matrix-org/matrix-react-sdk/pull/2786) + * Fix 'forgot password' warning to represent the reality of e2ee + [\#2787](https://github.com/matrix-org/matrix-react-sdk/pull/2787) + * Restore `Field` value getter for `RegistrationForm` + [\#2790](https://github.com/matrix-org/matrix-react-sdk/pull/2790) + * Initial portions of support for Field validation + [\#2780](https://github.com/matrix-org/matrix-react-sdk/pull/2780) + Changes in [1.0.5](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.5) (2019-03-21) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.4...v1.0.5) From 45e4948d9a17ff6126b70ecacbe8d3d25676ab85 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 27 Mar 2019 17:40:05 +0000 Subject: [PATCH 124/481] v1.0.6-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b753da182..a5175a9034 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "1.0.5", + "version": "1.0.6-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 85c8d4d0e5ebf69a1f7298158a9aa56b6c12313b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Mar 2019 13:03:25 -0600 Subject: [PATCH 125/481] Remove extra debug lines --- src/autocomplete/RoomProvider.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js index ab5c3a259f..f118a06b9e 100644 --- a/src/autocomplete/RoomProvider.js +++ b/src/autocomplete/RoomProvider.js @@ -70,11 +70,9 @@ export default class RoomProvider extends AutocompleteProvider { matcherObjects = matcherObjects.filter((r) => { const tombstone = r.room.currentState.getStateEvents("m.room.tombstone", ""); if (tombstone && tombstone.getContent() && tombstone.getContent()['replacement_room']) { - console.log(r.displayedAlias); const hasReplacementRoom = matcherObjects.some( (r2) => r2.room.roomId === tombstone.getContent()['replacement_room'], ); - console.log(hasReplacementRoom); return !hasReplacementRoom; } return true; From c94ae6401b53d0db4d00de6b1848ac95114fbee3 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Mar 2019 13:14:31 -0600 Subject: [PATCH 126/481] Use an AccessibleButton for the clickable element --- src/components/structures/RoomView.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 740e2dba7b..99d4ba5532 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -52,6 +52,7 @@ import RoomScrollStateStore from '../../stores/RoomScrollStateStore'; import WidgetEchoStore from '../../stores/WidgetEchoStore'; import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import WidgetUtils from '../../utils/WidgetUtils'; +import AccessibleButton from "../views/elements/AccessibleButton"; const DEBUG = false; let debuglog = function() {}; @@ -1736,12 +1737,13 @@ module.exports = React.createClass({ ); } else if (hiddenHighlightCount > 0) { aux = ( -
      + {_t( "You have %(count)s unread notifications in a prior version of this room.", {count: hiddenHighlightCount}, )} -
      +
      ); } From c8e42d61f510f224a7ba3ede37758057d712530f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Mar 2019 15:32:51 -0600 Subject: [PATCH 127/481] Persist breadcrumb state between sessions Fixes https://github.com/vector-im/riot-web/issues/8549 --- src/components/views/rooms/RoomBreadcrumbs.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index d661d439bf..403c017edb 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -35,14 +35,32 @@ export default class RoomBreadcrumbs extends React.Component { componentWillMount() { this._dispatcherRef = dis.register(this.onAction); + + const roomStr = localStorage.getItem("mx_breadcrumb_rooms"); + if (roomStr) { + try { + const roomIds = JSON.parse(roomStr); + this.setState({ + rooms: roomIds.map((r) => { + return { + room: MatrixClientPeg.get().getRoom(r), + animated: false, + }; + }).filter((r) => r.room), + }); + } catch (e) { + console.error("Failed to parse breadcrumbs:", e); + } + } } componentWillUnmount() { dis.unregister(this._dispatcherRef); } - componentDidUpdate() { + componentDidUpdate(props, state) { const rooms = this.state.rooms.slice(); + if (rooms.length) { const {room, animated} = rooms[0]; if (!animated) { @@ -50,6 +68,9 @@ export default class RoomBreadcrumbs extends React.Component { setTimeout(() => this.setState({rooms}), 0); } } + + const roomStr = JSON.stringify(rooms.map((r) => r.room.roomId)); + localStorage.setItem("mx_breadcrumb_rooms", roomStr); } onAction(payload) { From bbbf509a8c360b33cac96df217318e53abff446f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Mar 2019 15:38:42 -0600 Subject: [PATCH 128/481] Always append the current room to the breadcrumbs Fixes https://github.com/vector-im/riot-web/issues/8659 Fixes https://github.com/vector-im/riot-web/issues/8970 --- src/components/views/rooms/RoomBreadcrumbs.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index d661d439bf..6ea4b3e0ad 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -29,7 +29,6 @@ export default class RoomBreadcrumbs extends React.Component { super(props); this.state = {rooms: []}; this.onAction = this.onAction.bind(this); - this._previousRoomId = null; this._dispatcherRef = null; } @@ -55,10 +54,8 @@ export default class RoomBreadcrumbs extends React.Component { onAction(payload) { switch (payload.action) { case 'view_room': - if (this._previousRoomId) { - this._appendRoomId(this._previousRoomId); - } - this._previousRoomId = payload.room_id; + this._appendRoomId(payload.room_id); + break; } } From 90d7e82399037320fe1fe13e58046d800fcedeb5 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Mar 2019 17:46:34 -0600 Subject: [PATCH 129/481] Use custom tooltips on breadcrumb icons Fixes https://github.com/vector-im/riot-web/issues/9303 We have to track our own onHover for this, and out of safety we ensure that exactly 1 room is hovered at a time. --- src/components/views/rooms/RoomBreadcrumbs.js | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index d661d439bf..cefd278399 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -21,6 +21,7 @@ import MatrixClientPeg from "../../../MatrixClientPeg"; import AccessibleButton from '../elements/AccessibleButton'; import RoomAvatar from '../avatars/RoomAvatar'; import classNames from 'classnames'; +import sdk from "../../../index"; const MAX_ROOMS = 20; @@ -83,7 +84,24 @@ export default class RoomBreadcrumbs extends React.Component { dis.dispatch({action: "view_room", room_id: room.roomId}); } + _onMouseEnter(room) { + this._onHover(room); + } + + _onMouseLeave(room) { + this._onHover(null); // clear hover states + } + + _onHover(room) { + const rooms = this.state.rooms.slice(); + for (const r of rooms) { + r.hover = room && r.room.roomId === room.roomId; + } + this.setState({rooms}); + } + render() { + const Tooltip = sdk.getComponent('elements.Tooltip'); // check for collapsed here and // not at parent so we keep // rooms in our state @@ -92,15 +110,23 @@ export default class RoomBreadcrumbs extends React.Component { return null; } const rooms = this.state.rooms; - const avatars = rooms.map(({room, animated}, i) => { + const avatars = rooms.map(({room, animated, hover}, i) => { const isFirst = i === 0; const classes = classNames({ "mx_RoomBreadcrumbs_preAnimate": isFirst && !animated, "mx_RoomBreadcrumbs_animate": isFirst, }); + + let tooltip = null; + if (hover) { + tooltip = ; + } + return ( - this._viewRoom(room)}> + this._viewRoom(room)} + onMouseEnter={() => this._onMouseEnter(room)} onMouseLeave={() => this._onMouseLeave(room)}> + {tooltip} ); }); From 9b64dd0cd73787617935764f469d3934f0154375 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Mar 2019 17:51:23 -0600 Subject: [PATCH 130/481] Support horizontal scrolling on breadcrumbs Fixes https://github.com/vector-im/riot-web/issues/8714 Fixes https://github.com/vector-im/riot-web/issues/8890 Fixes https://github.com/vector-im/riot-web/issues/9034 Fixes https://github.com/vector-im/riot-web/issues/8954 This turned out to be much more complicated than it needed to be. We use an IndicatorScrollbar to do all the math for us and some minor changes have been made so it can flag left/right overflow. The complicated part is the css changes which make the gradients work: unlike the RoomSubList, we have to calculate the offset of the indicators (gradients) on our own because position:sticky doesn't work horizontally. The changes to the css (well, mostly pointer-events:none) make it so the gradient doesn't interfere with the room avatars. 9034 and 8954 are fixed by this because they represent an overflow-x:none style breakage where browsers won't let you scroll without a scrollbar. The gradient offset problem is also demonstrated in 8954. --- res/css/views/rooms/_RoomBreadcrumbs.scss | 55 ++++++++++++++----- .../structures/IndicatorScrollbar.js | 46 ++++++++++++++++ src/components/views/rooms/RoomBreadcrumbs.js | 10 +++- 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/res/css/views/rooms/_RoomBreadcrumbs.scss b/res/css/views/rooms/_RoomBreadcrumbs.scss index c5a149d5cd..dbd1d3cf5f 100644 --- a/res/css/views/rooms/_RoomBreadcrumbs.scss +++ b/res/css/views/rooms/_RoomBreadcrumbs.scss @@ -15,33 +15,29 @@ limitations under the License. */ .mx_RoomBreadcrumbs { - overflow-x: auto; position: relative; - height: 32px; + height: 42px; margin: 8px; margin-bottom: 0; - - overflow-x: hidden; + overflow-x: visible; display: flex; flex-direction: row; - > * { - margin-left: 4px; + .mx_AutoHideScrollbar_offset { + display: flex; + flex-direction: row; + height: 100%; } - &::after { - content: ""; - position: absolute; - width: 15px; - top: 0; - right: 0; - height: 100%; - background: linear-gradient(to right, $panel-gradient); + .mx_RoomBreadcrumbs_crumb { + margin-left: 4px; + height: 32px; + display: inline-block; + transition: transform 0.3s, width 0.3s; } .mx_RoomBreadcrumbs_animate { margin-left: 0; - transition: transform 0.3s, width 0.3s; width: 32px; transform: scale(1); } @@ -50,5 +46,34 @@ limitations under the License. width: 0; transform: scale(0); } + + + // Note: we have to manually control the gradient and stuff, but the IndicatorScrollbar + // will deal with left/right positioning for us. Normally we'd use position:sticky on + // a few key elements, however that doesn't work in horizontal scrolling scenarios. + + .mx_IndicatorScrollbar_leftOverflowIndicator, + .mx_IndicatorScrollbar_rightOverflowIndicator { + display: none; + } + + &.mx_IndicatorScrollbar_leftOverflow .mx_IndicatorScrollbar_leftOverflowIndicator, + &.mx_IndicatorScrollbar_rightOverflow .mx_IndicatorScrollbar_rightOverflowIndicator { + position: absolute; + top: 0; + bottom: 0; + width: 15px; + display: block; + pointer-events: none; + z-index: 100; + } + + .mx_IndicatorScrollbar_leftOverflowIndicator { + background: linear-gradient(to left, $panel-gradient); + } + + .mx_IndicatorScrollbar_rightOverflowIndicator { + background: linear-gradient(to right, $panel-gradient); + } } diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js index e1516d1f64..4dc77d73b9 100644 --- a/src/components/structures/IndicatorScrollbar.js +++ b/src/components/structures/IndicatorScrollbar.js @@ -15,9 +15,17 @@ limitations under the License. */ import React from "react"; +import PropTypes from "prop-types"; import AutoHideScrollbar from "./AutoHideScrollbar"; export default class IndicatorScrollbar extends React.Component { + static PropTypes = { + // If true, the scrollbar will append mx_IndicatorScrollbar_leftOverflowIndicator + // and mx_IndicatorScrollbar_rightOverflowIndicator elements to the list for positioning + // by the parent element. + trackHorizontalOverflow: PropTypes.bool, + }; + constructor(props) { super(props); this._collectScroller = this._collectScroller.bind(this); @@ -25,6 +33,11 @@ export default class IndicatorScrollbar extends React.Component { this.checkOverflow = this.checkOverflow.bind(this); this._scrollElement = null; this._autoHideScrollbar = null; + + this.state = { + leftIndicatorOffset: 0, + rightIndicatorOffset: 0, + }; } _collectScroller(scroller) { @@ -43,6 +56,10 @@ export default class IndicatorScrollbar extends React.Component { const hasTopOverflow = this._scrollElement.scrollTop > 0; const hasBottomOverflow = this._scrollElement.scrollHeight > (this._scrollElement.scrollTop + this._scrollElement.clientHeight); + const hasLeftOverflow = this._scrollElement.scrollLeft > 0; + const hasRightOverflow = this._scrollElement.scrollWidth > + (this._scrollElement.scrollLeft + this._scrollElement.clientWidth); + if (hasTopOverflow) { this._scrollElement.classList.add("mx_IndicatorScrollbar_topOverflow"); } else { @@ -53,10 +70,30 @@ export default class IndicatorScrollbar extends React.Component { } else { this._scrollElement.classList.remove("mx_IndicatorScrollbar_bottomOverflow"); } + if (hasLeftOverflow) { + this._scrollElement.classList.add("mx_IndicatorScrollbar_leftOverflow"); + } else { + this._scrollElement.classList.remove("mx_IndicatorScrollbar_leftOverflow"); + } + if (hasRightOverflow) { + this._scrollElement.classList.add("mx_IndicatorScrollbar_rightOverflow"); + } else { + this._scrollElement.classList.remove("mx_IndicatorScrollbar_rightOverflow"); + } if (this._autoHideScrollbar) { this._autoHideScrollbar.checkOverflow(); } + + if (this.props.trackHorizontalOverflow) { + this.setState({ + // Offset from absolute position of the container + leftIndicatorOffset: hasLeftOverflow ? `${this._scrollElement.scrollLeft}px` : 0, + + // Negative because we're coming from the right + rightIndicatorOffset: hasRightOverflow ? `-${this._scrollElement.scrollLeft}px` : 0, + }); + } } getScrollTop() { @@ -70,12 +107,21 @@ export default class IndicatorScrollbar extends React.Component { } render() { + const leftIndicatorStyle = {left: this.state.leftIndicatorOffset}; + const rightIndicatorStyle = {right: this.state.rightIndicatorOffset}; + const leftOverflowIndicator = this.props.trackHorizontalOverflow + ?
      : null; + const rightOverflowIndicator = this.props.trackHorizontalOverflow + ?
      : null; + return ( + { leftOverflowIndicator } { this.props.children } + { rightOverflowIndicator } ); } } diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index cefd278399..e3e1f2fc1e 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -102,6 +102,8 @@ export default class RoomBreadcrumbs extends React.Component { render() { const Tooltip = sdk.getComponent('elements.Tooltip'); + const IndicatorScrollbar = sdk.getComponent('structures.IndicatorScrollbar'); + // check for collapsed here and // not at parent so we keep // rooms in our state @@ -113,6 +115,7 @@ export default class RoomBreadcrumbs extends React.Component { const avatars = rooms.map(({room, animated, hover}, i) => { const isFirst = i === 0; const classes = classNames({ + "mx_RoomBreadcrumbs_crumb": true, "mx_RoomBreadcrumbs_preAnimate": isFirst && !animated, "mx_RoomBreadcrumbs_animate": isFirst, }); @@ -130,6 +133,11 @@ export default class RoomBreadcrumbs extends React.Component { ); }); - return (
      { avatars }
      ); + return ( + + { avatars } + + ); } } From 1928c4347697fda2271802d51878cb376079371a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 28 Mar 2019 12:27:33 +0000 Subject: [PATCH 131/481] Check the local storage fallback for crypto store This adds additional consistency checks to examine the local storage fallback for the crypto store as well as the primary IndexedDB variant. Part of https://github.com/vector-im/riot-web/issues/9309 --- src/utils/StorageManager.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index 472e1c93d4..a669ed9176 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -15,6 +15,7 @@ limitations under the License. */ import Matrix from 'matrix-js-sdk'; +import LocalStorageCryptoStore from 'matrix-js-sdk/lib/crypto/store/localStorage-crypto-store'; import Analytics from '../Analytics'; const localStorage = window.localStorage; @@ -78,15 +79,10 @@ export async function checkConsistency() { } if (indexedDB) { - try { - dataInCryptoStore = await Matrix.IndexedDBCryptoStore.exists( - indexedDB, CRYPTO_STORE_NAME, - ); - log(`Crypto store contains data? ${dataInCryptoStore}`); - } catch (e) { + const results = await checkCryptoStore(); + dataInCryptoStore = results.exists; + if (!results.healthy) { healthy = false; - error("Crypto store inaccessible", e); - track("Crypto store inaccessible"); } } else { healthy = false; @@ -111,3 +107,26 @@ export async function checkConsistency() { track("Consistency checks failed"); } } + +async function checkCryptoStore() { + let exists = false; + try { + exists = await Matrix.IndexedDBCryptoStore.exists( + indexedDB, CRYPTO_STORE_NAME, + ); + log(`Crypto store using IndexedDB contains data? ${exists}`); + return { exists, healthy: true }; + } catch (e) { + error("Crypto store using IndexedDB inaccessible", e); + track("Crypto store using IndexedDB inaccessible"); + } + try { + exists = await LocalStorageCryptoStore.exists(localStorage); + log(`Crypto store using local storage contains data? ${exists}`); + return { exists, healthy: true }; + } catch (e) { + error("Crypto store using local storage inaccessible", e); + track("Crypto store using local storage inaccessible"); + } + return { exists, healthy: false }; +} From f396cf830c7b626cd6fb1e174a7c4b2cffea7dc4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 28 Mar 2019 12:40:38 +0000 Subject: [PATCH 132/481] Clarify when memory stores are being used This adds logging for the cases where memory only stores are being used. It also reorganises the sync store path to match the crypto store. Part of https://github.com/vector-im/riot-web/issues/9309 --- src/utils/StorageManager.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index a669ed9176..89fa0d290b 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -62,15 +62,9 @@ export async function checkConsistency() { } if (indexedDB && localStorage) { - try { - const dataInSyncStore = await Matrix.IndexedDBStore.exists( - indexedDB, SYNC_STORE_NAME, - ); - log(`Sync store contains data? ${dataInSyncStore}`); - } catch (e) { + const results = await checkSyncStore(); + if (!results.healthy) { healthy = false; - error("Sync store inaccessible", e); - track("Sync store inaccessible"); } } else { healthy = false; @@ -108,6 +102,22 @@ export async function checkConsistency() { } } +async function checkSyncStore() { + let exists = false; + try { + exists = await Matrix.IndexedDBStore.exists( + indexedDB, SYNC_STORE_NAME, + ); + log(`Sync store using IndexedDB contains data? ${exists}`); + return { exists, healthy: true }; + } catch (e) { + error("Sync store using IndexedDB inaccessible", e); + track("Sync store using IndexedDB inaccessible"); + } + log("Sync store using memory only"); + return { exists, healthy: false }; +} + async function checkCryptoStore() { let exists = false; try { @@ -128,5 +138,6 @@ async function checkCryptoStore() { error("Crypto store using local storage inaccessible", e); track("Crypto store using local storage inaccessible"); } + log("Crypto store using memory only"); return { exists, healthy: false }; } From 6a840a56d6c232dfc51d6eed79eba6834e7e6edc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Mar 2019 09:50:17 -0600 Subject: [PATCH 133/481] Add a comment to explain the state of affairs for refs.messagePanel --- src/components/structures/RoomView.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 23d5b2f127..3e3e48cf25 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -429,6 +429,12 @@ module.exports = React.createClass({ roomView.addEventListener('dragend', this.onDragLeaveOrEnd); } } + + // Note: We check the ref here with a flag because componentDidMount, despite + // documentation, does not define our messagePanel ref. It looks like our spinner + // 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.refs.messagePanel && !this.state.atEndOfLiveTimelineInit) { this.setState({ atEndOfLiveTimelineInit: true, From f73556d27870f4f259e917d5f48c24e9e1b3070a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Mar 2019 09:52:12 -0600 Subject: [PATCH 134/481] Remove unnecessary params --- src/components/views/rooms/RoomBreadcrumbs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index 403c017edb..27d0adbdfe 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -58,7 +58,7 @@ export default class RoomBreadcrumbs extends React.Component { dis.unregister(this._dispatcherRef); } - componentDidUpdate(props, state) { + componentDidUpdate() { const rooms = this.state.rooms.slice(); if (rooms.length) { From c87ee979c72cbcc24040e453d8f904c0b64bd172 Mon Sep 17 00:00:00 2001 From: "J. A. Durieux" Date: Thu, 21 Mar 2019 15:47:01 +0000 Subject: [PATCH 135/481] Translated using Weblate (Dutch) Currently translated at 79.3% (1237 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 513 ++++++++++++++++++++++++++------------- 1 file changed, 350 insertions(+), 163 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 03bd3d4b7e..9fc7ef99b4 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -34,7 +34,7 @@ "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Kan niet met de thuisserver verbinden via HTTP wanneer er een HTTPS-URL in je browser balk staat. Gebruik HTTPS of activeer onveilige scripts.", "Can't load user settings": "Kan de gebruikersinstellingen niet laden", "Change Password": "Wachtwoord veranderen", - "%(senderName)s changed their profile picture.": "%(senderName)s heeft zijn of haar profielfoto veranderd.", + "%(senderName)s changed their profile picture.": "%(senderName)s heeft een nieuwe profielfoto ingesteld.", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s heeft het machtsniveau van %(powerLevelDiffText)s gewijzigd.", "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s heeft de ruimtenaam van %(roomName)s gewijzigd.", "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s heeft het onderwerp gewijzigd naar \"%(topic)s\".", @@ -43,12 +43,12 @@ "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het veranderen van het wachtwoord zal op het moment alle eind-tot-eind encryptie sleutels resetten, wat alle versleutelde gespreksgeschiedenis onleesbaar zou maken, behalve als je eerst je ruimtesleutels exporteert en achteraf opnieuw importeert. Dit zal worden verbeterd in de toekomst.", "Clear Cache and Reload": "Cache Legen en Herladen", "Clear Cache": "Cache Legen", - "Click here to fix": "Klik hier om op te lossen", - "Click to mute audio": "Klik om audio te dempen", - "Click to mute video": "Klik om de video te dempen", - "click to reveal": "klik om te laten zien", - "Click to unmute video": "Klik om de demping van de video op te heffen", - "Click to unmute audio": "Klik om het dempen van het geluid op te heffen", + "Click here to fix": "Klik hier om te repareren", + "Click to mute audio": "Klik om het geluid uit te zetten", + "Click to mute video": "Klik om het geluid van de video uit te zetten", + "click to reveal": "klik om te tonen", + "Click to unmute video": "Klik om het geluid van de video weer aan te zetten", + "Click to unmute audio": "Klik om het geluid weer aan te zetten", "Command error": "Opdrachtfout", "Commands": "Opdrachten", "Conference call failed.": "Conferentiegesprek mislukt.", @@ -58,7 +58,7 @@ "Confirm password": "Bevestigen wachtwoord", "Confirm your new password": "Bevestig je nieuwe wachtwoord", "Continue": "Doorgaan", - "Could not connect to the integration server": "Mislukt om te verbinden met de integratieserver", + "Could not connect to the integration server": "Verbinding met de integratieserver mislukt", "Cancel": "Annuleren", "Accept": "Accepteren", "Active call (%(roomName)s)": "Actief gesprek (%(roomName)s)", @@ -70,7 +70,7 @@ "No Microphones detected": "Geen microfoons gevonden", "No Webcams detected": "Geen webcams gevonden", "No media permissions": "Geen mediatoestemmingen", - "You may need to manually permit Riot to access your microphone/webcam": "U moet Riot wellicht handmatig toestemming geven om uw microfoon/webcam te gebruiken", + "You may need to manually permit Riot to access your microphone/webcam": "U moet Riot wellicht handmatig toestaan uw microfoon/webcam te gebruiken", "Default Device": "Standaardapparaat", "Microphone": "Microfoon", "Camera": "Camera", @@ -125,23 +125,23 @@ "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-gesprek gestart.", "Privacy warning": "Privacywaarschuwing", "Private Chat": "Privégesprek", - "Privileged Users": "Gebruikers met rechten", + "Privileged Users": "Bevoorrechte gebruikers", "Profile": "Profiel", "Public Chat": "Publiek Gesprek", "Reason": "Reden", "Reason: %(reasonText)s": "Reden: %(reasonText)s", "Revoke Moderator": "Beheerder terugtrekken", "Refer a friend to Riot:": "Laat een vriend weten over Riot:", - "Register": "Registreer", + "Register": "Registreren", "%(targetName)s rejected the invitation.": "%(targetName)s heeft de uitnodiging geweigerd.", "Reject invitation": "Uitnodiging weigeren", "Rejoin": "Opnieuw toetreden", "Remote addresses for this room:": "Adres op afstand voor deze ruimte:", "Remove Contact Information?": "Contactinformatie Verwijderen?", "Send Invites": "Uitnodigingen versturen", - "Start a chat": "Gesprek starten", + "Start a chat": "Gesprek beginnen", "Start authentication": "Authenticatie starten", - "Start Chat": "Gesprek starten", + "Start Chat": "Gesprek beginnen", "Submit": "Bevestigen", "Success": "Gereed", "Tagged as: ": "Gelabeld als: ", @@ -175,7 +175,7 @@ "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de naam van de ruimte verwijderd.", - "Create a new chat or reuse an existing one": "Maak een nieuw gesprek aan of hergebruik een al bestaand gesprek", + "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik een bestaand", "Create Room": "Maak een ruimte aan", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen commando", @@ -210,7 +210,7 @@ "Default": "Standaard", "Displays action": "Geeft actie weer", "Drop here to tag %(section)s": "Hier naartoe verplaatsen om %(section)s te etiketteren", - "Email, name or matrix ID": "E-mail, naam of matrix-ID", + "Email, name or matrix ID": "E-mailadres, naam of matrix-ID", "Emoji": "Emoji", "Enable encryption": "Versleuteling inschakelen", "Enable Notifications": "Notificaties inschakelen", @@ -231,26 +231,26 @@ "Existing Call": "Bestaande oproep", "Export": "Exporteren", "Export E2E room keys": "Exporteer E2E-ruimte-sleutels", - "Failed to ban user": "Niet gelukt om de gebruiker te verbannen", - "Failed to change power level": "Niet gelukt om het machtsniveau te wijzigen", - "Failed to fetch avatar URL": "Niet gelukt om de avatar-URL op te halen", - "Failed to join room": "Niet gelukt om tot de ruimte toe te treden", - "Failed to leave room": "Niet gelukt om de ruimte te verlaten", - "Failed to load timeline position": "Niet gelukt om de tijdlijnpositie te laden", - "Failed to mute user": "Niet gelukt om de gebruiker te dempen", - "Failed to reject invite": "Niet gelukt om de uitnodiging te weigeren", - "Failed to reject invitation": "Niet gelukt om de uitnodiging te weigeren", + "Failed to ban user": "Niet gelukt de gebruiker te verbannen", + "Failed to change power level": "Niet gelukt het machtsniveau te wijzigen", + "Failed to fetch avatar URL": "Niet gelukt de avatar-URL op te halen", + "Failed to join room": "Niet gelukt tot de ruimte toe te treden", + "Failed to leave room": "Niet gelukt de ruimte te verlaten", + "Failed to load timeline position": "Niet gelukt de tijdlijnpositie te laden", + "Failed to mute user": "Niet gelukt de gebruiker het zwijgen op te leggen", + "Failed to reject invite": "Niet gelukt de uitnodiging te weigeren", + "Failed to reject invitation": "Niet gelukt de uitnodiging te weigeren", "Failed to save settings": "Niet gelukt om de instellingen op te slaan", - "Failed to send email": "Niet gelukt om de e-mail te versturen", - "Failed to send request.": "Niet gelukt om het verzoek te versturen.", + "Failed to send email": "Niet gelukt de e-mail te versturen", + "Failed to send request.": "Niet gelukt het verzoek te versturen.", "Failed to set avatar.": "Niet gelukt om de avatar in te stellen.", - "Failed to set display name": "Niet gelukt om de weergavenaam in te stellen", + "Failed to set display name": "Niet gelukt de weergavenaam in te stellen", "Failed to set up conference call": "Niet gelukt om een vergadergesprek te maken", - "Failed to toggle moderator status": "Niet gelukt om de moderatorstatus te veranderen", - "Failed to unban": "Niet gelukt om te ontbannen", - "Failed to upload file": "Niet gelukt om het bestand te uploaden", - "Failed to upload profile picture!": "Niet gelukt om een profiel foto te uploaden!", - "Failed to verify email address: make sure you clicked the link in the email": "Niet gelukt om het e-mailadres te verifiëren: wees er zeker van dat je de link in de e-mail hebt aangeklikt", + "Failed to toggle moderator status": "Niet gelukt de moderatorstatus te veranderen", + "Failed to unban": "Ontbannen mislukt", + "Failed to upload file": "Niet gelukt het bestand te uploaden", + "Failed to upload profile picture!": "Niet gelukt een profielfoto te uploaden!", + "Failed to verify email address: make sure you clicked the link in the email": "Niet gelukt het e-mailadres te verifiëren: zorg ervoor dat je de link in de e-mail hebt aangeklikt", "Failure to create room": "Het aanmaken van een ruimte is mislukt", "Favourites": "Favorieten", "Fill screen": "Scherm vullen", @@ -283,7 +283,7 @@ "Invalid Email Address": "Ongeldig e-mailadres", "Invalid file%(extra)s": "Ongeldig bestand%(extra)s", "%(senderName)s invited %(targetName)s.": "%(senderName)s heeft %(targetName)s uitgenodigd.", - "Invite new room members": "Nieuwe ruimte leden uitnodigen", + "Invite new room members": "Nieuwe ruimteleden uitnodigen", "Invited": "Uitgenodigd", "Invites": "Uitnodigingen", "Invites user with given id to current room": "Nodigt de gebruiker met het gegeven ID uit in de huidige ruimte", @@ -319,8 +319,8 @@ "Missing user_id in request": "De user_id mist in het verzoek", "Mobile phone number": "Mobiele-telefoonnummer", "Mobile phone number (optional)": "Mobiele-telefoonnummer (optioneel)", - "Never send encrypted messages to unverified devices from this device": "Nooit versleutelde berichten vanaf dit apparaat naar niet geverifieerde apparaten versturen", - "Never send encrypted messages to unverified devices in this room from this device": "Nooit vanaf dit apparaat versleutelde berichten naar niet geverifieerde apparaten in deze ruimte sturen", + "Never send encrypted messages to unverified devices from this device": "Nooit versleutelde berichten vanaf dit apparaat naar ongeverifieerde apparaten versturen", + "Never send encrypted messages to unverified devices in this room from this device": "Vanaf dit apparaat nooit versleutelde berichten naar ongeverifieerde apparaten in deze ruimte sturen", "New address (e.g. #foo:%(localDomain)s)": "Nieuw adres (bijv. #foo:%(localDomain)s)", "New passwords don't match": "Nieuwe wachtwoorden komen niet overeen", "New passwords must match each other.": "Nieuwe wachtwoorden moeten overeenkomen.", @@ -330,23 +330,23 @@ "Power level must be positive integer.": "Machtsniveau moet een positief geheel getal zijn.", "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s heeft zijn of haar weergavenaam (%(oldDisplayName)s) verwijderd.", "%(senderName)s removed their profile picture.": "%(senderName)s heeft zijn of haar profielfoto verwijderd.", - "Failed to kick": "Niet gelukt om te er uit te zetten", + "Failed to kick": "Niet gelukt de ruimte uit te zetten", "Press to start a chat with someone": "Druk op om een gesprek met iemand te starten", "Remove %(threePid)s?": "%(threePid)s verwijderen?", "%(senderName)s requested a VoIP conference.": "%(senderName)s heeft een VoIP-gesprek aangevraagd.", "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het wachtwoord veranderen betekent momenteel dat alle end-to-endbeveiligingssleutels op alle apparaten veranderen waardoor versleutelde gespreksgeschiedenis onleesbaar wordt, behalve als je eerst de ruimte sleutels exporteert en daarna opnieuw importeert. Dit zal in de toekomst verbeterd worden.", "Results from DuckDuckGo": "Resultaten van DuckDuckGo", "Return to login screen": "Naar het inlogscherm terugkeren", - "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen permissie om je notificaties te versturen - controleer je browserinstellingen", - "Riot was not given permission to send notifications - please try again": "Riot heeft geen permissie gekregen om notificaties te versturen - probeer het opnieuw", + "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen toestemming je mededelingen te versturen - controleer je browserinstellingen", + "Riot was not given permission to send notifications - please try again": "Riot heeft geen toestemming gekregen mededelingen te versturen - probeer het opnieuw", "riot-web version:": "riot-web versie:", "Room %(roomId)s not visible": "Ruimte %(roomId)s is niet zichtbaar", - "Room Colour": "Ruimtekleur", + "Room Colour": "Kleur van de ruimte", "Room contains unknown devices": "De ruimte bevat onbekende apparaten", "Room name (optional)": "Ruimtenaam (optioneel)", "%(roomName)s does not exist.": "%(roomName)s bestaat niet.", "%(roomName)s is not accessible at this time.": "%(roomName)s is niet toegankelijk op dit moment.", - "Rooms": "Ruimtes", + "Rooms": "Ruimten", "Save": "Opslaan", "Scroll to bottom of page": "Scroll naar de onderkant van de pagina", "Scroll to unread messages": "Scroll naar ongelezen berichten", @@ -357,7 +357,7 @@ "Sender device information": "Afzenderapparaatinformatie", "Send Reset Email": "Stuur Reset-E-mail", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s stuurde een afbeelding.", - "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s stuurde een uitnodiging naar %(targetDisplayName)s om tot de ruimte toe te treden.", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s nodigde %(targetDisplayName)s uit tot de ruimte toe te treden.", "Server error": "Serverfout", "Server may be unavailable or overloaded": "De server kan onbereikbaar of overbelast zijn", "Server may be unavailable, overloaded, or search timed out :(": "De server is misschien onbereikbaar, overbelast of het zoeken duurde te lang :(", @@ -369,7 +369,7 @@ "Kick": "Er uit sturen", "Kicks user with given id": "Stuurt de gebruiker met het gegeven ID er uit", "%(senderName)s set a profile picture.": "%(senderName)s heeft een profielfoto ingesteld.", - "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s heeft zijn of haar weergavenaam naar %(displayName)s veranderd.", + "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s heeft de weergavenaam %(displayName)s aangenomen.", "Show panel": "Paneel weergeven", "Show Text Formatting Toolbar": "Tekstopmaakwerkbalk Weergeven", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Laat de tijd in twaalf uur formaat zien (bijv. 2:30pm)", @@ -383,10 +383,10 @@ "The phone number entered looks invalid": "Het telefoonnummer dat ingevoerd is ziet er ongeldig uit", "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "De versleutelingssleutel die je hebt verstrekt komt overeen met de versleutelingssleutel die je hebt ontvangen van %(userId)s's apparaat %(deviceId)s. Apparaat is gemarkeerd als geverifieerd.", "This email address is already in use": "Dit e-mailadres is al in gebruik", - "This email address was not found": "Dit e-mailadres was niet gevonden", + "This email address was not found": "Kon dit e-mailadres niet vinden", "The email address linked to your account must be entered.": "Het e-mailadres dat met je account verbonden is moet worden ingevoerd.", "The file '%(fileName)s' exceeds this home server's size limit for uploads": "Het bestand '%(fileName)s' overtreft de maximale bestandsgrootte voor uploads van deze thuisserver", - "The file '%(fileName)s' failed to upload": "Het is niet gelukt om het bestand '%(fileName)s' te uploaden", + "The file '%(fileName)s' failed to upload": "Het is niet gelukt het bestand '%(fileName)s' te uploaden", "The remote side failed to pick up": "De andere kant heeft niet opgenomen", "This Home Server does not support login using email address.": "Deze Thuisserver ondersteunt het inloggen met een e-mailadres niet.", "This invitation was sent to an email address which is not associated with this account:": "Deze uitnodiging was naar een e-mailadres gestuurd die niet geassocieerd is met dit account:", @@ -403,20 +403,20 @@ "To link to a room it must have an address.": "Om naar een ruimte te linken moet het een adres hebben.", "To reset your password, enter the email address linked to your account": "Voer het e-mailadres dat met je account verbonden is in om je wachtwoord opnieuw in te stellen", "To use it, just wait for autocomplete results to load and tab through them.": "Om het te gebruiken, wacht tot de automatisch aangevulde resultaten geladen zijn en tab er doorheen.", - "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Je probeerde een specifiek punt in de tijdlijn van deze ruimte te laden maar je hebt niet de permissie om de desbetreffende berichten te zien.", - "Tried to load a specific point in this room's timeline, but was unable to find it.": "Het is niet gelukt om een specifiek punt in de tijdlijn van deze ruimte te laden.", + "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Je probeerde een gegeven punt in de tijdlijn van deze ruimte te laden maar je hebt geen toestemming de desbetreffende berichten te zien.", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "Probeerde tevergeefs een gegeven punt in de tijdlijn van deze ruimte te laden.", "Turn Markdown off": "Zet Markdown uit", "Turn Markdown on": "Zet Markdown aan", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s heeft end-to-endbeveiliging aangezet (algoritme %(algorithm)s).", - "Unable to add email address": "Niet mogelijk om e-mailadres toe te voegen", - "Unable to remove contact information": "Niet mogelijk om contactinformatie te verwijderen", - "Unable to verify email address.": "Niet mogelijk om het e-mailadres te verifiëren.", + "Unable to add email address": "E-mailadres toevoegen mislukt", + "Unable to remove contact information": "Contactinformatie verwijderen mislukt", + "Unable to verify email address.": "Niet mogelijk het e-mailadres te controleren.", "Unban": "Ontbannen", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s ontbande %(targetName)s.", - "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Niet mogelijk om vast te stellen dat het adres waar deze uitnodiging naartoe was verstuurd overeenkomt met het adres dat is geassocieerd met je account.", - "Unable to capture screen": "Niet mogelijk om het scherm vast te leggen", - "Unable to enable Notifications": "Niet mogelijk om notificaties aan te zetten", - "Unable to load device list": "Niet mogelijk om de lijst met apparaten te laden", + "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Onmogelijk na te gaan of het adres waarheen deze uitnodiging was verstuurd overeenkomt met het adres dat bij je account behoort.", + "Unable to capture screen": "Niet mogelijk een schermfoto te maken", + "Unable to enable Notifications": "Niet mogelijk mededelingen aan te zetten", + "Unable to load device list": "Niet mogelijk de lijst van apparaten te laden", "Undecryptable": "Niet ontsleutelbaar", "Unencrypted room": "Ontsleutelde ruimte", "unencrypted": "ontsleuteld", @@ -474,9 +474,9 @@ "You are already in a call.": "Je bent al in gesprek.", "You're not in any rooms yet! Press to make a room or to browse the directory": "Je zit nog niet in een ruimte! Druk op om een ruimte te maken of om door de catalogus te bladeren", "You are trying to access %(roomName)s.": "Je probeert in %(roomName)s toe te treden.", - "You cannot place a call with yourself.": "Je kan geen spraakoproep met jezelf maken.", - "You cannot place VoIP calls in this browser.": "Je kan geen VoIP-oproepen in deze browser doen.", - "You do not have permission to post to this room": "Je hebt geen permissie om in deze ruimte te praten", + "You cannot place a call with yourself.": "Je kunt geen spraakoproep met jezelf maken.", + "You cannot place VoIP calls in this browser.": "Je kunt in deze browser geen VoIP-oproepen plegen.", + "You do not have permission to post to this room": "Je hebt geen toestemming in deze ruimte te praten", "You have been banned from %(roomName)s by %(userName)s.": "Je bent verbannen van %(roomName)s door %(userName)s.", "You have been invited to join this room by %(inviterName)s": "Je bent in deze ruimte uitgenodigd door %(inviterName)s", "You have been kicked from %(roomName)s by %(userName)s.": "Je bent uit %(roomName)s gezet door %(userName)s.", @@ -485,17 +485,17 @@ "You have enabled URL previews by default.": "Je hebt URL-voorvertoningen standaard aangezet.", "You have no visible notifications": "Je hebt geen zichtbare notificaties", "You may wish to login with a different account, or add this email to this account.": "Je wilt misschien met een ander account inloggen of deze e-mail aan je account toevoegen.", - "You must register to use this functionality": "Je moet je registreren om deze functionaliteit te gebruiken", - "You need to be able to invite users to do that.": "Je moet bevoegd zijn om gebruikers uit te nodigen om dat te doen.", - "You need to be logged in.": "Je moet ingelogd zijn.", + "You must register to use this functionality": "Je moet je registreren om deze functie te gebruiken", + "You need to be able to invite users to do that.": "Dat vereist de bevoegdheid gebruikers uit te nodigen.", + "You need to be logged in.": "Aanmelding vereist.", "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het ziet er naar uit dat je e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", - "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Je wachtwoord is succesvol veranderd. Je zal geen notificaties op andere apparaten ontvangen totdat je er opnieuw inlogd", + "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Je wachtwoord is succesvol veranderd. Je zult op andere apparaten geen mededelingen ontvangen totdat je er opnieuw inlogt", "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat je in een gesprek zit, weet je zeker dat je wilt afsluiten?", "You seem to be uploading files, are you sure you want to quit?": "Het ziet er naar uit dat je bestanden aan het uploaden bent, weet je zeker dat je wilt afsluiten?", "You should not yet trust it to secure data": "Je moet het nog niet vertrouwen om gegevens te beveiligen", - "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Je zal deze verandering niet terug kunnen draaien omdat je de gebruiker naar hetzelfde machtsniveau als jezelf promoot.", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Je zult deze verandering niet terug kunnen draaien omdat je de gebruiker tot je eigen machtsniveau bevordert.", "Your home server does not support device management.": "Je thuisserver ondersteund geen apparaatbeheer.", "This server does not support authentication with a phone number.": "Deze server ondersteunt geen authenticatie met een telefoonnummer.", "Missing password.": "Het wachtwoord mist.", @@ -533,42 +533,42 @@ "Desktop specific": "Desktop-specifiek", "Analytics": "Analysegegevens", "Options": "Opties", - "Riot collects anonymous analytics to allow us to improve the application.": "Riot verzamelt anonieme analysegegevens die het mogelijk maken om de applicatie te verbeteren.", + "Riot collects anonymous analytics to allow us to improve the application.": "Riot verzamelt anonieme analysegegevens die het mogelijk maken het programma te verbeteren.", "Passphrases must match": "Wachtzinnen moeten overeenkomen", "Passphrase must not be empty": "Wachtzin mag niet leeg zijn", "Export room keys": "Ruimtesleutels exporteren", "Confirm passphrase": "Wachtzin bevestigen", "Import room keys": "Ruimtesleutels importeren", - "File to import": "Bestand om te importeren", - "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.": "Dit proces maakt het mogelijk om de sleutels van je ontvangen berichten in versleutelde ruimtes naar een lokaal bestand te exporteren. Je zal daarna in de toekomst het bestand in een ander Matrix-programma kunnen importeren zodat dat programma ook deze berichten kan ontsleutelen.", - "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.": "Het geëxporteerde bestand zal het voor iedereen dat het kan lezen mogelijk maken om alle berichten die jij kan zien te ontsleutelen, je zal daarom voorzichtig moeten zijn en het veilig houden. Om hiermee te helpen zou je een wachtzin moeten invoeren hieronder, deze zal dan gebruikt worden om de geëxporteerde gegevens te versleutelen. Het is dan alleen mogelijk om de gegevens te importeren met hetzelfde wachtwoord.", - "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.": "Dit proces maakt het mogelijk om versleutelingssleutels die je eerst had geëxporteerd vanaf een ander Matrix-programma te importeren. Je zal daarna alle berichten kunnen ontsleutelen die het andere programma ook kon ontsleutelen.", - "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Het te exporteren bestand zal beveiligd zijn met een wachtzin. Je moet hier een wachtzin invoeren om het bestand te ontsleutelen.", - "You must join the room to see its files": "Je moet tot een ruimte toetreden om de bestanden te zien", + "File to import": "Het in te lezen bestand", + "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.": "Hiermee kun je de sleutels van je ontvangen berichten in versleutelde ruimten naar een lokaal bestand wegschrijven. Je kunt dan later het bestand in een ander Matrix-programma inlezen, zodat ook dat programma deze berichten kan ontsleutelen.", + "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.": "Iedereen die het weggeschreven bestand kan lezen kan daarmee alle berichten die jij kunt zien ontcijferen. Je zult dus voorzichtig moeten zijn en het bestand veilig bewaren. Daartoe kun je hieronder een wachtzin invoeren, die dan gebruikt zal worden om de geëxporteerde gegevens te versleutelen. Het is dan enkel mogelijk de gegevens in te lezen met dezelfde wachtzin.", + "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.": "Hiermee kun je eerder vanuit een ander Matrixprogramma weggeschreven versleutelingscodes inlezen, zodat je alle berichten die het andere programma kon ontcijferen ook hier zult kunnen lezen.", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Het weggeschreven bestand is beveiligd met een wachtzin. Voer die wachtzin hier in om het bestand te ontcijferen.", + "You must join the room to see its files": "Je moet tot de ruimte toetreden om de bestanden te kunnen zien", "Reject all %(invitedRooms)s invites": "Alle %(invitedRooms)s uitnodigingen afslaan", "Start new chat": "Nieuw gesprek starten", - "Failed to invite": "Niet gelukt om uit te nodigen", - "Failed to invite user": "Niet gelukt om de gebruiker uit te nodigen", - "Failed to invite the following users to the %(roomName)s room:": "Niet gelukt om de volgende gebruikers voor de %(roomName)s ruimte uit te nodigen:", + "Failed to invite": "Uitnodigen is mislukt", + "Failed to invite user": "Niet gelukt de gebruiker uit te nodigen", + "Failed to invite the following users to the %(roomName)s room:": "Niet gelukt de volgende gebruikers tot de ruimte %(roomName)s uit te nodigen:", "Confirm Removal": "Verwijdering Bevestigen", "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Weet je zeker dat je deze gebeurtenis wilt verwijderen? Wees er wel van bewust dat als je een ruimtenaam of onderwerp verwijderd je de verandering ongedaan kunt maken.", "Unknown error": "Onbekende fout", "Incorrect password": "Incorrect wachtwoord", - "To continue, please enter your password.": "Om verder te gaan, voer je wachtwoord in.", - "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Om te verifiëren dat dit apparaat vertrouwd kan worden, contacteer de eigenaar op een andere manier (bijv. persoonlijk of via een telefoontje) en vraag of de sleutel die ze zien in de Gebruikersinstellingen voor dit apparaat overeenkomt met de onderstaande sleutel:", + "To continue, please enter your password.": "Voer om verder te gaan je wachtwoord in.", + "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Zoek op een andere manier (bijv. in levenden lijve of per telefoon) contact met de eigenaar om te controleren of dit apparaat vertrouwd kan worden, en vraag of de sleutel voor dit apparaat in hun Gebruikersinstellingen gelijk is aan onderstaande sleutel:", "Device name": "Apparaatnaam", "Device Name": "Apparaatnaam", "Device key": "Apparaatsleutel", - "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Als het overeenkomt, druk op de knop 'verifiëren' hieronder. Als het niet overeenkomt, dan is er iemand anders die dit apparaat onderschept en dan zal je waarschijnlijk in plaats daarvan op de 'blokkeren' knop willen drukken.", + "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Komen ze overeen? Zo ja, druk dan op de knop 'verifiëren' hieronder. Zo neen, druk dan liever op de knop 'blokkeren', want dan onderschept iemand berichten naar dit apparaat.", "Blacklist": "Blokkeren", - "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Je bent momenteel geverifieerde apparaten aan het buitensluiten; om berichten naar deze apparaten te versturen moet je ze verifiëren.", - "Unblacklist": "Niet buitensluiten", + "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit je ongecontroleerde apparaten uit; om berichten naar deze apparaten te versturen moet je ze controleren.", + "Unblacklist": "Deblokkeren", "In future this verification process will be more sophisticated.": "In de toekomst zal dit verificatie proces meer geraffineerd zijn.", "Verify device": "Apparaat verifiëren", "I verify that the keys match": "Ik verifieer dat de sleutels overeenkomen", - "Unable to restore session": "Het is niet mogelijk om de sessie te herstellen", + "Unable to restore session": "Het is niet mogelijk de sessie te herstellen", "If you have previously used a more recent version of Riot, your session may be incompatible with this version. Close this window and return to the more recent version.": "Als je eerst gebruik hebt gemaakt van een recentere versie van Riot, dan is je sessie misschien onverenigbaar met deze versie. Sluit dit scherm en ga terug naar de recentere versie.", - "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We raden je aan om door het verificatieproces van elk apparaat te gaan om te bevestigen dat ze tot de legitieme eigenaar behoren maar je kan het bericht versturen zonder te verifiëren als je dat liever doet.", + "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We raden je aan ieder apparaat te controleren om te vast te stellen of ze tot de legitieme eigenaar behoren, maar je kunt het bericht desgewenst zonder controle versturen.", "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" bevat apparaten die je nog niet eerder hebt gezien.", "Unknown devices": "Onbekende apparaten", "Unknown Address": "Onbekend Adres", @@ -584,7 +584,7 @@ "Please check your email to continue registration.": "Bekijk je e-mail om door te gaan met de registratie.", "Token incorrect": "Bewijs incorrect", "Please enter the code it contains:": "Voer de code in die het bevat:", - "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Als je geen e-mailadres specificeert zal je niet je wachtwoord kunnen resetten. Weet je het zeker?", + "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Als je geen e-mailadres specificeert zul je je wachtwoord niet kunnen resetten. Weet je het zeker?", "You are registering with %(SelectedTeamName)s": "Je registreert je met %(SelectedTeamName)s", "Default server": "Standaardserver", "Custom server": "Alternatieve server", @@ -598,7 +598,7 @@ "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Je wordt zo naar een derde-partij-website verbonden zodat je het account kan legitimeren voor gebruik met %(integrationsUrl)s. Wil je doorgaan?", "Removed or unknown message type": "Verwijderd of onbekend berichttype", "URL Previews": "URL-Voorvertoningen", - "Drop file here to upload": "Bestand hier laten vallen om te uploaden", + "Drop file here to upload": "Bestand hierheen slepen om te uploaden", " (unsupported)": " (niet ondersteund)", "Ongoing conference call%(supportedText)s.": "Lopend groepsgesprek%(supportedText)s.", "Online": "Online", @@ -608,27 +608,27 @@ "Check for update": "Voor updates kijken", "Start chatting": "Start met praten", "Start Chatting": "Start Met Praten", - "Click on the button below to start chatting!": "Klik op de knop hieronder om te starten met praten!", + "Click on the button below to start chatting!": "Klik op de knop hieronder om het gesprek te beginnen!", "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s heeft de ruimte avatar aangepast naar ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s heeft de ruimte avatar verwijderd.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s veranderde de avatar voor %(roomName)s", "Username available": "Gebruikersnaam beschikbaar", "Username not available": "Gebruikersnaam niet beschikbaar", "Something went wrong!": "Iets ging niet goed!", - "This will be your account name on the homeserver, or you can pick a different server.": "Dit zal je account naam worden op de thuisserver of je kan een verschillende server pakken.", - "If you already have a Matrix account you can log in instead.": "Als je al een Matrix-account hebt kan je in plaats daarvan inloggen.", + "This will be your account name on the homeserver, or you can pick a different server.": "Dit zal je account naam worden op de thuisserver, of je kunt een andere server kiezen.", + "If you already have a Matrix account you can log in instead.": "Als je al een Matrix-account hebt kun je ook meteen inloggen.", "Your browser does not support the required cryptography extensions": "Je browser ondersteunt de benodigde cryptografie-extensies niet", "Not a valid Riot keyfile": "Niet een geldig Riot-sleutelbestand", "Authentication check failed: incorrect password?": "Authenticatie controle gefaald: incorrect wachtwoord?", "Disable Peer-to-Peer for 1:1 calls": "Peer-to-Peer voor 1:1 oproepen uitschakelen", "Do you want to set an email address?": "Wil je een e-mailadres instellen?", - "This will allow you to reset your password and receive notifications.": "Dit zal het mogelijk maken om je wachtwoord te resetten en notificaties te ontvangen.", + "This will allow you to reset your password and receive notifications.": "Hierdoor zul je je wachtwoord kunnen resetten en mededelingen ontvangen.", "To return to your account in future you need to set a password": "Om in de toekomst naar je account terug te gaan moet je een wachtwoord instellen", "Skip": "Overslaan", "Start verification": "Verificatie starten", "Share without verifying": "Delen zonder verificatie", "Ignore request": "Verzoek negeren", - "You added a new device '%(displayName)s', which is requesting encryption keys.": "Je hebt een nieuw apparaat '%(displayName)s' toegevoegd dat om versleutelingssleutels vraagt.", + "You added a new device '%(displayName)s', which is requesting encryption keys.": "Je hebt een nieuw apparaat '%(displayName)s' toegevoegd dat om ontcijferingssleutels vraagt.", "Your unverified device '%(displayName)s' is requesting encryption keys.": "Je niet geverifieerde apparaat '%(displayName)s' vraagt naar versleutelingssleutels.", "Encryption key request": "Verzoek voor versleutelingssleutel", "Define the power level of a user": "Definieer het machtsniveau van een gebruiker", @@ -649,11 +649,11 @@ "Revoke widget access": "Toegang tot widget intrekken", "Sets the room topic": "Wijzigt het ruimte-onderwerp", "The maximum permitted number of widgets have already been added to this room.": "Het maximum aantal toegestane widgets is al aan deze ruimte toegevoegd.", - "To get started, please pick a username!": "Om te beginnen, kies een gebruikersnaam!", - "Unable to create widget.": "Niet in staat om een widget te maken.", + "To get started, please pick a username!": "Kies allereerst een gebruikersnaam!", + "Unable to create widget.": "Niet in staat een widget te maken.", "Unbans user with given id": "Ontbant de gebruiker met het gegeven id", "You are not in this room.": "Je zit niet in deze ruimte.", - "You do not have permission to do that in this room.": "Je hebt geen permissie om dat te doen in deze ruimte.", + "You do not have permission to do that in this room.": "Je hebt geen toestemming dat in deze ruimte te doen.", "Verifies a user, device, and pubkey tuple": "Verifieert een combinatie van gebruiker, apparaat en publieke sleutel", "Autocomplete Delay (ms):": "Automatisch-aanvullen-vertraging (ms):", "Loading device info...": "Apparaatinformatie aan het laden...", @@ -662,7 +662,7 @@ "Featured Rooms:": "Prominente Ruimtes:", "Featured Users:": "Prominente Gebruikers:", "Automatically replace plain text Emoji": "Automatisch normale tekst vervangen met Emoji", - "Failed to upload image": "Het is niet gelukt om de afbeelding te uploaden", + "Failed to upload image": "Kon de afbeelding niet uploaden", "Hide avatars in user and room mentions": "Avatars in gebruiker- en ruimte-vermeldingen verbergen", "%(widgetName)s widget added by %(senderName)s": "%(widgetName)s-widget toegevoegd door %(senderName)s", "%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s-widget verwijderd door %(senderName)s", @@ -693,8 +693,8 @@ "Add to community": "Voeg toe aan community", "Failed to invite the following users to %(groupId)s:": "Inviteren gefaald van de volgende gebruikers in %(groupId)s:", "Failed to invite users to community": "Uitnodigen van gebruikers in community mislukt", - "Failed to invite users to %(groupId)s": "Niet gelukt om gebruikers uit te nodigen in %(groupId)s", - "Failed to add the following rooms to %(groupId)s:": "Niet gelukt om de volgende ruimtes toe te voegen aan %(groupId)s:", + "Failed to invite users to %(groupId)s": "Niet gelukt gebruikers uit te nodigen in %(groupId)s", + "Failed to add the following rooms to %(groupId)s:": "Niet gelukt de volgende ruimten toe te voegen aan %(groupId)s:", "Restricted": "Beperkte toegang", "Ignored user": "Genegeerde gebruiker", "You are now ignoring %(userId)s": "Je bent nu %(userId)s aan het negeren", @@ -704,14 +704,14 @@ "%(names)s and %(count)s others are typing|other": "%(names)s en %(count)s andere gebruikers zijn aan het typen", "%(names)s and %(count)s others are typing|one": "%(names)s en iemand anders is aan het typen", "Send": "Verstuur", - "Message Pinning": "Boodschap vastpinnen", + "Message Pinning": "Boodschap vastzetten", "Disable Emoji suggestions while typing": "Emoji suggesties tijdens het typen uitzetten", "Hide avatar changes": "Avatar veranderingen verbergen", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s", "Hide display name changes": "Weergavenaam wijzigingen verbergen", - "Enable inline URL previews by default": "Inline URL voorvertoning standaard aanzetten", - "Enable URL previews for this room (only affects you)": "URL voorvertoning in deze ruimte aanzetten (geldt alleen voor jou)", - "Enable URL previews by default for participants in this room": "URL voorvertoning standaard voor de gebruikers in deze ruimte aanzetten", + "Enable inline URL previews by default": "Inline URL-voorvertoning standaard aanzetten", + "Enable URL previews for this room (only affects you)": "URL-voorvertoning in deze ruimte aanzetten (geldt alleen voor jou)", + "Enable URL previews by default for participants in this room": "URL-voorvertoning standaard voor de gebruikers in deze ruimte aanzetten", "Delete %(count)s devices|other": "Verwijder %(count)s apparaten", "Delete %(count)s devices|one": "Verwijder apparaat", "Select devices": "Apparaten selecteren", @@ -723,8 +723,8 @@ "Unban this user?": "Deze gebruiker ontbannen?", "Ban this user?": "Deze gebruiker bannen?", "Disable big emoji in chat": "Grote emoji in gesprekken uitzetten", - "Mirror local video feed": "Lokale video aanvoering ook op andere locaties (Mirrors) opslaan", - "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Je kan deze actie niet ongedaan maken omdat je jezelf degradeert. Als je het laatste persoon met rechten bent, is het onmogelijk om de rechten terug te krijgen.", + "Mirror local video feed": "Lokale videoaanvoer ook elders opslaan (spiegelen)", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Je kunt deze actie niet ongedaan maken omdat je jezelf degradeert. Als je het laatste persoon met rechten bent, is het onmogelijk deze rechten terug te krijgen.", "Unignore": "Niet meer negeren", "Ignore": "Negeren", "Jump to read receipt": "Naar het laatst gelezen bericht gaan", @@ -749,16 +749,16 @@ "Unknown for %(duration)s": "Onbekend voor %(duration)s", "Unknown": "Onbekend", "Replying": "Aan het beantwoorden", - "No rooms to show": "Geen ruimtes om weer te geven", + "No rooms to show": "Geen ruimten om weer te geven", "Unnamed room": "Ruimte zonder naam", "World readable": "Leesbaar voor iedereen", "Guests can join": "Gasten kunnen toetreden", "Remove avatar": "Avatar verwijderen", "To change the room's avatar, you must be a": "Om de avatar van de ruimte te verwijderen, moet je het volgende zijn:", - "Drop here to favourite": "Hier laten vallen om aan favorieten toe te voegen", - "Drop here to tag direct chat": "Hier laten vallen om als privégesprek te markeren", - "Drop here to restore": "Hier laten vallen om te herstellen", - "Drop here to demote": "Hier laten vallen om te degraderen", + "Drop here to favourite": "Hierheen slepen om aan favorieten toe te voegen", + "Drop here to tag direct chat": "Hierheen slepen om als privégesprek te markeren", + "Drop here to restore": "Hierheen slepen om te herstellen", + "Drop here to demote": "Hierheen slepen om te degraderen", "Community Invites": "Gemeenschapsuitnodigingen", "You have been kicked from this room by %(userName)s.": "Je bent uit deze ruimte gezet door %(userName)s.", "You have been banned from this room by %(userName)s.": "Je bent uit deze ruimte verbannen door %(userName)s.", @@ -797,22 +797,22 @@ "Remove from community": "Verwijder van gemeenschap", "Disinvite this user from community?": "Uitnodiging van de gemeenschap voor deze gebruiker intrekken?", "Remove this user from community?": "Deze gebruiker van de gemeenschap verwijderen?", - "Failed to withdraw invitation": "Niet gelukt om de uitnodiging in te trekken", - "Failed to remove user from community": "Niet gelukt om de gebruiker van de gemeenschap te verwijderen", + "Failed to withdraw invitation": "Niet gelukt de uitnodiging in te trekken", + "Failed to remove user from community": "Niet gelukt de gebruiker uit de gemeenschap te verwijderen", "Filter community members": "Filter gemeenschapsleden", "Flair will appear if enabled in room settings": "Badge zal worden weergeven als het aangezet is in de ruimte-instellingen", "Flair will not appear": "Badge zal niet weergeven worden", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Weet je zeker dat je '%(roomName)s' van %(groupId)s wilt verwijderen?", "Removing a room from the community will also remove it from the community page.": "Het verwijderen van de ruimte van de gemeenschap zal de ruimte ook van de gemeenschapspagina verwijderen.", - "Failed to remove room from community": "Niet gelukt om de ruimte van de gemeenschap te verwijderen", - "Failed to remove '%(roomName)s' from %(groupId)s": "Niet gelijkt om '%(roomName)s' van %(groupId)s te verwijderen", + "Failed to remove room from community": "Niet gelukt de ruimte uit de gemeenschap te verwijderen", + "Failed to remove '%(roomName)s' from %(groupId)s": "Niet gelukt '%(roomName)s' uit %(groupId)s te verwijderen", "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "De zichtbaarheid van '%(roomName)s' in %(groupId)s kon niet geüpdatet worden.", "Visibility in Room List": "Zichtbaarheid in Ruimte Lijst", "Visible to everyone": "Zichtbaar voor iedereen", "Only visible to community members": "Alleen zichtbaar voor gemeenschapsleden", "Filter community rooms": "Gemeenschapsruimtes filteren", "Something went wrong when trying to get your communities.": "Iets ging verkeerd tijdens het ophalen van je gemeenschappen.", - "Display your community flair in rooms configured to show it.": "Geef je gemeenschapsbadge weer in ruimtes die geconfigureerd zijn om het te weergeven.", + "Display your community flair in rooms configured to show it.": "Toon je gemeenschapsbadge in ruimten die daarvoor ingesteld zijn.", "You're not currently a member of any communities.": "Je bent momenteel niet een lid van een gemeenschap.", "Minimize apps": "Applicaties minimaliseren", "Communities": "Gemeenschappen", @@ -858,12 +858,12 @@ "was kicked %(count)s times|one": "was er uit gezet", "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s veranderden hun naam %(count)s keer", "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s veranderden hun naam", - "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s veranderde zijn of haar naam %(count)s keer", - "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s veranderde zijn of haar naam", + "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s veranderde %(count)s keer van naam", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s veranderde van naam", "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s veranderden hun avatar %(count)s keer", "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s veranderden hun avatar", - "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)s veranderde zijn of haar avatar %(count)s keer", - "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s veranderde zijn of haar avatar", + "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)s veranderde %(count)s keer van avatar", + "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s veranderde van avatar", "%(items)s and %(count)s others|other": "%(items)s en %(count)s anderen", "%(items)s and %(count)s others|one": "%(items)s en één andere", "collapse": "inklappen", @@ -876,7 +876,7 @@ "email address": "e-mailadres", "Try using one of the following valid address types: %(validTypesList)s.": "Probeer één van de volgende geldige adrestypes: %(validTypesList)s.", "You have entered an invalid address.": "Je hebt een ongeldig adres ingevoerd.", - "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Een gemeenschaps-ID mag alleen de karakters a-z, 0-9, of '=_-./' bevatten.", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Een gemeenschaps-ID moet uit enkel de karakters a-z, 0-9, of '=_-./' bestaan", "Community IDs cannot be empty.": "Een gemeenschaps-ID kan niet leeg zijn.", "Something went wrong whilst creating your community": "Er is iets fout gegaan tijdens het aanmaken van je gemeenschap", "Create Community": "Gemeenschap Aanmaken", @@ -884,23 +884,23 @@ "Community ID": "Gemeenschap-ID", "example": "voorbeeld", "Advanced options": "Geavanceerde opties", - "Block users on other matrix homeservers from joining this room": "Gebruikers van andere matrix thuisservers niet toestaan om tot deze ruimte toe te treden", + "Block users on other matrix homeservers from joining this room": "Gebruikers van andere matrix thuisservers van deze ruimte uitsluiten", "This setting cannot be changed later!": "Deze instelling kan niet later veranderd worden!", - "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      HTML voor je gemeenschapspagina

      \n

      \n Gebruik de lange beschrijving om nieuwe leden in de gemeenschap te introduceren of om belangrijke links te verspreiden\n

      \n

      \n Je kan zelfs 'img' tags gebruiken\n

      \n", + "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      HTML voor je gemeenschapspagina

      \n

      \n Gebruik de lange beschrijving om nieuwe leden in de gemeenschap te introduceren of om belangrijke links aan te bieden.\n

      \n

      \n Je kunt zelfs 'img' tags gebruiken.\n

      \n", "Add rooms to the community summary": "Voeg ruimtes aan de gemeenschapssamenvatting toe", "Which rooms would you like to add to this summary?": "Welke ruimtes zou je aan deze samenvatting willen toevoegen?", "Add to summary": "Voeg aan samenvatting toe", - "Failed to add the following rooms to the summary of %(groupId)s:": "Het is niet gelukt om de volgende ruimtes aan de samenvatting van %(groupId)s toe te voegen:", + "Failed to add the following rooms to the summary of %(groupId)s:": "Kon de volgende ruimten niet aan het overzicht van %(groupId)s toevoegen:", "Add a Room": "Voeg een ruimte toe", - "Failed to remove the room from the summary of %(groupId)s": "Het is niet gelukt om de ruimte van de samenvatting van %(groupId)s te verwijderen", + "Failed to remove the room from the summary of %(groupId)s": "Kon de ruimte niet uit het overzicht van %(groupId)s verwijderen", "The room '%(roomName)s' could not be removed from the summary.": "De ruimte '%(roomName)s' kan niet van de samenvatting verwijderd worden.", "Add users to the community summary": "Voeg gebruikers aan de gemeenschapssamenvatting toe", "Who would you like to add to this summary?": "Wie zou je aan de samenvatting toe willen voegen?", - "Failed to add the following users to the summary of %(groupId)s:": "Het is niet gelukt om de volgende gebruikers aan de samenvatting van %(groupId)s toe te voegen:", + "Failed to add the following users to the summary of %(groupId)s:": "Kon de volgende gebruikers niet aan het overzicht van %(groupId)s toevoegen:", "Add a User": "Voeg een Gebruiker toe", - "Failed to remove a user from the summary of %(groupId)s": "Het is niet gelukt om een gebruiker van de samenvatting van %(groupId)s te verwijderen", + "Failed to remove a user from the summary of %(groupId)s": "Het is niet gelukt een gebruiker uit het overzicht van %(groupId)s te verwijderen", "The user '%(displayName)s' could not be removed from the summary.": "De gebruiker '%(displayName)s' kon niet van de samenvatting verwijderd worden.", - "Failed to update community": "Het is niet gelukt om de gemeenschap te updaten", + "Failed to update community": "Kon de gemeenschap niet bijwerken", "Unable to accept invite": "De uitnodiging kon niet geaccepteerd worden", "Unable to reject invite": "De uitnodiging kon niet afgewezen worden", "Leave Community": "Gemeenschap Verlaten", @@ -908,24 +908,24 @@ "Leave": "Verlaten", "Community Settings": "Gemeenschapsinstellingen", "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Deze ruimtes worden aan gemeenschapsleden getoond op de gemeenschapspagina. Gemeenschapsleden kunnen tot de ruimtes toetreden door er op te klikken.", - "%(inviter)s has invited you to join this community": "%(inviter)s heeft jou uitgenodigd om tot deze gemeenschap toe te treden", + "%(inviter)s has invited you to join this community": "%(inviter)s heeft jou uitgenodigd tot deze gemeenschap toe te treden", "You are an administrator of this community": "Je bent een administrator van deze gemeenschap", "You are a member of this community": "Je bent lid van deze gemeenschap", - "Your community hasn't got a Long Description, a HTML page to show to community members.
      Click here to open settings and give it one!": "Jouw gemeenschap heeft geen Lange Beschrijving (een HTML pagina dat aan de gemeenschapsleden wordt weergeven).
      Klik hier om de instellingen te openen en een Lange Beschrijving te maken!", + "Your community hasn't got a Long Description, a HTML page to show to community members.
      Click here to open settings and give it one!": "Je gemeenschap heeft geen Lange Beschrijving (een HTMLpagina die aan de gemeenschapsleden wordt getoond).
      Klik hier om de instellingen te openen en een Lange Beschrijving te maken!", "Long Description (HTML)": "Lange Beschrijving (HTML)", "Description": "Beschrijving", "Community %(groupId)s not found": "Gemeenschap %(groupId)s is niet gevonden", "This Home server does not support communities": "Deze Thuisserver ondersteunt geen gemeenschappen", - "Failed to load %(groupId)s": "Het is niet gelukt om %(groupId)s te laden", + "Failed to load %(groupId)s": "Het is niet gelukt %(groupId)s te laden", "Old cryptography data detected": "Oude cryptografie gegevens gedetecteerd", "Data from an older version of Riot 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.": "Er zijn gegevens van een oudere versie van Riot gedetecteerd. Dit verstoorde end-to-endbeveiliging in de oude versie. End-to-endbeveiligde berichten die recent uitgewisseld zijn met de oude versie zijn wellicht niet te ontsleutelen in deze versie. Dit zou er ook voor kunnen zorgen dat berichten die zijn uitgewisseld in deze versie falen. Log opnieuw in als je problemen ervaart. Exporteer de sleutels en importeer ze achteraf weer om de berichtgeschiedenis te behouden.", "Your Communities": "Jouw Gemeenschappen", "Error whilst fetching joined communities": "Er is een fout opgetreden tijdens het ophalen van de gemeenschappen waar je lid van bent", "Create a new community": "Maak een nieuwe gemeenschap aan", - "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Maak een gemeenschap aan om gebruikers en ruimtes samen te groeperen! Bouw een aangepaste homepagina om je eigen plek in het Matrix universum te maken.", + "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Maak een gemeenschap aan om gebruikers en ruimten bijeen te brengen! Vorm met een homepagina op maat je eigen plaats in het Matrix-universum.", "Show devices, send anyway or cancel.": "Toon apparaten, Toch versturen of annuleren.", "%(count)s of your messages have not been sent.|one": "Je bericht was niet verstuurd.", - "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Nu alles opnieuw versturen of annuleren. Je kan ook individuele berichten selecteren om opnieuw te versturen of te annuleren.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Alles nu herzenden of annuleren. Je kunt ook individuele berichten selecteren om te herzenden of te annuleren.", "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Nu bericht opnieuw versturen of bericht annuleren.", "Warning": "Waarschuwing", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Er is niemand anders hier! Wil je anderen uitnodigen of de waarschuwing over de lege ruimte stoppen?", @@ -943,33 +943,33 @@ "Stops ignoring a user, showing their messages going forward": "Stopt het negeren van een gebruiker, hierdoor worden de berichten van de gebruiker vanaf nu weer zichtbaar", "Notify the whole room": "Notificeer de gehele ruimte", "Room Notification": "Ruimte Notificatie", - "The information being sent to us to help make Riot.im better includes:": "De informatie dat naar ons wordt verstuurd om Riot.im beter te maken betrekt:", + "The information being sent to us to help make Riot.im better includes:": "De informatie die naar ons wordt verstuurd om Riot.im te verbeteren betreft:", "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Waar deze pagina identificeerbare informatie bevat, zoals een ruimte, gebruiker of groep ID, zal deze data verwijderd worden voordat het naar de server gestuurd wordt.", "The platform you're on": "Het platform waar je je op bevindt", "The version of Riot.im": "De versie van Riot.im", "Whether or not you're logged in (we don't record your user name)": "Of je wel of niet ingelogd bent (we nemen niet je gebruikersnaam op)", - "Your language of choice": "De taal waarin de applicatie wordt weergeven", - "Which officially provided instance you are using, if any": "Welke officieel verschafte instantie je gebruikt, in dat het geval is", - "Whether or not you're using the Richtext mode of the Rich Text Editor": "Of je wel of niet gebruik maakt van de Richttext modus of de Rich Text Editor", + "Your language of choice": "De door u gekozen taal", + "Which officially provided instance you are using, if any": "Welke eventuele officiële versie je gebruikt", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Of je de tekstverwerker al dan niet in de modus voor opgemaakte tekst gebruikt", "Your homeserver's URL": "De URL van je thuisserver", "Your identity server's URL": "De URL van je thuisserver", "In reply to ": "Als antwoord op ", - "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet publiekelijk. Je zal niet opnieuw kunnen toetreden zonder een uitnodiging.", + "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", "were unbanned %(count)s times|one": "waren ontbant", - "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s heeft zijn/haar weergavenaam veranderd naar %(displayName)s.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s de weergavenaam %(displayName)s aangenomen.", "Disable Community Filter Panel": "Gemeenschapsfilterpaneel uitzetten", - "Your key share request has been sent - please check your other devices for key share requests.": "Je verzoek om sleutels te delen is verzonden - controleer je andere apparaten voor het verzoek.", - "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Verzoeken om sleutels te delen worden automatisch naar andere apparaten verstuurd. Als je het verzoek hebt afgewezen of weg hebt geklikt, klik dan hier voor een nieuwe verzoek voor de sleutels van deze sessie.", - "If your other devices do not have the key for this message you will not be able to decrypt them.": "Het is niet mogelijk om dit bericht te ontsleutelen als je andere apparaten er geen sleutel voor hebben.", + "Your key share request has been sent - please check your other devices for key share requests.": "Je verzoek sleutels te delen is verzonden - controleer je andere apparaten voor het verzoek.", + "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Verzoeken sleutels te delen worden automatisch naar andere apparaten verstuurd. Als je het verzoek hebt afgewezen of weg hebt geklikt, klik dan hier voor een nieuw verzoek om de sleutels van deze sessie.", + "If your other devices do not have the key for this message you will not be able to decrypt them.": "Je kunt dit bericht niet ontsleutelen als geen van je andere apparaten er een sleutel voor heeft.", "Key request sent.": "Sleutel verzoek verstuurd.", "Re-request encryption keys from your other devices.": "Versleutelingssleutels opnieuw aanvragen van je andere apparaten.", "%(user)s is a %(userRole)s": "%(user)s is een %(userRole)s", - "Did you know: you can use communities to filter your Riot.im experience!": "Wist je dat: je gemeenschappen kan gebruiken om je Riot.im ervaring te filteren!", - "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.": "Sleep een gemeenschapsavatar naar het filterpaneel helemaal aan de linkerkant van het scherm om een filter te maken. Je kan dan altijd op de avatar in het filterpaneel klikken om alleen de ruimtes en mensen te zien die met die gemeenschap geassocieerd zijn.", + "Did you know: you can use communities to filter your Riot.im experience!": "Wist je dat: je gemeenschappen kan gebruiken om je Riot.im-beleving te filteren!", + "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.": "Sleep om een filter te maken een gemeenschapsavatar naar het filterpaneel helemaal links op het scherm. Je kunt daarna op de avatar in het filterpaneel klikken wanneer je je wilt beperken tot de ruimten en mensen uit die tot die gemeenschap.", "Clear filter": "Filter vrijmaken", - "Failed to set direct chat tag": "Het is niet gelukt om de 'privégesprek' label in te stellen", - "Failed to remove tag %(tagName)s from room": "Het is niet gelukt om de label %(tagName)s van de ruimte te verwijderen", - "Failed to add tag %(tagName)s to room": "Het is niet gelukt om de label %(tagName)s aan deze ruimte toe te voegen", + "Failed to set direct chat tag": "Het is niet gelukt het label 'privégesprek' in te stellen", + "Failed to remove tag %(tagName)s from room": "Het is niet gelukt het label %(tagName)s van de ruimte te verwijderen", + "Failed to add tag %(tagName)s to room": "Het is niet gelukt het label %(tagName)s aan deze ruimte toe te voegen", "Stickerpack": "Stickerpakket", "You don't currently have any stickerpacks enabled": "Je hebt momenteel geen stickerpakketten aan staan", "Add a stickerpack": "Stickerpakket toevoegen", @@ -985,7 +985,7 @@ "Everyone": "Iedereen", "Leave this community": "Deze gemeenschap verlaten", "Debug Logs Submission": "Debug Logs Indienen", - "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.": "Als je een bug via Github hebt ingediend kunnen debug logs ons helpen om het probleem te vinden. Debug logs bevatten applicatie-gebruik data inclusief je gebruikersnaam, de ID's of namen van de ruimtes en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", + "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.": "Als je een bug via Github hebt ingediend kunnen debug logs ons helpen het probleem te vinden. Debug logs bevatten applicatie-gebruiksgegevens, waaronder je gebruikersnaam, de ID's of namen van de ruimten en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", "Submit debug logs": "Debug logs indienen", "Opens the Developer Tools dialog": "Opent het Ontwikkelaars Gereedschappen dialoog", "Fetching third party location failed": "Het ophalen van de locatie van de derde partij is mislukt", @@ -1013,7 +1013,7 @@ "Send Custom Event": "Verzend aangepast evenement", "Advanced notification settings": "Geavanceerde meldingsinstellingen", "delete the alias.": "verwijder de alias.", - "To return to your account in future you need to set a password": "Om in de toekomst naar je account terug te gaan moet je een wachtwoord instellen", + "To return to your account in future you need to set a password": "Om in de toekomst naar je account terug te gaan is het nodig een wachtwoord in te stellen", "Forget": "Vergeten", "#example": "#voorbeeld", "Hide panel": "Paneel verbergen", @@ -1067,7 +1067,7 @@ "Direct Chat": "Privégesprek", "The server may be unavailable or overloaded": "De server is misschien niet beschikbaar of overbelast", "Reject": "Afwijzen", - "Failed to set Direct Message status of room": "Het is niet gelukt om de privéchat status van de ruimte in te stellen", + "Failed to set Direct Message status of room": "Het is niet gelukt de privéchat-status van de ruimte in te stellen", "Monday": "Maandag", "All messages (noisy)": "Alle berichten (luid)", "Enable them now": "Deze nu aanzetten", @@ -1089,10 +1089,10 @@ "What's new?": "Wat is er nieuw?", "Notify me for anything else": "Stuur een melding voor al het andere", "When I'm invited to a room": "Wanneer ik uitgenodigd word voor een ruimte", - "Can't update user notification settings": "Het is niet gelukt om de meldingsinstellingen van de gebruiker bij te werken", + "Can't update user notification settings": "Kan de meldingsinstellingen van de gebruiker niet bijwerken", "Notify for all other messages/rooms": "Stuur een melding voor alle andere berichten/ruimtes", - "Unable to look up room ID from server": "Het is mislukt om het ruimte-ID op te halen van de server", - "Couldn't find a matching Matrix room": "Het is niet gelukt om een bijbehorende Matrix-ruimte te vinden", + "Unable to look up room ID from server": "Kon het ruimte-ID niet van de server ophalen", + "Couldn't find a matching Matrix room": "Kon geen bijbehorende Matrix-ruimte vinden", "All Rooms": "Alle Ruimtes", "You cannot delete this message. (%(code)s)": "Je kunt dit bericht niet verwijderen. (%(code)s)", "Thursday": "Donderdag", @@ -1101,7 +1101,7 @@ "Reply": "Beantwoord", "Show message in desktop notification": "Toon boodschap in bureaublad popup", "Unhide Preview": "Zichtbaar maken preview", - "Unable to join network": "Het is mislukt om toe te treden tot dit netwerk", + "Unable to join network": "Kon niet toetreden tot dit netwerk", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Je hebt ze mogelijk ingesteld in een andere client dan Riot. Je kunt ze niet aanpassen in Riot maar ze zijn wel actief", "Sorry, your browser is not able to run Riot.": "Sorry, uw browser werkt niet met Riot.", "Uploaded on %(date)s by %(user)s": "Geüpload op %(date)s door %(user)s", @@ -1110,7 +1110,7 @@ "Error encountered (%(errorDetail)s).": "Fout ondervonden (%(errorDetail)s).", "Login": "Aanmelden", "Low Priority": "Lage prioriteit", - "Unable to fetch notification target list": "Het is mislukt om de lijst van notificatiedoelen op te halen", + "Unable to fetch notification target list": "Kan de bestemmingslijst voor de mededeling niet ophalen", "Set Password": "Wachtwoord instellen", "Enable audible notifications in web client": "Geluidsmeldingen in de webclient aanzetten", "Off": "Uit", @@ -1136,11 +1136,11 @@ "Logs sent": "Logs verstuurd", "GitHub issue link:": "GitHub opgave link:", "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.": "Debug logs bevatten applicatie-gebruik data inclusief je gebruikersnaam, de ID's of namen van de ruimtes en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", - "Failed to send logs: ": "Het is niet gelukt om de logs te versturen: ", + "Failed to send logs: ": "Het is niet gelukt de logs te versturen: ", "Notes:": "Constateringen:", - "Preparing to send logs": "Voorbereiden om logs te versturen", + "Preparing to send logs": "Logs voorbereiden voor verzending", "e.g. %(exampleValue)s": "bijv. %(exampleValue)s", - "Every page you use in the app": "Elke pagina die je in de applicatie gebruikt", + "Every page you use in the app": "Iedere bladzijde die je in de toepassing gebruikt", "e.g. ": "bijv. ", "Your User Agent": "Je gebruikersagent", "Your device resolution": "De resolutie van je apparaat", @@ -1149,9 +1149,9 @@ "Always show encryption icons": "Altijd versleutelingsiconen weergeven", "Send analytics data": "Statistische gegevens (analytics) versturen", "Enable widget screenshots on supported widgets": "Widget schermafbeeldingen op ondersteunde widgets aanzetten", - "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Op dit moment is het niet mogelijk om te reageren met een bestand het zal dus als een normaal bericht worden verstuurd.", - "Unable to reply": "Niet mogelijk om te reageren", - "At this time it is not possible to reply with an emote.": "Op dit moment is het niet mogelijk om met een emote te reageren.", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Het is nog niet mogelijk een bestand als antwoord te zenden; het zal dus als normaal bericht worden verstuurd.", + "Unable to reply": "Niet mogelijk te reageren", + "At this time it is not possible to reply with an emote.": "Het is nog niet mogelijk met een emoji te reageren.", "To notify everyone in the room, you must be a": "Om iedereen in de ruimte te notificeren moet je het volgende zijn:", "Muted Users": "Gedempte Gebruikers", "Please help improve Riot.im by sending anonymous usage data. This will use a cookie (please see our Cookie Policy).": "Help Riot.im te verbeteren door het versturen van anonieme gebruiksgegevens. Dit zal een cookie gebruiken (zie ons Cookiebeleid).", @@ -1160,10 +1160,10 @@ "Warning: This widget might use cookies.": "Waarschuwing: deze widget gebruikt misschien cookies.", "Popout widget": "Widget in nieuw venster openen", "Picture": "Afbeelding", - "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Niet mogelijk om de gebeurtenis te laden waar op gereageerd was. Het kan zijn dat het niet bestaat of dat je niet toestemming hebt om het te bekijken.", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Kan de gebeurtenis waarop gereageerd was niet laden. Wellicht bestaat die niet, of heb je geen toestemming die te bekijken.", "Riot bugs are tracked on GitHub: create a GitHub issue.": "Riot fouten worden bijgehouden op GitHub: maak een GitHub melding.", "Failed to indicate account erasure": "Niet gelukt om de accountverwijdering aan te geven", - "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Dit zal je account voorgoed onbruikbaar maken. Je zal niet meer in kunnen loggen en niemand anders zal met dezelfde gebruikers ID kunnen registreren. Dit zal er voor zorgen dat je account alle ruimtes verlaat waar het momenteel onderdeel van is en het verwijderd de accountgegevens van de identiteitsserver. Deze actie is onomkeerbaar.", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Dit zal je account voorgoed onbruikbaar maken. Je zult niet meer in kunnen loggen en niemand anders zal met dezelfde gebruikers ID kunnen registreren. Hierdoor zal je account alle ruimten waarin het deelneemt verlaten en worden de accountgegevens van de identiteitsserver verwijderd. Deze actie is onomkeerbaar.", "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.": "Het deactiveren van je account zal er niet standaard voor zorgen dat de berichten die je verzonden hebt vergeten worden. Als je wilt dat wij de berichten vergeten, klik alsjeblieft op het vakje hieronder.", "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.": "De zichtbaarheid van berichten in Matrix is hetzelfde als in e-mail. Het vergeten van je berichten betekent dat berichten die je hebt verstuurd niet meer gedeeld worden met nieuwe of ongeregistreerde gebruikers, maar geregistreerde gebruikers die al toegang hebben tot deze berichten zullen alsnog toegang hebben tot hun eigen kopie van het bericht.", "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)": "Vergeet alle berichten die ik heb verstuurd wanneer mijn account gedeactiveerd is (Waarschuwing: dit zal er voor zorgen dat toekomstige gebruikers een incompleet beeld krijgen van gesprekken)", @@ -1174,19 +1174,19 @@ "Send Logs": "Logboek Versturen", "Refresh": "Herladen", "We encountered an error trying to restore your previous session.": "Er is een fout opgetreden tijdens het herstellen van je vorige sessie.", - "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Het opschonen van je browser's opslag zal het probleem misschien oplossen, maar zal je uitloggen en ervoor zorgen dat alle versleutelde chat geschiedenis onleesbaar wordt.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Het legen van de opslag van je browser zal het probleem misschien verhelpen, maar zal je ook uitloggen en je gehele versleutelde chatgeschiedenis onleesbaar maken.", "Collapse Reply Thread": "Reactieketting Inklappen", "Can't leave Server Notices room": "Kan de Server Meldingen ruimte niet verlaten", - "This room is used for important messages from the Homeserver, so you cannot leave it.": "Deze ruimte wordt gebruikt voor belangrijke berichten van de thuisserver, dus je kan het niet verlaten.", + "This room is used for important messages from the Homeserver, so you cannot leave it.": "Deze ruimte wordt gebruikt voor belangrijke berichten van de thuisserver, dus je kunt haar niet verlaten.", "Terms and Conditions": "Voorwaarden", - "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Om de %(homeserverDomain)s thuisserver te blijven gebruiken zal je de voorwaarden moeten lezen en ermee akkoord moeten gaan.", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Om de %(homeserverDomain)s thuisserver te blijven gebruiken zul je de voorwaarden moeten lezen en aanvaarden.", "Review terms and conditions": "Voorwaarden lezen", "A conference call could not be started because the intgrations server is not available": "Een groepsgesprek kon niet worden gestart omdat de integratieserver niet beschikbaar is", "Call in Progress": "Lopend gesprek", "A call is currently being placed!": "Een gesprek wordt gestart!", "A call is already in progress!": "Er loopt al een gesprek!", "Permission Required": "Toestemming benodigd", - "You do not have permission to start a conference call in this room": "Je hebt niet de toestemming om in deze ruimte een groepsgesprek te starten", + "You do not have permission to start a conference call in this room": "Je hebt geen toestemming in deze ruimte een groepsgesprek te starten", "Show empty room list headings": "Lege koppen in ruimtelijst weergeven", "This event could not be displayed": "Deze gebeurtenis kon niet worden weergegeven", "Encrypting": "Versleutelen", @@ -1201,10 +1201,10 @@ "bulleted-list": "lijst met opsommingstekens", "numbered-list": "genummerde lijst", "Share room": "Ruimte delen", - "System Alerts": "Systeemmeldingen", + "System Alerts": "Systeemwaarschuwingen", "You have no historical rooms": "Je hebt geen historische ruimtes", - "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 versleutelde ruimtes, zoals deze, zijn URL-voorvertoningen standaard uitgeschakeld om ervoor te zorgen dat jouw thuisserver (waar de voorvertoningen worden gemaakt) geen informatie kan verzamelen over de links die je in deze ruimte ziet.", - "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.": "Als iemand een URL in zijn of haar bericht zet, kan er een URL-voorvertoning weergegeven worden om meer informatie over de link te geven, zoals de titel, omschrijving en een afbeelding van de website.", + "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 versleutelde ruimten, zoals deze, zijn URL-voorvertoningen standaard uitgeschakeld om te voorkomen dat jouw thuisserver (waar de voorvertoningen worden gemaakt) informatie kan verzamelen over de links die je hier ziet.", + "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.": "Als iemand een URL in een bericht zet, kan er een URL-voorvertoning weergegeven worden met meer informatie over de link, zoals de titel, omschrijving en een afbeelding van de website.", "The email field must not be blank.": "Het e-mailveld mag niet leeg zijn.", "The user name field must not be blank.": "Het gebruikersnaamveld mag niet leeg zijn.", "The phone number field must not be blank.": "Het telefoonnummerveld mag niet leeg zijn.", @@ -1230,7 +1230,194 @@ "Ignored users": "Genegeerde gebruikers", "Bulk options": "Bulkinstellingen", "Registration Required": "Registratie vereist", - "You need to register to do this. Would you like to register now?": "U moet zich registreren om dit te doen. Wilt u zich nu registreren?", + "You need to register to do this. Would you like to register now?": "Hiervoor dient u zich te registreren. Wilt u dat nu doen?", "This homeserver has hit its Monthly Active User limit.": "Deze homeserver heeft de maandelijks actieve gebruikerslimiet bereikt.", - "This homeserver has exceeded one of its resource limits.": "Deze homeserver heeft de limiet van een van de systeembronnen bereikt." + "This homeserver has exceeded one of its resource limits.": "Deze homeserver heeft de limiet van een van de systeembronnen bereikt.", + "Whether or not you're logged in (we don't record your username)": "Of u al dan niet ingelogd bent (we slaan uw gebruiksnaam niet op)", + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Het bestand %(fileName)s is groter dan de uploadlimiet van de thuisserver", + "Unable to load! Check your network connectivity and try again.": "Laden mislukt! Controleer uw netwerktoegang en probeer opnieuw.", + "Failed to invite users to the room:": "Kon de volgende gebruikers hier niet uitnodigen:", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Plakt ¯\\_(ツ)_/¯ vòòr een bericht in kale tekst", + "Upgrades a room to a new version": "Actualiseert de kamer tot een nieuwe versie", + "Changes your display nickname in the current room only": "Stelt uw gebruikte naam in enkel de huidige ruimte in", + "Gets or sets the room topic": "Geeft het thema van de ruimte of stelt het in", + "This room has no topic.": "Ruimte zonder thema.", + "Sets the room name": "Stelt de naam van de ruimte in", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s heeft deze ruimte geactualiseerd.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s heeft de ruimte toegankelijk gemaakt voor allen die de verwijzing kennen.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s heeft de ruimte enkel op uitgenodiging toegankelijk gemaakt.", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s heeft de toegangsregel veranderd tot '%(rule)s'", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s heeft gasten toegestaan de ruimte te betreden.", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s heeft gasten de toegang tot de ruimte ontzegd.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s heeft de toegangsregel voor gasten op '%(rule)s' gesteld", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s heeft emblemen voor %(groups)s in deze kamer aangezet.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s heeft enblemen voor %(groups)s in deze ruimte uitgezet.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s heeft emblemen voor %(newGroups)s aan-, en voor %(oldGroups)s uitgezet in deze ruimte.", + "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s heeft de adressen %(addedAddresses)s aan deze ruimte toegekend.", + "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s heeft %(addedAddresses)s als ruimteadres toegevoegd.", + "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|other": "%(senderName)s heeft het ruimteadres '%(removedAddresses)s' verwijderd.", + "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s heeft de ruimteadressen %(removedAddresses)s verwijderd.", + "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s heeft de ruimteadressen %(addedAddresses)s toegevoegd, en %(removedAddresses)s verwijderd.", + "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s heeft '%(address)s' als hoofdadres voor deze ruimte ingesteld.", + "%(senderName)s removed the main address for this room.": "%(senderName)s heeft het hoofdadres voor deze ruimte verwijderd.", + "%(displayName)s is typing …": "%(displayName)s%(displayName)s is aan het schrijven …", + "%(names)s and %(count)s others are typing …|other": "%(names)s en %(count)s anderen zijn aan het schrijven …", + "%(names)s and %(count)s others are typing …|one": "%(names)s en nog iemand zijn aan het schrijven …", + "%(names)s and %(lastPerson)s are typing …": "%(names)s en %(lastPerson)s zijn aan het schrijven …", + "Please contact your service administrator to continue using the service.": "Neemt u a.u.b. contact met uw systeembeheerder op om deze dienst te blijven gebruiken.", + "Unable to connect to Homeserver. Retrying...": "Kon geen verbinding met de thuisserver maken. Nieuwe poging...", + "Unrecognised address": "Adres niet herkend", + "You do not have permission to invite people to this room.": "U hebt geen toestemming mensen tot deze ruimte uit te nodigen.", + "User %(userId)s is already in the room": "De gebruiker %(userId)s is al aanwezig", + "User %(user_id)s does not exist": "Er bestaat geen gebruiker '%(user_id)s'", + "User %(user_id)s may or may not exist": "Er bestaat mogelijk geen gebruiker '%(user_id)s'", + "The user must be unbanned before they can be invited.": "De gebruiker kan niet uitgenodigd worden voordat diens ban ongedaan is gemaakt.", + "Unknown server error": "Onbekende serverfout", + "Use a few words, avoid common phrases": "Gebruik enige woorden - maar geen staande uitdrukkingen", + "No need for symbols, digits, or uppercase letters": "Hoofdletters, cijfers of speciale tekens hoeven niet, mogen wel", + "Use a longer keyboard pattern with more turns": "Gebruik een langer patroon met meer variatie", + "Avoid repeated words and characters": "Vermijd herhaling van woorden of tekens", + "Avoid sequences": "Vermijd rijtjes", + "Avoid recent years": "Vermijd recente jaren", + "Avoid years that are associated with you": "Vermijd jaren die op uzelf betrekking hebben", + "Avoid dates and years that are associated with you": "Vermijd data en jaren die op uzelf betrekking hebben", + "Capitalization doesn't help very much": "Schrijven in hoofdletters maakt niet veel uit", + "All-uppercase is almost as easy to guess as all-lowercase": "Tekst in hoofdletters is vrijwel even gemakkelijk te raden als tekst in kleine letters", + "Reversed words aren't much harder to guess": "Omgedraaide woorden zijn bijna even gemakkelijk te raden", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Voorspelbare vervangingen (zoals '@' i.p.v. 'a') zijn niet erg zinvol", + "Add another word or two. Uncommon words are better.": "Voeg nog een paar (liefst infrequente) woorden toe.", + "Repeats like \"aaa\" are easy to guess": "Herhalingen als \"aaa\" worden gemakkelijk geraden", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Herhalingen als \"abcabcabc\" zijn haast even gemakkelijk te raden als \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Rijtjes als \"abc\" of \"6543\" zijn gemakkelijk te raden", + "Recent years are easy to guess": "Recente jaartallen zijn eenvoudig te raden", + "Dates are often easy to guess": "Data zijn vaak gemakkelijk te raden", + "This is a top-10 common password": "Dit staat in de top 10 van meestgebruikte wachtwoorden", + "This is a top-100 common password": "Dit wachtwoord staat in de top-100 qua gebruik", + "This is a very common password": "Dit is een veelgebruikt wachtwoord", + "This is similar to a commonly used password": "Dit lijkt sterk op een veelgebruikt wachtwoord", + "A word by itself is easy to guess": "Één enkel woord is zeer gemakkelijk te raden", + "Names and surnames by themselves are easy to guess": "Een alleenstaande voor- of achternaam is eenvoudig te raden", + "Common names and surnames are easy to guess": "Voor- en achternamen zijn eenvoudig te raden", + "Straight rows of keys are easy to guess": "Zo'n aaneengesloten rijtje toetsen is eenvoudig te raden", + "Short keyboard patterns are easy to guess": "Korte patronen op het toetsenbord worden gemakkelijk geraden", + "There was an error joining the room": "Het betreden van de ruimte ging mis", + "Sorry, your homeserver is too old to participate in this room.": "Helaas - uw thuisserver is te oud voor deze ruimte.", + "Please contact your homeserver administrator.": "Gelieve contact op te nemen met de beheerder van uw thuisserver.", + "Custom user status messages": "Aangepaste berichten over de staat van de gebruiker", + "Show recent room avatars above the room list (refresh to apply changes)": "Toon de recentste avatars bovenaan in de lijst (herlaad om de verandering te zien)", + "Group & filter rooms by custom tags (refresh to apply changes)": "Groepeer en filter de ruimten volgens eigen labels (herlaad om de verandering te zien)", + "Render simple counters in room header": "Toon eenvoudige tellers bovenin de ruimte", + "Enable Emoji suggestions while typing": "Suggereer emoji's onder het typen", + "Show a placeholder for removed messages": "Toon vulling voor verwijderde berichten", + "Show join/leave messages (invites/kicks/bans unaffected)": "Toon in- en uittredeberichten (dit heeft geen effect op uitnodigingen, berispingen of verbanningen)", + "Show avatar changes": "Toon veranderingen van avatar", + "Show display name changes": "Toon veranderingen van getoonde naam", + "Show read receipts sent by other users": "Toon door andere gebruikers gezonden leesberichten", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Herinner me eraan Veilig Berichtherstel in versleutelde ruimten aan te zetten", + "Show avatars in user and room mentions": "Toon avatars als gebruikers of ruimten genoemd worden", + "Enable big emoji in chat": "Sta grote emoji's in gesprekken toe", + "Send typing notifications": "Stuur bericht bij schrijven", + "Enable Community Filter Panel": "Zet het gemeenschapsfilterpaneel aan", + "Allow Peer-to-Peer for 1:1 calls": "Sta evenknieverbindingen toe voor tweegesprekken", + "Prompt before sending invites to potentially invalid matrix IDs": "Vraag na voordat uitnodigingen naar mogelijk ongeldige MatrixIDs worden verstuurd", + "Show developer tools": "Toon het ontwikkelinstrumentarium", + "Order rooms in the room list by most important first instead of most recent": "Sorteer de ruimten naar belang in plaats van laatste gebruik", + "Messages containing my username": "Berichten die mijn naam bevatten", + "Messages containing @room": "Berichten die \"@room\" bevatten", + "Encrypted messages in one-to-one chats": "Versleutelde berichten in tweegesprekken", + "Encrypted messages in group chats": "Versleutelde berichten in groepsgesprekken", + "The other party cancelled the verification.": "De tegenpartij brak de contrôle af.", + "Verified!": "Contrôle geslaagd!", + "You've successfully verified this user.": "Gebruiker succesvol gecontroleerd.", + "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Berichten met deze gebruiker zijn voluit versleuteld en kunnen niet door derden worden gelezen.", + "Got It": "Snap ik", + "Verify this user by confirming the following emoji appear on their screen.": "Controleer deze gebruiker door te bevestigen dat hun scherm de volgende emoji toont.", + "Verify this user by confirming the following number appears on their screen.": "Controleer deze gebruiker door te bevestigen dat hun scherm het volgende getal toont.", + "Unable to find a supported verification method.": "Kan geen ondersteunde wijze van controleren vinden.", + "For maximum security, we recommend you do this in person or use another trusted means of communication.": "Voor maximale veiligheid kunt u dit het beste persoonlijk, of via een vertrouwd communicatiemedium, doen.", + "Dog": "Hond", + "Cat": "Kat", + "Lion": "Leeuw", + "Horse": "Paard", + "Unicorn": "Eenhoorn", + "Pig": "Varken", + "Elephant": "Olifant", + "Rabbit": "Konijn", + "Panda": "Panda", + "Rooster": "Haan", + "Penguin": "Pinguïn", + "Turtle": "Schildpad", + "Fish": "Vis", + "Octopus": "Inktvis", + "Butterfly": "Vlinder", + "Flower": "Bloem", + "Tree": "Boom", + "Cactus": "Cactus", + "Mushroom": "Paddestoel", + "Globe": "Wereldbol", + "Moon": "Maan", + "Cloud": "Wolk", + "Fire": "Vuur", + "Banana": "Banaan", + "Apple": "Appel", + "Strawberry": "Aardbei", + "Corn": "Maïs", + "Pizza": "Pizza", + "Cake": "Gebak", + "Heart": "Hart", + "Smiley": "Lachebekje", + "Robot": "Robot", + "Hat": "Hoed", + "Glasses": "Bril", + "Spanner": "Steeksleutel", + "Santa": "De kerstman", + "Thumbs up": "Duim omhoog", + "Umbrella": "Paraplu", + "Hourglass": "Zandloper", + "Clock": "Klok", + "Gift": "Geschenk", + "Light bulb": "Peertje", + "Book": "Boek", + "Pencil": "Potlood", + "Paperclip": "Paperclip", + "Scissors": "Schaar", + "Padlock": "Hangslot", + "Key": "Sleutel", + "Hammer": "Hamer", + "Telephone": "Telefoontoestel", + "Flag": "Vlag", + "Train": "Trein", + "Bicycle": "Fiets", + "Aeroplane": "Vliegtuig", + "Rocket": "Raket", + "Trophy": "Erebeker", + "Ball": "Bal", + "Guitar": "Gitaar", + "Trumpet": "Trompet", + "Bell": "Bel", + "Anchor": "Anker", + "Headphones": "Hoofdtelefoon", + "Folder": "Ordner", + "Pin": "Speld", + "Your homeserver does not support device management.": "Je thuisserver ondersteunt geen apparaatbeheer.", + "Yes": "Ja", + "No": "Neen", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Om uw adres te controleren hebben wij een email gestuurd. Gelieve de daarin gegeven aanwijzingen op te volgen en dan op de knop hieronder te klikken.", + "Email Address": "E-mailadres", + "Delete Backup": "Reservekopie verwijderen", + "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Weet u het zeker? Zonder reservekopie kunt u uw versleutelde berichten kwijtraken.", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Versleutelde berichten zijn over het gehele pad beveiligd. Enkel u en de ontvanger(s) hebben de ontcijferingssleutels.", + "Unable to load key backup status": "Kon de reservekopiestatus voor de sleutels niet laden", + "Restore from Backup": "Herstellen vanuit de reservekopie", + "This device is backing up your keys. ": "Dit apparaat houdt een reservekopie van uw sleutels bij. ", + "This device is not backing up your keys.": "Dit apparaat houdt geen reservekopie van uw sleutels bij.", + "Back up your keys before signing out to avoid losing them.": "Maak voor u zich afmeldt een reservekopie van uw sleutels, om ze niet te verliezen.", + "Use key backup": "Houdt een reservekopie van uw sleutels bij", + "Backing up %(sessionsRemaining)s keys...": "Reservekopie van %(sessionsRemaining)s sleutels maken...", + "All keys backed up": "Reservekopie compleet", + "Backup has a valid signature from this device": "De veiligheidskopie heeft een geldige handtekening van dit apparaat", + "Backup is not signed by any of your devices": "De reservekopie is door geen van uw apparaten ondertekend", + "This backup is trusted because it has been restored on this device": "Deze reservekopie wordt vertrouwd, daar hij op dit apparaat herladen is", + "Backup version: ": "Versie reservekopie: ", + "Algorithm: ": "Algoritme: " } From 13c71c7a6a1eb3b243dbb68511218c1b991671a5 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 16:08:46 +0000 Subject: [PATCH 136/481] Translated using Weblate (Dutch) Currently translated at 79.3% (1237 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 9fc7ef99b4..5a059e003e 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -1419,5 +1419,6 @@ "Backup is not signed by any of your devices": "De reservekopie is door geen van uw apparaten ondertekend", "This backup is trusted because it has been restored on this device": "Deze reservekopie wordt vertrouwd, daar hij op dit apparaat herladen is", "Backup version: ": "Versie reservekopie: ", - "Algorithm: ": "Algoritme: " + "Algorithm: ": "Algoritme: ", + "Chat with Riot Bot": "Chatten met Riot Bot" } From 7f0ca878c0382c5177e7e9a694b6d2df66106556 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 16:10:09 +0000 Subject: [PATCH 137/481] Translated using Weblate (Dutch) Currently translated at 79.3% (1237 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 5a059e003e..13a37260fb 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -250,7 +250,7 @@ "Failed to unban": "Ontbannen mislukt", "Failed to upload file": "Niet gelukt het bestand te uploaden", "Failed to upload profile picture!": "Niet gelukt een profielfoto te uploaden!", - "Failed to verify email address: make sure you clicked the link in the email": "Niet gelukt het e-mailadres te verifiëren: zorg ervoor dat je de link in de e-mail hebt aangeklikt", + "Failed to verify email address: make sure you clicked the link in the email": "Kan het e-mailadres niet verifiëren: zorg ervoor dat u de koppeling in de e-mail heeft aangeklikt", "Failure to create room": "Het aanmaken van een ruimte is mislukt", "Favourites": "Favorieten", "Fill screen": "Scherm vullen", @@ -945,13 +945,13 @@ "Room Notification": "Ruimte Notificatie", "The information being sent to us to help make Riot.im better includes:": "De informatie die naar ons wordt verstuurd om Riot.im te verbeteren betreft:", "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Waar deze pagina identificeerbare informatie bevat, zoals een ruimte, gebruiker of groep ID, zal deze data verwijderd worden voordat het naar de server gestuurd wordt.", - "The platform you're on": "Het platform waar je je op bevindt", + "The platform you're on": "Het platform dat u gebruikt", "The version of Riot.im": "De versie van Riot.im", "Whether or not you're logged in (we don't record your user name)": "Of je wel of niet ingelogd bent (we nemen niet je gebruikersnaam op)", "Your language of choice": "De door u gekozen taal", - "Which officially provided instance you are using, if any": "Welke eventuele officiële versie je gebruikt", - "Whether or not you're using the Richtext mode of the Rich Text Editor": "Of je de tekstverwerker al dan niet in de modus voor opgemaakte tekst gebruikt", - "Your homeserver's URL": "De URL van je thuisserver", + "Which officially provided instance you are using, if any": "Welke officieel aangeboden instantie u eventueel gebruikt", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Of u de tekstverwerker al dan niet in de modus voor opgemaakte tekst gebruikt", + "Your homeserver's URL": "De URL van uw thuisserver", "Your identity server's URL": "De URL van je thuisserver", "In reply to ": "Als antwoord op ", "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", From 81aafcebcab4279d7e98d7e8f218dbb4861cda6d Mon Sep 17 00:00:00 2001 From: "J. A. Durieux" Date: Thu, 28 Mar 2019 16:18:38 +0000 Subject: [PATCH 138/481] Translated using Weblate (Dutch) Currently translated at 79.3% (1237 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 13a37260fb..7d790a8706 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -952,7 +952,7 @@ "Which officially provided instance you are using, if any": "Welke officieel aangeboden instantie u eventueel gebruikt", "Whether or not you're using the Richtext mode of the Rich Text Editor": "Of u de tekstverwerker al dan niet in de modus voor opgemaakte tekst gebruikt", "Your homeserver's URL": "De URL van uw thuisserver", - "Your identity server's URL": "De URL van je thuisserver", + "Your identity server's URL": "De URL van je identiteitsserver", "In reply to ": "Als antwoord op ", "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", "were unbanned %(count)s times|one": "waren ontbant", From dc6c0e26b070359d6397f9390eb8568f6df1a907 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 16:18:44 +0000 Subject: [PATCH 139/481] Translated using Weblate (Dutch) Currently translated at 79.4% (1238 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 110 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 7d790a8706..55c1ed5766 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -30,7 +30,7 @@ "Bans user with given id": "Verbant de gebruiker met het gegeven ID", "Blacklisted": "Buitengesloten", "Bulk Options": "Bulk opties", - "Call Timeout": "Gesprek time-out", + "Call Timeout": "Oproeptime-out", "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Kan niet met de thuisserver verbinden via HTTP wanneer er een HTTPS-URL in je browser balk staat. Gebruik HTTPS of activeer onveilige scripts.", "Can't load user settings": "Kan de gebruikersinstellingen niet laden", "Change Password": "Wachtwoord veranderen", @@ -58,7 +58,7 @@ "Confirm password": "Bevestigen wachtwoord", "Confirm your new password": "Bevestig je nieuwe wachtwoord", "Continue": "Doorgaan", - "Could not connect to the integration server": "Verbinding met de integratieserver mislukt", + "Could not connect to the integration server": "Verbinding met de integratieserver is mislukt", "Cancel": "Annuleren", "Accept": "Accepteren", "Active call (%(roomName)s)": "Actief gesprek (%(roomName)s)", @@ -164,9 +164,9 @@ "Oct": "Okt", "Nov": "Nov", "Dec": "Dec", - "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s %(time)s", - "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s %(day)s %(monthName)s, %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s, %(time)s", + "%(weekDayName)s %(time)s": "%(weekDayName)s, %(time)s", "Set a display name:": "Weergavenaam instellen:", "Upload an avatar:": "Een avatar uploaden:", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Geen verbinding met de thuisserver - controleer je verbinding. Controleer het SSL-certificaat van de thuisserver en browser-extensies die verzoeken kunnen blokkeren.", @@ -251,7 +251,7 @@ "Failed to upload file": "Niet gelukt het bestand te uploaden", "Failed to upload profile picture!": "Niet gelukt een profielfoto te uploaden!", "Failed to verify email address: make sure you clicked the link in the email": "Kan het e-mailadres niet verifiëren: zorg ervoor dat u de koppeling in de e-mail heeft aangeklikt", - "Failure to create room": "Het aanmaken van een ruimte is mislukt", + "Failure to create room": "Aanmaken van kamer is mislukt", "Favourites": "Favorieten", "Fill screen": "Scherm vullen", "Filter room members": "Ruimteleden filteren", @@ -337,8 +337,8 @@ "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het wachtwoord veranderen betekent momenteel dat alle end-to-endbeveiligingssleutels op alle apparaten veranderen waardoor versleutelde gespreksgeschiedenis onleesbaar wordt, behalve als je eerst de ruimte sleutels exporteert en daarna opnieuw importeert. Dit zal in de toekomst verbeterd worden.", "Results from DuckDuckGo": "Resultaten van DuckDuckGo", "Return to login screen": "Naar het inlogscherm terugkeren", - "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen toestemming je mededelingen te versturen - controleer je browserinstellingen", - "Riot was not given permission to send notifications - please try again": "Riot heeft geen toestemming gekregen mededelingen te versturen - probeer het opnieuw", + "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen toestemming om u meldingen te versturen - controleer uw browserinstellingen", + "Riot was not given permission to send notifications - please try again": "Riot heeft geen toestemming gekregen om u meldingen te versturen - probeer het opnieuw", "riot-web version:": "riot-web versie:", "Room %(roomId)s not visible": "Ruimte %(roomId)s is niet zichtbaar", "Room Colour": "Kleur van de ruimte", @@ -362,7 +362,7 @@ "Server may be unavailable or overloaded": "De server kan onbereikbaar of overbelast zijn", "Server may be unavailable, overloaded, or search timed out :(": "De server is misschien onbereikbaar, overbelast of het zoeken duurde te lang :(", "Server may be unavailable, overloaded, or the file too big": "De server is misschien onbereikbaar, overbelast of het bestand is te groot", - "Server may be unavailable, overloaded, or you hit a bug.": "De server is misschien onbereikbaar, overbelast of je bent tegen een fout aangelopen.", + "Server may be unavailable, overloaded, or you hit a bug.": "De server is misschien onbereikbaar of overbelast, of u bent een fout tegengekomen.", "Server unavailable, overloaded, or something else went wrong.": "De server is onbereikbaar, overbelast of iets anders ging fout.", "Session ID": "Sessie-ID", "%(senderName)s kicked %(targetName)s.": "%(senderName)s heeft %(targetName)s de ruimte uitgestuurd.", @@ -383,10 +383,10 @@ "The phone number entered looks invalid": "Het telefoonnummer dat ingevoerd is ziet er ongeldig uit", "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "De versleutelingssleutel die je hebt verstrekt komt overeen met de versleutelingssleutel die je hebt ontvangen van %(userId)s's apparaat %(deviceId)s. Apparaat is gemarkeerd als geverifieerd.", "This email address is already in use": "Dit e-mailadres is al in gebruik", - "This email address was not found": "Kon dit e-mailadres niet vinden", + "This email address was not found": "Dit e-mailadres is niet gevonden", "The email address linked to your account must be entered.": "Het e-mailadres dat met je account verbonden is moet worden ingevoerd.", "The file '%(fileName)s' exceeds this home server's size limit for uploads": "Het bestand '%(fileName)s' overtreft de maximale bestandsgrootte voor uploads van deze thuisserver", - "The file '%(fileName)s' failed to upload": "Het is niet gelukt het bestand '%(fileName)s' te uploaden", + "The file '%(fileName)s' failed to upload": "Uploaden van bestand ‘%(fileName)s’ is mislukt", "The remote side failed to pick up": "De andere kant heeft niet opgenomen", "This Home Server does not support login using email address.": "Deze Thuisserver ondersteunt het inloggen met een e-mailadres niet.", "This invitation was sent to an email address which is not associated with this account:": "Deze uitnodiging was naar een e-mailadres gestuurd die niet geassocieerd is met dit account:", @@ -414,8 +414,8 @@ "Unban": "Ontbannen", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s ontbande %(targetName)s.", "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Onmogelijk na te gaan of het adres waarheen deze uitnodiging was verstuurd overeenkomt met het adres dat bij je account behoort.", - "Unable to capture screen": "Niet mogelijk een schermfoto te maken", - "Unable to enable Notifications": "Niet mogelijk mededelingen aan te zetten", + "Unable to capture screen": "Kan geen schermafdruk maken", + "Unable to enable Notifications": "Kan meldingen niet inschakelen", "Unable to load device list": "Niet mogelijk de lijst van apparaten te laden", "Undecryptable": "Niet ontsleutelbaar", "Unencrypted room": "Ontsleutelde ruimte", @@ -426,7 +426,7 @@ "Unknown room %(roomId)s": "Onbekende ruimte %(roomId)s", "Unknown (user, device) pair:": "Onbekend (gebruiker/apparaat-)paar:", "Unmute": "Niet dempen", - "Unnamed Room": "Naamloze Ruimte", + "Unnamed Room": "Naamloze kamer", "Unrecognised command:": "Onbekende commando:", "Unrecognised room alias:": "Onbekende ruimte alias:", "Unverified": "Niet geverifieerd", @@ -434,7 +434,7 @@ "Uploading %(filename)s and %(count)s others|one": "%(filename)s en %(count)s andere aan het uploaden", "Uploading %(filename)s and %(count)s others|other": "%(filename)s en %(count)s anderen aan het uploaden", "Upload avatar": "Avatar uploaden", - "Upload Failed": "Uploaden Mislukt", + "Upload Failed": "Uploaden mislukt", "Upload Files": "Bestanden Uploaden", "Upload file": "Bestand uploaden", "Upload new:": "Nieuwe uploaden:", @@ -456,7 +456,7 @@ "Voice call": "Spraakoproep", "VoIP conference finished.": "VoIP-vergadering beëindigd.", "VoIP conference started.": "VoIP-vergadering gestart.", - "VoIP is unsupported": "VoIP is niet ondersteund", + "VoIP is unsupported": "VoIP wordt niet ondersteund", "(could not connect media)": "(kan media niet verbinden)", "(no answer)": "(geen antwoord)", "(unknown failure: %(reason)s)": "(onbekende fout: %(reason)s)", @@ -471,11 +471,11 @@ "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s trok %(targetName)s's uitnodiging terug.", "Would you like to accept or decline this invitation?": "Wil je deze uitnodiging accepteren of afwijzen?", "You already have existing direct chats with this user:": "Je hebt al bestaande privé-gesprekken met deze gebruiker:", - "You are already in a call.": "Je bent al in gesprek.", + "You are already in a call.": "U bent al in gesprek.", "You're not in any rooms yet! Press to make a room or to browse the directory": "Je zit nog niet in een ruimte! Druk op om een ruimte te maken of om door de catalogus te bladeren", "You are trying to access %(roomName)s.": "Je probeert in %(roomName)s toe te treden.", - "You cannot place a call with yourself.": "Je kunt geen spraakoproep met jezelf maken.", - "You cannot place VoIP calls in this browser.": "Je kunt in deze browser geen VoIP-oproepen plegen.", + "You cannot place a call with yourself.": "U kunt uzelf niet bellen.", + "You cannot place VoIP calls in this browser.": "U kunt in deze browser geen VoIP-oproepen plegen.", "You do not have permission to post to this room": "Je hebt geen toestemming in deze ruimte te praten", "You have been banned from %(roomName)s by %(userName)s.": "Je bent verbannen van %(roomName)s door %(userName)s.", "You have been invited to join this room by %(inviterName)s": "Je bent in deze ruimte uitgenodigd door %(inviterName)s", @@ -531,7 +531,7 @@ "New Password": "Nieuw wachtwoord", "Start automatically after system login": "Start automatisch na systeem-aanmelding", "Desktop specific": "Desktop-specifiek", - "Analytics": "Analysegegevens", + "Analytics": "Statistische gegevens", "Options": "Opties", "Riot collects anonymous analytics to allow us to improve the application.": "Riot verzamelt anonieme analysegegevens die het mogelijk maken het programma te verbeteren.", "Passphrases must match": "Wachtzinnen moeten overeenkomen", @@ -673,28 +673,28 @@ "Unpin Message": "Maak pin los", "Add rooms to this community": "Voeg ruimtes toe aan deze gemeenschap", "Call Failed": "Oproep mislukt", - "Call": "Bel", - "Answer": "Antwoord", - "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Opgepast: elke persoon die je toevoegt aan een community zal publiek zichtbaar zijn voor iedereen die het community ID kent", - "Invite new community members": "Nodig nieuwe community leden uit", - "Name or matrix ID": "Naam of Matrix ID", - "Which rooms would you like to add to this community?": "Welke ruimtes wil je toevoegen aan deze community?", + "Call": "Bellen", + "Answer": "Beantwoorden", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Let op: elke persoon die u toevoegt aan een gemeenschap zal publiek zichtbaar zijn voor iedereen die de gemeenschaps-ID kent", + "Invite new community members": "Nodig nieuwe gemeenschapsleden uit", + "Name or matrix ID": "Naam of Matrix-ID", + "Which rooms would you like to add to this community?": "Welke kamers wilt u toevoegen aan deze gemeenschap?", "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Een widget verwijderen doet dat voor alle gebruikers in deze ruimte. Ben je zeker dat je het widget wil verwijderen?", "Delete Widget": "Widget verwijderen", - "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "Er zijn onbekende toestellen in deze ruimte: als je verder gaat zonder ze te verifiëren zal het mogelijk zijn dat iemand je oproep afluistert.", - "Review Devices": "Toestellen nakijken", - "Call Anyway": "Bel toch", - "Answer Anyway": "Antwoord toch", - "Who would you like to add to this community?": "Wie wil je toevoegen aan deze community?", - "Invite to Community": "Nodig uit in deze community", - "Show these rooms to non-members on the community page and room list?": "Toon deze ruimtes aan niet-leden op de community pagina en lijst van ruimtes?", - "Add rooms to the community": "Voeg ruimtes toe aan de community", - "Room name or alias": "Ruimte naam of alias", - "Add to community": "Voeg toe aan community", - "Failed to invite the following users to %(groupId)s:": "Inviteren gefaald van de volgende gebruikers in %(groupId)s:", - "Failed to invite users to community": "Uitnodigen van gebruikers in community mislukt", - "Failed to invite users to %(groupId)s": "Niet gelukt gebruikers uit te nodigen in %(groupId)s", - "Failed to add the following rooms to %(groupId)s:": "Niet gelukt de volgende ruimten toe te voegen aan %(groupId)s:", + "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "Er zijn onbekende apparaten in deze kamer: als u verder gaat zonder ze te verifiëren zal het mogelijk zijn dat iemand uw oproep afluistert.", + "Review Devices": "Apparaten nakijken", + "Call Anyway": "Toch bellen", + "Answer Anyway": "Toch beantwoorden", + "Who would you like to add to this community?": "Wie wilt u toevoegen aan deze gemeenschap?", + "Invite to Community": "Uitnodigen in gemeenschap", + "Show these rooms to non-members on the community page and room list?": "Deze kamers tonen aan niet-leden op de gemeenschapspagina en kamerlijst?", + "Add rooms to the community": "Voeg kamers toe aan de gemeenschap", + "Room name or alias": "Kamernaam of -alias", + "Add to community": "Toevoegen aan gemeenschap", + "Failed to invite the following users to %(groupId)s:": "Uitnodigen van volgende gebruikers in %(groupId)s is mislukt:", + "Failed to invite users to community": "Uitnodigen van gebruikers in gemeenschap is mislukt", + "Failed to invite users to %(groupId)s": "Uitnodigen van gebruikers in %(groupId)s is mislukt", + "Failed to add the following rooms to %(groupId)s:": "Toevoegen van volgende kamers aan %(groupId)s is mislukt:", "Restricted": "Beperkte toegang", "Ignored user": "Genegeerde gebruiker", "You are now ignoring %(userId)s": "Je bent nu %(userId)s aan het negeren", @@ -703,11 +703,11 @@ "%(senderName)s changed the pinned messages for the room.": "%(senderName)s heeft de gepinde boodschappen voor de ruimte gewijzigd.", "%(names)s and %(count)s others are typing|other": "%(names)s en %(count)s andere gebruikers zijn aan het typen", "%(names)s and %(count)s others are typing|one": "%(names)s en iemand anders is aan het typen", - "Send": "Verstuur", + "Send": "Versturen", "Message Pinning": "Boodschap vastzetten", "Disable Emoji suggestions while typing": "Emoji suggesties tijdens het typen uitzetten", "Hide avatar changes": "Avatar veranderingen verbergen", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s", "Hide display name changes": "Weergavenaam wijzigingen verbergen", "Enable inline URL previews by default": "Inline URL-voorvertoning standaard aanzetten", "Enable URL previews for this room (only affects you)": "URL-voorvertoning in deze ruimte aanzetten (geldt alleen voor jou)", @@ -944,7 +944,7 @@ "Notify the whole room": "Notificeer de gehele ruimte", "Room Notification": "Ruimte Notificatie", "The information being sent to us to help make Riot.im better includes:": "De informatie die naar ons wordt verstuurd om Riot.im te verbeteren betreft:", - "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Waar deze pagina identificeerbare informatie bevat, zoals een ruimte, gebruiker of groep ID, zal deze data verwijderd worden voordat het naar de server gestuurd wordt.", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Waar deze pagina identificeerbare informatie bevat, zoals een kamer, gebruikers- of groeps-ID, zullen deze gegevens verwijderd worden voordat ze naar de server gestuurd worden.", "The platform you're on": "Het platform dat u gebruikt", "The version of Riot.im": "De versie van Riot.im", "Whether or not you're logged in (we don't record your user name)": "Of je wel of niet ingelogd bent (we nemen niet je gebruikersnaam op)", @@ -952,7 +952,7 @@ "Which officially provided instance you are using, if any": "Welke officieel aangeboden instantie u eventueel gebruikt", "Whether or not you're using the Richtext mode of the Rich Text Editor": "Of u de tekstverwerker al dan niet in de modus voor opgemaakte tekst gebruikt", "Your homeserver's URL": "De URL van uw thuisserver", - "Your identity server's URL": "De URL van je identiteitsserver", + "Your identity server's URL": "De URL van uw identiteitsserver", "In reply to ": "Als antwoord op ", "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", "were unbanned %(count)s times|one": "waren ontbant", @@ -1139,11 +1139,11 @@ "Failed to send logs: ": "Het is niet gelukt de logs te versturen: ", "Notes:": "Constateringen:", "Preparing to send logs": "Logs voorbereiden voor verzending", - "e.g. %(exampleValue)s": "bijv. %(exampleValue)s", - "Every page you use in the app": "Iedere bladzijde die je in de toepassing gebruikt", - "e.g. ": "bijv. ", - "Your User Agent": "Je gebruikersagent", - "Your device resolution": "De resolutie van je apparaat", + "e.g. %(exampleValue)s": "bv. %(exampleValue)s", + "Every page you use in the app": "Iedere bladzijde die u in de toepassing gebruikt", + "e.g. ": "bv. ", + "Your User Agent": "Uw gebruikersagent", + "Your device resolution": "De resolutie van uw apparaat", "Reload widget": "Widget herladen", "Missing roomId.": "roomId mist.", "Always show encryption icons": "Altijd versleutelingsiconen weergeven", @@ -1181,12 +1181,12 @@ "Terms and Conditions": "Voorwaarden", "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Om de %(homeserverDomain)s thuisserver te blijven gebruiken zul je de voorwaarden moeten lezen en aanvaarden.", "Review terms and conditions": "Voorwaarden lezen", - "A conference call could not be started because the intgrations server is not available": "Een groepsgesprek kon niet worden gestart omdat de integratieserver niet beschikbaar is", + "A conference call could not be started because the intgrations server is not available": "Een groepsgesprek kon niet gestart worden omdat de integratieserver niet beschikbaar is", "Call in Progress": "Lopend gesprek", - "A call is currently being placed!": "Een gesprek wordt gestart!", + "A call is currently being placed!": "Er wordt al een oproep gepleegd!", "A call is already in progress!": "Er loopt al een gesprek!", - "Permission Required": "Toestemming benodigd", - "You do not have permission to start a conference call in this room": "Je hebt geen toestemming in deze ruimte een groepsgesprek te starten", + "Permission Required": "Toestemming vereist", + "You do not have permission to start a conference call in this room": "U heeft geen toestemming om in deze kamer een vergadergesprek te starten", "Show empty room list headings": "Lege koppen in ruimtelijst weergeven", "This event could not be displayed": "Deze gebeurtenis kon niet worden weergegeven", "Encrypting": "Versleutelen", @@ -1234,8 +1234,8 @@ "This homeserver has hit its Monthly Active User limit.": "Deze homeserver heeft de maandelijks actieve gebruikerslimiet bereikt.", "This homeserver has exceeded one of its resource limits.": "Deze homeserver heeft de limiet van een van de systeembronnen bereikt.", "Whether or not you're logged in (we don't record your username)": "Of u al dan niet ingelogd bent (we slaan uw gebruiksnaam niet op)", - "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Het bestand %(fileName)s is groter dan de uploadlimiet van de thuisserver", - "Unable to load! Check your network connectivity and try again.": "Laden mislukt! Controleer uw netwerktoegang en probeer opnieuw.", + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Het bestand ‘%(fileName)s’ is groter dan de uploadlimiet van de thuisserver", + "Unable to load! Check your network connectivity and try again.": "Laden mislukt! Controleer uw netwerktoegang en probeer het opnieuw.", "Failed to invite users to the room:": "Kon de volgende gebruikers hier niet uitnodigen:", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Plakt ¯\\_(ツ)_/¯ vòòr een bericht in kale tekst", "Upgrades a room to a new version": "Actualiseert de kamer tot een nieuwe versie", From 2d79957d94214fbcef76f5bb506b693e0e764b71 Mon Sep 17 00:00:00 2001 From: "J. A. Durieux" Date: Thu, 28 Mar 2019 16:33:26 +0000 Subject: [PATCH 140/481] Translated using Weblate (Dutch) Currently translated at 79.4% (1238 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 55c1ed5766..ac169161a0 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -489,7 +489,7 @@ "You need to be able to invite users to do that.": "Dat vereist de bevoegdheid gebruikers uit te nodigen.", "You need to be logged in.": "Aanmelding vereist.", "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", - "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het ziet er naar uit dat je e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat je e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Je wachtwoord is succesvol veranderd. Je zult op andere apparaten geen mededelingen ontvangen totdat je er opnieuw inlogt", "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat je in een gesprek zit, weet je zeker dat je wilt afsluiten?", From 87ca3069bb1ff0b5143a9bc5bb511b39430d1fc2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Mar 2019 10:43:01 -0600 Subject: [PATCH 141/481] Misc code cleanup --- src/components/structures/IndicatorScrollbar.js | 4 ++-- src/components/views/rooms/RoomBreadcrumbs.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js index 4dc77d73b9..263a0a22ba 100644 --- a/src/components/structures/IndicatorScrollbar.js +++ b/src/components/structures/IndicatorScrollbar.js @@ -88,10 +88,10 @@ export default class IndicatorScrollbar extends React.Component { if (this.props.trackHorizontalOverflow) { this.setState({ // Offset from absolute position of the container - leftIndicatorOffset: hasLeftOverflow ? `${this._scrollElement.scrollLeft}px` : 0, + leftIndicatorOffset: hasLeftOverflow ? `${this._scrollElement.scrollLeft}px` : '0', // Negative because we're coming from the right - rightIndicatorOffset: hasRightOverflow ? `-${this._scrollElement.scrollLeft}px` : 0, + rightIndicatorOffset: hasRightOverflow ? `-${this._scrollElement.scrollLeft}px` : '0', }); } } diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index e3e1f2fc1e..3a71ec4ec2 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -134,8 +134,7 @@ export default class RoomBreadcrumbs extends React.Component { ); }); return ( - + { avatars } ); From 41c5582a7b46835dbaae775569758b6d52e9d993 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 28 Mar 2019 17:56:12 +0100 Subject: [PATCH 142/481] make resizeNotifier optional so tests don't fail --- src/components/structures/RoomView.js | 8 ++++++-- src/components/views/rooms/RoomList.js | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index ba6b54bdbc..cfc645abb4 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -392,7 +392,9 @@ module.exports = React.createClass({ this._updateConfCallNotification(); window.addEventListener('beforeunload', this.onPageUnload); - this.props.resizeNotifier.on("middlePanelResized", this.onResize); + if (this.props.resizeNotifier) { + this.props.resizeNotifier.on("middlePanelResized", this.onResize); + } this.onResize(); document.addEventListener("keydown", this.onKeyDown); @@ -472,7 +474,9 @@ module.exports = React.createClass({ } window.removeEventListener('beforeunload', this.onPageUnload); - this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); + if (this.props.resizeNotifier) { + this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize); + } document.removeEventListener("keydown", this.onKeyDown); diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 2de9918e6e..33b97964f6 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -212,7 +212,9 @@ module.exports = React.createClass({ this._checkSubListsOverflow(); this.resizer.attach(); - this.props.resizeNotifier.on("leftPanelResized", this.onResize); + if (this.props.resizeNotifier) { + this.props.resizeNotifier.on("leftPanelResized", this.onResize); + } this.mounted = true; }, @@ -271,7 +273,10 @@ module.exports = React.createClass({ MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); } - this.props.resizeNotifier.removeListener("leftPanelResized", this.onResize); + + if (this.props.resizeNotifier) { + this.props.resizeNotifier.removeListener("leftPanelResized", this.onResize); + } if (this._tagStoreToken) { From 30dc6a9150078abc8ddb0156ba956b0dd6812d0a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 28 Mar 2019 17:57:08 +0100 Subject: [PATCH 143/481] remove tests relying on scrollpanel behaviour as BACAT scrolling relies on CSS from riot, which is not included in the karma tests, we're removing these tests in favor of later adding them to the e2e tests. --- .../components/structures/ScrollPanel-test.js | 283 ------------- .../structures/TimelinePanel-test.js | 372 ------------------ 2 files changed, 655 deletions(-) delete mode 100644 test/components/structures/ScrollPanel-test.js delete mode 100644 test/components/structures/TimelinePanel-test.js diff --git a/test/components/structures/ScrollPanel-test.js b/test/components/structures/ScrollPanel-test.js deleted file mode 100644 index 41d0f4469b..0000000000 --- a/test/components/structures/ScrollPanel-test.js +++ /dev/null @@ -1,283 +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. -*/ - -const React = require('react'); -const ReactDOM = require("react-dom"); -const ReactTestUtils = require('react-addons-test-utils'); -const expect = require('expect'); -import Promise from 'bluebird'; -import { EventEmitter } from "events"; - -const sdk = require('matrix-react-sdk'); - -const ScrollPanel = sdk.getComponent('structures.ScrollPanel'); -const test_utils = require('test-utils'); - -const Tester = React.createClass({ - getInitialState: function() { - return { - tileKeys: [], - resizeNotifier: new EventEmitter(), - }; - }, - - componentWillMount: function() { - this.fillCounts = {'b': 0, 'f': 0}; - this._fillHandlers = {'b': null, 'f': null}; - this._fillDefers = {'b': null, 'f': null}; - this._scrollDefer = null; - - // scrollTop at the last scroll event - this.lastScrollEvent = null; - }, - - _onFillRequest: function(back) { - const dir = back ? 'b': 'f'; - console.log("FillRequest: " + dir); - this.fillCounts[dir]++; - - const handler = this._fillHandlers[dir]; - const defer = this._fillDefers[dir]; - - // don't use the same handler twice - this._fillHandlers[dir] = null; - this._fillDefers[dir] = null; - - let res; - if (handler) { - res = handler(); - } else { - res = Promise.resolve(false); - } - - if (defer) { - defer.resolve(); - } - return res; - }, - - addFillHandler: function(dir, handler) { - this._fillHandlers[dir] = handler; - }, - - /* returns a promise which will resolve when the fill happens */ - awaitFill: function(dir) { - console.log("ScrollPanel Tester: awaiting " + dir + " fill"); - const defer = Promise.defer(); - this._fillDefers[dir] = defer; - return defer.promise; - }, - - _onScroll: function(ev) { - const st = ev.target.scrollTop; - console.log("ScrollPanel Tester: scroll event; scrollTop: " + st); - this.lastScrollEvent = st; - - const d = this._scrollDefer; - if (d) { - this._scrollDefer = null; - d.resolve(); - } - }, - - /* returns a promise which will resolve when a scroll event happens */ - awaitScroll: function() { - console.log("Awaiting scroll"); - this._scrollDefer = Promise.defer(); - return this._scrollDefer.promise; - }, - - setTileKeys: function(keys) { - console.log("Updating keys: len=" + keys.length); - this.setState({tileKeys: keys.slice()}); - }, - - scrollPanel: function() { - return this.refs.sp; - }, - - _mkTile: function(key) { - // each tile is 150 pixels high: - // 98 pixels of body - // 2 pixels of border - // 50 pixels of margin - // - // there is an extra 50 pixels of margin at the bottom. - return ( -
    1. -
      - { key } -
      -
    2. - ); - }, - - render: function() { - const tiles = this.state.tileKeys.map(this._mkTile); - console.log("rendering with " + tiles.length + " tiles"); - return ( - - { tiles } - - ); - }, -}); - -describe('ScrollPanel', function() { - let parentDiv; - let tester; - let scrollingDiv; - - beforeEach(function(done) { - test_utils.beforeEach(this); - - // create a div of a useful size to put our panel in, and attach it to - // the document so that we can interact with it properly. - parentDiv = document.createElement('div'); - parentDiv.style.width = '800px'; - parentDiv.style.height = '600px'; - parentDiv.style.overflow = 'hidden'; - document.body.appendChild(parentDiv); - - tester = ReactDOM.render(, parentDiv); - expect(tester.fillCounts.b).toEqual(1); - expect(tester.fillCounts.f).toEqual(1); - - scrollingDiv = ReactTestUtils.findRenderedDOMComponentWithClass( - tester, "gm-scroll-view"); - - // we need to make sure we don't call done() until q has finished - // running the completion handlers from the fill requests. We can't - // just use .done(), because that will end up ahead of those handlers - // in the queue. We can't use window.setTimeout(0), because that also might - // run ahead of those handlers. - const sp = tester.scrollPanel(); - let retriesRemaining = 1; - const awaitReady = function() { - return Promise.resolve().then(() => { - if (sp._pendingFillRequests.b === false && - sp._pendingFillRequests.f === false - ) { - return; - } - - if (retriesRemaining == 0) { - throw new Error("fillRequests did not complete"); - } - retriesRemaining--; - return awaitReady(); - }); - }; - awaitReady().done(done); - }); - - afterEach(function() { - if (parentDiv) { - document.body.removeChild(parentDiv); - parentDiv = null; - } - }); - - it('should handle scrollEvent strangeness', function() { - const events = []; - - return Promise.resolve().then(() => { - // initialise with a load of events - for (let i = 0; i < 20; i++) { - events.push(i+80); - } - tester.setTileKeys(events); - expect(scrollingDiv.scrollHeight).toEqual(3050); // 20*150 + 50 - expect(scrollingDiv.scrollTop).toEqual(3050 - 600); - return tester.awaitScroll(); - }).then(() => { - expect(tester.lastScrollEvent).toBe(3050 - 600); - - tester.scrollPanel().scrollToToken("92", 0); - - // at this point, ScrollPanel will have updated scrollTop, but - // the event hasn't fired. - expect(tester.lastScrollEvent).toEqual(3050 - 600); - expect(scrollingDiv.scrollTop).toEqual(1950); - - // now stamp over the scrollTop. - console.log('faking #528'); - scrollingDiv.scrollTop = 500; - - return tester.awaitScroll(); - }).then(() => { - expect(tester.lastScrollEvent).toBe(1950); - expect(scrollingDiv.scrollTop).toEqual(1950); - }); - }); - - it('should not get stuck in #528 workaround', function(done) { - let events = []; - Promise.resolve().then(() => { - // initialise with a bunch of events - for (let i = 0; i < 40; i++) { - events.push(i); - } - tester.setTileKeys(events); - expect(tester.fillCounts.b).toEqual(1); - expect(tester.fillCounts.f).toEqual(2); - expect(scrollingDiv.scrollHeight).toEqual(6050); // 40*150 + 50 - expect(scrollingDiv.scrollTop).toEqual(6050 - 600); - - // try to scroll up, to a non-integer offset. - tester.scrollPanel().scrollToToken("30", -101/3); - - expect(scrollingDiv.scrollTop).toEqual(4616); // 31*150 - 34 - - // wait for the scroll event to land - return tester.awaitScroll(); // fails - }).then(() => { - expect(tester.lastScrollEvent).toEqual(4616); - - // Now one more event; this will make it reset the scroll, but - // because the delta will be less than 1, will not trigger a - // scroll event, this leaving recentEventScroll defined. - console.log("Adding event 50"); - events.push(50); - tester.setTileKeys(events); - - // wait for the scrollpanel to stop trying to paginate - }).then(() => { - // Now, simulate hitting "scroll to bottom". - events = []; - for (let i = 100; i < 120; i++) { - events.push(i); - } - tester.setTileKeys(events); - tester.scrollPanel().scrollToBottom(); - - // wait for the scroll event to land - return tester.awaitScroll(); // fails - }).then(() => { - expect(scrollingDiv.scrollTop).toEqual(20*150 + 50 - 600); - - // simulate a user-initiated scroll on the div - scrollingDiv.scrollTop = 1200; - return tester.awaitScroll(); - }).then(() => { - expect(scrollingDiv.scrollTop).toEqual(1200); - }).done(done); - }); -}); diff --git a/test/components/structures/TimelinePanel-test.js b/test/components/structures/TimelinePanel-test.js deleted file mode 100644 index 01ea6d8421..0000000000 --- a/test/components/structures/TimelinePanel-test.js +++ /dev/null @@ -1,372 +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. -*/ - -const React = require('react'); -const ReactDOM = require('react-dom'); -const ReactTestUtils = require('react-addons-test-utils'); -const expect = require('expect'); -import Promise from 'bluebird'; -const sinon = require('sinon'); - -const jssdk = require('matrix-js-sdk'); -const EventTimeline = jssdk.EventTimeline; - -const sdk = require('matrix-react-sdk'); -const TimelinePanel = sdk.getComponent('structures.TimelinePanel'); -const peg = require('../../../src/MatrixClientPeg'); - -const test_utils = require('test-utils'); - -const ROOM_ID = '!room:localhost'; -const USER_ID = '@me:localhost'; - -// wrap TimelinePanel with a component which provides the MatrixClient in the context. -const WrappedTimelinePanel = React.createClass({ - childContextTypes: { - matrixClient: React.PropTypes.object, - }, - - getChildContext: function() { - return { - matrixClient: peg.get(), - }; - }, - - render: function() { - return ; - }, -}); - - -describe('TimelinePanel', function() { - let sandbox; - let timelineSet; - let room; - let client; - let timeline; - let parentDiv; - - // make a dummy message. eventNum is put in the message text to help - // identification during debugging, and also in the timestamp so that we - // don't get lots of events with the same timestamp. - function mkMessage(eventNum, opts) { - return test_utils.mkMessage( - { - event: true, room: ROOM_ID, user: USER_ID, - ts: Date.now() + eventNum, - msg: "Event " + eventNum, - ...opts, - }); - } - - function scryEventTiles(panel) { - return ReactTestUtils.scryRenderedComponentsWithType( - panel, sdk.getComponent('rooms.EventTile')); - } - - beforeEach(function() { - test_utils.beforeEach(this); - sandbox = test_utils.stubClient(sandbox); - - room = sinon.createStubInstance(jssdk.Room); - room.currentState = sinon.createStubInstance(jssdk.RoomState); - room.currentState.members = {}; - room.roomId = ROOM_ID; - - timelineSet = sinon.createStubInstance(jssdk.EventTimelineSet); - timelineSet.getPendingEvents.returns([]); - timelineSet.room = room; - - timeline = new jssdk.EventTimeline(timelineSet); - - timelineSet.getLiveTimeline.returns(timeline); - - client = peg.get(); - client.credentials = {userId: USER_ID}; - - // create a div of a useful size to put our panel in, and attach it to - // the document so that we can interact with it properly. - parentDiv = document.createElement('div'); - parentDiv.style.width = '800px'; - - // This has to be slightly carefully chosen. We expect to have to do - // exactly one pagination to fill it. - parentDiv.style.height = '500px'; - - parentDiv.style.overflow = 'hidden'; - document.body.appendChild(parentDiv); - }); - - afterEach(function() { - if (parentDiv) { - ReactDOM.unmountComponentAtNode(parentDiv); - parentDiv.remove(); - parentDiv = null; - } - sandbox.restore(); - }); - - it('should load new events even if you are scrolled up', function(done) { - // this is https://github.com/vector-im/vector-web/issues/1367 - - // enough events to allow us to scroll back - const N_EVENTS = 30; - for (let i = 0; i < N_EVENTS; i++) { - timeline.addEvent(mkMessage(i)); - } - - let scrollDefer; - const onScroll = (e) => { - console.log(`TimelinePanel called onScroll: ${e.target.scrollTop}`); - if (scrollDefer) { - scrollDefer.resolve(); - } - }; - const rendered = ReactDOM.render( - , - parentDiv, - ); - const panel = rendered.refs.panel; - const scrollingDiv = ReactTestUtils.findRenderedDOMComponentWithClass( - panel, "gm-scroll-view"); - - // helper function which will return a promise which resolves when the - // panel isn't paginating - var awaitPaginationCompletion = function() { - if(!panel.state.forwardPaginating) {return Promise.resolve();} else {return Promise.delay(0).then(awaitPaginationCompletion);} - }; - - // helper function which will return a promise which resolves when - // the TimelinePanel fires a scroll event - const awaitScroll = function() { - scrollDefer = Promise.defer(); - return scrollDefer.promise; - }; - - // let the first round of pagination finish off - Promise.delay(5).then(() => { - expect(panel.state.canBackPaginate).toBe(false); - expect(scryEventTiles(panel).length).toEqual(N_EVENTS); - - // scroll up - console.log("setting scrollTop = 0"); - scrollingDiv.scrollTop = 0; - - // wait for the scroll event to land - }).then(awaitScroll).then(() => { - expect(scrollingDiv.scrollTop).toEqual(0); - - // there should be no pagination going on now - expect(panel.state.backPaginating).toBe(false); - expect(panel.state.forwardPaginating).toBe(false); - expect(panel.state.canBackPaginate).toBe(false); - expect(panel.state.canForwardPaginate).toBe(false); - expect(panel.isAtEndOfLiveTimeline()).toBe(false); - expect(scrollingDiv.scrollTop).toEqual(0); - - console.log("adding event"); - - // a new event! - const ev = mkMessage(N_EVENTS+1); - timeline.addEvent(ev); - panel.onRoomTimeline(ev, room, false, false, { - liveEvent: true, - timeline: timeline, - }); - - // that won't make much difference, because we don't paginate - // unless we're at the bottom of the timeline, but a scroll event - // should be enough to set off a pagination. - expect(scryEventTiles(panel).length).toEqual(N_EVENTS); - - scrollingDiv.scrollTop = 10; - - return awaitScroll(); - }).then(awaitPaginationCompletion).then(() => { - expect(scryEventTiles(panel).length).toEqual(N_EVENTS+1); - }).done(done, done); - }); - - it('should not paginate forever if there are no events', function(done) { - // start with a handful of events in the timeline, as would happen when - // joining a room - const d = Date.now(); - for (let i = 0; i < 3; i++) { - timeline.addEvent(mkMessage(i)); - } - timeline.setPaginationToken('tok', EventTimeline.BACKWARDS); - - // back-pagination returns a promise for true, but adds no events - client.paginateEventTimeline = sinon.spy((tl, opts) => { - console.log("paginate:", opts); - expect(opts.backwards).toBe(true); - return Promise.resolve(true); - }); - - const rendered = ReactDOM.render( - , - parentDiv, - ); - const panel = rendered.refs.panel; - - const messagePanel = ReactTestUtils.findRenderedComponentWithType( - panel, sdk.getComponent('structures.MessagePanel')); - - expect(messagePanel.props.backPaginating).toBe(true); - - // let the first round of pagination finish off - setTimeout(() => { - // at this point, the timeline window should have tried to paginate - // 5 times, and we should have given up paginating - expect(client.paginateEventTimeline.callCount).toEqual(5); - expect(messagePanel.props.backPaginating).toBe(false); - expect(messagePanel.props.suppressFirstDateSeparator).toBe(false); - - // now, if we update the events, there shouldn't be any - // more requests. - client.paginateEventTimeline.resetHistory(); - panel.forceUpdate(); - expect(messagePanel.props.backPaginating).toBe(false); - setTimeout(() => { - expect(client.paginateEventTimeline.callCount).toEqual(0); - done(); - }, 0); - }, 10); - }); - - it("should let you scroll down to the bottom after you've scrolled up", function(done) { - const N_EVENTS = 120; // the number of events to simulate being added to the timeline - - // sadly, loading all those events takes a while - this.timeout(N_EVENTS * 50); - - // client.getRoom is called a /lot/ in this test, so replace - // sinon's spy with a fast noop. - client.getRoom = function(id) { return null; }; - - // fill the timeline with lots of events - for (let i = 0; i < N_EVENTS; i++) { - timeline.addEvent(mkMessage(i)); - } - console.log("added events to timeline"); - - let scrollDefer; - const rendered = ReactDOM.render( - {scrollDefer.resolve();}} />, - parentDiv, - ); - console.log("TimelinePanel rendered"); - const panel = rendered.refs.panel; - const messagePanel = ReactTestUtils.findRenderedComponentWithType( - panel, sdk.getComponent('structures.MessagePanel')); - const scrollingDiv = ReactTestUtils.findRenderedDOMComponentWithClass( - panel, "gm-scroll-view"); - - // helper function which will return a promise which resolves when - // the TimelinePanel fires a scroll event - const awaitScroll = function() { - scrollDefer = Promise.defer(); - - return scrollDefer.promise.then(() => { - console.log("got scroll event; scrollTop now " + - scrollingDiv.scrollTop); - }); - }; - - function setScrollTop(scrollTop) { - const before = scrollingDiv.scrollTop; - scrollingDiv.scrollTop = scrollTop; - console.log("setScrollTop: before update: " + before + - "; assigned: " + scrollTop + - "; after update: " + scrollingDiv.scrollTop); - } - - function backPaginate() { - console.log("back paginating..."); - setScrollTop(0); - return awaitScroll().then(() => { - const eventTiles = scryEventTiles(panel); - const firstEvent = eventTiles[0].props.mxEvent; - - console.log("TimelinePanel contains " + eventTiles.length + - " events; first is " + - firstEvent.getContent().body); - - if(scrollingDiv.scrollTop > 0) { - // need to go further - return backPaginate(); - } - console.log("paginated to start."); - }); - } - - function scrollDown() { - // Scroll the bottom of the viewport to the bottom of the panel - setScrollTop(scrollingDiv.scrollHeight - scrollingDiv.clientHeight); - console.log("scrolling down... " + scrollingDiv.scrollTop); - return awaitScroll().delay(0).then(() => { - const eventTiles = scryEventTiles(panel); - const events = timeline.getEvents(); - - const lastEventInPanel = eventTiles[eventTiles.length - 1].props.mxEvent; - const lastEventInTimeline = events[events.length - 1]; - - // Scroll until the last event in the panel = the last event in the timeline - if(lastEventInPanel.getId() !== lastEventInTimeline.getId()) { - // need to go further - return scrollDown(); - } - console.log("paginated to end."); - }); - } - - // let the first round of pagination finish off - awaitScroll().then(() => { - // we should now have loaded the first few events - expect(messagePanel.props.backPaginating).toBe(false); - expect(messagePanel.props.suppressFirstDateSeparator).toBe(true); - - // back-paginate until we hit the start - return backPaginate(); - }).then(() => { - // hopefully, we got to the start of the timeline - expect(messagePanel.props.backPaginating).toBe(false); - - expect(messagePanel.props.suppressFirstDateSeparator).toBe(false); - const events = scryEventTiles(panel); - expect(events[0].props.mxEvent).toBe(timeline.getEvents()[0]); - - // At this point, we make no assumption that unpagination has happened. This doesn't - // mean that we shouldn't be able to scroll all the way down to the bottom to see the - // most recent event in the timeline. - - // scroll all the way to the bottom - return scrollDown(); - }).then(() => { - expect(messagePanel.props.backPaginating).toBe(false); - expect(messagePanel.props.forwardPaginating).toBe(false); - - const events = scryEventTiles(panel); - - // Expect to be able to see the most recent event - const lastEventInPanel = events[events.length - 1].props.mxEvent; - const lastEventInTimeline = timeline.getEvents()[timeline.getEvents().length - 1]; - expect(lastEventInPanel.getContent()).toBe(lastEventInTimeline.getContent()); - - console.log("done"); - }).done(done, done); - }); -}); From a916007d9788a435af415e333b267f6dc7286262 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 16:33:33 +0000 Subject: [PATCH 144/481] Translated using Weblate (Dutch) Currently translated at 79.5% (1240 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 279 ++++++++++++++++++++------------------- 1 file changed, 140 insertions(+), 139 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index ac169161a0..77b7892925 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -1,7 +1,7 @@ { "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "Voer alsjeblieft de verificatiecode in die is verstuurd naar +%(msisdn)s", - "%(targetName)s accepted an invitation.": "%(targetName)s heeft een uitnodiging geaccepteerd.", - "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s heeft de uitnodiging voor %(displayName)s geaccepteerd.", + "%(targetName)s accepted an invitation.": "%(targetName)s heeft een uitnodiging aanvaard.", + "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s heeft de uitnodiging voor %(displayName)s aanvaard.", "Account": "Account", "Access Token:": "Toegangstoken:", "Add email address": "Voeg een e-mailadres toe", @@ -9,25 +9,25 @@ "Admin": "Beheerder", "Advanced": "Geavanceerd", "Algorithm": "Algoritme", - "Always show message timestamps": "Laat altijd tijdstempels van berichten zien", + "Always show message timestamps": "Altijd tijdstempels van berichten tonen", "Authentication": "Authenticatie", "%(items)s and %(lastItem)s": "%(items)s en %(lastItem)s", "and %(count)s others...|other": "en %(count)s andere...", "and %(count)s others...|one": "en één andere...", "%(names)s and %(lastPerson)s are typing": "%(names)s en %(lastPerson)s zijn aan het typen", "A new password must be entered.": "Er moet een nieuw wachtwoord worden ingevoerd.", - "%(senderName)s answered the call.": "%(senderName)s heeft deelgenomen aan het audiogesprek.", + "%(senderName)s answered the call.": "%(senderName)s heeft de oproep beantwoord.", "An error has occurred.": "Er is een fout opgetreden.", "Anyone who knows the room's link, apart from guests": "Iedereen die de link van de ruimte weet, behalve gasten", "Anyone who knows the room's link, including guests": "Iedereen die link van de ruimte weet, inclusief gasten", "Are you sure?": "Weet je het zeker?", "Are you sure you want to reject the invitation?": "Weet je zeker dat je de uitnodiging wilt weigeren?", "Attachment": "Bijlage", - "Autoplay GIFs and videos": "Start GIFs en videos automatisch", + "Autoplay GIFs and videos": "GIF’s en video’s automatisch afspelen", "%(senderName)s banned %(targetName)s.": "%(senderName)s heeft %(targetName)s verbannen.", "Ban": "Verban", "Banned users": "Verbannen gebruikers", - "Bans user with given id": "Verbant de gebruiker met het gegeven ID", + "Bans user with given id": "Verbant de gebruiker met de gegeven ID", "Blacklisted": "Buitengesloten", "Bulk Options": "Bulk opties", "Call Timeout": "Oproeptime-out", @@ -36,10 +36,10 @@ "Change Password": "Wachtwoord veranderen", "%(senderName)s changed their profile picture.": "%(senderName)s heeft een nieuwe profielfoto ingesteld.", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s heeft het machtsniveau van %(powerLevelDiffText)s gewijzigd.", - "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s heeft de ruimtenaam van %(roomName)s gewijzigd.", - "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s heeft het onderwerp gewijzigd naar \"%(topic)s\".", + "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s heeft de kamernaam gewijzigd naar %(roomName)s.", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s heeft het onderwerp gewijzigd naar ‘%(topic)s’.", "Changes to who can read history will only apply to future messages in this room": "Veranderingen aan wie de geschiedenis kan lezen worden alleen maar toegepast op toekomstige berichten in deze ruimte", - "Changes your display nickname": "Verandert jouw weergavenaam", + "Changes your display nickname": "Verandert uw weergavenaam", "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het veranderen van het wachtwoord zal op het moment alle eind-tot-eind encryptie sleutels resetten, wat alle versleutelde gespreksgeschiedenis onleesbaar zou maken, behalve als je eerst je ruimtesleutels exporteert en achteraf opnieuw importeert. Dit zal worden verbeterd in de toekomst.", "Clear Cache and Reload": "Cache Legen en Herladen", "Clear Cache": "Cache Legen", @@ -90,7 +90,7 @@ "Favourite": "Favoriet", "Mute": "Dempen", "Notifications": "Notificaties", - "Operation failed": "Actie mislukt", + "Operation failed": "Handeling is mislukt", "powered by Matrix": "mogelijk gemaakt door Matrix", "Remove": "Verwijderen", "Room directory": "Ruimtelijst", @@ -122,7 +122,7 @@ "People": "Personen", "Permissions": "Toestemmingen", "Phone": "Telefoon", - "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-gesprek gestart.", + "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gepleegd.", "Privacy warning": "Privacywaarschuwing", "Private Chat": "Privégesprek", "Privileged Users": "Bevoorrechte gebruikers", @@ -174,11 +174,11 @@ "Create an account": "Open een account", "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", - "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de naam van de ruimte verwijderd.", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik een bestaand", "Create Room": "Maak een ruimte aan", "Curve25519 identity key": "Curve25519-identiteitssleutel", - "/ddg is not a command": "/ddg is geen commando", + "/ddg is not a command": "/ddg is geen opdracht", "Deactivate Account": "Account Deactiveren", "Deactivate my account": "Mijn account deactiveren", "Decline": "Weigeren", @@ -206,7 +206,7 @@ "Claimed Ed25519 fingerprint key": "Geclaimde Ed25519-sleutelvingerafdruk", "Custom": "Aangepast", "Custom level": "Aangepast niveau", - "Deops user with given id": "Ontmachtigd gebruiker met het gegeven ID", + "Deops user with given id": "Ontmachtigt gebruiker met de gegeven ID", "Default": "Standaard", "Displays action": "Geeft actie weer", "Drop here to tag %(section)s": "Hier naartoe verplaatsen om %(section)s te etiketteren", @@ -234,7 +234,7 @@ "Failed to ban user": "Niet gelukt de gebruiker te verbannen", "Failed to change power level": "Niet gelukt het machtsniveau te wijzigen", "Failed to fetch avatar URL": "Niet gelukt de avatar-URL op te halen", - "Failed to join room": "Niet gelukt tot de ruimte toe te treden", + "Failed to join room": "Toetreden van kamer is mislukt", "Failed to leave room": "Niet gelukt de ruimte te verlaten", "Failed to load timeline position": "Niet gelukt de tijdlijnpositie te laden", "Failed to mute user": "Niet gelukt de gebruiker het zwijgen op te leggen", @@ -242,7 +242,7 @@ "Failed to reject invitation": "Niet gelukt de uitnodiging te weigeren", "Failed to save settings": "Niet gelukt om de instellingen op te slaan", "Failed to send email": "Niet gelukt de e-mail te versturen", - "Failed to send request.": "Niet gelukt het verzoek te versturen.", + "Failed to send request.": "Versturen van verzoek is mislukt.", "Failed to set avatar.": "Niet gelukt om de avatar in te stellen.", "Failed to set display name": "Niet gelukt de weergavenaam in te stellen", "Failed to set up conference call": "Niet gelukt om een vergadergesprek te maken", @@ -283,40 +283,40 @@ "Invalid Email Address": "Ongeldig e-mailadres", "Invalid file%(extra)s": "Ongeldig bestand%(extra)s", "%(senderName)s invited %(targetName)s.": "%(senderName)s heeft %(targetName)s uitgenodigd.", - "Invite new room members": "Nieuwe ruimteleden uitnodigen", + "Invite new room members": "Nieuwe kamerleden uitnodigen", "Invited": "Uitgenodigd", "Invites": "Uitnodigingen", - "Invites user with given id to current room": "Nodigt de gebruiker met het gegeven ID uit in de huidige ruimte", + "Invites user with given id to current room": "Nodigt de gebruiker met de gegeven ID uit in de huidige kamer", "'%(alias)s' is not a valid format for an address": "'%(alias)s' is niet een geldig formaat voor een adres", "'%(alias)s' is not a valid format for an alias": "'%(alias)s' is niet een geldig formaat voor een naam", "%(displayName)s is typing": "%(displayName)s is aan het typen", "Sign in with": "Inloggen met", "Join as voice or video.": "Toetreden als spraak of video.", "Join Room": "Ruimte toetreden", - "%(targetName)s joined the room.": "%(targetName)s is tot de ruimte toegetreden.", - "Joins room with given alias": "Treed de ruimte toe met een gegeven naam", + "%(targetName)s joined the room.": "%(targetName)s is tot de kamer toegetreden.", + "Joins room with given alias": "Treedt de kamer toe met een gegeven alias", "Jump to first unread message.": "Spring naar het eerste ongelezen bericht.", "Labs": "Labs", "Last seen": "Laatst gezien", - "Leave room": "Ruimte verlaten", - "%(targetName)s left the room.": "%(targetName)s heeft de ruimte verlaten.", + "Leave room": "Kamer verlaten", + "%(targetName)s left the room.": "%(targetName)s heeft de kamer verlaten.", "Level:": "Niveau:", "Local addresses for this room:": "Lokale adressen voor deze ruimte:", "Logged in as:": "Ingelogd als:", "Logout": "Uitloggen", "Low priority": "Lage prioriteit", - "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s heeft de toekomstige ruimtegeschiedenis zichtbaar gemaakt voor alle ruimte deelnemers, vanaf het moment dat ze uitgenodigd zijn.", - "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s heeft de toekomstige ruimte geschiedenis zichtbaar gemaakt voor alle ruimte deelnemers, vanaf het moment dat ze toegetreden zijn.", - "%(senderName)s made future room history visible to all room members.": "%(senderName)s heeft de toekomstige ruimte geschiedenis zichtbaar gemaakt voor alle ruimte deelnemers.", - "%(senderName)s made future room history visible to anyone.": "%(senderName)s heeft de toekomstige ruimte geschiedenis zichtbaar gemaakt voor iedereen.", - "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s heeft de toekomstige ruimte geschiedenis zichtbaar gemaakt voor onbekend (%(visibility)s).", + "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor alle kamerdeelnemers, vanaf het moment dat ze uitgenodigd zijn.", + "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor alle kamerdeelnemers, vanaf het moment dat ze toegetreden zijn.", + "%(senderName)s made future room history visible to all room members.": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor alle kamerdeelnemers.", + "%(senderName)s made future room history visible to anyone.": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor iedereen.", + "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor onbekend (%(visibility)s).", "Manage Integrations": "Integraties beheren", "Markdown is disabled": "Markdown is uitgeschakeld", "Markdown is enabled": "Markdown ingeschakeld", "matrix-react-sdk version:": "matrix-react-sdk-versie:", "Message not sent due to unknown devices being present": "Bericht niet verzonden doordat er een onbekende apparaten aanwezig zijn", - "Missing room_id in request": "Het room_id mist in het verzoek", - "Missing user_id in request": "De user_id mist in het verzoek", + "Missing room_id in request": "room_id ontbreekt in verzoek", + "Missing user_id in request": "user_id ontbreekt in verzoek", "Mobile phone number": "Mobiele-telefoonnummer", "Mobile phone number (optional)": "Mobiele-telefoonnummer (optioneel)", "Never send encrypted messages to unverified devices from this device": "Nooit versleutelde berichten vanaf dit apparaat naar ongeverifieerde apparaten versturen", @@ -328,19 +328,19 @@ "Only people who have been invited": "Alleen personen die zijn uitgenodigd", "Please check your email and click on the link it contains. Once this is done, click continue.": "Bekijk je e-mail en klik op de link die het bevat. Zodra dit klaar is, klik op verder gaan.", "Power level must be positive integer.": "Machtsniveau moet een positief geheel getal zijn.", - "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s heeft zijn of haar weergavenaam (%(oldDisplayName)s) verwijderd.", - "%(senderName)s removed their profile picture.": "%(senderName)s heeft zijn of haar profielfoto verwijderd.", + "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s heeft zijn/haar weergavenaam (%(oldDisplayName)s) verwijderd.", + "%(senderName)s removed their profile picture.": "%(senderName)s heeft zijn/haar profielfoto verwijderd.", "Failed to kick": "Niet gelukt de ruimte uit te zetten", "Press to start a chat with someone": "Druk op om een gesprek met iemand te starten", "Remove %(threePid)s?": "%(threePid)s verwijderen?", - "%(senderName)s requested a VoIP conference.": "%(senderName)s heeft een VoIP-gesprek aangevraagd.", + "%(senderName)s requested a VoIP conference.": "%(senderName)s heeft een VoIP-vergadering aangevraagd.", "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het wachtwoord veranderen betekent momenteel dat alle end-to-endbeveiligingssleutels op alle apparaten veranderen waardoor versleutelde gespreksgeschiedenis onleesbaar wordt, behalve als je eerst de ruimte sleutels exporteert en daarna opnieuw importeert. Dit zal in de toekomst verbeterd worden.", "Results from DuckDuckGo": "Resultaten van DuckDuckGo", "Return to login screen": "Naar het inlogscherm terugkeren", "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen toestemming om u meldingen te versturen - controleer uw browserinstellingen", "Riot was not given permission to send notifications - please try again": "Riot heeft geen toestemming gekregen om u meldingen te versturen - probeer het opnieuw", "riot-web version:": "riot-web versie:", - "Room %(roomId)s not visible": "Ruimte %(roomId)s is niet zichtbaar", + "Room %(roomId)s not visible": "Kamer %(roomId)s is niet zichtbaar", "Room Colour": "Kleur van de ruimte", "Room contains unknown devices": "De ruimte bevat onbekende apparaten", "Room name (optional)": "Ruimtenaam (optioneel)", @@ -356,8 +356,8 @@ "Send anyway": "Alsnog versturen", "Sender device information": "Afzenderapparaatinformatie", "Send Reset Email": "Stuur Reset-E-mail", - "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s stuurde een afbeelding.", - "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s nodigde %(targetDisplayName)s uit tot de ruimte toe te treden.", + "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s heeft een afbeelding gestuurd.", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s heeft %(targetDisplayName)s in de kamer uitgenodigd.", "Server error": "Serverfout", "Server may be unavailable or overloaded": "De server kan onbereikbaar of overbelast zijn", "Server may be unavailable, overloaded, or search timed out :(": "De server is misschien onbereikbaar, overbelast of het zoeken duurde te lang :(", @@ -365,14 +365,14 @@ "Server may be unavailable, overloaded, or you hit a bug.": "De server is misschien onbereikbaar of overbelast, of u bent een fout tegengekomen.", "Server unavailable, overloaded, or something else went wrong.": "De server is onbereikbaar, overbelast of iets anders ging fout.", "Session ID": "Sessie-ID", - "%(senderName)s kicked %(targetName)s.": "%(senderName)s heeft %(targetName)s de ruimte uitgestuurd.", + "%(senderName)s kicked %(targetName)s.": "%(senderName)s heeft %(targetName)s de kamer uitgestuurd.", "Kick": "Er uit sturen", - "Kicks user with given id": "Stuurt de gebruiker met het gegeven ID er uit", + "Kicks user with given id": "Stuurt de gebruiker met de gegeven ID uit de kamer", "%(senderName)s set a profile picture.": "%(senderName)s heeft een profielfoto ingesteld.", - "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s heeft de weergavenaam %(displayName)s aangenomen.", + "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s heeft zijn/haar weergavenaam ingesteld op %(displayName)s.", "Show panel": "Paneel weergeven", "Show Text Formatting Toolbar": "Tekstopmaakwerkbalk Weergeven", - "Show timestamps in 12 hour format (e.g. 2:30pm)": "Laat de tijd in twaalf uur formaat zien (bijv. 2:30pm)", + "Show timestamps in 12 hour format (e.g. 2:30pm)": "Tijd in 12-uursformaat weergeven (bv. 2:30pm)", "Signed Out": "Uitgelogd", "Sign in": "Inloggen", "Sign out": "Uitloggen", @@ -381,7 +381,7 @@ "The default role for new room members is": "De standaardrol voor nieuwe ruimteleden is", "The main address for this room is": "Het hoofdadres voor deze ruimte is", "The phone number entered looks invalid": "Het telefoonnummer dat ingevoerd is ziet er ongeldig uit", - "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "De versleutelingssleutel die je hebt verstrekt komt overeen met de versleutelingssleutel die je hebt ontvangen van %(userId)s's apparaat %(deviceId)s. Apparaat is gemarkeerd als geverifieerd.", + "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "De versleutelingssleutel die u heeft verstrekt komt overeen met de versleutelingssleutel die u heeft ontvangen van het apparaat %(deviceId)s van %(userId)s. Het apparaat is gemarkeerd als geverifieerd.", "This email address is already in use": "Dit e-mailadres is al in gebruik", "This email address was not found": "Dit e-mailadres is niet gevonden", "The email address linked to your account must be entered.": "Het e-mailadres dat met je account verbonden is moet worden ingevoerd.", @@ -391,7 +391,7 @@ "This Home Server does not support login using email address.": "Deze Thuisserver ondersteunt het inloggen met een e-mailadres niet.", "This invitation was sent to an email address which is not associated with this account:": "Deze uitnodiging was naar een e-mailadres gestuurd die niet geassocieerd is met dit account:", "This room has no local addresses": "Deze ruimte heeft geen lokale adressen", - "This room is not recognised.": "Deze ruimte wordt niet herkend.", + "This room is not recognised.": "Deze kamer wordt niet herkend.", "These are experimental features that may break in unexpected ways": "Dit zijn experimentele functies die misschien kunnen breken op onverwachte manieren", "The visibility of existing history will be unchanged": "De zichtbaarheid van de bestaande geschiedenis zal onveranderd blijven", "This doesn't appear to be a valid email address": "Het ziet er niet naar uit dat dit een geldig e-mailadres is", @@ -402,17 +402,17 @@ "This room's internal ID is": "Het interne ID van deze ruimte is", "To link to a room it must have an address.": "Om naar een ruimte te linken moet het een adres hebben.", "To reset your password, enter the email address linked to your account": "Voer het e-mailadres dat met je account verbonden is in om je wachtwoord opnieuw in te stellen", - "To use it, just wait for autocomplete results to load and tab through them.": "Om het te gebruiken, wacht tot de automatisch aangevulde resultaten geladen zijn en tab er doorheen.", + "To use it, just wait for autocomplete results to load and tab through them.": "Om het te gebruiken, wacht u tot de automatisch aangevulde resultaten geladen zijn en tabt u erdoorheen.", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Je probeerde een gegeven punt in de tijdlijn van deze ruimte te laden maar je hebt geen toestemming de desbetreffende berichten te zien.", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Probeerde tevergeefs een gegeven punt in de tijdlijn van deze ruimte te laden.", "Turn Markdown off": "Zet Markdown uit", "Turn Markdown on": "Zet Markdown aan", - "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s heeft end-to-endbeveiliging aangezet (algoritme %(algorithm)s).", + "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s heeft eind-tot-eind-versleuteling aangezet (%(algorithm)s-algoritme).", "Unable to add email address": "E-mailadres toevoegen mislukt", "Unable to remove contact information": "Contactinformatie verwijderen mislukt", "Unable to verify email address.": "Niet mogelijk het e-mailadres te controleren.", "Unban": "Ontbannen", - "%(senderName)s unbanned %(targetName)s.": "%(senderName)s ontbande %(targetName)s.", + "%(senderName)s unbanned %(targetName)s.": "%(senderName)s heeft %(targetName)s ontbannen.", "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Onmogelijk na te gaan of het adres waarheen deze uitnodiging was verstuurd overeenkomt met het adres dat bij je account behoort.", "Unable to capture screen": "Kan geen schermafdruk maken", "Unable to enable Notifications": "Kan meldingen niet inschakelen", @@ -424,11 +424,11 @@ "unknown caller": "onbekende beller", "unknown device": "Onbekend apparaat", "Unknown room %(roomId)s": "Onbekende ruimte %(roomId)s", - "Unknown (user, device) pair:": "Onbekend (gebruiker/apparaat-)paar:", + "Unknown (user, device) pair:": "Onbekend paar (gebruiker, apparaat):", "Unmute": "Niet dempen", "Unnamed Room": "Naamloze kamer", - "Unrecognised command:": "Onbekende commando:", - "Unrecognised room alias:": "Onbekende ruimte alias:", + "Unrecognised command:": "Onbekende opdracht:", + "Unrecognised room alias:": "Onbekende kameralias:", "Unverified": "Niet geverifieerd", "Uploading %(filename)s and %(count)s others|zero": "Aan het uploaden %(filename)s", "Uploading %(filename)s and %(count)s others|one": "%(filename)s en %(count)s andere aan het uploaden", @@ -439,7 +439,7 @@ "Upload file": "Bestand uploaden", "Upload new:": "Nieuwe uploaden:", "Usage": "Gebruik", - "Use compact timeline layout": "Gebruik een compacte tijdlijnindeling", + "Use compact timeline layout": "Compacte tijdlijnindeling gebruiken", "Use with caution": "Gebruik met behoedzaamheid", "User ID": "Gebruikers-ID", "User Interface": "Gebruikersinterface", @@ -462,13 +462,13 @@ "(unknown failure: %(reason)s)": "(onbekende fout: %(reason)s)", "(warning: cannot be disabled again!)": "(waarschuwing: kan niet meer uitgezet worden!)", "Warning!": "Waarschuwing!", - "WARNING: Device already verified, but keys do NOT MATCH!": "WAARSCHUWING: Apparaat al geverifieerd, maar de sleutels KOMEN NIET OVEREEN!", - "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WAARSCHUWING: SLEUTELVERIFICATIE IS MISLUKT! De ondertekende sleutel voor %(userId)s en apparaat %(deviceId)s is \"%(fprint)s\" wat niet overeenkomt met de verschafte sleutel \"%(fingerprint)s\". Dit kan betekenen dat je communicatie onderschept wordt!", + "WARNING: Device already verified, but keys do NOT MATCH!": "LET OP: apparaat reeds geverifieerd, maar de sleutels KOMEN NIET OVEREEN!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "LET OP: SLEUTELVERIFICATIE IS MISLUKT! De ondertekende sleutel voor %(userId)s en apparaat %(deviceId)s is ‘%(fprint)s’, wat niet overeenkomt met de verschafte sleutel ‘%(fingerprint)s’. Dit kan betekenen dat uw communicatie onderschept wordt!", "Who can access this room?": "Wie heeft toegang tot deze ruimte?", "Who can read history?": "Wie kan de geschiedenis lezen?", - "Who would you like to add to this room?": "Wie wil je aan deze ruimte toevoegen?", - "Who would you like to communicate with?": "Met wie zou je willen communiceren?", - "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s trok %(targetName)s's uitnodiging terug.", + "Who would you like to add to this room?": "Wie wilt u aan deze kamer toevoegen?", + "Who would you like to communicate with?": "Met wie zou u willen communiceren?", + "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s heeft de uitnodiging van %(targetName)s ingetrokken.", "Would you like to accept or decline this invitation?": "Wil je deze uitnodiging accepteren of afwijzen?", "You already have existing direct chats with this user:": "Je hebt al bestaande privé-gesprekken met deze gebruiker:", "You are already in a call.": "U bent al in gesprek.", @@ -486,10 +486,10 @@ "You have no visible notifications": "Je hebt geen zichtbare notificaties", "You may wish to login with a different account, or add this email to this account.": "Je wilt misschien met een ander account inloggen of deze e-mail aan je account toevoegen.", "You must register to use this functionality": "Je moet je registreren om deze functie te gebruiken", - "You need to be able to invite users to do that.": "Dat vereist de bevoegdheid gebruikers uit te nodigen.", - "You need to be logged in.": "Aanmelding vereist.", + "You need to be able to invite users to do that.": "Om dit te kunnen doen, moet u gebruikers kunnen uitnodigen.", + "You need to be logged in.": "Aanmelding is vereist.", "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", - "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat je e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat uw e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Je wachtwoord is succesvol veranderd. Je zult op andere apparaten geen mededelingen ontvangen totdat je er opnieuw inlogt", "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat je in een gesprek zit, weet je zeker dat je wilt afsluiten?", @@ -548,8 +548,8 @@ "Reject all %(invitedRooms)s invites": "Alle %(invitedRooms)s uitnodigingen afslaan", "Start new chat": "Nieuw gesprek starten", "Failed to invite": "Uitnodigen is mislukt", - "Failed to invite user": "Niet gelukt de gebruiker uit te nodigen", - "Failed to invite the following users to the %(roomName)s room:": "Niet gelukt de volgende gebruikers tot de ruimte %(roomName)s uit te nodigen:", + "Failed to invite user": "Uitnodigen van gebruiker is mislukt", + "Failed to invite the following users to the %(roomName)s room:": "Uitnodigen van volgende gebruikers in kamer %(roomName)s is mislukt:", "Confirm Removal": "Verwijdering Bevestigen", "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Weet je zeker dat je deze gebeurtenis wilt verwijderen? Wees er wel van bewust dat als je een ruimtenaam of onderwerp verwijderd je de verandering ongedaan kunt maken.", "Unknown error": "Onbekende fout", @@ -617,9 +617,9 @@ "Something went wrong!": "Iets ging niet goed!", "This will be your account name on the homeserver, or you can pick a different server.": "Dit zal je account naam worden op de thuisserver, of je kunt een andere server kiezen.", "If you already have a Matrix account you can log in instead.": "Als je al een Matrix-account hebt kun je ook meteen inloggen.", - "Your browser does not support the required cryptography extensions": "Je browser ondersteunt de benodigde cryptografie-extensies niet", - "Not a valid Riot keyfile": "Niet een geldig Riot-sleutelbestand", - "Authentication check failed: incorrect password?": "Authenticatie controle gefaald: incorrect wachtwoord?", + "Your browser does not support the required cryptography extensions": "Uw browser ondersteunt de benodigde cryptografie-extensies niet", + "Not a valid Riot keyfile": "Geen geldig Riot-sleutelbestand", + "Authentication check failed: incorrect password?": "Aanmeldingscontrole mislukt: onjuist wachtwoord?", "Disable Peer-to-Peer for 1:1 calls": "Peer-to-Peer voor 1:1 oproepen uitschakelen", "Do you want to set an email address?": "Wil je een e-mailadres instellen?", "This will allow you to reset your password and receive notifications.": "Hierdoor zul je je wachtwoord kunnen resetten en mededelingen ontvangen.", @@ -631,15 +631,15 @@ "You added a new device '%(displayName)s', which is requesting encryption keys.": "Je hebt een nieuw apparaat '%(displayName)s' toegevoegd dat om ontcijferingssleutels vraagt.", "Your unverified device '%(displayName)s' is requesting encryption keys.": "Je niet geverifieerde apparaat '%(displayName)s' vraagt naar versleutelingssleutels.", "Encryption key request": "Verzoek voor versleutelingssleutel", - "Define the power level of a user": "Definieer het machtsniveau van een gebruiker", + "Define the power level of a user": "Bepaal het machtsniveau van een gebruiker", "Add a widget": "Voeg een widget toe", "Allow": "Toestaan", "Cannot add any more widgets": "Er kunnen niet meer widgets toegevoegd worden", - "Changes colour scheme of current room": "Verander het kleurenschema van de huidige ruimte", + "Changes colour scheme of current room": "Verandert het kleurenschema van de huidige kamer", "Delete widget": "Widget verwijderen", "Do you want to load widget from URL:": "Wil je de widget laden van de URL:", "Edit": "Aanpassen", - "Enable automatic language detection for syntax highlighting": "Automatische taaldetectie voor zinsbouwmarkeringen aanzetten", + "Enable automatic language detection for syntax highlighting": "Automatische taaldetectie voor zinsbouwmarkeringen inschakelen", "Hide join/leave messages (invites/kicks/bans unaffected)": "Toetreed/verlaat berichten verbergen (uitnodigingen/verwijderingen/verbanningen zullen ongeschonden blijven)", "Integrations Error": "Integratiesfout", "Publish this room to the public in %(domain)s's room directory?": "Deze ruimte publiekelijk maken in %(domain)s's ruimte catalogus?", @@ -650,10 +650,10 @@ "Sets the room topic": "Wijzigt het ruimte-onderwerp", "The maximum permitted number of widgets have already been added to this room.": "Het maximum aantal toegestane widgets is al aan deze ruimte toegevoegd.", "To get started, please pick a username!": "Kies allereerst een gebruikersnaam!", - "Unable to create widget.": "Niet in staat een widget te maken.", - "Unbans user with given id": "Ontbant de gebruiker met het gegeven id", - "You are not in this room.": "Je zit niet in deze ruimte.", - "You do not have permission to do that in this room.": "Je hebt geen toestemming dat in deze ruimte te doen.", + "Unable to create widget.": "Kan widget niet aanmaken.", + "Unbans user with given id": "Ontbant de gebruiker met de gegeven ID", + "You are not in this room.": "U zit niet in deze kamer.", + "You do not have permission to do that in this room.": "U heeft geen toestemming om dat in deze kamer te doen.", "Verifies a user, device, and pubkey tuple": "Verifieert een combinatie van gebruiker, apparaat en publieke sleutel", "Autocomplete Delay (ms):": "Automatisch-aanvullen-vertraging (ms):", "Loading device info...": "Apparaatinformatie aan het laden...", @@ -661,7 +661,7 @@ "Create": "Creëer", "Featured Rooms:": "Prominente Ruimtes:", "Featured Users:": "Prominente Gebruikers:", - "Automatically replace plain text Emoji": "Automatisch normale tekst vervangen met Emoji", + "Automatically replace plain text Emoji": "Tekst automatisch vervangen door emoticons", "Failed to upload image": "Kon de afbeelding niet uploaden", "Hide avatars in user and room mentions": "Avatars in gebruiker- en ruimte-vermeldingen verbergen", "%(widgetName)s widget added by %(senderName)s": "%(widgetName)s-widget toegevoegd door %(senderName)s", @@ -697,14 +697,14 @@ "Failed to add the following rooms to %(groupId)s:": "Toevoegen van volgende kamers aan %(groupId)s is mislukt:", "Restricted": "Beperkte toegang", "Ignored user": "Genegeerde gebruiker", - "You are now ignoring %(userId)s": "Je bent nu %(userId)s aan het negeren", - "Unignored user": "Niet genegeerde gebruiker", - "You are no longer ignoring %(userId)s": "Je bent %(userId)s niet meer aan het negeren", - "%(senderName)s changed the pinned messages for the room.": "%(senderName)s heeft de gepinde boodschappen voor de ruimte gewijzigd.", + "You are now ignoring %(userId)s": "U negeert nu %(userId)s", + "Unignored user": "Niet-genegeerde gebruiker", + "You are no longer ignoring %(userId)s": "U negeert %(userId)s niet meer", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s heeft de vastgeprikte boodschappen voor de kamer gewijzigd.", "%(names)s and %(count)s others are typing|other": "%(names)s en %(count)s andere gebruikers zijn aan het typen", "%(names)s and %(count)s others are typing|one": "%(names)s en iemand anders is aan het typen", "Send": "Versturen", - "Message Pinning": "Boodschap vastzetten", + "Message Pinning": "Bericht vastprikken", "Disable Emoji suggestions while typing": "Emoji suggesties tijdens het typen uitzetten", "Hide avatar changes": "Avatar veranderingen verbergen", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s", @@ -939,8 +939,8 @@ "Please note you are logging into the %(hs)s server, not matrix.org.": "Merk op dat je aan het inloggen bent in de %(hs)s server, niet matrix.org.", "This homeserver doesn't offer any login flows which are supported by this client.": "Deze thuisserver heeft geen inlogmethodes die bij deze client ondersteunt worden.", "Sign in to get started": "Log in om te beginnen", - "Ignores a user, hiding their messages from you": "Negeert een gebruiker, waardoor de berichten van de gebruiker onzichtbaar voor je worden", - "Stops ignoring a user, showing their messages going forward": "Stopt het negeren van een gebruiker, hierdoor worden de berichten van de gebruiker vanaf nu weer zichtbaar", + "Ignores a user, hiding their messages from you": "Negeert een gebruiker, waardoor de berichten ervan onzichtbaar voor u worden", + "Stops ignoring a user, showing their messages going forward": "Stopt het negeren van een gebruiker, hierdoor worden de berichten van de gebruiker weer zichtbaar", "Notify the whole room": "Notificeer de gehele ruimte", "Room Notification": "Ruimte Notificatie", "The information being sent to us to help make Riot.im better includes:": "De informatie die naar ons wordt verstuurd om Riot.im te verbeteren betreft:", @@ -956,7 +956,7 @@ "In reply to ": "Als antwoord op ", "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", "were unbanned %(count)s times|one": "waren ontbant", - "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s de weergavenaam %(displayName)s aangenomen.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s heeft zijn/haar weergavenaam gewijzigd naar %(displayName)s.", "Disable Community Filter Panel": "Gemeenschapsfilterpaneel uitzetten", "Your key share request has been sent - please check your other devices for key share requests.": "Je verzoek sleutels te delen is verzonden - controleer je andere apparaten voor het verzoek.", "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Verzoeken sleutels te delen worden automatisch naar andere apparaten verstuurd. Als je het verzoek hebt afgewezen of weg hebt geklikt, klik dan hier voor een nieuw verzoek om de sleutels van deze sessie.", @@ -987,7 +987,7 @@ "Debug Logs Submission": "Debug Logs Indienen", "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.": "Als je een bug via Github hebt ingediend kunnen debug logs ons helpen het probleem te vinden. Debug logs bevatten applicatie-gebruiksgegevens, waaronder je gebruikersnaam, de ID's of namen van de ruimten en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", "Submit debug logs": "Debug logs indienen", - "Opens the Developer Tools dialog": "Opent het Ontwikkelaars Gereedschappen dialoog", + "Opens the Developer Tools dialog": "Opent het dialoogvenster met ontwikkelaarsgereedschap", "Fetching third party location failed": "Het ophalen van de locatie van de derde partij is mislukt", "A new version of Riot is available.": "Er is een nieuwe versie van Riot beschikbaar.", "I understand the risks and wish to continue": "Ik begrijp de risico's en wil graag verder gaan", @@ -1145,8 +1145,8 @@ "Your User Agent": "Uw gebruikersagent", "Your device resolution": "De resolutie van uw apparaat", "Reload widget": "Widget herladen", - "Missing roomId.": "roomId mist.", - "Always show encryption icons": "Altijd versleutelingsiconen weergeven", + "Missing roomId.": "roomId ontbreekt.", + "Always show encryption icons": "Versleutelingspictogrammen altijd tonen", "Send analytics data": "Statistische gegevens (analytics) versturen", "Enable widget screenshots on supported widgets": "Widget schermafbeeldingen op ondersteunde widgets aanzetten", "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Het is nog niet mogelijk een bestand als antwoord te zenden; het zal dus als normaal bericht worden verstuurd.", @@ -1231,49 +1231,49 @@ "Bulk options": "Bulkinstellingen", "Registration Required": "Registratie vereist", "You need to register to do this. Would you like to register now?": "Hiervoor dient u zich te registreren. Wilt u dat nu doen?", - "This homeserver has hit its Monthly Active User limit.": "Deze homeserver heeft de maandelijks actieve gebruikerslimiet bereikt.", - "This homeserver has exceeded one of its resource limits.": "Deze homeserver heeft de limiet van een van de systeembronnen bereikt.", + "This homeserver has hit its Monthly Active User limit.": "Deze thuisserver heeft zijn limiet voor maandelijks actieve gebruikers bereikt.", + "This homeserver has exceeded one of its resource limits.": "Deze thuisserver heeft één van zijn systeembronlimieten overschreden.", "Whether or not you're logged in (we don't record your username)": "Of u al dan niet ingelogd bent (we slaan uw gebruiksnaam niet op)", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Het bestand ‘%(fileName)s’ is groter dan de uploadlimiet van de thuisserver", "Unable to load! Check your network connectivity and try again.": "Laden mislukt! Controleer uw netwerktoegang en probeer het opnieuw.", - "Failed to invite users to the room:": "Kon de volgende gebruikers hier niet uitnodigen:", - "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Plakt ¯\\_(ツ)_/¯ vòòr een bericht in kale tekst", + "Failed to invite users to the room:": "Uitnodigen van gebruikers in kamer is mislukt:", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Plakt ¯\\_(ツ)_/¯ vóór een bericht zonder opmaak", "Upgrades a room to a new version": "Actualiseert de kamer tot een nieuwe versie", - "Changes your display nickname in the current room only": "Stelt uw gebruikte naam in enkel de huidige ruimte in", - "Gets or sets the room topic": "Geeft het thema van de ruimte of stelt het in", - "This room has no topic.": "Ruimte zonder thema.", - "Sets the room name": "Stelt de naam van de ruimte in", - "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s heeft deze ruimte geactualiseerd.", - "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s heeft de ruimte toegankelijk gemaakt voor allen die de verwijzing kennen.", - "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s heeft de ruimte enkel op uitgenodiging toegankelijk gemaakt.", - "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s heeft de toegangsregel veranderd tot '%(rule)s'", - "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s heeft gasten toegestaan de ruimte te betreden.", - "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s heeft gasten de toegang tot de ruimte ontzegd.", - "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s heeft de toegangsregel voor gasten op '%(rule)s' gesteld", - "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s heeft emblemen voor %(groups)s in deze kamer aangezet.", - "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s heeft enblemen voor %(groups)s in deze ruimte uitgezet.", - "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s heeft emblemen voor %(newGroups)s aan-, en voor %(oldGroups)s uitgezet in deze ruimte.", - "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s heeft de adressen %(addedAddresses)s aan deze ruimte toegekend.", - "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s heeft %(addedAddresses)s als ruimteadres toegevoegd.", - "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|other": "%(senderName)s heeft het ruimteadres '%(removedAddresses)s' verwijderd.", - "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s heeft de ruimteadressen %(removedAddresses)s verwijderd.", - "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s heeft de ruimteadressen %(addedAddresses)s toegevoegd, en %(removedAddresses)s verwijderd.", - "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s heeft '%(address)s' als hoofdadres voor deze ruimte ingesteld.", - "%(senderName)s removed the main address for this room.": "%(senderName)s heeft het hoofdadres voor deze ruimte verwijderd.", - "%(displayName)s is typing …": "%(displayName)s%(displayName)s is aan het schrijven …", - "%(names)s and %(count)s others are typing …|other": "%(names)s en %(count)s anderen zijn aan het schrijven …", - "%(names)s and %(count)s others are typing …|one": "%(names)s en nog iemand zijn aan het schrijven …", - "%(names)s and %(lastPerson)s are typing …": "%(names)s en %(lastPerson)s zijn aan het schrijven …", - "Please contact your service administrator to continue using the service.": "Neemt u a.u.b. contact met uw systeembeheerder op om deze dienst te blijven gebruiken.", - "Unable to connect to Homeserver. Retrying...": "Kon geen verbinding met de thuisserver maken. Nieuwe poging...", + "Changes your display nickname in the current room only": "Stelt uw weergavenaam enkel in de huidige kamer in", + "Gets or sets the room topic": "Verkrijgt het thema van de kamer of stelt het in", + "This room has no topic.": "Kamer zonder thema.", + "Sets the room name": "Stelt de kamernaam in", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s heeft deze kamer geactualiseerd.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s heeft de kamer toegankelijk gemaakt voor iedereen die de verwijzing kent.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s heeft de kamer enkel op uitgenodiging toegankelijk gemaakt.", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s heeft de toegangsregel veranderd naar ‘%(rule)s’", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s heeft gasten toegestaan de kamer te betreden.", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s heeft gasten de toegang tot de kamer ontzegd.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s heeft de toegangsregel voor gasten op ‘%(rule)s’ ingesteld", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s heeft badges voor %(groups)s in deze kamer ingeschakeld.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s heeft badges voor %(groups)s in deze kamer uitgeschakeld.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s heeft badges in deze kamer voor %(newGroups)s in-, en voor %(oldGroups)s uitgeschakeld.", + "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s heeft de adressen %(addedAddresses)s aan deze kamer toegekend.", + "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s heeft %(addedAddresses)s als kameradres toegevoegd.", + "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|other": "%(senderName)s heeft het kameradres ‘%(removedAddresses)s’ verwijderd.", + "%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s heeft de kameradressen %(removedAddresses)s verwijderd.", + "%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s heeft de kameradressen %(addedAddresses)s toegevoegd, en %(removedAddresses)s verwijderd.", + "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s heeft ‘%(address)s’ als hoofdadres voor deze kamer ingesteld.", + "%(senderName)s removed the main address for this room.": "%(senderName)s heeft het hoofdadres voor deze kamer verwijderd.", + "%(displayName)s is typing …": "%(displayName)s%(displayName)s is aan het typen…", + "%(names)s and %(count)s others are typing …|other": "%(names)s en %(count)s anderen zijn aan het typen…", + "%(names)s and %(count)s others are typing …|one": "%(names)s en nog iemand zijn aan het typen…", + "%(names)s and %(lastPerson)s are typing …": "%(names)s en %(lastPerson)s zijn aan het typen…", + "Please contact your service administrator to continue using the service.": "Gelieve contact op te nemen met uw systeembeheerder om deze dienst te blijven gebruiken.", + "Unable to connect to Homeserver. Retrying...": "Kon geen verbinding met de thuisserver maken. Nieuwe poging…", "Unrecognised address": "Adres niet herkend", - "You do not have permission to invite people to this room.": "U hebt geen toestemming mensen tot deze ruimte uit te nodigen.", + "You do not have permission to invite people to this room.": "U heeft geen toestemming om mensen in deze kamer uit te nodigen.", "User %(userId)s is already in the room": "De gebruiker %(userId)s is al aanwezig", - "User %(user_id)s does not exist": "Er bestaat geen gebruiker '%(user_id)s'", - "User %(user_id)s may or may not exist": "Er bestaat mogelijk geen gebruiker '%(user_id)s'", + "User %(user_id)s does not exist": "Er bestaat geen gebruiker ‘%(user_id)s’", + "User %(user_id)s may or may not exist": "Er bestaat mogelijk geen gebruiker ‘%(user_id)s’", "The user must be unbanned before they can be invited.": "De gebruiker kan niet uitgenodigd worden voordat diens ban ongedaan is gemaakt.", "Unknown server error": "Onbekende serverfout", - "Use a few words, avoid common phrases": "Gebruik enige woorden - maar geen staande uitdrukkingen", + "Use a few words, avoid common phrases": "Gebruik enkele woorden - maar geen bekende uitdrukkingen", "No need for symbols, digits, or uppercase letters": "Hoofdletters, cijfers of speciale tekens hoeven niet, mogen wel", "Use a longer keyboard pattern with more turns": "Gebruik een langer patroon met meer variatie", "Avoid repeated words and characters": "Vermijd herhaling van woorden of tekens", @@ -1285,38 +1285,38 @@ "All-uppercase is almost as easy to guess as all-lowercase": "Tekst in hoofdletters is vrijwel even gemakkelijk te raden als tekst in kleine letters", "Reversed words aren't much harder to guess": "Omgedraaide woorden zijn bijna even gemakkelijk te raden", "Predictable substitutions like '@' instead of 'a' don't help very much": "Voorspelbare vervangingen (zoals '@' i.p.v. 'a') zijn niet erg zinvol", - "Add another word or two. Uncommon words are better.": "Voeg nog een paar (liefst infrequente) woorden toe.", - "Repeats like \"aaa\" are easy to guess": "Herhalingen als \"aaa\" worden gemakkelijk geraden", - "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Herhalingen als \"abcabcabc\" zijn haast even gemakkelijk te raden als \"abc\"", - "Sequences like abc or 6543 are easy to guess": "Rijtjes als \"abc\" of \"6543\" zijn gemakkelijk te raden", + "Add another word or two. Uncommon words are better.": "Voeg nog een paar (liefst weinig gebruikte) woorden toe.", + "Repeats like \"aaa\" are easy to guess": "Herhalingen als ‘aaa’ worden gemakkelijk geraden", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Herhalingen als ‘abcabcabc’ zijn haast even gemakkelijk te raden als ‘abc’", + "Sequences like abc or 6543 are easy to guess": "Rijtjes als ‘abc’ of ‘6543’ zijn gemakkelijk te raden", "Recent years are easy to guess": "Recente jaartallen zijn eenvoudig te raden", "Dates are often easy to guess": "Data zijn vaak gemakkelijk te raden", "This is a top-10 common password": "Dit staat in de top 10 van meestgebruikte wachtwoorden", - "This is a top-100 common password": "Dit wachtwoord staat in de top-100 qua gebruik", + "This is a top-100 common password": "Dit staat in de top 100 van meestgebruikte wachtwoorden", "This is a very common password": "Dit is een veelgebruikt wachtwoord", "This is similar to a commonly used password": "Dit lijkt sterk op een veelgebruikt wachtwoord", - "A word by itself is easy to guess": "Één enkel woord is zeer gemakkelijk te raden", + "A word by itself is easy to guess": "Eén enkel woord is zeer gemakkelijk te raden", "Names and surnames by themselves are easy to guess": "Een alleenstaande voor- of achternaam is eenvoudig te raden", "Common names and surnames are easy to guess": "Voor- en achternamen zijn eenvoudig te raden", - "Straight rows of keys are easy to guess": "Zo'n aaneengesloten rijtje toetsen is eenvoudig te raden", + "Straight rows of keys are easy to guess": "Zo’n aaneengesloten rijtje toetsen is eenvoudig te raden", "Short keyboard patterns are easy to guess": "Korte patronen op het toetsenbord worden gemakkelijk geraden", - "There was an error joining the room": "Het betreden van de ruimte ging mis", - "Sorry, your homeserver is too old to participate in this room.": "Helaas - uw thuisserver is te oud voor deze ruimte.", + "There was an error joining the room": "Er is een fout opgetreden bij het betreden van de kamer", + "Sorry, your homeserver is too old to participate in this room.": "Helaas - uw thuisserver is te oud voor deze kamer.", "Please contact your homeserver administrator.": "Gelieve contact op te nemen met de beheerder van uw thuisserver.", - "Custom user status messages": "Aangepaste berichten over de staat van de gebruiker", - "Show recent room avatars above the room list (refresh to apply changes)": "Toon de recentste avatars bovenaan in de lijst (herlaad om de verandering te zien)", - "Group & filter rooms by custom tags (refresh to apply changes)": "Groepeer en filter de ruimten volgens eigen labels (herlaad om de verandering te zien)", - "Render simple counters in room header": "Toon eenvoudige tellers bovenin de ruimte", - "Enable Emoji suggestions while typing": "Suggereer emoji's onder het typen", - "Show a placeholder for removed messages": "Toon vulling voor verwijderde berichten", - "Show join/leave messages (invites/kicks/bans unaffected)": "Toon in- en uittredeberichten (dit heeft geen effect op uitnodigingen, berispingen of verbanningen)", - "Show avatar changes": "Toon veranderingen van avatar", - "Show display name changes": "Toon veranderingen van getoonde naam", - "Show read receipts sent by other users": "Toon door andere gebruikers gezonden leesberichten", - "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Herinner me eraan Veilig Berichtherstel in versleutelde ruimten aan te zetten", - "Show avatars in user and room mentions": "Toon avatars als gebruikers of ruimten genoemd worden", - "Enable big emoji in chat": "Sta grote emoji's in gesprekken toe", - "Send typing notifications": "Stuur bericht bij schrijven", + "Custom user status messages": "Aangepaste gebruikersstatusberichten", + "Show recent room avatars above the room list (refresh to apply changes)": "Recente avatars bovenaan in de lijst tonen (herlaad om de verandering te zien)", + "Group & filter rooms by custom tags (refresh to apply changes)": "Kamers groeperen en filteren volgens eigen labels (herlaad om de verandering te zien)", + "Render simple counters in room header": "Eenvoudige tellers bovenaan de kamer tonen", + "Enable Emoji suggestions while typing": "Emoticons voorstellen tijdens het typen", + "Show a placeholder for removed messages": "Vulling tonen voor verwijderde berichten", + "Show join/leave messages (invites/kicks/bans unaffected)": "Berichten over deelnamen en verlatingen tonen (dit heeft geen effect op uitnodigingen, berispingen of verbanningen)", + "Show avatar changes": "Veranderingen van avatar tonen", + "Show display name changes": "Veranderingen van weergavenamen tonen", + "Show read receipts sent by other users": "Door andere gebruikers verstuurde leesbevestigingen tonen", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Herinnering tonen om veilig berichtherstel in te schakelen in versleutelde kamers", + "Show avatars in user and room mentions": "Avatars tonen wanneer gebruikers of kamers vermeld worden", + "Enable big emoji in chat": "Grote emoticons in gesprekken inschakelen", + "Send typing notifications": "Typmeldingen versturen", "Enable Community Filter Panel": "Zet het gemeenschapsfilterpaneel aan", "Allow Peer-to-Peer for 1:1 calls": "Sta evenknieverbindingen toe voor tweegesprekken", "Prompt before sending invites to potentially invalid matrix IDs": "Vraag na voordat uitnodigingen naar mogelijk ongeldige MatrixIDs worden verstuurd", @@ -1420,5 +1420,6 @@ "This backup is trusted because it has been restored on this device": "Deze reservekopie wordt vertrouwd, daar hij op dit apparaat herladen is", "Backup version: ": "Versie reservekopie: ", "Algorithm: ": "Algoritme: ", - "Chat with Riot Bot": "Chatten met Riot Bot" + "Chat with Riot Bot": "Chatten met Riot Bot", + "Forces the current outbound group session in an encrypted room to be discarded": "Dwingt de huidige uitwaartse groepssessie in een versleutelde kamer om verworpen te worden" } From ce089d5409ce76747ac270fbeeb086117bf22604 Mon Sep 17 00:00:00 2001 From: Nathan van Beelen Date: Thu, 28 Mar 2019 17:16:21 +0000 Subject: [PATCH 145/481] Translated using Weblate (Dutch) Currently translated at 79.5% (1240 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 77b7892925..74a8d1bd33 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -723,7 +723,7 @@ "Unban this user?": "Deze gebruiker ontbannen?", "Ban this user?": "Deze gebruiker bannen?", "Disable big emoji in chat": "Grote emoji in gesprekken uitzetten", - "Mirror local video feed": "Lokale videoaanvoer ook elders opslaan (spiegelen)", + "Mirror local video feed": "Lokale video aanvoering op meerdere locaties opslaan (mirrors)", "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Je kunt deze actie niet ongedaan maken omdat je jezelf degradeert. Als je het laatste persoon met rechten bent, is het onmogelijk deze rechten terug te krijgen.", "Unignore": "Niet meer negeren", "Ignore": "Negeren", From 0a4ef44bcf8a1e92f6a6c998531e9eeb5b144e35 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 28 Mar 2019 18:29:48 +0100 Subject: [PATCH 146/481] fix lint --- src/components/views/rooms/WhoIsTypingTile.js | 3 +-- src/utils/ResizeNotifier.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/views/rooms/WhoIsTypingTile.js b/src/components/views/rooms/WhoIsTypingTile.js index 95cf0717c7..eb5e14876d 100644 --- a/src/components/views/rooms/WhoIsTypingTile.js +++ b/src/components/views/rooms/WhoIsTypingTile.js @@ -64,8 +64,7 @@ module.exports = React.createClass({ const isVisible = this._isVisible(this.state); if (this.props.onShown && !wasVisible && isVisible) { this.props.onShown(); - } - else if (this.props.onHidden && wasVisible && !isVisible) { + } else if (this.props.onHidden && wasVisible && !isVisible) { this.props.onHidden(); } }, diff --git a/src/utils/ResizeNotifier.js b/src/utils/ResizeNotifier.js index ff4b79091b..35ec1a0269 100644 --- a/src/utils/ResizeNotifier.js +++ b/src/utils/ResizeNotifier.js @@ -22,7 +22,6 @@ import { EventEmitter } from "events"; import { throttle } from "lodash"; export default class ResizeNotifier extends EventEmitter { - constructor() { super(); // with default options, will call fn once at first call, and then every x ms From 1a264006f774bcbd2423d3cdd6d0914f4d722179 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 28 Mar 2019 18:42:49 +0100 Subject: [PATCH 147/481] turn off debug logging --- src/components/structures/ScrollPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 4043631d39..bb01da03da 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -21,7 +21,7 @@ import { KeyCode } from '../../Keyboard'; import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; -const DEBUG_SCROLL = true; +const DEBUG_SCROLL = false; // The amount of extra scroll distance to allow prior to unfilling. // See _getExcessHeight. From 43aa31cc191e99440897d7331aaa39aa66631fc8 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 17:16:26 +0000 Subject: [PATCH 148/481] Translated using Weblate (Dutch) Currently translated at 83.8% (1307 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 316 +++++++++++++++++++++++---------------- 1 file changed, 191 insertions(+), 125 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 74a8d1bd33..b403137ee7 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -1,5 +1,5 @@ { - "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "Voer alsjeblieft de verificatiecode in die is verstuurd naar +%(msisdn)s", + "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "Er is een sms verstuurd naar +%(msisdn)s. Voer de verificatiecode ervan hier in", "%(targetName)s accepted an invitation.": "%(targetName)s heeft een uitnodiging aanvaard.", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s heeft de uitnodiging voor %(displayName)s aanvaard.", "Account": "Account", @@ -20,7 +20,7 @@ "An error has occurred.": "Er is een fout opgetreden.", "Anyone who knows the room's link, apart from guests": "Iedereen die de link van de ruimte weet, behalve gasten", "Anyone who knows the room's link, including guests": "Iedereen die link van de ruimte weet, inclusief gasten", - "Are you sure?": "Weet je het zeker?", + "Are you sure?": "Weet u het zeker?", "Are you sure you want to reject the invitation?": "Weet je zeker dat je de uitnodiging wilt weigeren?", "Attachment": "Bijlage", "Autoplay GIFs and videos": "GIF’s en video’s automatisch afspelen", @@ -40,8 +40,8 @@ "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s heeft het onderwerp gewijzigd naar ‘%(topic)s’.", "Changes to who can read history will only apply to future messages in this room": "Veranderingen aan wie de geschiedenis kan lezen worden alleen maar toegepast op toekomstige berichten in deze ruimte", "Changes your display nickname": "Verandert uw weergavenaam", - "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het veranderen van het wachtwoord zal op het moment alle eind-tot-eind encryptie sleutels resetten, wat alle versleutelde gespreksgeschiedenis onleesbaar zou maken, behalve als je eerst je ruimtesleutels exporteert en achteraf opnieuw importeert. Dit zal worden verbeterd in de toekomst.", - "Clear Cache and Reload": "Cache Legen en Herladen", + "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het veranderen van het wachtwoord zal op vooralsnog alle sleutels voor eind-tot-eind-versleuteling op alle apparaten opnieuw instellen, waardoor de versleutelde gespreksgeschiedenis onleesbaar wordt, tenzij u eerst uw kamersleutels exporteert en achteraf opnieuw importeert. Dit zal in de toekomst verbeterd worden.", + "Clear Cache and Reload": "Cache wissen en herladen", "Clear Cache": "Cache Legen", "Click here to fix": "Klik hier om te repareren", "Click to mute audio": "Klik om het geluid uit te zetten", @@ -55,13 +55,13 @@ "Conference calling is in development and may not be reliable.": "Conferentiegesprekken zijn nog in ontwikkelingen en kunnen onbetrouwbaar zijn.", "Conference calls are not supported in encrypted rooms": "Conferentiegesprekken worden niet ondersteunt in versleutelde ruimtes", "Conference calls are not supported in this client": "Conferentiegesprekken worden niet ondersteunt in deze client", - "Confirm password": "Bevestigen wachtwoord", + "Confirm password": "Bevestig wachtwoord", "Confirm your new password": "Bevestig je nieuwe wachtwoord", "Continue": "Doorgaan", "Could not connect to the integration server": "Verbinding met de integratieserver is mislukt", "Cancel": "Annuleren", - "Accept": "Accepteren", - "Active call (%(roomName)s)": "Actief gesprek (%(roomName)s)", + "Accept": "Aanvaarden", + "Active call (%(roomName)s)": "Actieve oproep (%(roomName)s)", "Add": "Toevoegen", "Add a topic": "Een onderwerp toevoegen", "Admin Tools": "Beheerdersgereedschap", @@ -89,7 +89,7 @@ "Failed to forget room %(errCode)s": "Ruimte vergeten mislukt %(errCode)s", "Favourite": "Favoriet", "Mute": "Dempen", - "Notifications": "Notificaties", + "Notifications": "Meldingen", "Operation failed": "Handeling is mislukt", "powered by Matrix": "mogelijk gemaakt door Matrix", "Remove": "Verwijderen", @@ -98,8 +98,8 @@ "Start chat": "Gesprek starten", "unknown error code": "onbekende foutcode", "Search": "Zoeken", - "OK": "OK", - "Failed to change password. Is your password correct?": "Wachtwoord wijzigen mislukt. Is uw wachtwoord juist?", + "OK": "Oké", + "Failed to change password. Is your password correct?": "Wijzigen van wachtwoord is mislukt. Is uw wachtwoord juist?", "Moderator": "Moderator", "%(serverName)s Matrix ID": "%(serverName)s Matrix-ID", "Name": "Naam", @@ -114,15 +114,15 @@ "No display name": "Geen weergavenaam", "No more results": "Geen resultaten meer", "No results": "Geen resultaten", - "No users have specific privileges in this room": "Geen gebruikers hebben specifieke privileges in deze ruimte", - "olm version:": "olm versie:", + "No users have specific privileges in this room": "Geen gebruikers hebben specifieke privileges in deze kamer", + "olm version:": "olm-versie:", "Password": "Wachtwoord", "Password:": "Wachtwoord:", "Passwords can't be empty": "Wachtwoorden kunnen niet leeg zijn", "People": "Personen", "Permissions": "Toestemmingen", "Phone": "Telefoon", - "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gepleegd.", + "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gemaakt.", "Privacy warning": "Privacywaarschuwing", "Private Chat": "Privégesprek", "Privileged Users": "Bevoorrechte gebruikers", @@ -143,7 +143,7 @@ "Start authentication": "Authenticatie starten", "Start Chat": "Gesprek beginnen", "Submit": "Bevestigen", - "Success": "Gereed", + "Success": "Klaar", "Tagged as: ": "Gelabeld als: ", "Sun": "Zo", "Mon": "Ma", @@ -179,21 +179,21 @@ "Create Room": "Maak een ruimte aan", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen opdracht", - "Deactivate Account": "Account Deactiveren", + "Deactivate Account": "Account deactiveren", "Deactivate my account": "Mijn account deactiveren", "Decline": "Weigeren", "Decrypt %(text)s": "Ontsleutel %(text)s", "Decryption error": "Ontsleutelfout", "Delete": "Verwijderen", "Device already verified!": "Apparaat reeds geverifieerd!", - "Device ID": "Apparaat-ID", - "Device ID:": "Apparaat-ID:", + "Device ID": "Apparaats-ID", + "Device ID:": "Apparaats-ID:", "device id: ": "apparaat-ID: ", - "Device key:": "Apparaatsleutel:", + "Device key:": "Apparaatssleutel:", "Devices": "Apparaten", "Devices will not yet be able to decrypt history from before they joined the room": "Apparaten kunnen nog niet de geschiedenis van voordat ze de ruimte betraden ontsleutelen", "Direct chats": "Privégesprekken", - "Disable Notifications": "Notificaties uitschakelen", + "Disable Notifications": "Meldingen uitschakelen", "Disinvite": "Uitnodiging terugtrekken", "Display name": "Weergavenaam", "Don't send typing notifications": "Geen typnotificatie sturen", @@ -213,7 +213,7 @@ "Email, name or matrix ID": "E-mailadres, naam of matrix-ID", "Emoji": "Emoji", "Enable encryption": "Versleuteling inschakelen", - "Enable Notifications": "Notificaties inschakelen", + "Enable Notifications": "Meldingen inschakelen", "Encrypted by a verified device": "Versleuteld door een geverifieerd apparaat", "Encrypted by an unverified device": "Versleuteld door een niet-geverifieerd apparaat", "Encrypted messages will not be visible on clients that do not yet implement encryption": "Versleutelde berichten zullen nog niet zichtbaar zijn op applicaties die geen versleuteling ondersteunen", @@ -230,7 +230,7 @@ "Event information": "Gebeurtenis-informatie", "Existing Call": "Bestaande oproep", "Export": "Exporteren", - "Export E2E room keys": "Exporteer E2E-ruimte-sleutels", + "Export E2E room keys": "E2E-kamersleutels exporteren", "Failed to ban user": "Niet gelukt de gebruiker te verbannen", "Failed to change power level": "Niet gelukt het machtsniveau te wijzigen", "Failed to fetch avatar URL": "Niet gelukt de avatar-URL op te halen", @@ -244,12 +244,12 @@ "Failed to send email": "Niet gelukt de e-mail te versturen", "Failed to send request.": "Versturen van verzoek is mislukt.", "Failed to set avatar.": "Niet gelukt om de avatar in te stellen.", - "Failed to set display name": "Niet gelukt de weergavenaam in te stellen", + "Failed to set display name": "Instellen van weergavenaam is mislukt", "Failed to set up conference call": "Niet gelukt om een vergadergesprek te maken", "Failed to toggle moderator status": "Niet gelukt de moderatorstatus te veranderen", "Failed to unban": "Ontbannen mislukt", "Failed to upload file": "Niet gelukt het bestand te uploaden", - "Failed to upload profile picture!": "Niet gelukt een profielfoto te uploaden!", + "Failed to upload profile picture!": "Uploaden van profielfoto is mislukt!", "Failed to verify email address: make sure you clicked the link in the email": "Kan het e-mailadres niet verifiëren: zorg ervoor dat u de koppeling in de e-mail heeft aangeklikt", "Failure to create room": "Aanmaken van kamer is mislukt", "Favourites": "Favorieten", @@ -271,12 +271,12 @@ "Identity Server is": "Identiteitsserver is", "I have verified my email address": "Ik heb mijn e-mailadres geverifieerd", "Import": "Importeren", - "Import E2E room keys": "E2E-ruimte-sleutels importeren", + "Import E2E room keys": "E2E-kamersleutels importeren", "Incoming call from %(name)s": "Inkomende oproep van %(name)s", "Incoming video call from %(name)s": "Inkomende video-oproep van %(name)s", "Incoming voice call from %(name)s": "Inkomende spraakoproep van %(name)s", "Incorrect username and/or password.": "Incorrecte gebruikersnaam en/of wachtwoord.", - "Incorrect verification code": "Incorrecte verificatiecode", + "Incorrect verification code": "Onjuiste verificatiecode", "Interface Language": "Interfacetaal", "Invalid alias format": "Ongeldig naamformaat", "Invalid address format": "Ongeldig adresformaat", @@ -296,7 +296,7 @@ "%(targetName)s joined the room.": "%(targetName)s is tot de kamer toegetreden.", "Joins room with given alias": "Treedt de kamer toe met een gegeven alias", "Jump to first unread message.": "Spring naar het eerste ongelezen bericht.", - "Labs": "Labs", + "Labs": "Experimenteel", "Last seen": "Laatst gezien", "Leave room": "Kamer verlaten", "%(targetName)s left the room.": "%(targetName)s heeft de kamer verlaten.", @@ -319,8 +319,8 @@ "Missing user_id in request": "user_id ontbreekt in verzoek", "Mobile phone number": "Mobiele-telefoonnummer", "Mobile phone number (optional)": "Mobiele-telefoonnummer (optioneel)", - "Never send encrypted messages to unverified devices from this device": "Nooit versleutelde berichten vanaf dit apparaat naar ongeverifieerde apparaten versturen", - "Never send encrypted messages to unverified devices in this room from this device": "Vanaf dit apparaat nooit versleutelde berichten naar ongeverifieerde apparaten in deze ruimte sturen", + "Never send encrypted messages to unverified devices from this device": "Versleutelde berichten vanaf dit apparaat nooit naar ongeverifieerde apparaten versturen", + "Never send encrypted messages to unverified devices in this room from this device": "Versleutelde berichten vanaf dit apparaat nooit naar ongeverifieerde apparaten in deze kamer versturen", "New address (e.g. #foo:%(localDomain)s)": "Nieuw adres (bijv. #foo:%(localDomain)s)", "New passwords don't match": "Nieuwe wachtwoorden komen niet overeen", "New passwords must match each other.": "Nieuwe wachtwoorden moeten overeenkomen.", @@ -339,9 +339,9 @@ "Return to login screen": "Naar het inlogscherm terugkeren", "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen toestemming om u meldingen te versturen - controleer uw browserinstellingen", "Riot was not given permission to send notifications - please try again": "Riot heeft geen toestemming gekregen om u meldingen te versturen - probeer het opnieuw", - "riot-web version:": "riot-web versie:", + "riot-web version:": "riot-web-versie:", "Room %(roomId)s not visible": "Kamer %(roomId)s is niet zichtbaar", - "Room Colour": "Kleur van de ruimte", + "Room Colour": "Kamerkleur", "Room contains unknown devices": "De ruimte bevat onbekende apparaten", "Room name (optional)": "Ruimtenaam (optioneel)", "%(roomName)s does not exist.": "%(roomName)s bestaat niet.", @@ -398,7 +398,7 @@ "This is a preview of this room. Room interactions have been disabled": "Dit is een voorvertoning van de ruimte. Ruimte-interacties zijn uitgeschakeld", "This phone number is already in use": "Dit telefoonnummer is al in gebruik", "This room": "Deze ruimte", - "This room is not accessible by remote Matrix servers": "Deze ruimte is niet toegankelijk voor afgelegen Matrix-servers", + "This room is not accessible by remote Matrix servers": "Deze kamer is niet toegankelijk voor externe Matrix-servers", "This room's internal ID is": "Het interne ID van deze ruimte is", "To link to a room it must have an address.": "Om naar een ruimte te linken moet het een adres hebben.", "To reset your password, enter the email address linked to your account": "Voer het e-mailadres dat met je account verbonden is in om je wachtwoord opnieuw in te stellen", @@ -408,15 +408,15 @@ "Turn Markdown off": "Zet Markdown uit", "Turn Markdown on": "Zet Markdown aan", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s heeft eind-tot-eind-versleuteling aangezet (%(algorithm)s-algoritme).", - "Unable to add email address": "E-mailadres toevoegen mislukt", - "Unable to remove contact information": "Contactinformatie verwijderen mislukt", - "Unable to verify email address.": "Niet mogelijk het e-mailadres te controleren.", + "Unable to add email address": "Kan e-mailadres niet toevoegen", + "Unable to remove contact information": "Kan contactinformatie niet verwijderen", + "Unable to verify email address.": "Kan e-mailadres niet verifiëren.", "Unban": "Ontbannen", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s heeft %(targetName)s ontbannen.", "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Onmogelijk na te gaan of het adres waarheen deze uitnodiging was verstuurd overeenkomt met het adres dat bij je account behoort.", "Unable to capture screen": "Kan geen schermafdruk maken", "Unable to enable Notifications": "Kan meldingen niet inschakelen", - "Unable to load device list": "Niet mogelijk de lijst van apparaten te laden", + "Unable to load device list": "Kan lijst van apparaten niet laden", "Undecryptable": "Niet ontsleutelbaar", "Unencrypted room": "Ontsleutelde ruimte", "unencrypted": "ontsleuteld", @@ -437,7 +437,7 @@ "Upload Failed": "Uploaden mislukt", "Upload Files": "Bestanden Uploaden", "Upload file": "Bestand uploaden", - "Upload new:": "Nieuwe uploaden:", + "Upload new:": "Upload er een nieuwe:", "Usage": "Gebruik", "Use compact timeline layout": "Compacte tijdlijnindeling gebruiken", "Use with caution": "Gebruik met behoedzaamheid", @@ -461,7 +461,7 @@ "(no answer)": "(geen antwoord)", "(unknown failure: %(reason)s)": "(onbekende fout: %(reason)s)", "(warning: cannot be disabled again!)": "(waarschuwing: kan niet meer uitgezet worden!)", - "Warning!": "Waarschuwing!", + "Warning!": "Let op!", "WARNING: Device already verified, but keys do NOT MATCH!": "LET OP: apparaat reeds geverifieerd, maar de sleutels KOMEN NIET OVEREEN!", "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "LET OP: SLEUTELVERIFICATIE IS MISLUKT! De ondertekende sleutel voor %(userId)s en apparaat %(deviceId)s is ‘%(fprint)s’, wat niet overeenkomt met de verschafte sleutel ‘%(fingerprint)s’. Dit kan betekenen dat uw communicatie onderschept wordt!", "Who can access this room?": "Wie heeft toegang tot deze ruimte?", @@ -491,7 +491,7 @@ "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat uw e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", - "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Je wachtwoord is succesvol veranderd. Je zult op andere apparaten geen mededelingen ontvangen totdat je er opnieuw inlogt", + "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Uw wachtwoord is gewijzigd. U zult op andere apparaten geen pushmeldingen meer ontvangen totdat u zich er opnieuw op aanmeldt", "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat je in een gesprek zit, weet je zeker dat je wilt afsluiten?", "You seem to be uploading files, are you sure you want to quit?": "Het ziet er naar uit dat je bestanden aan het uploaden bent, weet je zeker dat je wilt afsluiten?", "You should not yet trust it to secure data": "Je moet het nog niet vertrouwen om gegevens te beveiligen", @@ -529,11 +529,11 @@ "numbullet": "genummerd opsommingsteken", "Please select the destination room for this message": "Selecteer de destinatie-ruimte voor dit bericht", "New Password": "Nieuw wachtwoord", - "Start automatically after system login": "Start automatisch na systeem-aanmelding", + "Start automatically after system login": "Automatisch starten na systeemaanmelding", "Desktop specific": "Desktop-specifiek", "Analytics": "Statistische gegevens", "Options": "Opties", - "Riot collects anonymous analytics to allow us to improve the application.": "Riot verzamelt anonieme analysegegevens die het mogelijk maken het programma te verbeteren.", + "Riot collects anonymous analytics to allow us to improve the application.": "Riot verzamelt anonieme analysegegevens die het mogelijk maken de toepassing te verbeteren.", "Passphrases must match": "Wachtzinnen moeten overeenkomen", "Passphrase must not be empty": "Wachtzin mag niet leeg zijn", "Export room keys": "Ruimtesleutels exporteren", @@ -545,7 +545,7 @@ "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.": "Hiermee kun je eerder vanuit een ander Matrixprogramma weggeschreven versleutelingscodes inlezen, zodat je alle berichten die het andere programma kon ontcijferen ook hier zult kunnen lezen.", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Het weggeschreven bestand is beveiligd met een wachtzin. Voer die wachtzin hier in om het bestand te ontcijferen.", "You must join the room to see its files": "Je moet tot de ruimte toetreden om de bestanden te kunnen zien", - "Reject all %(invitedRooms)s invites": "Alle %(invitedRooms)s uitnodigingen afslaan", + "Reject all %(invitedRooms)s invites": "Alle %(invitedRooms)s-uitnodigingen weigeren", "Start new chat": "Nieuw gesprek starten", "Failed to invite": "Uitnodigen is mislukt", "Failed to invite user": "Uitnodigen van gebruiker is mislukt", @@ -597,15 +597,15 @@ "Add an Integration": "Voeg een integratie toe", "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Je wordt zo naar een derde-partij-website verbonden zodat je het account kan legitimeren voor gebruik met %(integrationsUrl)s. Wil je doorgaan?", "Removed or unknown message type": "Verwijderd of onbekend berichttype", - "URL Previews": "URL-Voorvertoningen", + "URL Previews": "URL-voorvertoningen", "Drop file here to upload": "Bestand hierheen slepen om te uploaden", " (unsupported)": " (niet ondersteund)", - "Ongoing conference call%(supportedText)s.": "Lopend groepsgesprek%(supportedText)s.", + "Ongoing conference call%(supportedText)s.": "Lopend groepsgesprek %(supportedText)s.", "Online": "Online", "Idle": "Afwezig", "Offline": "Offline", "Updates": "Updates", - "Check for update": "Voor updates kijken", + "Check for update": "Controleren op updates", "Start chatting": "Start met praten", "Start Chatting": "Start Met Praten", "Click on the button below to start chatting!": "Klik op de knop hieronder om het gesprek te beginnen!", @@ -621,7 +621,7 @@ "Not a valid Riot keyfile": "Geen geldig Riot-sleutelbestand", "Authentication check failed: incorrect password?": "Aanmeldingscontrole mislukt: onjuist wachtwoord?", "Disable Peer-to-Peer for 1:1 calls": "Peer-to-Peer voor 1:1 oproepen uitschakelen", - "Do you want to set an email address?": "Wil je een e-mailadres instellen?", + "Do you want to set an email address?": "Wilt u een e-mailadres instellen?", "This will allow you to reset your password and receive notifications.": "Hierdoor zul je je wachtwoord kunnen resetten en mededelingen ontvangen.", "To return to your account in future you need to set a password": "Om in de toekomst naar je account terug te gaan moet je een wachtwoord instellen", "Skip": "Overslaan", @@ -642,7 +642,7 @@ "Enable automatic language detection for syntax highlighting": "Automatische taaldetectie voor zinsbouwmarkeringen inschakelen", "Hide join/leave messages (invites/kicks/bans unaffected)": "Toetreed/verlaat berichten verbergen (uitnodigingen/verwijderingen/verbanningen zullen ongeschonden blijven)", "Integrations Error": "Integratiesfout", - "Publish this room to the public in %(domain)s's room directory?": "Deze ruimte publiekelijk maken in %(domain)s's ruimte catalogus?", + "Publish this room to the public in %(domain)s's room directory?": "Deze kamer openbaar maken in de kamercatalogus van %(domain)s?", "AM": "AM", "PM": "PM", "NOTE: Apps are not end-to-end encrypted": "OPMERKING: Apps zijn niet end-to-endbeveiligd", @@ -709,12 +709,12 @@ "Hide avatar changes": "Avatar veranderingen verbergen", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s", "Hide display name changes": "Weergavenaam wijzigingen verbergen", - "Enable inline URL previews by default": "Inline URL-voorvertoning standaard aanzetten", - "Enable URL previews for this room (only affects you)": "URL-voorvertoning in deze ruimte aanzetten (geldt alleen voor jou)", - "Enable URL previews by default for participants in this room": "URL-voorvertoning standaard voor de gebruikers in deze ruimte aanzetten", - "Delete %(count)s devices|other": "Verwijder %(count)s apparaten", - "Delete %(count)s devices|one": "Verwijder apparaat", - "Select devices": "Apparaten selecteren", + "Enable inline URL previews by default": "Inline URL-voorvertoning standaard inschakelen", + "Enable URL previews for this room (only affects you)": "URL-voorvertoning in deze kamer inschakelen (geldt alleen voor u)", + "Enable URL previews by default for participants in this room": "URL-voorvertoning standaard voor de gebruikers in deze kamer inschakelen", + "Delete %(count)s devices|other": "%(count)s apparaten verwijderen", + "Delete %(count)s devices|one": "Apparaat verwijderen", + "Select devices": "Selecteer apparaten", "%(senderName)s sent an image": "%(senderName)s heeft een afbeelding gestuurd", "%(senderName)s sent a video": "%(senderName)s heeft een video gestuurd", "%(senderName)s uploaded a file": "%(senderName)s heeft een bestand geüpload", @@ -723,7 +723,7 @@ "Unban this user?": "Deze gebruiker ontbannen?", "Ban this user?": "Deze gebruiker bannen?", "Disable big emoji in chat": "Grote emoji in gesprekken uitzetten", - "Mirror local video feed": "Lokale video aanvoering op meerdere locaties opslaan (mirrors)", + "Mirror local video feed": "Lokale videoaanvoer ook elders opslaan (spiegelen)", "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Je kunt deze actie niet ongedaan maken omdat je jezelf degradeert. Als je het laatste persoon met rechten bent, is het onmogelijk deze rechten terug te krijgen.", "Unignore": "Niet meer negeren", "Ignore": "Negeren", @@ -934,7 +934,7 @@ "Status.im theme": "Status.im thema", "Ignored Users": "Genegeerde Gebruikers", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is belangrijk voor ons, dus we verzamelen geen persoonlijke of identificeerbare gegevens voor onze gegevensanalyse.", - "Learn more about how we use analytics.": "Leer meer over hoe we uw gegevens gebruiken.", + "Learn more about how we use analytics.": "Lees meer over hoe we uw gegevens gebruiken.", "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Een e-mail is naar %(emailAddress)s verstuurd. Klik hieronder zodra je de link hebt gevolgd.", "Please note you are logging into the %(hs)s server, not matrix.org.": "Merk op dat je aan het inloggen bent in de %(hs)s server, niet matrix.org.", "This homeserver doesn't offer any login flows which are supported by this client.": "Deze thuisserver heeft geen inlogmethodes die bij deze client ondersteunt worden.", @@ -985,18 +985,18 @@ "Everyone": "Iedereen", "Leave this community": "Deze gemeenschap verlaten", "Debug Logs Submission": "Debug Logs Indienen", - "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.": "Als je een bug via Github hebt ingediend kunnen debug logs ons helpen het probleem te vinden. Debug logs bevatten applicatie-gebruiksgegevens, waaronder je gebruikersnaam, de ID's of namen van de ruimten en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", - "Submit debug logs": "Debug logs indienen", + "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.": "Als u een bug via GitHub heeft ingediend, kunnen foutopsporingslogboeken ons helpen het probleem te vinden. Foutopsporingslogboeken bevatten gebruiksgegevens van de toepassing, waaronder uw gebruikersnaam, de ID’s of aliassen van de kamers en groepen die u heeft bezocht, evenals de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", + "Submit debug logs": "Foutopsporingslogboeken indienen", "Opens the Developer Tools dialog": "Opent het dialoogvenster met ontwikkelaarsgereedschap", "Fetching third party location failed": "Het ophalen van de locatie van de derde partij is mislukt", "A new version of Riot is available.": "Er is een nieuwe versie van Riot beschikbaar.", "I understand the risks and wish to continue": "Ik begrijp de risico's en wil graag verder gaan", "Couldn't load home page": "Kon de home pagina niet laden", "Send Account Data": "Stuur account informatie", - "All notifications are currently disabled for all targets.": "Alle meldingen zijn momenteel uitgeschakeld voor alle doelen.", - "Uploading report": "Rapport uploaden", + "All notifications are currently disabled for all targets.": "Alle meldingen zijn momenteel uitgeschakeld voor alle bestemmingen.", + "Uploading report": "Rapport wordt geüpload", "Sunday": "Zondag", - "Notification targets": "Meldingsdoelen", + "Notification targets": "Meldingsbestemmingen", "Today": "Vandaag", "Files": "Bestanden", "You are not receiving desktop notifications": "Je ontvangt momenteel geen desktopmeldingen", @@ -1027,26 +1027,26 @@ "Messages in one-to-one chats": "Berichten in één-op-één-gesprekken", "Unavailable": "Niet beschikbaar", "View Decrypted Source": "Bekijk ontsleutelde bron", - "Failed to update keywords": "Trefwoorden bijwerken mislukt", + "Failed to update keywords": "Bijwerken van trefwoorden is mislukt", "remove %(name)s from the directory.": "verwijder %(name)s uit de ruimtelijst.", - "Notifications on the following keywords follow rules which can’t be displayed here:": "Meldingen op de volgende trefwoorden volgen regels die hier niet kunnen worden getoond:", + "Notifications on the following keywords follow rules which can’t be displayed here:": "Meldingen op de volgende trefwoorden volgen regels die hier niet getoond kunnen worden:", "Safari and Opera work too.": "Safari en Opera werken ook.", "Please set a password!": "Stel een wachtwoord in!", "You have successfully set a password!": "U heeft met succes een wachtwoord ingesteld!", "An error occurred whilst saving your email notification preferences.": "Er is een fout opgetreden tijdens het opslaan van uw e-mailmeldingsvoorkeuren.", "Explore Room State": "Verken Ruimtetoestand", "Source URL": "Bron-URL", - "Messages sent by bot": "Berichten verzonden door een bot", + "Messages sent by bot": "Berichten verzonden door een robot", "Filter results": "Resultaten filteren", "Members": "Leden", "No update available.": "Geen update beschikbaar.", - "Noisy": "Luidruchtig", + "Noisy": "Lawaaierig", "Failed to get protocol list from Home Server": "Protocollijst ophalen van de homeserver mislukt", - "Collecting app version information": "App-versieinformatie verzamelen", + "Collecting app version information": "App-versieinformatie wordt verzameld", "Delete the room alias %(alias)s and remove %(name)s from the directory?": "De alias %(alias)s verwijderen en %(name)s uit de ruimtelijst verwijderen?", "This will allow you to return to your account after signing out, and sign in on other devices.": "Hiermee kunt u naar uw account terugkeren nadat u zich heeft afgemeld, en u aanmelden op andere apparaten.", "Keywords": "Trefwoorden", - "Enable notifications for this account": "Meldingen voor dit account aanzetten", + "Enable notifications for this account": "Meldingen inschakelen voor deze account", "Directory": "Ruimtelijst", "Invite to this community": "Nodig uit in deze community", "Search for a room": "Een ruimte opzoeken", @@ -1059,7 +1059,7 @@ "Remove %(name)s from the directory?": "%(name)s uit de ruimtelijst verwijderen?", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot gebrukt veel geavanceerde browserfuncties, waarvan enkele niet (of experimenteel) in uw webbrowser beschikbaar zijn.", "Developer Tools": "Ontwikkelaarsgereedschap", - "Enable desktop notifications": "Desktopmeldingen aanzetten", + "Enable desktop notifications": "Bureaubladmeldingen inschakelen", "Explore Account Data": "Bekijk account informatie", "Remove from Directory": "Uit de ruimtelijst verwijderen", "Saturday": "Zaterdag", @@ -1073,7 +1073,7 @@ "Enable them now": "Deze nu aanzetten", "Messages containing my user name": "Berichten die mijn gebruikersnaam bevatten", "Toolbox": "Eigenschappen", - "Collecting logs": "Logboeken verzamelen", + "Collecting logs": "Logboeken worden verzameld", "more": "meer", "You must specify an event type!": "Je moet een event-type specificeren!", "(HTTP status %(httpStatus)s)": "(HTTP-status %(httpStatus)s)", @@ -1090,7 +1090,7 @@ "Notify me for anything else": "Stuur een melding voor al het andere", "When I'm invited to a room": "Wanneer ik uitgenodigd word voor een ruimte", "Can't update user notification settings": "Kan de meldingsinstellingen van de gebruiker niet bijwerken", - "Notify for all other messages/rooms": "Stuur een melding voor alle andere berichten/ruimtes", + "Notify for all other messages/rooms": "Stuur een melding voor alle andere berichten/kamers", "Unable to look up room ID from server": "Kon het ruimte-ID niet van de server ophalen", "Couldn't find a matching Matrix room": "Kon geen bijbehorende Matrix-ruimte vinden", "All Rooms": "Alle Ruimtes", @@ -1099,10 +1099,10 @@ "Forward Message": "Bericht doorsturen", "Back": "Terug", "Reply": "Beantwoord", - "Show message in desktop notification": "Toon boodschap in bureaublad popup", + "Show message in desktop notification": "Bericht tonen in bureaubladmelding", "Unhide Preview": "Zichtbaar maken preview", "Unable to join network": "Kon niet toetreden tot dit netwerk", - "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Je hebt ze mogelijk ingesteld in een andere client dan Riot. Je kunt ze niet aanpassen in Riot maar ze zijn wel actief", + "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "U heeft ze mogelijk ingesteld in een andere cliënt dan Riot. U kunt ze niet aanpassen in Riot, maar ze zijn wel actief", "Sorry, your browser is not able to run Riot.": "Sorry, uw browser werkt niet met Riot.", "Uploaded on %(date)s by %(user)s": "Geüpload op %(date)s door %(user)s", "Messages in group chats": "Berichten in groepsgesprekken", @@ -1110,19 +1110,19 @@ "Error encountered (%(errorDetail)s).": "Fout ondervonden (%(errorDetail)s).", "Login": "Aanmelden", "Low Priority": "Lage prioriteit", - "Unable to fetch notification target list": "Kan de bestemmingslijst voor de mededeling niet ophalen", + "Unable to fetch notification target list": "Kan de bestemmingslijst voor meldingen niet ophalen", "Set Password": "Wachtwoord instellen", - "Enable audible notifications in web client": "Geluidsmeldingen in de webclient aanzetten", + "Enable audible notifications in web client": "Geluidsmeldingen in de webcliënt inschakelen", "Off": "Uit", "Riot does not know how to join a room on this network": "Riot weet niet hoe het moet deelnemen in een ruimte op dit netwerk", "Mentions only": "Alleen vermeldingen", "Wednesday": "Woensdag", "You can now return to your account after signing out, and sign in on other devices.": "U kunt nu terugkeren naar uw account nadat u bent afgemeld, en u aanmelden op andere apparaten.", - "Enable email notifications": "E-mailmeldingen aanzetten", + "Enable email notifications": "E-mailmeldingen inschakelen", "Event Type": "Event-type", "Download this file": "Download dit bestand", "Pin Message": "Bericht vastpinnen", - "Failed to change settings": "Instellingen wijzigen mislukt", + "Failed to change settings": "Wijzigen van instellingen mislukt", "View Community": "Gemeenschap Weergeven", "%(count)s Members|one": "%(count)s Deelnemer", "Event sent!": "Event verstuurd!", @@ -1132,7 +1132,7 @@ "Collapse panel": "Paneel inklappen", "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!": "Met uw huidige browser kan de applicatie er volledig incorrect uitzien. Tevens is het mogelijk dat niet alle functies naar behoren werken. U kunt doorgaan als u het toch wil proberen, maar bij problemen bent u volledig op uzelf aangewezen!", "Checking for an update...": "Aan het kijken voor een update...", - "There are advanced notifications which are not shown here": "Er zijn geavanceerde notificaties die hier niet getoond worden", + "There are advanced notifications which are not shown here": "Er zijn geavanceerde meldingen die hier niet getoond worden", "Logs sent": "Logs verstuurd", "GitHub issue link:": "GitHub opgave link:", "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.": "Debug logs bevatten applicatie-gebruik data inclusief je gebruikersnaam, de ID's of namen van de ruimtes en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", @@ -1148,7 +1148,7 @@ "Missing roomId.": "roomId ontbreekt.", "Always show encryption icons": "Versleutelingspictogrammen altijd tonen", "Send analytics data": "Statistische gegevens (analytics) versturen", - "Enable widget screenshots on supported widgets": "Widget schermafbeeldingen op ondersteunde widgets aanzetten", + "Enable widget screenshots on supported widgets": "Widget-schermafbeeldingen inschakelen op ondersteunde widgets", "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Het is nog niet mogelijk een bestand als antwoord te zenden; het zal dus als normaal bericht worden verstuurd.", "Unable to reply": "Niet mogelijk te reageren", "At this time it is not possible to reply with an emote.": "Het is nog niet mogelijk met een emoji te reageren.", @@ -1183,8 +1183,8 @@ "Review terms and conditions": "Voorwaarden lezen", "A conference call could not be started because the intgrations server is not available": "Een groepsgesprek kon niet gestart worden omdat de integratieserver niet beschikbaar is", "Call in Progress": "Lopend gesprek", - "A call is currently being placed!": "Er wordt al een oproep gepleegd!", - "A call is already in progress!": "Er loopt al een gesprek!", + "A call is currently being placed!": "Er wordt al een oproep gemaakt!", + "A call is already in progress!": "Er is al een gesprek actief!", "Permission Required": "Toestemming vereist", "You do not have permission to start a conference call in this room": "U heeft geen toestemming om in deze kamer een vergadergesprek te starten", "Show empty room list headings": "Lege koppen in ruimtelijst weergeven", @@ -1228,7 +1228,7 @@ "Please contact your service administrator to continue using this service.": "Neem contact op met de beheerder van je thuisserver om de dienst te kunnen blijven gebruiken.", "Try the app first": "De app eerst proberen", "Ignored users": "Genegeerde gebruikers", - "Bulk options": "Bulkinstellingen", + "Bulk options": "Bulkopties", "Registration Required": "Registratie vereist", "You need to register to do this. Would you like to register now?": "Hiervoor dient u zich te registreren. Wilt u dat nu doen?", "This homeserver has hit its Monthly Active User limit.": "Deze thuisserver heeft zijn limiet voor maandelijks actieve gebruikers bereikt.", @@ -1317,24 +1317,24 @@ "Show avatars in user and room mentions": "Avatars tonen wanneer gebruikers of kamers vermeld worden", "Enable big emoji in chat": "Grote emoticons in gesprekken inschakelen", "Send typing notifications": "Typmeldingen versturen", - "Enable Community Filter Panel": "Zet het gemeenschapsfilterpaneel aan", - "Allow Peer-to-Peer for 1:1 calls": "Sta evenknieverbindingen toe voor tweegesprekken", - "Prompt before sending invites to potentially invalid matrix IDs": "Vraag na voordat uitnodigingen naar mogelijk ongeldige MatrixIDs worden verstuurd", - "Show developer tools": "Toon het ontwikkelinstrumentarium", - "Order rooms in the room list by most important first instead of most recent": "Sorteer de ruimten naar belang in plaats van laatste gebruik", - "Messages containing my username": "Berichten die mijn naam bevatten", - "Messages containing @room": "Berichten die \"@room\" bevatten", - "Encrypted messages in one-to-one chats": "Versleutelde berichten in tweegesprekken", + "Enable Community Filter Panel": "Gemeenschapsfilterpaneel inschakelen", + "Allow Peer-to-Peer for 1:1 calls": "Peer-to-peer toestaan voor één-op-één-gesprekken", + "Prompt before sending invites to potentially invalid matrix IDs": "Bevestiging vragen voordat uitnodigingen naar mogelijk ongeldige Matrix-ID’s worden verstuurd", + "Show developer tools": "Ontwikkelgereedschap tonen", + "Order rooms in the room list by most important first instead of most recent": "Kamers in de kamerlijst sorteren op belang in plaats van laatste gebruik", + "Messages containing my username": "Berichten die mijn gebruikersnaam bevatten", + "Messages containing @room": "Berichten die ‘@room’ bevatten", + "Encrypted messages in one-to-one chats": "Versleutelde berichten in één-op-één-gesprekken", "Encrypted messages in group chats": "Versleutelde berichten in groepsgesprekken", - "The other party cancelled the verification.": "De tegenpartij brak de contrôle af.", - "Verified!": "Contrôle geslaagd!", - "You've successfully verified this user.": "Gebruiker succesvol gecontroleerd.", - "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Berichten met deze gebruiker zijn voluit versleuteld en kunnen niet door derden worden gelezen.", - "Got It": "Snap ik", - "Verify this user by confirming the following emoji appear on their screen.": "Controleer deze gebruiker door te bevestigen dat hun scherm de volgende emoji toont.", - "Verify this user by confirming the following number appears on their screen.": "Controleer deze gebruiker door te bevestigen dat hun scherm het volgende getal toont.", - "Unable to find a supported verification method.": "Kan geen ondersteunde wijze van controleren vinden.", - "For maximum security, we recommend you do this in person or use another trusted means of communication.": "Voor maximale veiligheid kunt u dit het beste persoonlijk, of via een vertrouwd communicatiemedium, doen.", + "The other party cancelled the verification.": "De tegenpartij heeft de verificatie geannuleerd.", + "Verified!": "Geverifieerd!", + "You've successfully verified this user.": "U heeft deze gebruiker geverifieerd.", + "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Beveiligde berichten met deze gebruiker zijn eind-tot-eind-versleuteld en kunnen niet door derden worden gelezen.", + "Got It": "Ik snap het", + "Verify this user by confirming the following emoji appear on their screen.": "Verifieer deze gebruiker door te bevestigen dat hun scherm de volgende emoji toont.", + "Verify this user by confirming the following number appears on their screen.": "Verifieer deze gebruiker door te bevestigen dat hun scherm het volgende getal toont.", + "Unable to find a supported verification method.": "Kan geen ondersteunde verificatiemethode vinden.", + "For maximum security, we recommend you do this in person or use another trusted means of communication.": "Voor maximale veiligheid kunt u dit het beste persoonlijk, of via een ander vertrouwd communicatiemedium, doen.", "Dog": "Hond", "Cat": "Kat", "Lion": "Leeuw", @@ -1363,20 +1363,20 @@ "Strawberry": "Aardbei", "Corn": "Maïs", "Pizza": "Pizza", - "Cake": "Gebak", + "Cake": "Taart", "Heart": "Hart", - "Smiley": "Lachebekje", + "Smiley": "Smiley", "Robot": "Robot", "Hat": "Hoed", "Glasses": "Bril", "Spanner": "Steeksleutel", - "Santa": "De kerstman", + "Santa": "Kerstman", "Thumbs up": "Duim omhoog", "Umbrella": "Paraplu", "Hourglass": "Zandloper", "Clock": "Klok", - "Gift": "Geschenk", - "Light bulb": "Peertje", + "Gift": "Cadeau", + "Light bulb": "Gloeilamp", "Book": "Boek", "Pencil": "Potlood", "Paperclip": "Paperclip", @@ -1384,42 +1384,108 @@ "Padlock": "Hangslot", "Key": "Sleutel", "Hammer": "Hamer", - "Telephone": "Telefoontoestel", + "Telephone": "Telefoon", "Flag": "Vlag", "Train": "Trein", "Bicycle": "Fiets", "Aeroplane": "Vliegtuig", "Rocket": "Raket", - "Trophy": "Erebeker", + "Trophy": "Trofee", "Ball": "Bal", "Guitar": "Gitaar", "Trumpet": "Trompet", "Bell": "Bel", "Anchor": "Anker", - "Headphones": "Hoofdtelefoon", - "Folder": "Ordner", + "Headphones": "Koptelefoon", + "Folder": "Map", "Pin": "Speld", - "Your homeserver does not support device management.": "Je thuisserver ondersteunt geen apparaatbeheer.", + "Your homeserver does not support device management.": "Uw thuisserver ondersteunt geen apparaatbeheer.", "Yes": "Ja", - "No": "Neen", - "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Om uw adres te controleren hebben wij een email gestuurd. Gelieve de daarin gegeven aanwijzingen op te volgen en dan op de knop hieronder te klikken.", + "No": "Nee", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "We hebben u een e-mail gestuurd om uw adres te verifiëren. Gelieve de daarin gegeven aanwijzingen op te volgen en dan op de knop hieronder te klikken.", "Email Address": "E-mailadres", - "Delete Backup": "Reservekopie verwijderen", - "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Weet u het zeker? Zonder reservekopie kunt u uw versleutelde berichten kwijtraken.", - "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Versleutelde berichten zijn over het gehele pad beveiligd. Enkel u en de ontvanger(s) hebben de ontcijferingssleutels.", - "Unable to load key backup status": "Kon de reservekopiestatus voor de sleutels niet laden", - "Restore from Backup": "Herstellen vanuit de reservekopie", - "This device is backing up your keys. ": "Dit apparaat houdt een reservekopie van uw sleutels bij. ", - "This device is not backing up your keys.": "Dit apparaat houdt geen reservekopie van uw sleutels bij.", - "Back up your keys before signing out to avoid losing them.": "Maak voor u zich afmeldt een reservekopie van uw sleutels, om ze niet te verliezen.", - "Use key backup": "Houdt een reservekopie van uw sleutels bij", - "Backing up %(sessionsRemaining)s keys...": "Reservekopie van %(sessionsRemaining)s sleutels maken...", - "All keys backed up": "Reservekopie compleet", - "Backup has a valid signature from this device": "De veiligheidskopie heeft een geldige handtekening van dit apparaat", - "Backup is not signed by any of your devices": "De reservekopie is door geen van uw apparaten ondertekend", - "This backup is trusted because it has been restored on this device": "Deze reservekopie wordt vertrouwd, daar hij op dit apparaat herladen is", - "Backup version: ": "Versie reservekopie: ", + "Delete Backup": "Back-up verwijderen", + "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Weet u het zeker? U zult uw versleutelde berichten verliezen als uw sleutels niet correct geback-upt zijn.", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Versleutelde berichten zijn beveiligd met eind-tot-eind-versleuteling. Enkel de ontvanger(s) en u hebben de sleutels om deze berichten te lezen.", + "Unable to load key backup status": "Kan sleutelback-upstatus niet laden", + "Restore from Backup": "Herstellen uit back-up", + "This device is backing up your keys. ": "Dit apparaat maakt een back-up van uw sleutels. ", + "This device is not backing up your keys.": "Dit apparaat maakt geen back-up van uw sleutels.", + "Back up your keys before signing out to avoid losing them.": "Maak een back-up van uw sleutels vooraleer u zich afmeldt om ze niet te verliezen.", + "Use key backup": "Sleutelback-up gebruiken", + "Backing up %(sessionsRemaining)s keys...": "%(sessionsRemaining)s sleutels worden geback-upt…", + "All keys backed up": "Alle sleutels zijn geback-upt", + "Backup has a valid signature from this device": "De back-up heeft een geldige ondertekening van dit apparaat", + "Backup is not signed by any of your devices": "De back-up is door geen van uw apparaten ondertekend", + "This backup is trusted because it has been restored on this device": "Deze back-up wordt vertrouwd, omdat hij op dit apparaat hersteld is", + "Backup version: ": "Back-upversie: ", "Algorithm: ": "Algoritme: ", - "Chat with Riot Bot": "Chatten met Riot Bot", - "Forces the current outbound group session in an encrypted room to be discarded": "Dwingt de huidige uitwaartse groepssessie in een versleutelde kamer om verworpen te worden" + "Chat with Riot Bot": "Chatten met Riot-robot", + "Forces the current outbound group session in an encrypted room to be discarded": "Dwingt de huidige uitwaartse groepssessie in een versleutelde kamer om verworpen te worden", + "Backup has a signature from unknown device with ID %(deviceId)s.": "De back-up heeft een ondertekening van een onbekend apparaat met ID %(deviceId)s.", + "Backup has a valid signature from verified device ": "De back-up heeft een geldige ondertekening van een geverifieerd apparaat ", + "Backup has a valid signature from unverified device ": "De back-up heeft een geldige ondertekening van een ongeverifieerd apparaat ", + "Backup has an invalid signature from verified device ": "De back-up heeft een ongeldige ondertekening van een geverifieerd apparaat ", + "Backup has an invalid signature from unverified device ": "De back-up heeft een ongeldige ondertekening van een ongeverifieerd apparaat ", + "Your keys are not being backed up from this device.": "Uw sleutels worden niet geback-upt van dit apparaat.", + "Start using Key Backup": "Begin sleutelback-up te gebruiken", + "Add an email address to configure email notifications": "Voeg een e-mailadres toe om e-mailmeldingen in te stellen", + "Unable to verify phone number.": "Kan telefoonnummer niet verifiëren.", + "Verification code": "Verificatiecode", + "Phone Number": "Telefoonnummer", + "Profile picture": "Profielfoto", + "Upload profile picture": "Profielfoto uploaden", + "Upgrade to your own domain": "Opwaardeer naar uw eigen domein", + "Display Name": "Weergavenaam", + "Set a new account password...": "Stel een nieuw accountwachtwoord in…", + "Email addresses": "E-mailadressen", + "Phone numbers": "Telefoonnummers", + "Language and region": "Taal en regio", + "Theme": "Thema", + "Account management": "Accountbeheer", + "Deactivating your account is a permanent action - be careful!": "Het deactiveren van uw account kan niet ongedaan gemaakt worden - wees voorzichtig!", + "General": "Algemeen", + "Legal": "Wettelijk", + "Credits": "Met dank aan", + "For help with using Riot, click here.": "Klik hier voor hulp bij het gebruiken van Riot.", + "For help with using Riot, click here or start a chat with our bot using the button below.": "Klik hier voor hulp bij het gebruiken van Riot, of begin een gesprek met onze robot met de knop hieronder.", + "Help & About": "Hulp & Info", + "Bug reporting": "Foutmeldingen", + "FAQ": "VGV", + "Versions": "Versies", + "Close button should minimize window to tray": "Venster minimaliseren naar systeemvak bij sluiten", + "Preferences": "Instellingen", + "Composer": "Opsteller", + "Timeline": "Tijdslijn", + "Room list": "Kamerlijst", + "Autocomplete delay (ms)": "Vertraging voor automatisch aanvullen (ms)", + "Accept all %(invitedRooms)s invites": "Alle %(invitedRooms)s-uitnodigingen aanvaarden", + "Key backup": "Sleutelback-up", + "Security & Privacy": "Veiligheid & privacy", + "Missing media permissions, click the button below to request.": "Mediatoestemmingen ontbreken, klik op de knop hieronder om deze aan te vragen.", + "Request media permissions": "Mediatoestemmingen verzoeken", + "Voice & Video": "Spraak & video", + "Upgrade room to version %(ver)s": "Kamer opwaarderen naar versie %(ver)s", + "Room information": "Kamerinformatie", + "Internal room ID:": "Interne kamer-ID:", + "Room version": "Kamerversie", + "Room version:": "Kamerversie:", + "Developer options": "Ontwikkelaarsopties", + "Open Devtools": "Ontwikkelgereedschap openen", + "Room Addresses": "Kameradressen", + "Change room avatar": "Kameravatar wijzigen", + "Change room name": "Kamernaam wijzigen", + "Change main address for the room": "Hoofdadres voor de kamer wijzigen", + "Change history visibility": "Zichtbaarheid van geschiedenis wijzigen", + "Change permissions": "Toestemmingen wijzigen", + "Change topic": "Onderwerp wijzigen", + "Modify widgets": "Widgets aanpassen", + "Default role": "Standaardrol", + "Send messages": "Berichten versturen", + "Invite users": "Gebruikers uitnodigen", + "Change settings": "Instellingen wijzigen", + "Kick users": "Gebruikers uit de kamer verwijderen", + "Ban users": "Gebruikers verbannen", + "Remove messages": "Berichten verwijderen", + "Notify everyone": "Iedereen melden" } From d12036cb93c2651f3259851907b8111802dd3aa2 Mon Sep 17 00:00:00 2001 From: Nathan van Beelen Date: Thu, 28 Mar 2019 18:59:03 +0000 Subject: [PATCH 149/481] Translated using Weblate (Dutch) Currently translated at 83.8% (1307 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index b403137ee7..f6821913fa 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -125,7 +125,7 @@ "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gemaakt.", "Privacy warning": "Privacywaarschuwing", "Private Chat": "Privégesprek", - "Privileged Users": "Bevoorrechte gebruikers", + "Privileged Users": "Gerechtigde Gebruikers", "Profile": "Profiel", "Public Chat": "Publiek Gesprek", "Reason": "Reden", From a32a700d6324c81850ac3f47b3602b6c3bcb400b Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 18:59:15 +0000 Subject: [PATCH 150/481] Translated using Weblate (Dutch) Currently translated at 87.2% (1360 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 379 ++++++++++++++++++++++----------------- 1 file changed, 215 insertions(+), 164 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index f6821913fa..fbdd1a59b7 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -12,20 +12,20 @@ "Always show message timestamps": "Altijd tijdstempels van berichten tonen", "Authentication": "Authenticatie", "%(items)s and %(lastItem)s": "%(items)s en %(lastItem)s", - "and %(count)s others...|other": "en %(count)s andere...", - "and %(count)s others...|one": "en één andere...", + "and %(count)s others...|other": "en %(count)s andere…", + "and %(count)s others...|one": "en één andere…", "%(names)s and %(lastPerson)s are typing": "%(names)s en %(lastPerson)s zijn aan het typen", "A new password must be entered.": "Er moet een nieuw wachtwoord worden ingevoerd.", "%(senderName)s answered the call.": "%(senderName)s heeft de oproep beantwoord.", "An error has occurred.": "Er is een fout opgetreden.", - "Anyone who knows the room's link, apart from guests": "Iedereen die de link van de ruimte weet, behalve gasten", - "Anyone who knows the room's link, including guests": "Iedereen die link van de ruimte weet, inclusief gasten", + "Anyone who knows the room's link, apart from guests": "Iedereen die de koppeling van de kamer kent, behalve gasten", + "Anyone who knows the room's link, including guests": "Iedereen die de koppeling van de kamer kent, inclusief gasten", "Are you sure?": "Weet u het zeker?", "Are you sure you want to reject the invitation?": "Weet je zeker dat je de uitnodiging wilt weigeren?", "Attachment": "Bijlage", "Autoplay GIFs and videos": "GIF’s en video’s automatisch afspelen", "%(senderName)s banned %(targetName)s.": "%(senderName)s heeft %(targetName)s verbannen.", - "Ban": "Verban", + "Ban": "Verbannen", "Banned users": "Verbannen gebruikers", "Bans user with given id": "Verbant de gebruiker met de gegeven ID", "Blacklisted": "Buitengesloten", @@ -43,7 +43,7 @@ "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het veranderen van het wachtwoord zal op vooralsnog alle sleutels voor eind-tot-eind-versleuteling op alle apparaten opnieuw instellen, waardoor de versleutelde gespreksgeschiedenis onleesbaar wordt, tenzij u eerst uw kamersleutels exporteert en achteraf opnieuw importeert. Dit zal in de toekomst verbeterd worden.", "Clear Cache and Reload": "Cache wissen en herladen", "Clear Cache": "Cache Legen", - "Click here to fix": "Klik hier om te repareren", + "Click here to fix": "Klik hier om dit op te lossen", "Click to mute audio": "Klik om het geluid uit te zetten", "Click to mute video": "Klik om het geluid van de video uit te zetten", "click to reveal": "klik om te tonen", @@ -63,7 +63,7 @@ "Accept": "Aanvaarden", "Active call (%(roomName)s)": "Actieve oproep (%(roomName)s)", "Add": "Toevoegen", - "Add a topic": "Een onderwerp toevoegen", + "Add a topic": "Voeg een onderwerp toe", "Admin Tools": "Beheerdersgereedschap", "VoIP": "VoiP", "Missing Media Permissions, click here to request.": "Ontbrekende mediatoestemmingen, klik hier om aan te vragen.", @@ -78,8 +78,8 @@ "Alias (optional)": "Alias (optioneel)", "Anyone": "Iedereen", "Are you sure you want to leave the room '%(roomName)s'?": "Weet u zeker dat u de ruimte '%(roomName)s' wil verlaten?", - "Are you sure you want to upload the following files?": "Weet u zeker dat u de volgende bestanden wil uploaden?", - "Click here to join the discussion!": "Klik hier om mee te doen aan de discussie!", + "Are you sure you want to upload the following files?": "Weet u zeker dat u de volgende bestanden wilt uploaden?", + "Click here to join the discussion!": "Klik hier om mee te doen aan het gesprek!", "Close": "Sluiten", "%(count)s new messages|one": "%(count)s nieuw bericht", "Create new room": "Een nieuwe ruimte maken", @@ -110,7 +110,7 @@ "(not supported by this browser)": "(niet ondersteund door deze browser)", "": "", "NOT verified": "NIET geverifieerd", - "No devices with registered encryption keys": "Geen apparaten met geregistreerde sleutels", + "No devices with registered encryption keys": "Geen apparaten met geregistreerde versleutelingssleutels", "No display name": "Geen weergavenaam", "No more results": "Geen resultaten meer", "No results": "Geen resultaten", @@ -125,18 +125,18 @@ "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gemaakt.", "Privacy warning": "Privacywaarschuwing", "Private Chat": "Privégesprek", - "Privileged Users": "Gerechtigde Gebruikers", + "Privileged Users": "Bevoorrechte gebruikers", "Profile": "Profiel", "Public Chat": "Publiek Gesprek", "Reason": "Reden", "Reason: %(reasonText)s": "Reden: %(reasonText)s", - "Revoke Moderator": "Beheerder terugtrekken", + "Revoke Moderator": "Moderator degraderen", "Refer a friend to Riot:": "Laat een vriend weten over Riot:", "Register": "Registreren", "%(targetName)s rejected the invitation.": "%(targetName)s heeft de uitnodiging geweigerd.", "Reject invitation": "Uitnodiging weigeren", "Rejoin": "Opnieuw toetreden", - "Remote addresses for this room:": "Adres op afstand voor deze ruimte:", + "Remote addresses for this room:": "Externe adressen voor deze kamer:", "Remove Contact Information?": "Contactinformatie Verwijderen?", "Send Invites": "Uitnodigingen versturen", "Start a chat": "Gesprek beginnen", @@ -182,23 +182,23 @@ "Deactivate Account": "Account deactiveren", "Deactivate my account": "Mijn account deactiveren", "Decline": "Weigeren", - "Decrypt %(text)s": "Ontsleutel %(text)s", + "Decrypt %(text)s": "%(text)s ontsleutelen", "Decryption error": "Ontsleutelfout", "Delete": "Verwijderen", "Device already verified!": "Apparaat reeds geverifieerd!", "Device ID": "Apparaats-ID", "Device ID:": "Apparaats-ID:", - "device id: ": "apparaat-ID: ", + "device id: ": "apparaats-ID: ", "Device key:": "Apparaatssleutel:", "Devices": "Apparaten", "Devices will not yet be able to decrypt history from before they joined the room": "Apparaten kunnen nog niet de geschiedenis van voordat ze de ruimte betraden ontsleutelen", - "Direct chats": "Privégesprekken", + "Direct chats": "Eén-op-één-gesprekken", "Disable Notifications": "Meldingen uitschakelen", - "Disinvite": "Uitnodiging terugtrekken", + "Disinvite": "Uitnodiging intrekken", "Display name": "Weergavenaam", "Don't send typing notifications": "Geen typnotificatie sturen", - "Download %(text)s": "%(text)s Downloaden", - "Drop File Here": "Plaats Bestand Hier", + "Download %(text)s": "%(text)s downloaden", + "Drop File Here": "Versleep het bestand naar hier", "Ed25519 fingerprint": "Ed25519-vingerafdruk", "Email": "E-mail", "Email address": "E-mailadres", @@ -209,13 +209,13 @@ "Deops user with given id": "Ontmachtigt gebruiker met de gegeven ID", "Default": "Standaard", "Displays action": "Geeft actie weer", - "Drop here to tag %(section)s": "Hier naartoe verplaatsen om %(section)s te etiketteren", + "Drop here to tag %(section)s": "Versleep hierheen om %(section)s te labellen", "Email, name or matrix ID": "E-mailadres, naam of matrix-ID", "Emoji": "Emoji", "Enable encryption": "Versleuteling inschakelen", "Enable Notifications": "Meldingen inschakelen", "Encrypted by a verified device": "Versleuteld door een geverifieerd apparaat", - "Encrypted by an unverified device": "Versleuteld door een niet-geverifieerd apparaat", + "Encrypted by an unverified device": "Versleuteld door een ongeverifieerd apparaat", "Encrypted messages will not be visible on clients that do not yet implement encryption": "Versleutelde berichten zullen nog niet zichtbaar zijn op applicaties die geen versleuteling ondersteunen", "Encrypted room": "Versleutelde ruimte", "Encryption is enabled in this room": "Versleuteling is ingeschakeld in deze ruimte", @@ -225,19 +225,19 @@ "End-to-end encryption is in beta and may not be reliable": "End-to-endbeveiliging is nog in bèta en kan onbetrouwbaar zijn", "Enter Code": "Voer code in", "Enter passphrase": "Voer wachtzin in", - "Error decrypting attachment": "Fout tijdens het ontsleutelen van de bijlage", + "Error decrypting attachment": "Fout bij het ontsleutelen van de bijlage", "Error: Problem communicating with the given homeserver.": "Fout: Er doet zich een probleem voor met het communiceren met de gegeven thuisserver.", "Event information": "Gebeurtenis-informatie", "Existing Call": "Bestaande oproep", "Export": "Exporteren", "Export E2E room keys": "E2E-kamersleutels exporteren", - "Failed to ban user": "Niet gelukt de gebruiker te verbannen", - "Failed to change power level": "Niet gelukt het machtsniveau te wijzigen", + "Failed to ban user": "Verbannen van gebruiker is mislukt", + "Failed to change power level": "Wijzigen van machtsniveau is mislukt", "Failed to fetch avatar URL": "Niet gelukt de avatar-URL op te halen", "Failed to join room": "Toetreden van kamer is mislukt", "Failed to leave room": "Niet gelukt de ruimte te verlaten", "Failed to load timeline position": "Niet gelukt de tijdlijnpositie te laden", - "Failed to mute user": "Niet gelukt de gebruiker het zwijgen op te leggen", + "Failed to mute user": "Dempen van gebruiker is mislukt", "Failed to reject invite": "Niet gelukt de uitnodiging te weigeren", "Failed to reject invitation": "Niet gelukt de uitnodiging te weigeren", "Failed to save settings": "Niet gelukt om de instellingen op te slaan", @@ -246,7 +246,7 @@ "Failed to set avatar.": "Niet gelukt om de avatar in te stellen.", "Failed to set display name": "Instellen van weergavenaam is mislukt", "Failed to set up conference call": "Niet gelukt om een vergadergesprek te maken", - "Failed to toggle moderator status": "Niet gelukt de moderatorstatus te veranderen", + "Failed to toggle moderator status": "Aanpassen van moderatorstatus is mislukt", "Failed to unban": "Ontbannen mislukt", "Failed to upload file": "Niet gelukt het bestand te uploaden", "Failed to upload profile picture!": "Uploaden van profielfoto is mislukt!", @@ -254,17 +254,17 @@ "Failure to create room": "Aanmaken van kamer is mislukt", "Favourites": "Favorieten", "Fill screen": "Scherm vullen", - "Filter room members": "Ruimteleden filteren", - "Forget room": "Ruimte vergeten", + "Filter room members": "Kamerleden filteren", + "Forget room": "Kamer vergeten", "Forgot your password?": "Wachtwoord vergeten?", "For security, this session has been signed out. Please sign in again.": "Voor veiligheidsredenen is deze sessie uitgelogd. Log alsjeblieft opnieuw in.", "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "In verband met veiligheidsredenen zullen alle end-to-endbeveiligingsleutels van deze browser verwijderd worden. Als je je gespreksgeschiedenis van toekomstige Riot sessies wilt kunnen ontsleutelen, exporteer en bewaar dan de ruimte sleutels.", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s van %(fromPowerLevel)s naar %(toPowerLevel)s", "Guest access is disabled on this Home Server.": "Gasttoegang is uitgeschakeld op deze thuisserver.", - "Guests cannot join this room even if explicitly invited.": "Gasten kunnen niet tot deze ruimte toetreden, zelfs als ze expliciet uitgenodigd zijn.", + "Guests cannot join this room even if explicitly invited.": "Gasten kunnen niet tot deze kamer toetreden, zelfs als ze uitdrukkelijk uitgenodigd zijn.", "Hangup": "Ophangen", "Hide read receipts": "Leesbewijzen verbergen", - "Hide Text Formatting Toolbar": "Tekstopmaakgereedschapsbalk verbergen", + "Hide Text Formatting Toolbar": "Tekstopmaakwerkbalk verbergen", "Historical": "Historisch", "Home": "Home", "Homeserver is": "Thuisserver is", @@ -278,21 +278,21 @@ "Incorrect username and/or password.": "Incorrecte gebruikersnaam en/of wachtwoord.", "Incorrect verification code": "Onjuiste verificatiecode", "Interface Language": "Interfacetaal", - "Invalid alias format": "Ongeldig naamformaat", + "Invalid alias format": "Ongeldig aliasformaat", "Invalid address format": "Ongeldig adresformaat", "Invalid Email Address": "Ongeldig e-mailadres", - "Invalid file%(extra)s": "Ongeldig bestand%(extra)s", + "Invalid file%(extra)s": "Ongeldig bestand %(extra)s", "%(senderName)s invited %(targetName)s.": "%(senderName)s heeft %(targetName)s uitgenodigd.", "Invite new room members": "Nieuwe kamerleden uitnodigen", "Invited": "Uitgenodigd", "Invites": "Uitnodigingen", "Invites user with given id to current room": "Nodigt de gebruiker met de gegeven ID uit in de huidige kamer", "'%(alias)s' is not a valid format for an address": "'%(alias)s' is niet een geldig formaat voor een adres", - "'%(alias)s' is not a valid format for an alias": "'%(alias)s' is niet een geldig formaat voor een naam", + "'%(alias)s' is not a valid format for an alias": "‘%(alias)s’ is geen geldig formaat voor een alias", "%(displayName)s is typing": "%(displayName)s is aan het typen", "Sign in with": "Inloggen met", - "Join as voice or video.": "Toetreden als spraak of video.", - "Join Room": "Ruimte toetreden", + "Join as voice or video.": "Deelnemen met spraak of video.", + "Join Room": "Kamer toetreden", "%(targetName)s joined the room.": "%(targetName)s is tot de kamer toegetreden.", "Joins room with given alias": "Treedt de kamer toe met een gegeven alias", "Jump to first unread message.": "Spring naar het eerste ongelezen bericht.", @@ -301,7 +301,7 @@ "Leave room": "Kamer verlaten", "%(targetName)s left the room.": "%(targetName)s heeft de kamer verlaten.", "Level:": "Niveau:", - "Local addresses for this room:": "Lokale adressen voor deze ruimte:", + "Local addresses for this room:": "Lokale adressen voor deze kamer:", "Logged in as:": "Ingelogd als:", "Logout": "Uitloggen", "Low priority": "Lage prioriteit", @@ -312,7 +312,7 @@ "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor onbekend (%(visibility)s).", "Manage Integrations": "Integraties beheren", "Markdown is disabled": "Markdown is uitgeschakeld", - "Markdown is enabled": "Markdown ingeschakeld", + "Markdown is enabled": "Markdown is ingeschakeld", "matrix-react-sdk version:": "matrix-react-sdk-versie:", "Message not sent due to unknown devices being present": "Bericht niet verzonden doordat er een onbekende apparaten aanwezig zijn", "Missing room_id in request": "room_id ontbreekt in verzoek", @@ -321,7 +321,7 @@ "Mobile phone number (optional)": "Mobiele-telefoonnummer (optioneel)", "Never send encrypted messages to unverified devices from this device": "Versleutelde berichten vanaf dit apparaat nooit naar ongeverifieerde apparaten versturen", "Never send encrypted messages to unverified devices in this room from this device": "Versleutelde berichten vanaf dit apparaat nooit naar ongeverifieerde apparaten in deze kamer versturen", - "New address (e.g. #foo:%(localDomain)s)": "Nieuw adres (bijv. #foo:%(localDomain)s)", + "New address (e.g. #foo:%(localDomain)s)": "Nieuw adres (bv. #foo:%(localDomain)s)", "New passwords don't match": "Nieuwe wachtwoorden komen niet overeen", "New passwords must match each other.": "Nieuwe wachtwoorden moeten overeenkomen.", "Once encryption is enabled for a room it cannot be turned off again (for now)": "Zodra versleuteling in een ruimte is ingeschakeld kan het niet meer worden uitgeschakeld (kan later wijzigen)", @@ -330,7 +330,7 @@ "Power level must be positive integer.": "Machtsniveau moet een positief geheel getal zijn.", "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s heeft zijn/haar weergavenaam (%(oldDisplayName)s) verwijderd.", "%(senderName)s removed their profile picture.": "%(senderName)s heeft zijn/haar profielfoto verwijderd.", - "Failed to kick": "Niet gelukt de ruimte uit te zetten", + "Failed to kick": "Uit de kamer zetten is mislukt", "Press to start a chat with someone": "Druk op om een gesprek met iemand te starten", "Remove %(threePid)s?": "%(threePid)s verwijderen?", "%(senderName)s requested a VoIP conference.": "%(senderName)s heeft een VoIP-vergadering aangevraagd.", @@ -345,14 +345,14 @@ "Room contains unknown devices": "De ruimte bevat onbekende apparaten", "Room name (optional)": "Ruimtenaam (optioneel)", "%(roomName)s does not exist.": "%(roomName)s bestaat niet.", - "%(roomName)s is not accessible at this time.": "%(roomName)s is niet toegankelijk op dit moment.", - "Rooms": "Ruimten", + "%(roomName)s is not accessible at this time.": "%(roomName)s is op dit moment niet toegankelijk.", + "Rooms": "Kamers", "Save": "Opslaan", "Scroll to bottom of page": "Scroll naar de onderkant van de pagina", "Scroll to unread messages": "Scroll naar ongelezen berichten", "Search failed": "Zoeken mislukt", "Searches DuckDuckGo for results": "Zoekt op DuckDuckGo voor resultaten", - "Seen by %(userName)s at %(dateTime)s": "Gezien bij %(userName)s op %(dateTime)s", + "Seen by %(userName)s at %(dateTime)s": "Gezien door %(userName)s op %(dateTime)s", "Send anyway": "Alsnog versturen", "Sender device information": "Afzenderapparaatinformatie", "Send Reset Email": "Stuur Reset-E-mail", @@ -363,15 +363,15 @@ "Server may be unavailable, overloaded, or search timed out :(": "De server is misschien onbereikbaar, overbelast of het zoeken duurde te lang :(", "Server may be unavailable, overloaded, or the file too big": "De server is misschien onbereikbaar, overbelast of het bestand is te groot", "Server may be unavailable, overloaded, or you hit a bug.": "De server is misschien onbereikbaar of overbelast, of u bent een fout tegengekomen.", - "Server unavailable, overloaded, or something else went wrong.": "De server is onbereikbaar, overbelast of iets anders ging fout.", + "Server unavailable, overloaded, or something else went wrong.": "De server is onbereikbaar of overbelast, of er is iets anders foutgegaan.", "Session ID": "Sessie-ID", "%(senderName)s kicked %(targetName)s.": "%(senderName)s heeft %(targetName)s de kamer uitgestuurd.", - "Kick": "Er uit sturen", + "Kick": "Uit de kamer sturen", "Kicks user with given id": "Stuurt de gebruiker met de gegeven ID uit de kamer", "%(senderName)s set a profile picture.": "%(senderName)s heeft een profielfoto ingesteld.", "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s heeft zijn/haar weergavenaam ingesteld op %(displayName)s.", "Show panel": "Paneel weergeven", - "Show Text Formatting Toolbar": "Tekstopmaakwerkbalk Weergeven", + "Show Text Formatting Toolbar": "Tekstopmaakwerkbalk weergeven", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Tijd in 12-uursformaat weergeven (bv. 2:30pm)", "Signed Out": "Uitgelogd", "Sign in": "Inloggen", @@ -389,15 +389,15 @@ "The file '%(fileName)s' failed to upload": "Uploaden van bestand ‘%(fileName)s’ is mislukt", "The remote side failed to pick up": "De andere kant heeft niet opgenomen", "This Home Server does not support login using email address.": "Deze Thuisserver ondersteunt het inloggen met een e-mailadres niet.", - "This invitation was sent to an email address which is not associated with this account:": "Deze uitnodiging was naar een e-mailadres gestuurd die niet geassocieerd is met dit account:", - "This room has no local addresses": "Deze ruimte heeft geen lokale adressen", + "This invitation was sent to an email address which is not associated with this account:": "Deze uitnodiging was naar een e-mailadres gestuurd dat niet geassocieerd is met deze account:", + "This room has no local addresses": "Deze kamer heeft geen lokale adressen", "This room is not recognised.": "Deze kamer wordt niet herkend.", "These are experimental features that may break in unexpected ways": "Dit zijn experimentele functies die misschien kunnen breken op onverwachte manieren", "The visibility of existing history will be unchanged": "De zichtbaarheid van de bestaande geschiedenis zal onveranderd blijven", "This doesn't appear to be a valid email address": "Het ziet er niet naar uit dat dit een geldig e-mailadres is", - "This is a preview of this room. Room interactions have been disabled": "Dit is een voorvertoning van de ruimte. Ruimte-interacties zijn uitgeschakeld", + "This is a preview of this room. Room interactions have been disabled": "Dit is een voorvertoning van de kamer. Kamerinteracties zijn uitgeschakeld", "This phone number is already in use": "Dit telefoonnummer is al in gebruik", - "This room": "Deze ruimte", + "This room": "Deze kamer", "This room is not accessible by remote Matrix servers": "Deze kamer is niet toegankelijk voor externe Matrix-servers", "This room's internal ID is": "Het interne ID van deze ruimte is", "To link to a room it must have an address.": "Om naar een ruimte te linken moet het een adres hebben.", @@ -413,14 +413,14 @@ "Unable to verify email address.": "Kan e-mailadres niet verifiëren.", "Unban": "Ontbannen", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s heeft %(targetName)s ontbannen.", - "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Onmogelijk na te gaan of het adres waarheen deze uitnodiging was verstuurd overeenkomt met het adres dat bij je account behoort.", + "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Onmogelijk na te gaan of het adres waarheen deze uitnodiging was verstuurd overeenkomt met het adres dat bij uw account hoort.", "Unable to capture screen": "Kan geen schermafdruk maken", "Unable to enable Notifications": "Kan meldingen niet inschakelen", "Unable to load device list": "Kan lijst van apparaten niet laden", - "Undecryptable": "Niet ontsleutelbaar", + "Undecryptable": "Onontsleutelbaar", "Unencrypted room": "Ontsleutelde ruimte", "unencrypted": "ontsleuteld", - "Unencrypted message": "Niet-versleuteld bericht", + "Unencrypted message": "Onversleuteld bericht", "unknown caller": "onbekende beller", "unknown device": "Onbekend apparaat", "Unknown room %(roomId)s": "Onbekende ruimte %(roomId)s", @@ -435,7 +435,7 @@ "Uploading %(filename)s and %(count)s others|other": "%(filename)s en %(count)s anderen aan het uploaden", "Upload avatar": "Avatar uploaden", "Upload Failed": "Uploaden mislukt", - "Upload Files": "Bestanden Uploaden", + "Upload Files": "Bestanden uploaden", "Upload file": "Bestand uploaden", "Upload new:": "Upload er een nieuwe:", "Usage": "Gebruik", @@ -464,27 +464,27 @@ "Warning!": "Let op!", "WARNING: Device already verified, but keys do NOT MATCH!": "LET OP: apparaat reeds geverifieerd, maar de sleutels KOMEN NIET OVEREEN!", "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "LET OP: SLEUTELVERIFICATIE IS MISLUKT! De ondertekende sleutel voor %(userId)s en apparaat %(deviceId)s is ‘%(fprint)s’, wat niet overeenkomt met de verschafte sleutel ‘%(fingerprint)s’. Dit kan betekenen dat uw communicatie onderschept wordt!", - "Who can access this room?": "Wie heeft toegang tot deze ruimte?", + "Who can access this room?": "Wie heeft toegang tot deze kamer?", "Who can read history?": "Wie kan de geschiedenis lezen?", "Who would you like to add to this room?": "Wie wilt u aan deze kamer toevoegen?", "Who would you like to communicate with?": "Met wie zou u willen communiceren?", "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s heeft de uitnodiging van %(targetName)s ingetrokken.", - "Would you like to accept or decline this invitation?": "Wil je deze uitnodiging accepteren of afwijzen?", + "Would you like to accept or decline this invitation?": "Wilt u deze uitnodiging aanvaarden of afwijzen?", "You already have existing direct chats with this user:": "Je hebt al bestaande privé-gesprekken met deze gebruiker:", "You are already in a call.": "U bent al in gesprek.", "You're not in any rooms yet! Press to make a room or to browse the directory": "Je zit nog niet in een ruimte! Druk op om een ruimte te maken of om door de catalogus te bladeren", - "You are trying to access %(roomName)s.": "Je probeert in %(roomName)s toe te treden.", + "You are trying to access %(roomName)s.": "U probeert toegang te verkrijgen tot %(roomName)s.", "You cannot place a call with yourself.": "U kunt uzelf niet bellen.", "You cannot place VoIP calls in this browser.": "U kunt in deze browser geen VoIP-oproepen plegen.", - "You do not have permission to post to this room": "Je hebt geen toestemming in deze ruimte te praten", - "You have been banned from %(roomName)s by %(userName)s.": "Je bent verbannen van %(roomName)s door %(userName)s.", - "You have been invited to join this room by %(inviterName)s": "Je bent in deze ruimte uitgenodigd door %(inviterName)s", - "You have been kicked from %(roomName)s by %(userName)s.": "Je bent uit %(roomName)s gezet door %(userName)s.", + "You do not have permission to post to this room": "U heeft geen toestemming om in deze kamer te posten", + "You have been banned from %(roomName)s by %(userName)s.": "%(userName)s heeft u uit %(roomName)s verbannen.", + "You have been invited to join this room by %(inviterName)s": "U bent in deze kamer uitgenodigd door %(inviterName)s", + "You have been kicked from %(roomName)s by %(userName)s.": "%(userName)s heeft u uit %(roomName)s gezet.", "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Je bent op alle apparaten uitgelegd en je zal niet langer notificaties ontvangen. Om notificaties weer aan te zetten, log op elk apparaat opnieuw in", - "You have disabled URL previews by default.": "Je hebt URL-voorvertoningen standaard uitgezet.", - "You have enabled URL previews by default.": "Je hebt URL-voorvertoningen standaard aangezet.", + "You have disabled URL previews by default.": "U heeft URL-voorvertoningen standaard uitgeschakeld.", + "You have enabled URL previews by default.": "U heeft URL-voorvertoningen standaard ingeschakeld.", "You have no visible notifications": "Je hebt geen zichtbare notificaties", - "You may wish to login with a different account, or add this email to this account.": "Je wilt misschien met een ander account inloggen of deze e-mail aan je account toevoegen.", + "You may wish to login with a different account, or add this email to this account.": "U kunt zich met een andere account aanmelden, of dit e-mailadres aan uw account toevoegen.", "You must register to use this functionality": "Je moet je registreren om deze functie te gebruiken", "You need to be able to invite users to do that.": "Om dit te kunnen doen, moet u gebruikers kunnen uitnodigen.", "You need to be logged in.": "Aanmelding is vereist.", @@ -495,7 +495,7 @@ "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat je in een gesprek zit, weet je zeker dat je wilt afsluiten?", "You seem to be uploading files, are you sure you want to quit?": "Het ziet er naar uit dat je bestanden aan het uploaden bent, weet je zeker dat je wilt afsluiten?", "You should not yet trust it to secure data": "Je moet het nog niet vertrouwen om gegevens te beveiligen", - "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Je zult deze verandering niet terug kunnen draaien omdat je de gebruiker tot je eigen machtsniveau bevordert.", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "U kunt deze veranderingen niet ongedaan maken aangezien u de gebruiker tot hetzelfde niveau als uzelf promoveert.", "Your home server does not support device management.": "Je thuisserver ondersteund geen apparaatbeheer.", "This server does not support authentication with a phone number.": "Deze server ondersteunt geen authenticatie met een telefoonnummer.", "Missing password.": "Het wachtwoord mist.", @@ -508,7 +508,7 @@ "I already have an account": "Ik heb al een account", "An error occurred: %(error_string)s": "Er is een fout voorgevallen: %(error_string)s", "Topic": "Onderwerp", - "Make Moderator": "Moderator maken", + "Make Moderator": "Benoemen tot moderator", "Make this room private": "Deze ruimte privé maken", "Share message history with new users": "Bericht geschiedenis met nieuwe gebruikers delen", "Encrypt room": "Ruimte versleutelen", @@ -527,7 +527,7 @@ "quote": "citaat", "bullet": "opsommingsteken", "numbullet": "genummerd opsommingsteken", - "Please select the destination room for this message": "Selecteer de destinatie-ruimte voor dit bericht", + "Please select the destination room for this message": "Selecteer de bestemmingskamer voor dit bericht", "New Password": "Nieuw wachtwoord", "Start automatically after system login": "Automatisch starten na systeemaanmelding", "Desktop specific": "Desktop-specifiek", @@ -571,7 +571,7 @@ "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We raden je aan ieder apparaat te controleren om te vast te stellen of ze tot de legitieme eigenaar behoren, maar je kunt het bericht desgewenst zonder controle versturen.", "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" bevat apparaten die je nog niet eerder hebt gezien.", "Unknown devices": "Onbekende apparaten", - "Unknown Address": "Onbekend Adres", + "Unknown Address": "Onbekend adres", "Unverify": "Ontverifïeren", "Verify...": "Verifiëren...", "ex. @bob:example.com": "bijv. @bob:voorbeeld.com", @@ -591,16 +591,16 @@ "Home server URL": "Thuisserver-URL", "Identity server URL": "Identiteitsserver-URL", "What does this mean?": "Wat betekent dit?", - "Error decrypting audio": "Fout met het ontsleutelen van de audio", - "Error decrypting image": "Fout met het ontsleutelen van de afbeelding", - "Error decrypting video": "Fout met het ontsleutelen van de video", + "Error decrypting audio": "Fout bij het ontsleutelen van de audio", + "Error decrypting image": "Fout bij het ontsleutelen van de afbeelding", + "Error decrypting video": "Fout bij het ontsleutelen van de video", "Add an Integration": "Voeg een integratie toe", - "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Je wordt zo naar een derde-partij-website verbonden zodat je het account kan legitimeren voor gebruik met %(integrationsUrl)s. Wil je doorgaan?", + "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "U wordt zo dadelijk naar een derdepartijwebsite gebracht zodat u de account kunt legitimeren voor gebruik met %(integrationsUrl)s. Wilt u doorgaan?", "Removed or unknown message type": "Verwijderd of onbekend berichttype", "URL Previews": "URL-voorvertoningen", - "Drop file here to upload": "Bestand hierheen slepen om te uploaden", + "Drop file here to upload": "Versleep het bestand naar hier om het te uploaden", " (unsupported)": " (niet ondersteund)", - "Ongoing conference call%(supportedText)s.": "Lopend groepsgesprek %(supportedText)s.", + "Ongoing conference call%(supportedText)s.": "Lopend vergadergesprek %(supportedText)s.", "Online": "Online", "Idle": "Afwezig", "Offline": "Offline", @@ -609,12 +609,12 @@ "Start chatting": "Start met praten", "Start Chatting": "Start Met Praten", "Click on the button below to start chatting!": "Klik op de knop hieronder om het gesprek te beginnen!", - "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s heeft de ruimte avatar aangepast naar ", - "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s heeft de ruimte avatar verwijderd.", - "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s veranderde de avatar voor %(roomName)s", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s heeft de kameravatar aangepast naar ", + "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s heeft de kameravatar verwijderd.", + "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s heeft de avatar van %(roomName)s veranderd", "Username available": "Gebruikersnaam beschikbaar", "Username not available": "Gebruikersnaam niet beschikbaar", - "Something went wrong!": "Iets ging niet goed!", + "Something went wrong!": "Er is iets misgegaan!", "This will be your account name on the homeserver, or you can pick a different server.": "Dit zal je account naam worden op de thuisserver, of je kunt een andere server kiezen.", "If you already have a Matrix account you can log in instead.": "Als je al een Matrix-account hebt kun je ook meteen inloggen.", "Your browser does not support the required cryptography extensions": "Uw browser ondersteunt de benodigde cryptografie-extensies niet", @@ -632,23 +632,23 @@ "Your unverified device '%(displayName)s' is requesting encryption keys.": "Je niet geverifieerde apparaat '%(displayName)s' vraagt naar versleutelingssleutels.", "Encryption key request": "Verzoek voor versleutelingssleutel", "Define the power level of a user": "Bepaal het machtsniveau van een gebruiker", - "Add a widget": "Voeg een widget toe", + "Add a widget": "Widget toevoegen", "Allow": "Toestaan", - "Cannot add any more widgets": "Er kunnen niet meer widgets toegevoegd worden", + "Cannot add any more widgets": "Er kunnen niet nog meer widgets toegevoegd worden", "Changes colour scheme of current room": "Verandert het kleurenschema van de huidige kamer", "Delete widget": "Widget verwijderen", - "Do you want to load widget from URL:": "Wil je de widget laden van de URL:", - "Edit": "Aanpassen", + "Do you want to load widget from URL:": "Wilt u de widget laden van de URL:", + "Edit": "Bewerken", "Enable automatic language detection for syntax highlighting": "Automatische taaldetectie voor zinsbouwmarkeringen inschakelen", "Hide join/leave messages (invites/kicks/bans unaffected)": "Toetreed/verlaat berichten verbergen (uitnodigingen/verwijderingen/verbanningen zullen ongeschonden blijven)", "Integrations Error": "Integratiesfout", "Publish this room to the public in %(domain)s's room directory?": "Deze kamer openbaar maken in de kamercatalogus van %(domain)s?", "AM": "AM", "PM": "PM", - "NOTE: Apps are not end-to-end encrypted": "OPMERKING: Apps zijn niet end-to-endbeveiligd", + "NOTE: Apps are not end-to-end encrypted": "LET OP: apps zijn niet eind-tot-eind-versleuteld", "Revoke widget access": "Toegang tot widget intrekken", "Sets the room topic": "Wijzigt het ruimte-onderwerp", - "The maximum permitted number of widgets have already been added to this room.": "Het maximum aantal toegestane widgets is al aan deze ruimte toegevoegd.", + "The maximum permitted number of widgets have already been added to this room.": "Het maximale aantal toegestane widgets is al aan deze kamer toegevoegd.", "To get started, please pick a username!": "Kies allereerst een gebruikersnaam!", "Unable to create widget.": "Kan widget niet aanmaken.", "Unbans user with given id": "Ontbant de gebruiker met de gegeven ID", @@ -670,8 +670,8 @@ "%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s-widget aangepast door %(senderName)s", "Copied!": "Gekopieerd!", "Failed to copy": "Kopiëren mislukt", - "Unpin Message": "Maak pin los", - "Add rooms to this community": "Voeg ruimtes toe aan deze gemeenschap", + "Unpin Message": "Bericht losmaken", + "Add rooms to this community": "Voeg kamers toe aan deze gemeenschap", "Call Failed": "Oproep mislukt", "Call": "Bellen", "Answer": "Beantwoorden", @@ -679,7 +679,7 @@ "Invite new community members": "Nodig nieuwe gemeenschapsleden uit", "Name or matrix ID": "Naam of Matrix-ID", "Which rooms would you like to add to this community?": "Welke kamers wilt u toevoegen aan deze gemeenschap?", - "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Een widget verwijderen doet dat voor alle gebruikers in deze ruimte. Ben je zeker dat je het widget wil verwijderen?", + "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Een widget verwijderen doet dat voor alle gebruikers in deze kamer. Weet u zeker dat u deze widget wilt verwijderen?", "Delete Widget": "Widget verwijderen", "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "Er zijn onbekende apparaten in deze kamer: als u verder gaat zonder ze te verifiëren zal het mogelijk zijn dat iemand uw oproep afluistert.", "Review Devices": "Apparaten nakijken", @@ -719,12 +719,12 @@ "%(senderName)s sent a video": "%(senderName)s heeft een video gestuurd", "%(senderName)s uploaded a file": "%(senderName)s heeft een bestand geüpload", "Disinvite this user?": "Uitnodiging van deze gebruiker intrekken?", - "Kick this user?": "Deze gebruiker er uit zetten?", + "Kick this user?": "Deze gebruiker uit de kamer zetten?", "Unban this user?": "Deze gebruiker ontbannen?", - "Ban this user?": "Deze gebruiker bannen?", + "Ban this user?": "Deze gebruiker verbannen?", "Disable big emoji in chat": "Grote emoji in gesprekken uitzetten", "Mirror local video feed": "Lokale videoaanvoer ook elders opslaan (spiegelen)", - "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Je kunt deze actie niet ongedaan maken omdat je jezelf degradeert. Als je het laatste persoon met rechten bent, is het onmogelijk deze rechten terug te krijgen.", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "U kunt deze actie niet ongedaan maken omdat u zichzelf degradeert. Als u de laatste bevoorrechte gebruiker in de kamer bent, is het onmogelijk deze rechten terug te krijgen.", "Unignore": "Niet meer negeren", "Ignore": "Negeren", "Jump to read receipt": "Naar het laatst gelezen bericht gaan", @@ -735,34 +735,34 @@ "Send a reply (unencrypted)…": "Verstuur een antwoord (onversleuteld)…", "Send an encrypted message…": "Verstuur een versleuteld bericht…", "Send a message (unencrypted)…": "Verstuur een bericht (onversleuteld)…", - "Jump to message": "Naar bericht gaan", - "No pinned messages.": "Geen gepinde berichten.", - "Loading...": "Laden...", - "Pinned Messages": "Gepinde Berichten", + "Jump to message": "Naar bericht springen", + "No pinned messages.": "Geen vastgeprikte berichten.", + "Loading...": "Bezig met laden…", + "Pinned Messages": "Vastgeprikte berichten", "%(duration)ss": "%(duration)ss", "%(duration)sm": "%(duration)sm", "%(duration)sh": "%(duration)su", "%(duration)sd": "%(duration)sd", "Online for %(duration)s": "Online voor %(duration)s", - "Idle for %(duration)s": "Inactief voor %(duration)s", + "Idle for %(duration)s": "Afwezig voor %(duration)s", "Offline for %(duration)s": "Offline voor %(duration)s", "Unknown for %(duration)s": "Onbekend voor %(duration)s", "Unknown": "Onbekend", "Replying": "Aan het beantwoorden", - "No rooms to show": "Geen ruimten om weer te geven", - "Unnamed room": "Ruimte zonder naam", + "No rooms to show": "Geen kamers om weer te geven", + "Unnamed room": "Naamloze kamer", "World readable": "Leesbaar voor iedereen", "Guests can join": "Gasten kunnen toetreden", "Remove avatar": "Avatar verwijderen", "To change the room's avatar, you must be a": "Om de avatar van de ruimte te verwijderen, moet je het volgende zijn:", - "Drop here to favourite": "Hierheen slepen om aan favorieten toe te voegen", - "Drop here to tag direct chat": "Hierheen slepen om als privégesprek te markeren", - "Drop here to restore": "Hierheen slepen om te herstellen", - "Drop here to demote": "Hierheen slepen om te degraderen", + "Drop here to favourite": "Versleep hierheen om toe te voegen aan favorieten", + "Drop here to tag direct chat": "Versleep hierheen om als één-op-één-gesprek te markeren", + "Drop here to restore": "Versleep hierheen om te herstellen", + "Drop here to demote": "Versleep hierheen om te degraderen", "Community Invites": "Gemeenschapsuitnodigingen", - "You have been kicked from this room by %(userName)s.": "Je bent uit deze ruimte gezet door %(userName)s.", - "You have been banned from this room by %(userName)s.": "Je bent uit deze ruimte verbannen door %(userName)s.", - "You are trying to access a room.": "Je probeert een ruimte te betreden.", + "You have been kicked from this room by %(userName)s.": "%(userName)s heeft u uit deze kamer gezet.", + "You have been banned from this room by %(userName)s.": "%(userName)s heeft u uit deze kamer verbannen.", + "You are trying to access a room.": "U probeert toegang te verkrijgen tot een kamer.", "To change the room's name, you must be a": "Om de ruimtenaam te veranderen moet je het volgende zijn:", "To change the room's main address, you must be a": "Om het hoofdadres van deze ruimte te wijzigen moet je het volgende zijn:", "To change the room's history visibility, you must be a": "Om de zichtbaarheid van de geschiedenis van de ruimte te veranderen moet je het volgende zijn:", @@ -770,9 +770,9 @@ "To change the topic, you must be a": "Om het onderwerp te veranderen moet je het volgende zijn:", "To modify widgets in the room, you must be a": "Om een widget in de ruimte aan te passen moet je het volgende zijn:", "Banned by %(displayName)s": "Verbannen door %(displayName)s", - "Members only (since the point in time of selecting this option)": "Alleen gebruikers (vanaf het moment dat deze optie wordt geselecteerd)", - "Members only (since they were invited)": "Alleen gebruikers (vanaf het moment dat ze uitgenodigd zijn)", - "Members only (since they joined)": "Alleen gebruikers (vanaf het moment dat ze toegetreden zijn)", + "Members only (since the point in time of selecting this option)": "Alleen deelnemers (vanaf het moment dat deze optie wordt geselecteerd)", + "Members only (since they were invited)": "Alleen deelnemers (vanaf het moment dat ze uitgenodigd zijn)", + "Members only (since they joined)": "Alleen deelnemers (vanaf het moment dat ze toegetreden zijn)", "To send messages, you must be a": "Om berichten te versturen moet je het volgende zijn:", "To invite users into the room, you must be a": "Om gebruikers in de ruimte uit te nodigen moet je het volgende zijn:", "To configure the room, you must be a": "Om de ruimte te configureren moet je het volgende zijn:", @@ -781,40 +781,40 @@ "To remove other users' messages, you must be a": "Om de berichten van andere gebruikers te verwijderen moet je het volgende zijn:", "To send events of type , you must be a": "Om gebeurtenissen van het type te versturen, moet je het volgende zijn:", "Addresses": "Adressen", - "Invalid community ID": "Ongeldig gemeenschaps-ID", - "'%(groupId)s' is not a valid community ID": "'%(groupId)s' is niet een geldig gemeenschaps-ID", + "Invalid community ID": "Ongeldige gemeenschaps-ID", + "'%(groupId)s' is not a valid community ID": "‘%(groupId)s’ is geen geldige gemeenschaps-ID", "Flair": "Badge", "Showing flair for these communities:": "Badges voor deze gemeenschappen weergeven:", - "This room is not showing flair for any communities": "Deze ruimte geeft geen badges voor gemeenschappen weer", - "New community ID (e.g. +foo:%(localDomain)s)": "Nieuw gemeenschaps-ID (bv. +foo:%(localDomain)s)", - "URL previews are enabled by default for participants in this room.": "URL voorvertoning staat standaard aan voor deelnemers in deze ruimte.", - "URL previews are disabled by default for participants in this room.": "URL voorvertoning staat standaard uit voor deelnemers in deze ruimte.", + "This room is not showing flair for any communities": "Deze kamer geeft geen badges voor gemeenschappen weer", + "New community ID (e.g. +foo:%(localDomain)s)": "Nieuwe gemeenschaps-ID (bv. +foo:%(localDomain)s)", + "URL previews are enabled by default for participants in this room.": "URL-voorvertoningen zijn voor deelnemers in deze kamer standaard ingeschakeld.", + "URL previews are disabled by default for participants in this room.": "URL-voorvertoningen zijn voor deelnemers in deze kamer standaard uitgeschakeld.", "Message removed by %(userId)s": "Bericht verwijderd door %(userId)s", "Message removed": "Bericht verwijderd", "An email has been sent to %(emailAddress)s": "Een e-mail is naar %(emailAddress)s verstuurd", "A text message has been sent to %(msisdn)s": "Een tekstbericht is naar %(msisdn)s versuurd", "Username on %(hs)s": "Gebruikersnaam op %(hs)s", - "Remove from community": "Verwijder van gemeenschap", - "Disinvite this user from community?": "Uitnodiging van de gemeenschap voor deze gebruiker intrekken?", - "Remove this user from community?": "Deze gebruiker van de gemeenschap verwijderen?", - "Failed to withdraw invitation": "Niet gelukt de uitnodiging in te trekken", - "Failed to remove user from community": "Niet gelukt de gebruiker uit de gemeenschap te verwijderen", - "Filter community members": "Filter gemeenschapsleden", + "Remove from community": "Verwijderen uit gemeenschap", + "Disinvite this user from community?": "Uitnodiging voor deze gebruiker tot de gemeenschap intrekken?", + "Remove this user from community?": "Deze gebruiker uit de gemeenschap verwijderen?", + "Failed to withdraw invitation": "Intrekken van uitnodiging is mislukt", + "Failed to remove user from community": "Verwijderen van gebruiker uit gemeenschap is mislukt", + "Filter community members": "Gemeenschapsleden filteren", "Flair will appear if enabled in room settings": "Badge zal worden weergeven als het aangezet is in de ruimte-instellingen", "Flair will not appear": "Badge zal niet weergeven worden", - "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Weet je zeker dat je '%(roomName)s' van %(groupId)s wilt verwijderen?", - "Removing a room from the community will also remove it from the community page.": "Het verwijderen van de ruimte van de gemeenschap zal de ruimte ook van de gemeenschapspagina verwijderen.", - "Failed to remove room from community": "Niet gelukt de ruimte uit de gemeenschap te verwijderen", - "Failed to remove '%(roomName)s' from %(groupId)s": "Niet gelukt '%(roomName)s' uit %(groupId)s te verwijderen", - "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "De zichtbaarheid van '%(roomName)s' in %(groupId)s kon niet geüpdatet worden.", - "Visibility in Room List": "Zichtbaarheid in Ruimte Lijst", + "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Weet u zeker dat u ‘%(roomName)s’ uit %(groupId)s wilt verwijderen?", + "Removing a room from the community will also remove it from the community page.": "De ruimte uit de gemeenschap verwijderen zal deze ook van de gemeenschapspagina verwijderen.", + "Failed to remove room from community": "Verwijderen van ruimte uit gemeenschap is mislukt", + "Failed to remove '%(roomName)s' from %(groupId)s": "Verwijderen van ‘%(roomName)s’ uit %(groupId)s is mislukt", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "De zichtbaarheid van ‘%(roomName)s’ in %(groupId)s kon niet bijgewerkt worden.", + "Visibility in Room List": "Zichtbaarheid in kamerlijst", "Visible to everyone": "Zichtbaar voor iedereen", "Only visible to community members": "Alleen zichtbaar voor gemeenschapsleden", - "Filter community rooms": "Gemeenschapsruimtes filteren", - "Something went wrong when trying to get your communities.": "Iets ging verkeerd tijdens het ophalen van je gemeenschappen.", - "Display your community flair in rooms configured to show it.": "Toon je gemeenschapsbadge in ruimten die daarvoor ingesteld zijn.", - "You're not currently a member of any communities.": "Je bent momenteel niet een lid van een gemeenschap.", - "Minimize apps": "Applicaties minimaliseren", + "Filter community rooms": "Gemeenschapskamers filteren", + "Something went wrong when trying to get your communities.": "Er ging iets mis bij het ophalen van uw gemeenschappen.", + "Display your community flair in rooms configured to show it.": "Toon uw gemeenschapsbadge in ruimten die daarvoor ingesteld zijn.", + "You're not currently a member of any communities.": "U bent momenteel geen lid van een gemeenschap.", + "Minimize apps": "Apps minimaliseren", "Communities": "Gemeenschappen", "%(nameList)s %(transitionList)s": "%(nameList)s%(transitionList)s", "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s traden %(count)s keer toe", @@ -927,7 +927,7 @@ "%(count)s of your messages have not been sent.|one": "Je bericht was niet verstuurd.", "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Alles nu herzenden of annuleren. Je kunt ook individuele berichten selecteren om te herzenden of te annuleren.", "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Nu bericht opnieuw versturen of bericht annuleren.", - "Warning": "Waarschuwing", + "Warning": "Let op", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Er is niemand anders hier! Wil je anderen uitnodigen of de waarschuwing over de lege ruimte stoppen?", "Light theme": "Licht thema", "Dark theme": "Donker thema", @@ -958,11 +958,11 @@ "were unbanned %(count)s times|one": "waren ontbant", "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s heeft zijn/haar weergavenaam gewijzigd naar %(displayName)s.", "Disable Community Filter Panel": "Gemeenschapsfilterpaneel uitzetten", - "Your key share request has been sent - please check your other devices for key share requests.": "Je verzoek sleutels te delen is verzonden - controleer je andere apparaten voor het verzoek.", - "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Verzoeken sleutels te delen worden automatisch naar andere apparaten verstuurd. Als je het verzoek hebt afgewezen of weg hebt geklikt, klik dan hier voor een nieuw verzoek om de sleutels van deze sessie.", - "If your other devices do not have the key for this message you will not be able to decrypt them.": "Je kunt dit bericht niet ontsleutelen als geen van je andere apparaten er een sleutel voor heeft.", - "Key request sent.": "Sleutel verzoek verstuurd.", - "Re-request encryption keys from your other devices.": "Versleutelingssleutels opnieuw aanvragen van je andere apparaten.", + "Your key share request has been sent - please check your other devices for key share requests.": "Uw sleuteldeelverzoek is verstuurd - controleer uw andere apparaten voor sleuteldeelverzoeken.", + "Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Sleuteldeelverzoeken worden automatisch naar andere apparaten verstuurd. Als u het verzoek heeft afgewezen of gesloten, klik dan hier om de sleutels van deze sessie opnieuw aan te vragen.", + "If your other devices do not have the key for this message you will not be able to decrypt them.": "U zult dit bericht niet kunnen ontsleutelen als geen van uw andere apparaten er de sleutel voor heeft.", + "Key request sent.": "Sleutelverzoek verstuurd.", + "Re-request encryption keys from your other devices.": "Versleutelingssleutels opnieuw aanvragen van uw andere apparaten.", "%(user)s is a %(userRole)s": "%(user)s is een %(userRole)s", "Did you know: you can use communities to filter your Riot.im experience!": "Wist je dat: je gemeenschappen kan gebruiken om je Riot.im-beleving te filteren!", "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.": "Sleep om een filter te maken een gemeenschapsavatar naar het filterpaneel helemaal links op het scherm. Je kunt daarna op de avatar in het filterpaneel klikken wanneer je je wilt beperken tot de ruimten en mensen uit die tot die gemeenschap.", @@ -971,7 +971,7 @@ "Failed to remove tag %(tagName)s from room": "Het is niet gelukt het label %(tagName)s van de ruimte te verwijderen", "Failed to add tag %(tagName)s to room": "Het is niet gelukt het label %(tagName)s aan deze ruimte toe te voegen", "Stickerpack": "Stickerpakket", - "You don't currently have any stickerpacks enabled": "Je hebt momenteel geen stickerpakketten aan staan", + "You don't currently have any stickerpacks enabled": "U heeft momenteel geen stickerpakketten ingeschakeld", "Add a stickerpack": "Stickerpakket toevoegen", "Hide Stickers": "Stickers verbergen", "Show Stickers": "Stickers weergeven", @@ -999,7 +999,7 @@ "Notification targets": "Meldingsbestemmingen", "Today": "Vandaag", "Files": "Bestanden", - "You are not receiving desktop notifications": "Je ontvangt momenteel geen desktopmeldingen", + "You are not receiving desktop notifications": "U ontvangt momenteel geen bureaubladmeldingen", "Friday": "Vrijdag", "Update": "Bijwerken", "What's New": "Wat is er nieuw", @@ -1013,13 +1013,13 @@ "Send Custom Event": "Verzend aangepast evenement", "Advanced notification settings": "Geavanceerde meldingsinstellingen", "delete the alias.": "verwijder de alias.", - "To return to your account in future you need to set a password": "Om in de toekomst naar je account terug te gaan is het nodig een wachtwoord in te stellen", + "To return to your account in future you need to set a password": "Om in de toekomst naar uw account terug te gaan is het nodig een wachtwoord in te stellen", "Forget": "Vergeten", "#example": "#voorbeeld", "Hide panel": "Paneel verbergen", "You cannot delete this image. (%(code)s)": "Je kunt deze afbeelding niet verwijderen. (%(code)s)", "Cancel Sending": "Versturen annuleren", - "This Room": "Deze Ruimte", + "This Room": "Deze kamer", "The Home Server may be too old to support third party networks": "De thuisserver is misschien te oud om netwerken van derde partijen te ondersteunen", "Resend": "Opnieuw verzenden", "Error saving email notification preferences": "Fout bij het opslaan van de meldingsvoorkeuren voor e-mail", @@ -1048,7 +1048,7 @@ "Keywords": "Trefwoorden", "Enable notifications for this account": "Meldingen inschakelen voor deze account", "Directory": "Ruimtelijst", - "Invite to this community": "Nodig uit in deze community", + "Invite to this community": "Uitnodigen in deze gemeenschap", "Search for a room": "Een ruimte opzoeken", "Messages containing keywords": "Berichten die trefwoorden bevatten", "Room not found": "De ruimte is niet gevonden", @@ -1070,20 +1070,20 @@ "Failed to set Direct Message status of room": "Het is niet gelukt de privéchat-status van de ruimte in te stellen", "Monday": "Maandag", "All messages (noisy)": "Alle berichten (luid)", - "Enable them now": "Deze nu aanzetten", + "Enable them now": "Deze nu inschakelen", "Messages containing my user name": "Berichten die mijn gebruikersnaam bevatten", "Toolbox": "Eigenschappen", "Collecting logs": "Logboeken worden verzameld", "more": "meer", "You must specify an event type!": "Je moet een event-type specificeren!", "(HTTP status %(httpStatus)s)": "(HTTP-status %(httpStatus)s)", - "Invite to this room": "Uitnodigen voor deze ruimte", + "Invite to this room": "Uitnodigen in deze kamer", "Please install Chrome or Firefox for the best experience.": "Installeer alstublieft Chrome of Firefox voor de beste gebruikerservaring.", "Failed to get public room list": "Lijst met publieke ruimtes ophalen mislukt", "Send logs": "Logboeken versturen", "All messages": "Alle berichten", "Call invitation": "Oproep-uitnodiging", - "Downloading update...": "Update aan het downloaden...", + "Downloading update...": "Update wordt gedownload…", "State Key": "Toestandssleutel", "Failed to send custom event.": "Aangepast Event verzenden mislukt.", "What's new?": "Wat is er nieuw?", @@ -1093,7 +1093,7 @@ "Notify for all other messages/rooms": "Stuur een melding voor alle andere berichten/kamers", "Unable to look up room ID from server": "Kon het ruimte-ID niet van de server ophalen", "Couldn't find a matching Matrix room": "Kon geen bijbehorende Matrix-ruimte vinden", - "All Rooms": "Alle Ruimtes", + "All Rooms": "Alle kamers", "You cannot delete this message. (%(code)s)": "Je kunt dit bericht niet verwijderen. (%(code)s)", "Thursday": "Donderdag", "Forward Message": "Bericht doorsturen", @@ -1107,7 +1107,7 @@ "Uploaded on %(date)s by %(user)s": "Geüpload op %(date)s door %(user)s", "Messages in group chats": "Berichten in groepsgesprekken", "Yesterday": "Gisteren", - "Error encountered (%(errorDetail)s).": "Fout ondervonden (%(errorDetail)s).", + "Error encountered (%(errorDetail)s).": "Er is een fout opgetreden (%(errorDetail)s).", "Login": "Aanmelden", "Low Priority": "Lage prioriteit", "Unable to fetch notification target list": "Kan de bestemmingslijst voor meldingen niet ophalen", @@ -1131,7 +1131,7 @@ "Thank you!": "Bedankt!", "Collapse panel": "Paneel inklappen", "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!": "Met uw huidige browser kan de applicatie er volledig incorrect uitzien. Tevens is het mogelijk dat niet alle functies naar behoren werken. U kunt doorgaan als u het toch wil proberen, maar bij problemen bent u volledig op uzelf aangewezen!", - "Checking for an update...": "Aan het kijken voor een update...", + "Checking for an update...": "Bezig met controleren op updates…", "There are advanced notifications which are not shown here": "Er zijn geavanceerde meldingen die hier niet getoond worden", "Logs sent": "Logs verstuurd", "GitHub issue link:": "GitHub opgave link:", @@ -1149,15 +1149,15 @@ "Always show encryption icons": "Versleutelingspictogrammen altijd tonen", "Send analytics data": "Statistische gegevens (analytics) versturen", "Enable widget screenshots on supported widgets": "Widget-schermafbeeldingen inschakelen op ondersteunde widgets", - "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Het is nog niet mogelijk een bestand als antwoord te zenden; het zal dus als normaal bericht worden verstuurd.", - "Unable to reply": "Niet mogelijk te reageren", - "At this time it is not possible to reply with an emote.": "Het is nog niet mogelijk met een emoji te reageren.", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "Het is nog niet mogelijk een bestand als antwoord te versturen; het zal dus als normaal bericht worden verstuurd.", + "Unable to reply": "Kan niet reageren", + "At this time it is not possible to reply with an emote.": "Het is nog niet mogelijk met een emoticon te reageren.", "To notify everyone in the room, you must be a": "Om iedereen in de ruimte te notificeren moet je het volgende zijn:", - "Muted Users": "Gedempte Gebruikers", - "Please help improve Riot.im by sending anonymous usage data. This will use a cookie (please see our Cookie Policy).": "Help Riot.im te verbeteren door het versturen van anonieme gebruiksgegevens. Dit zal een cookie gebruiken (zie ons Cookiebeleid).", - "Please help improve Riot.im by sending anonymous usage data. This will use a cookie.": "Help Riot.im te verbeteren door het versturen van anonieme gebruiksgegevens. Dit zal een cookie gebruiken.", + "Muted Users": "Gedempte gebruikers", + "Please help improve Riot.im by sending anonymous usage data. This will use a cookie (please see our Cookie Policy).": "Help Riot.im te verbeteren door anonieme gebruiksgegevens te versturen. Dit zal een cookie gebruiken (bekijk hiervoor ons cookiebeleid).", + "Please help improve Riot.im by sending anonymous usage data. This will use a cookie.": "Help Riot.im te verbeteren door anonieme gebruiksgegevens te versturen. Dit zal een cookie gebruiken.", "Yes, I want to help!": "Ja, ik wil helpen!", - "Warning: This widget might use cookies.": "Waarschuwing: deze widget gebruikt misschien cookies.", + "Warning: This widget might use cookies.": "Waarschuwing: deze widget gebruikt mogelijk cookies.", "Popout widget": "Widget in nieuw venster openen", "Picture": "Afbeelding", "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Kan de gebeurtenis waarop gereageerd was niet laden. Wellicht bestaat die niet, of heb je geen toestemming die te bekijken.", @@ -1188,30 +1188,30 @@ "Permission Required": "Toestemming vereist", "You do not have permission to start a conference call in this room": "U heeft geen toestemming om in deze kamer een vergadergesprek te starten", "Show empty room list headings": "Lege koppen in ruimtelijst weergeven", - "This event could not be displayed": "Deze gebeurtenis kon niet worden weergegeven", + "This event could not be displayed": "Deze gebeurtenis kon niet weergegeven worden", "Encrypting": "Versleutelen", "Encrypted, not sent": "Versleuteld, niet verstuurd", - "Demote yourself?": "Jezelf degraderen?", + "Demote yourself?": "Uzelf degraderen?", "Demote": "Degraderen", - "Share Link to User": "Link met gebruiker delen", + "Share Link to User": "Koppeling met gebruiker delen", "deleted": "verwijderd", "underlined": "onderstreept", - "inline-code": "code in de regel", + "inline-code": "code", "block-quote": "citaat", - "bulleted-list": "lijst met opsommingstekens", + "bulleted-list": "opsomming", "numbered-list": "genummerde lijst", - "Share room": "Ruimte delen", - "System Alerts": "Systeemwaarschuwingen", + "Share room": "Kamer delen", + "System Alerts": "Systeemmeldingen", "You have no historical rooms": "Je hebt geen historische ruimtes", - "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 versleutelde ruimten, zoals deze, zijn URL-voorvertoningen standaard uitgeschakeld om te voorkomen dat jouw thuisserver (waar de voorvertoningen worden gemaakt) informatie kan verzamelen over de links die je hier ziet.", - "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.": "Als iemand een URL in een bericht zet, kan er een URL-voorvertoning weergegeven worden met meer informatie over de link, zoals de titel, omschrijving en een afbeelding van de website.", + "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 versleutelde kamers zoals deze zijn URL-voorvertoningen standaard uitgeschakeld, om te voorkomen dat uw thuisserver (waar de voorvertoningen worden gemaakt) informatie kan verzamelen over de koppelingen die u hier ziet.", + "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.": "Als iemand een URL in een bericht invoegt, kan er een URL-voorvertoning weergegeven worden met meer informatie over de koppeling, zoals de titel, omschrijving en een afbeelding van de website.", "The email field must not be blank.": "Het e-mailveld mag niet leeg zijn.", "The user name field must not be blank.": "Het gebruikersnaamveld mag niet leeg zijn.", "The phone number field must not be blank.": "Het telefoonnummerveld mag niet leeg zijn.", "The password field must not be blank.": "Het wachtwoordveld mag niet leeg zijn.", "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.": "Deze thuisserver heeft zijn maandelijkse gebruikerslimiet bereikt. Neem contact op met de beheerder van je thuisserver om de dienst weer te kunnen gebruiken.", "Failed to remove widget": "Widget kon niet worden verwijderd", - "An error ocurred whilst trying to remove the widget from the room": "Er is een fout opgetreden tijdens het verwijderen van de widget uit deze ruimte", + "An error ocurred whilst trying to remove the widget from the room": "Er is een fout opgetreden bij het verwijderen van de widget uit deze kamer", "Share Room": "Ruimte delen", "Link to most recent message": "Link naar meest recente bericht", "Share User": "Gebruiker delen", @@ -1487,5 +1487,56 @@ "Kick users": "Gebruikers uit de kamer verwijderen", "Ban users": "Gebruikers verbannen", "Remove messages": "Berichten verwijderen", - "Notify everyone": "Iedereen melden" + "Notify everyone": "Iedereen melden", + "Send %(eventType)s events": "%(eventType)s-gebeurtenissen versturen", + "Roles & Permissions": "Rollen & toestemmingen", + "Select the roles required to change various parts of the room": "Selecteer de rollen vereist om verschillende delen van de kamer te wijzigen", + "Enable encryption?": "Versleuteling inschakelen?", + "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.": "Van zodra versleuteling voor een kamer is ingeschakeld, kan dit niet meer worden uitgeschakeld. Berichten die in een versleutelde kamer worden verstuurd worden niet gezien door de server, enkel door de deelnemers van de kamer. Door versleuteling in te schakelen kunnen veel robots en overbruggingen niet correct functioneren. Lees meer over versleuteling.", + "To link to this room, please add an alias.": "Voeg een alias toe om naar deze kamer te verwijzen.", + "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Wijzigingen aan wie de geschiedenis kan lezen zijn enkel van toepassing op toekomstige berichten in deze kamer. De zichtbaarheid van de bestaande geschiedenis blijft ongewijzigd.", + "Encryption": "Versleuteling", + "Once enabled, encryption cannot be disabled.": "Eenmaal ingeschakeld kan versleuteling niet meer worden uitgeschakeld.", + "Encrypted": "Versleuteld", + "Some devices for this user are not trusted": "Er worden enkele apparaten van deze gebruiker niet vertrouwd", + "Some devices in this encrypted room are not trusted": "Er worden enkele apparaten in deze versleutelde kamer niet vertrouwd", + "All devices for this user are trusted": "Alle apparaten van deze gebruiker worden vertrouwd", + "All devices in this encrypted room are trusted": "Alle apparaten in deze versleutelde kamer worden vertrouwd", + "The following files cannot be uploaded:": "De volgende bestanden kunnen niet geüpload worden:", + "This room has been replaced and is no longer active.": "Deze kamer is vervangen en is niet langer actief.", + "The conversation continues here.": "Het gesprek gaat hier verder.", + "Joining room...": "Toetreden tot kamer…", + "Use Key Backup": "Sleutelback-up gebruiken", + "Never lose encrypted messages": "Verlies nooit uw versleutelde berichten", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "De berichten in deze kamer worden beveiligd met eind-tot-eind-versleuteling. Enkel de ontvanger(s) en u hebben de sleutels om deze berichten te lezen.", + "Securely back up your keys to avoid losing them. Learn more.": "Maak een veilige back-up van uw sleutels om ze niet te verliezen. Lees meer.", + "Not now": "Nu niet", + "Don't ask me again": "Vraag het me niet opnieuw", + "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "Deze kamer maakt gebruik van een onstabiele kamerversie. Als u dit niet verwacht, opwaardeer dan de kamer.", + "Click here to upgrade to the latest room version.": "Klik hier om op te waarderen naar de laatste kamerversie.", + "There is a known vulnerability affecting this room.": "Deze kamer bevat een bekende kwetsbaarheid.", + "This room version is vulnerable to malicious modification of room state.": "De versie van deze kamer is kwetsbaar voor kwaadwillige wijzigingen aan de kamerstatus.", + "Click here to upgrade to the latest room version and ensure room integrity is protected.": "Klik hier om op te waarderen naar de laatste kamerversie en te verzekeren dat de kamerintegriteit beschermd is.", + "Only room administrators will see this warning": "Enkel kamerbeheerders zullen deze waarschuwing zien", + "Add some now": "Voeg er nu een paar toe", + "Error updating main address": "Fout bij bijwerken van hoofdadres", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Er is een fout opgetreden bij het bijwerken van het hoofdadres van de kamer. Dit wordt mogelijk niet toegestaan door de server, of er is een tijdelijk probleem opgetreden.", + "Error creating alias": "Fout bij aanmaken van alias", + "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "Er is een fout opgetreden bij het aanmaken van die alias. Dit wordt mogelijk niet toegestaan door de server, of er is een tijdelijk probleem opgetreden.", + "Error removing alias": "Fout bij verwijderen van alias", + "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Er is een fout opgetreden bij het verwijderen van die alias. Deze bestaat mogelijk niet meer, of er is een tijdelijke fout opgetreden.", + "Main address": "Hoofdadres", + "Error updating flair": "Fout bij bijwerken van badge", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Er is een fout opgetreden bij het bijwerken van de badge voor deze kamer. De server ondersteunt dit mogelijk niet, of er is een tijdelijke fout opgetreden.", + "Room avatar": "Kameravatar", + "Upload room avatar": "Kameravatar uploaden", + "No room avatar": "Geen kameravatar", + "Room Name": "Kamernaam", + "Room Topic": "Kameronderwerp", + "This room is a continuation of another conversation.": "Deze kamer is een voortzetting van een ander gesprek.", + "Click here to see older messages.": "Klik hier om oudere berichten te bekijken.", + "Failed to load group members": "Laden van groepsleden is mislukt", + "Please contact your service administrator to get this limit increased.": "Gelieve contact op te nemen met uw dienstbeheerder om deze limiet te verhogen.", + "This homeserver has hit its Monthly Active User limit so some users will not be able to log in.": "Deze thuisserver heeft zijn limiet voor maandelijks actieve gebruikers bereikt, waardoor sommige gebruikers zich niet zullen kunnen aanmelden.", + "This homeserver has exceeded one of its resource limits so some users will not be able to log in.": "Deze thuisserver heeft één van zijn systeembronlimieten overschreden, waardoor sommige gebruikers zich niet zullen kunnen aanmelden." } From 1614bb66e87a6a95ed12ec45827919ec459a19d6 Mon Sep 17 00:00:00 2001 From: Joachim Nielandt Date: Thu, 28 Mar 2019 21:27:03 +0000 Subject: [PATCH 151/481] Translated using Weblate (Dutch) Currently translated at 87.2% (1360 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index fbdd1a59b7..5bc6d7c9dc 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -560,7 +560,7 @@ "Device Name": "Apparaatnaam", "Device key": "Apparaatsleutel", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Komen ze overeen? Zo ja, druk dan op de knop 'verifiëren' hieronder. Zo neen, druk dan liever op de knop 'blokkeren', want dan onderschept iemand berichten naar dit apparaat.", - "Blacklist": "Blokkeren", + "Blacklist": "Op zwarte lijst zetten", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit je ongecontroleerde apparaten uit; om berichten naar deze apparaten te versturen moet je ze controleren.", "Unblacklist": "Deblokkeren", "In future this verification process will be more sophisticated.": "In de toekomst zal dit verificatie proces meer geraffineerd zijn.", From fdc259926d5c8e6c9a4fda67c1eb30d8029a97e3 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 21:27:14 +0000 Subject: [PATCH 152/481] Translated using Weblate (Dutch) Currently translated at 87.8% (1370 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 154 +++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 72 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 5bc6d7c9dc..c7a2e4a72d 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -93,9 +93,9 @@ "Operation failed": "Handeling is mislukt", "powered by Matrix": "mogelijk gemaakt door Matrix", "Remove": "Verwijderen", - "Room directory": "Ruimtelijst", + "Room directory": "Kamercatalogus", "Settings": "Instellingen", - "Start chat": "Gesprek starten", + "Start chat": "Gesprek beginnen", "unknown error code": "onbekende foutcode", "Search": "Zoeken", "OK": "Oké", @@ -266,7 +266,7 @@ "Hide read receipts": "Leesbewijzen verbergen", "Hide Text Formatting Toolbar": "Tekstopmaakwerkbalk verbergen", "Historical": "Historisch", - "Home": "Home", + "Home": "Thuis", "Homeserver is": "Thuisserver is", "Identity Server is": "Identiteitsserver is", "I have verified my email address": "Ik heb mijn e-mailadres geverifieerd", @@ -560,7 +560,7 @@ "Device Name": "Apparaatnaam", "Device key": "Apparaatsleutel", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Komen ze overeen? Zo ja, druk dan op de knop 'verifiëren' hieronder. Zo neen, druk dan liever op de knop 'blokkeren', want dan onderschept iemand berichten naar dit apparaat.", - "Blacklist": "Op zwarte lijst zetten", + "Blacklist": "Blokkeren", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit je ongecontroleerde apparaten uit; om berichten naar deze apparaten te versturen moet je ze controleren.", "Unblacklist": "Deblokkeren", "In future this verification process will be more sophisticated.": "In de toekomst zal dit verificatie proces meer geraffineerd zijn.", @@ -572,10 +572,10 @@ "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" bevat apparaten die je nog niet eerder hebt gezien.", "Unknown devices": "Onbekende apparaten", "Unknown Address": "Onbekend adres", - "Unverify": "Ontverifïeren", - "Verify...": "Verifiëren...", - "ex. @bob:example.com": "bijv. @bob:voorbeeld.com", - "Add User": "Gebruiker Toevoegen", + "Unverify": "Ontverifiëren", + "Verify...": "Verifiëren…", + "ex. @bob:example.com": "bv. @jan:voorbeeld.com", + "Add User": "Gebruiker toevoegen", "This Home Server would like to make sure you are not a robot": "Deze thuisserver wil er zeker van zijn dat je geen robot bent", "Sign in with CAS": "Inloggen met CAS", "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.": "Je kan de alternatieve-serverinstellingen gebruiken om bij andere Matrix-servers in te loggen door een andere thuisserver-URL te specificeren.", @@ -816,66 +816,66 @@ "You're not currently a member of any communities.": "U bent momenteel geen lid van een gemeenschap.", "Minimize apps": "Apps minimaliseren", "Communities": "Gemeenschappen", - "%(nameList)s %(transitionList)s": "%(nameList)s%(transitionList)s", - "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s traden %(count)s keer toe", + "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", + "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s zijn %(count)s keer toegetreden", "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)s zijn toegetreden", - "%(oneUser)sjoined %(count)s times|other": "%(oneUser)s trad %(count)s keer toe", + "%(oneUser)sjoined %(count)s times|other": "%(oneUser)s is %(count)s keer toegetreden", "%(oneUser)sjoined %(count)s times|one": "%(oneUser)s is toegetreden", - "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)s gingen %(count)s keer weg", - "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s gingen weg", - "%(oneUser)sleft %(count)s times|other": "%(oneUser)s ging %(count)s keer weg", - "%(oneUser)sleft %(count)s times|one": "%(oneUser)s ging weg", - "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s traden toe en gingen weer weg voor %(count)s keer", - "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s traden toe en gingen weer weg", - "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s trad toe en ging weer weg voor %(count)s keer", - "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s trad toe en ging weer weg", - "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s ging weg en trad weer toe voor %(count)s keer", - "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)s gingen weg en kwamen weer terug", - "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)s ging weg en kwam weer terug voor %(count)s keer", - "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s ging weg en kwam weer terug", - "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s wezen hun uitnodiging af voor %(count)s keer", - "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s wezen hun uitnodiging af", - "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s wees %(count)s keer zijn of haar uitnodiging af", - "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s wees zijn of haar uitnodiging af", - "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "De uitnodigingen naar %(severalUsers)s zijn %(count)s keer ingetrokken", - "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "De uitnodigingen voor %(severalUsers)s zijn ingetrokken", + "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)s is %(count)s keer weggegaan", + "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s is weggegaan", + "%(oneUser)sleft %(count)s times|other": "%(oneUser)s is %(count)s keer weggegaan", + "%(oneUser)sleft %(count)s times|one": "%(oneUser)s is weggegaan", + "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s zijn %(count)s keer toegetreden en weggegaan", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s zijn toegetreden en weggegaan", + "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s is %(count)s keer toegetreden en weggegaan", + "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s is toegetreden en weggegaan", + "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s zijn %(count)s keer weggegaan en weer toegetreden", + "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)s zijn weggegaan en weer toegetreden", + "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)s is %(count)s keer weggegaan en weer toegetreden", + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s is weggegaan en weer toegetreden", + "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s hebben hun uitnodigingen %(count)s keer afgewezen", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s hebben hun uitnodigingen afgewezen", + "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s heeft zijn/haar uitnodiging %(count)s keer afgewezen", + "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s heeft zijn/haar uitnodiging afgewezen", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "De uitnodigingen van %(severalUsers)s zijn %(count)s keer ingetrokken", + "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "De uitnodigingen van %(severalUsers)s zijn ingetrokken", "%(oneUser)shad their invitation withdrawn %(count)s times|other": "De uitnodiging van %(oneUser)s is %(count)s keer ingetrokken", "%(oneUser)shad their invitation withdrawn %(count)s times|one": "De uitnodiging van %(oneUser)s is ingetrokken", - "were invited %(count)s times|other": "was %(count)s keer uitgenodigd", - "were invited %(count)s times|one": "was uitgenodigd", - "was invited %(count)s times|other": "was %(count)s keer uitgenodigd", - "was invited %(count)s times|one": "was uitgenodigd", - "were banned %(count)s times|other": "was %(count)s keer verbannen", - "were banned %(count)s times|one": "was verbannen", - "was banned %(count)s times|other": "was %(count)s keer verbannen", - "was banned %(count)s times|one": "was verbannen", - "were unbanned %(count)s times|other": "zijn voor %(count)s keer ontbannen", - "was unbanned %(count)s times|other": "was %(count)s keer ontbannen", - "was unbanned %(count)s times|one": "was ontbannen", - "were kicked %(count)s times|other": "werden er %(count)s keer uitgezet", - "were kicked %(count)s times|one": "werden er uit gezet", - "was kicked %(count)s times|other": "was er %(count)s keer uitgezet", - "was kicked %(count)s times|one": "was er uit gezet", - "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s veranderden hun naam %(count)s keer", - "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s veranderden hun naam", - "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s veranderde %(count)s keer van naam", - "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s veranderde van naam", - "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s veranderden hun avatar %(count)s keer", - "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s veranderden hun avatar", - "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)s veranderde %(count)s keer van avatar", - "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s veranderde van avatar", - "%(items)s and %(count)s others|other": "%(items)s en %(count)s anderen", - "%(items)s and %(count)s others|one": "%(items)s en één andere", - "collapse": "inklappen", - "expand": "openklappen", + "were invited %(count)s times|other": "zijn %(count)s keer uitgenodigd", + "were invited %(count)s times|one": "zijn uitgenodigd", + "was invited %(count)s times|other": "is %(count)s keer uitgenodigd", + "was invited %(count)s times|one": "is uitgenodigd", + "were banned %(count)s times|other": "zijn %(count)s keer verbannen", + "were banned %(count)s times|one": "zijn verbannen", + "was banned %(count)s times|other": "is %(count)s keer verbannen", + "was banned %(count)s times|one": "is verbannen", + "were unbanned %(count)s times|other": "zijn %(count)s keer ontbannen", + "was unbanned %(count)s times|other": "is %(count)s keer ontbannen", + "was unbanned %(count)s times|one": "is ontbannen", + "were kicked %(count)s times|other": "zijn %(count)s keer uit de kamer gezet", + "were kicked %(count)s times|one": "zijn uit de kamer gezet", + "was kicked %(count)s times|other": "is %(count)s keer uit de kamer gezet", + "was kicked %(count)s times|one": "is uit de kamer gezet", + "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s hebben hun naam %(count)s keer gewijzigd", + "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s hebben hun naam gewijzigd", + "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s heeft zijn/haar naam %(count)s keer gewijzigd", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s heeft zijn/haar naam gewijzigd", + "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s hebben hun avatar %(count)s keer gewijzigd", + "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s hebben hun avatar gewijzigd", + "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)s heeft zijn/haar avatar %(count)s keer gewijzigd", + "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s heeft zijn/haar avatar gewijzigd", + "%(items)s and %(count)s others|other": "%(items)s en %(count)s andere", + "%(items)s and %(count)s others|one": "%(items)s en één ander", + "collapse": "dichtvouwen", + "expand": "uitvouwen", "Custom of %(powerLevel)s": "Aangepast rank van %(powerLevel)s", "Quote": "Citeren", - "And %(count)s more...|other": "En %(count)s meer...", - "Matrix ID": "Matrix ID", - "Matrix Room ID": "Matrix Ruimte ID", + "And %(count)s more...|other": "En %(count)s meer…", + "Matrix ID": "Matrix-ID", + "Matrix Room ID": "Matrix-kamer-ID", "email address": "e-mailadres", "Try using one of the following valid address types: %(validTypesList)s.": "Probeer één van de volgende geldige adrestypes: %(validTypesList)s.", - "You have entered an invalid address.": "Je hebt een ongeldig adres ingevoerd.", + "You have entered an invalid address.": "U heeft een ongeldig adres ingevoerd.", "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Een gemeenschaps-ID moet uit enkel de karakters a-z, 0-9, of '=_-./' bestaan", "Community IDs cannot be empty.": "Een gemeenschaps-ID kan niet leeg zijn.", "Something went wrong whilst creating your community": "Er is iets fout gegaan tijdens het aanmaken van je gemeenschap", @@ -955,7 +955,7 @@ "Your identity server's URL": "De URL van uw identiteitsserver", "In reply to ": "Als antwoord op ", "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", - "were unbanned %(count)s times|one": "waren ontbant", + "were unbanned %(count)s times|one": "zijn ontbannen", "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s heeft zijn/haar weergavenaam gewijzigd naar %(displayName)s.", "Disable Community Filter Panel": "Gemeenschapsfilterpaneel uitzetten", "Your key share request has been sent - please check your other devices for key share requests.": "Uw sleuteldeelverzoek is verstuurd - controleer uw andere apparaten voor sleuteldeelverzoeken.", @@ -1008,7 +1008,7 @@ "On": "Aan", "%(count)s Members|other": "%(count)s Deelnemers", "Filter room names": "Filter ruimtenamen", - "Changelog": "Logboek van wijzigingen", + "Changelog": "Wijzigingslogboek", "Waiting for response from server": "Wachten op antwoord van de server", "Send Custom Event": "Verzend aangepast evenement", "Advanced notification settings": "Geavanceerde meldingsinstellingen", @@ -1017,7 +1017,7 @@ "Forget": "Vergeten", "#example": "#voorbeeld", "Hide panel": "Paneel verbergen", - "You cannot delete this image. (%(code)s)": "Je kunt deze afbeelding niet verwijderen. (%(code)s)", + "You cannot delete this image. (%(code)s)": "U kunt deze afbeelding niet verwijderen. (%(code)s)", "Cancel Sending": "Versturen annuleren", "This Room": "Deze kamer", "The Home Server may be too old to support third party networks": "De thuisserver is misschien te oud om netwerken van derde partijen te ondersteunen", @@ -1104,7 +1104,7 @@ "Unable to join network": "Kon niet toetreden tot dit netwerk", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "U heeft ze mogelijk ingesteld in een andere cliënt dan Riot. U kunt ze niet aanpassen in Riot, maar ze zijn wel actief", "Sorry, your browser is not able to run Riot.": "Sorry, uw browser werkt niet met Riot.", - "Uploaded on %(date)s by %(user)s": "Geüpload op %(date)s door %(user)s", + "Uploaded on %(date)s by %(user)s": "Geüpload door %(user)s op %(date)s", "Messages in group chats": "Berichten in groepsgesprekken", "Yesterday": "Gisteren", "Error encountered (%(errorDetail)s).": "Er is een fout opgetreden (%(errorDetail)s).", @@ -1120,7 +1120,7 @@ "You can now return to your account after signing out, and sign in on other devices.": "U kunt nu terugkeren naar uw account nadat u bent afgemeld, en u aanmelden op andere apparaten.", "Enable email notifications": "E-mailmeldingen inschakelen", "Event Type": "Event-type", - "Download this file": "Download dit bestand", + "Download this file": "Dit bestand downloaden", "Pin Message": "Bericht vastpinnen", "Failed to change settings": "Wijzigen van instellingen mislukt", "View Community": "Gemeenschap Weergeven", @@ -1133,12 +1133,12 @@ "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!": "Met uw huidige browser kan de applicatie er volledig incorrect uitzien. Tevens is het mogelijk dat niet alle functies naar behoren werken. U kunt doorgaan als u het toch wil proberen, maar bij problemen bent u volledig op uzelf aangewezen!", "Checking for an update...": "Bezig met controleren op updates…", "There are advanced notifications which are not shown here": "Er zijn geavanceerde meldingen die hier niet getoond worden", - "Logs sent": "Logs verstuurd", + "Logs sent": "Logboeken verstuurd", "GitHub issue link:": "GitHub opgave link:", - "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.": "Debug logs bevatten applicatie-gebruik data inclusief je gebruikersnaam, de ID's of namen van de ruimtes en groepen die je hebt bezocht en de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", - "Failed to send logs: ": "Het is niet gelukt de logs te versturen: ", - "Notes:": "Constateringen:", - "Preparing to send logs": "Logs voorbereiden voor verzending", + "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.": "Foutopsporingslogboeken bevatten gebruiksgegevens over de toepassing, inclusief uw gebruikersnaam, de ID’s of aliassen van de kamers en groepen die u heeft bezocht, evenals de gebruikersnamen van andere gebruikers. Ze bevatten geen berichten.", + "Failed to send logs: ": "Versturen van logboeken mislukt: ", + "Notes:": "Notities:", + "Preparing to send logs": "Logboeken worden voorbereid voor verzending", "e.g. %(exampleValue)s": "bv. %(exampleValue)s", "Every page you use in the app": "Iedere bladzijde die u in de toepassing gebruikt", "e.g. ": "bv. ", @@ -1160,7 +1160,7 @@ "Warning: This widget might use cookies.": "Waarschuwing: deze widget gebruikt mogelijk cookies.", "Popout widget": "Widget in nieuw venster openen", "Picture": "Afbeelding", - "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Kan de gebeurtenis waarop gereageerd was niet laden. Wellicht bestaat die niet, of heb je geen toestemming die te bekijken.", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Kan de gebeurtenis waarop gereageerd was niet laden. Wellicht bestaat die niet, of heeft u geen toestemming die te bekijken.", "Riot bugs are tracked on GitHub: create a GitHub issue.": "Riot fouten worden bijgehouden op GitHub: maak een GitHub melding.", "Failed to indicate account erasure": "Niet gelukt om de accountverwijdering aan te geven", "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Dit zal je account voorgoed onbruikbaar maken. Je zult niet meer in kunnen loggen en niemand anders zal met dezelfde gebruikers ID kunnen registreren. Hierdoor zal je account alle ruimten waarin het deelneemt verlaten en worden de accountgegevens van de identiteitsserver verwijderd. Deze actie is onomkeerbaar.", @@ -1538,5 +1538,15 @@ "Failed to load group members": "Laden van groepsleden is mislukt", "Please contact your service administrator to get this limit increased.": "Gelieve contact op te nemen met uw dienstbeheerder om deze limiet te verhogen.", "This homeserver has hit its Monthly Active User limit so some users will not be able to log in.": "Deze thuisserver heeft zijn limiet voor maandelijks actieve gebruikers bereikt, waardoor sommige gebruikers zich niet zullen kunnen aanmelden.", - "This homeserver has exceeded one of its resource limits so some users will not be able to log in.": "Deze thuisserver heeft één van zijn systeembronlimieten overschreden, waardoor sommige gebruikers zich niet zullen kunnen aanmelden." + "This homeserver has exceeded one of its resource limits so some users will not be able to log in.": "Deze thuisserver heeft één van zijn systeembronlimieten overschreden, waardoor sommige gebruikers zich niet zullen kunnen aanmelden.", + "Join": "Deelnemen", + "Power level": "Machtsniveau", + "That doesn't look like a valid email address": "Dit is geen geldig e-mailadres", + "The following users may not exist": "Volgende gebruikers bestaan mogelijk niet", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Kan geen profielen voor de Matrix-ID’s hieronder vinden - wilt u ze toch uitnodigen?", + "Invite anyway and never warn me again": "Alsnog uitnodigen en mij nooit meer waarschuwen", + "Invite anyway": "Alsnog uitnodigen", + "Before submitting logs, you must create a GitHub issue to describe your problem.": "Vooraleer u logboeken indient, dient u een melding te openen op GitHub waarin u uw probleem beschrijft.", + "What GitHub issue are these logs for?": "Voor welke melding op GitHub zijn deze logboeken?", + "Unable to load commit detail: %(msg)s": "Kan commitdetail niet laden: %(msg)s" } From 0bf8db35be46caae844e07b8c41d68a107b2c5b9 Mon Sep 17 00:00:00 2001 From: Gary Date: Thu, 28 Mar 2019 21:55:32 +0000 Subject: [PATCH 153/481] Translated using Weblate (Dutch) Currently translated at 87.8% (1370 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index c7a2e4a72d..4da2ead2a7 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -175,7 +175,7 @@ "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", - "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik een bestaand", + "Create a new chat or reuse an existing one": "Start een nieuwe chat of heropen een bestaande", "Create Room": "Maak een ruimte aan", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen opdracht", From 1669984f92ffa696b41c90a5f19f8a1f3a333507 Mon Sep 17 00:00:00 2001 From: i47320673 Date: Thu, 21 Mar 2019 19:25:09 +0000 Subject: [PATCH 154/481] Translated using Weblate (Russian) Currently translated at 88.0% (1373 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/ru/ --- src/i18n/strings/ru.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 59abe13dc2..2cf2fe90c6 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -1578,5 +1578,21 @@ "For help with using Riot, click here.": "Для получения помощи по использованию Riot, нажмите здесь.", "For help with using Riot, click here or start a chat with our bot using the button below.": "Для получения помощи по использованию Riot, нажмите здесь или начните чат с нашим ботом, используюя кнопку ниже.", "Bug reporting": "Сообщить об ошибке", - "Open Devtools": "Открыть инструменты разработчика" + "Open Devtools": "Открыть инструменты разработчика", + "Change room avatar": "Изменить аватар комнаты", + "Change main address for the room": "Изменить основной адрес комнаты", + "Change permissions": "Изменить разрешения", + "Default role": "Роль по умолчанию", + "Send messages": "Отправить сообщения", + "Change settings": "Изменить настройки", + "Remove messages": "Удалить сообщения", + "Notify everyone": "Уведомить всех", + "Enable encryption?": "Разрешить шифрование?", + "Not now": "Не сейчас", + "Error updating main address": "Ошибка обновления основного адреса", + "Incompatible local cache": "Несовместимый локальный кэш", + "You'll lose access to your encrypted messages": "Вы потеряете доступ к вашим шифрованным сообщениям", + "Are you sure you want to sign out?": "Вы уверены, что хотите выйти?", + "Room Settings - %(roomName)s": "Настройки комнаты - %(roomName)s", + "A username can only contain lower case letters, numbers and '=_-./'": "Имя пользователя может содержать только буквы нижнего регистра, цифры и знаки '=_-./'" } From aff5e1f50d2e633da28c687101fe36870da5afe5 Mon Sep 17 00:00:00 2001 From: sergio Date: Tue, 26 Mar 2019 20:31:06 +0000 Subject: [PATCH 155/481] Translated using Weblate (Russian) Currently translated at 88.0% (1373 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/ru/ --- src/i18n/strings/ru.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 2cf2fe90c6..8f155a35f9 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -1594,5 +1594,6 @@ "You'll lose access to your encrypted messages": "Вы потеряете доступ к вашим шифрованным сообщениям", "Are you sure you want to sign out?": "Вы уверены, что хотите выйти?", "Room Settings - %(roomName)s": "Настройки комнаты - %(roomName)s", - "A username can only contain lower case letters, numbers and '=_-./'": "Имя пользователя может содержать только буквы нижнего регистра, цифры и знаки '=_-./'" + "A username can only contain lower case letters, numbers and '=_-./'": "Имя пользователя может содержать только буквы нижнего регистра, цифры и знаки '=_-./'", + "Composer": "Редактор" } From 60aead1dd50e5a694de8796574e84d3ee565f8cf Mon Sep 17 00:00:00 2001 From: Vladimir Hodakov Date: Thu, 28 Mar 2019 19:10:22 +0000 Subject: [PATCH 156/481] Translated using Weblate (Russian) Currently translated at 88.0% (1373 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/ru/ --- src/i18n/strings/ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 8f155a35f9..38a7fbf115 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -165,7 +165,7 @@ "%(displayName)s is typing": "%(displayName)s печатает", "%(targetName)s joined the room.": "%(targetName)s вошел(-ла) в комнату.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s выгнал(а) %(targetName)s.", - "%(targetName)s left the room.": "%(targetName)s покинул(а) комнату.", + "%(targetName)s left the room.": "Комнату покидает %(targetName)s.", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s сделал(а) историю разговора видимой для всех собеседников с момента их приглашения.", "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s сделал(а) историю разговора видимой для всех собеседников с момента их входа в комнату.", "%(senderName)s made future room history visible to all room members.": "%(senderName)s сделал(а) историю разговора видимой для всех собеседников.", From 99dc2c4738a046158240b2a79ff4feefb849ad3f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Mar 2019 20:38:15 -0600 Subject: [PATCH 157/481] Add MemberInfo for 3pid invites and support revoking those invites Fixes https://github.com/vector-im/riot-web/issues/625 Fixes https://github.com/vector-im/riot-web/issues/6411 Fixes https://github.com/vector-im/riot-web/issues/5490 --- src/TextForEvent.js | 9 ++ src/components/structures/RightPanel.js | 5 + .../views/right_panel/RoomHeaderButtons.js | 7 + src/components/views/rooms/MemberList.js | 8 + .../views/rooms/ThirdPartyMemberInfo.js | 142 ++++++++++++++++++ src/i18n/strings/en_EN.json | 5 + 6 files changed, 176 insertions(+) create mode 100644 src/components/views/rooms/ThirdPartyMemberInfo.js diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 030c346ccc..05d83d740a 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -366,6 +366,15 @@ function textForCallInviteEvent(event) { function textForThreePidInviteEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); + + if (!event.getContent().display_name) { + const targetDisplayName = event.getPrevContent().display_name || _t("Someone"); + return _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { + senderName, + targetDisplayName, + }); + } + return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', { senderName, targetDisplayName: event.getContent().display_name, diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 5c745b04cc..74820c804a 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -50,6 +50,7 @@ export default class RightPanel extends React.Component { FilePanel: 'FilePanel', NotificationPanel: 'NotificationPanel', RoomMemberInfo: 'RoomMemberInfo', + Room3pidMemberInfo: 'Room3pidMemberInfo', GroupMemberInfo: 'GroupMemberInfo', }); @@ -155,6 +156,7 @@ export default class RightPanel extends React.Component { groupRoomId: payload.groupRoomId, groupId: payload.groupId, member: payload.member, + event: payload.event, }); } } @@ -162,6 +164,7 @@ export default class RightPanel extends React.Component { render() { const MemberList = sdk.getComponent('rooms.MemberList'); const MemberInfo = sdk.getComponent('rooms.MemberInfo'); + const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo'); const NotificationPanel = sdk.getComponent('structures.NotificationPanel'); const FilePanel = sdk.getComponent('structures.FilePanel'); @@ -180,6 +183,8 @@ export default class RightPanel extends React.Component { panel = ; } else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) { panel = ; + } else if (this.state.phase === RightPanel.Phase.Room3pidMemberInfo) { + panel = ; } else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) { panel = { if (query) { @@ -408,6 +415,7 @@ module.exports = React.createClass({ return this._onPending3pidInviteClick(e)} />; })); } diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.js b/src/components/views/rooms/ThirdPartyMemberInfo.js new file mode 100644 index 0000000000..3fe8382251 --- /dev/null +++ b/src/components/views/rooms/ThirdPartyMemberInfo.js @@ -0,0 +1,142 @@ +/* +Copyright 2019 New Vector 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 MatrixClientPeg from "../../../MatrixClientPeg"; +import {MatrixEvent} from "matrix-js-sdk"; +import {_t} from "../../../languageHandler"; +import dis from "../../../dispatcher"; +import sdk from "../../../index"; +import Modal from "../../../Modal"; + +export default class ThirdPartyMemberInfo extends React.Component { + static propTypes = { + event: PropTypes.instanceOf(MatrixEvent).isRequired, + }; + + constructor(props) { + super(props); + + const room = MatrixClientPeg.get().getRoom(this.props.event.getRoomId()); + const me = room.getMember(MatrixClientPeg.get().getUserId()); + const powerLevels = room.currentState.getStateEvents("m.room.power_levels", ""); + + let kickLevel = powerLevels ? powerLevels.getContent().kick : 50; + if (typeof(kickLevel) !== 'number') kickLevel = 50; + + const sender = room.getMember(this.props.event.getSender()); + + this.state = { + stateKey: this.props.event.getStateKey(), + roomId: this.props.event.getRoomId(), + displayName: this.props.event.getContent().display_name, + invited: true, + canKick: me ? me.powerLevel > kickLevel : false, + senderName: sender ? sender.name : this.props.event.getSender(), + }; + } + + componentWillMount(): void { + MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents); + } + + componentWillUnmount(): void { + const client = MatrixClientPeg.get(); + if (client) { + client.removeListener("RoomState.events", this.onRoomStateEvents); + } + } + + onRoomStateEvents = (ev) => { + if (ev.getType() === "m.room.third_party_invite" && ev.getStateKey() === this.state.stateKey) { + const newDisplayName = ev.getContent().display_name; + const isInvited = !!newDisplayName; // display_name indicates a valid invite + + const newState = {invited: isInvited}; + if (newDisplayName) newState['displayName'] = newDisplayName; + this.setState(newState); + } + }; + + onCancel = () => { + dis.dispatch({ + action: "view_3pid_invite", + event: null, + }); + }; + + onKickClick = () => { + MatrixClientPeg.get().sendStateEvent(this.state.roomId, "m.room.third_party_invite", {}, this.state.stateKey) + .catch((err) => { + console.error(err); + + // Revert echo because of error + this.setState({invited: true}); + + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog('Revoke 3pid invite failed', '', ErrorDialog, { + title: _t("Failed to revoke invite"), + description: _t( + "Could not revoke the invite. The server may be experiencing a temporary problem or " + + "you do not have sufficient permissions to revoke the invite.", + ), + }); + }); + + // Local echo + this.setState({invited: false}); + }; + + render() { + const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); + + let adminTools = null; + if (this.state.canKick && this.state.invited) { + adminTools = ( +
      +

      {_t("Admin Tools")}

      +
      + + {_t("Revoke invite")} + +
      +
      + ); + } + + // We shamelessly rip off the MemberInfo styles here. + return ( +
      +
      + +

      {this.state.displayName}

      +
      +
      +
      +
      + {_t("Invited by %(sender)s", {sender: this.state.senderName})} +
      +
      +
      + {adminTools} +
      + ); + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3b24f28c2c..b40c6aab13 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -223,6 +223,7 @@ "(unknown failure: %(reason)s)": "(unknown failure: %(reason)s)", "%(senderName)s ended the call.": "%(senderName)s ended the call.", "%(senderName)s placed a %(callType)s call.": "%(senderName)s placed a %(callType)s call.", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.", "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s made future room history visible to all room members, from the point they are invited.", "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s made future room history visible to all room members, from the point they joined.", @@ -823,6 +824,10 @@ "Stickerpack": "Stickerpack", "Hide Stickers": "Hide Stickers", "Show Stickers": "Show Stickers", + "Failed to revoke invite": "Failed to revoke invite", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.", + "Revoke invite": "Revoke invite", + "Invited by %(sender)s": "Invited by %(sender)s", "Jump to first unread message.": "Jump to first unread message.", "Error updating main address": "Error updating main address", "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.", From 0258f61f633b06246176ec7839c60fad0cc0d6eb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Mar 2019 20:39:35 -0600 Subject: [PATCH 158/481] Fix typo preventing custom status from deregistering listeners on tiles --- src/components/views/rooms/MemberTile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js index e782604eb3..7303a4e34f 100644 --- a/src/components/views/rooms/MemberTile.js +++ b/src/components/views/rooms/MemberTile.js @@ -56,7 +56,7 @@ module.exports = React.createClass({ user.on("User._unstable_statusMessage", this._onStatusMessageCommitted); }, - componentWillUmount() { + componentWillUnmount() { const { user } = this.props.member; if (!user) { return; From c2e92a478fb33b801f0043fcaf943d91149c964c Mon Sep 17 00:00:00 2001 From: Tuomas Hietala Date: Fri, 22 Mar 2019 21:39:54 +0000 Subject: [PATCH 159/481] Translated using Weblate (Finnish) Currently translated at 97.3% (1518 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fi/ --- src/i18n/strings/fi.json | 135 ++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index e47b9498d0..f9bb3f8861 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -91,7 +91,7 @@ "Confirm password": "Varmista salasana", "Confirm your new password": "Varmista uusi salasanasi", "Could not connect to the integration server": "Yhteys integraatiopalvelimeen epäonnistui", - "Create a new chat or reuse an existing one": "Luo uusi keskustelu tai uudelleenkäytä vanha", + "Create a new chat or reuse an existing one": "Luo uusi keskustelu tai uudelleenkäytä vanhaa", "Create an account": "Luo tili", "Create Room": "Luo huone", "Cryptography": "Salaus", @@ -117,7 +117,7 @@ "Display name": "Näyttönimi", "Download %(text)s": "Lataa %(text)s", "Drop File Here": "Pudota tiedosto tähän", - "Ed25519 fingerprint": "Ed25519 sormenjälki", + "Ed25519 fingerprint": "Ed25519-sormenjälki", "Edit": "Muokkaa", "Email": "Sähköposti", "Email address": "Sähköpostiosoite", @@ -163,7 +163,7 @@ "Filter room members": "Suodata jäsenistä", "Forget room": "Unohda huone", "Forgot your password?": "Unohditko salasanasi?", - "For security, this session has been signed out. Please sign in again.": "Turvallisuussyistä tämä istunto on vanhentunut. Ole hyvä ja kirjaudu uudestaan.", + "For security, this session has been signed out. Please sign in again.": "Turvallisuussyistä tämä istunto on kirjattu ulos. Ole hyvä ja kirjaudu uudestaan.", "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "Turvallusuussyistä uloskirjautuminen poistaa kaikki päästä päähän-salausavaimet tästä selaimesta. Jos haluat purkaa keskustelujen salaukset tulevaisuudessa pitää sinun viedä purkuavaimet ja pitää ne turvallisesti tallessa.", "Hide read receipts": "Piilota lukukuittaukset", "Hide Text Formatting Toolbar": "Piilota tekstinmuotoilutyökalupalkki", @@ -420,7 +420,7 @@ "Export room keys": "Vie huoneen avaimet", "Confirm passphrase": "Varmista salasana", "Import room keys": "Tuo huoneen avaimet", - "File to import": "Tiedosto", + "File to import": "Tuotava tiedosto", "You must join the room to see its files": "Sinun pitää liittyä huoneeseen voidaksesi nähdä sen sisältämät tiedostot", "Reject all %(invitedRooms)s invites": "Hylkää kaikki %(invitedRooms)s kutsut", "Start new chat": "Aloita uusi keskustelu", @@ -524,7 +524,7 @@ "To use it, just wait for autocomplete results to load and tab through them.": "Käyttääksesi sitä odota vain automaattitäydennyksiä ja selaa niiden läpi.", "To reset your password, enter the email address linked to your account": "Syötä tiliisi liitetty sähköpostiosoite uudelleenalustaaksesi salasanasi", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Aikajanan tietty hetki yritettiin ladata, mutta sinulla ei ole oikeutta nähdä kyseistä viestiä.", - "Tried to load a specific point in this room's timeline, but was unable to find it.": "Aikajanan tietty hetki yritettiin ladata, mutta se ei löytynyt.", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "Huoneen aikajanan tietty hetki yritettiin ladata, mutta sitä ei löytynyt.", "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Ei voida varmistaa että osoite, johon tämä kutsu lähetettiin vastaa tiliisi liittettyä osoitetta.", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (oikeustaso %(powerLevelNumber)s)", "Verification Pending": "Varmennus on vireillä", @@ -610,8 +610,8 @@ "The maximum permitted number of widgets have already been added to this room.": "Maksimimäärä sovelmia on jo lisätty tähän huoneeseen.", "Unable to create widget.": "Sovelman luominen epäonnistui.", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Et voi kumota tätä toimintoa koska olet antamassa käyttäjälle saman oikeustason kuin sinullakin on.", - "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.": "Tämä prosessi mahdollistaa salatuissa huoneissa vastaanottamasi viestien salausavainten vieminen tiedostoon. Voit sitten myöhemmin tuoda ne toiseen Matrix-asiakasohjelmaan niin että myös se ohjema voi purkaa viestit.", - "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.": "Tämän tiedoston avulla kuka tahansa pystyy purkamaan kaikki salatut viestit jotka sinä voit nähdä, joten sinun täytyy säilyttää se turvallisesti. Helpottaaksesi tätä sinun pitäisi syötää salasana alla jonka avulla tiedosto salataan. Käyttäen samaa salasanaa voit myöhemmin tuoda tiedot ohjelmaan.", + "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.": "Tämä prosessi mahdollistaa salatuissa huoneissa vastaanottamiesi viestien salausavainten viemisen tiedostoon. Voit myöhemmin tuoda ne toiseen Matrix-asiakasohjelmaan, jolloin myös se voi purkaa viestit.", + "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.": "Viedyn tiedoston avulla kuka tahansa pystyy purkamaan kaikki salatut viestit jotka voit nähdä, joten sinun täytyy säilyttää sitä huolellisesti. Helpottaaksesi tätä, syötä alle salasana jonka avulla viedyt tiedot salataan. Voit myöhemmin tuoda tiedot ainoastaan samalla salasanalla.", "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.": "Tämä prosessi mahdollistaa aiemmin tallennettujen salausavainten tuominen toiseen Matrix-asiakasohjelmaan. Tämän jälkeen voit purkaa kaikki salatut viestit jotka toinen asiakasohjelma pystyisi purkamaan.", "Who would you like to add to this community?": "Kenet sinä haluaisit lisätä tähän yhteisöön?", "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Varioitus: henkilöt jotka lisäät yhteisöön näkyvät kaikille jotka tietävät yhteisön tunnisteen", @@ -712,9 +712,9 @@ "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.": "Voit kirjautua toiselle Matrix kotipalvelimelle syöttämällä palvelimen URL-osoite palvelinasetuksissa.", "This allows you to use this app with an existing Matrix account on a different home server.": "Tämä mahdollistaa tämän ohjelman käytön olemassa olevan toisella palvelimella sijaitsevan Matrix tilin kanssa.", "You can also set a custom identity server but this will typically prevent interaction with users based on email address.": "Voit myös käyttää toista identiteettipalvelinta mutta tyypillisesti tämä estää sähköpostiosoitteisiin perustuvan kanssakäynnin muiden käyttäjien kanssa.", - "An email has been sent to %(emailAddress)s": "Viesti lähetetty osoitteeseen %(emailAddress)s", + "An email has been sent to %(emailAddress)s": "Sähköpostia lähetetty osoitteeseen %(emailAddress)s", "Please check your email to continue registration.": "Ole hyvä ja tarkista sähköpostisi jatkaaksesi.", - "A text message has been sent to %(msisdn)s": "Tekstiviesti on lähetetty numeroon %(msisdn)s", + "A text message has been sent to %(msisdn)s": "Tekstiviesti lähetetty numeroon %(msisdn)s", "Username on %(hs)s": "Käyttäjänimi palvelimella %(hs)s", "Custom server": "Muu palvelin", "Remove from community": "Poista yhteisöstä", @@ -739,7 +739,7 @@ "Matrix ID": "Matrix ID", "Matrix Room ID": "Matrix huonetunniste", "email address": "sähköpostiosoite", - "Try using one of the following valid address types: %(validTypesList)s.": "Kokeile käyttää yhtä näistä valideista osoitetyypeistä: %(validTypesList)s.", + "Try using one of the following valid address types: %(validTypesList)s.": "Kokeile käyttää yhtä näistä kelvollisista osoitetyypeistä: %(validTypesList)s.", "You have entered an invalid address.": "Olet syöttänyt virheellisen sähköpostiosoitteen.", "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.": "Oletko varma että haluat poistaa tämän tapahtuman? Huomaa että jos poistat huoneen nimen tai aiheen muutoksen, saattaa muutos kumoutua.", "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Yhteisötunnisteet voivat sisältää vain merkkejä a-z, 0-9 tai '=_-/'", @@ -777,15 +777,15 @@ "%(inviter)s has invited you to join this community": "%(inviter)s on kutsunut sinut tähän yhteisöön", "You are an administrator of this community": "Olet tämän yhteisön ylläpitäjä", "You are a member of this community": "Olet tämän yhteisön jäsen", - "Your community hasn't got a Long Description, a HTML page to show to community members.
      Click here to open settings and give it one!": "Sinun yhteistöltäsi puuttuu pitkä kuvaus, HTML sivu joka näytetään yhteistön jäsenille.
      Klikkaa tästä avataksesi asetukset luodaksesi sivun!", + "Your community hasn't got a Long Description, a HTML page to show to community members.
      Click here to open settings and give it one!": "Sinun yhteisöltäsi puuttuu pitkä kuvaus, HTML-sivu joka näytetään yhteisön jäsenille.
      Klikkaa tästä avataksesi asetukset ja luodaksesi sivun!", "Long Description (HTML)": "Pitkä kuvaus (HTML)", "Description": "Kuvaus", "Community %(groupId)s not found": "Yhteisöä %(groupId)s ei löytynyt", "This Home server does not support communities": "Tämä kotipalvelin ei tue yhteisöjä", "Failed to load %(groupId)s": "Yhteisön %(groupId)s lataaminen epäonnistui", - "Your Communities": "Sinun yhteistösi", + "Your Communities": "Sinun yhteisösi", "You're not currently a member of any communities.": "Et ole minkään yhteisön jäsen tällä hetkellä.", - "Error whilst fetching joined communities": "Virhe ladatessa listaa yhteistöistä joihin olet liittynyt", + "Error whilst fetching joined communities": "Virhe ladatessa listaa yhteisöistä joihin olet liittynyt", "Create a new community": "Luo uusi yhteisö", "Light theme": "Vaalea teema", "Dark theme": "Tumma teema", @@ -799,8 +799,8 @@ "Deops user with given id": "Poistaa annetun tunnisteen omaavalta käyttäjältä ylläpito-oikeudet", "Ignores a user, hiding their messages from you": "Jättää käyttäjän huomioimatta, jotta hänen viestejään ei näytetä sinulle", "Stops ignoring a user, showing their messages going forward": "Lopettaa käyttäjän huomiotta jättämisen, jotta hänen viestinsä näytetään sinulle", - "Notify the whole room": "Hälytä koko huone", - "Room Notification": "Huonehälytys", + "Notify the whole room": "Ilmoita koko huoneelle", + "Room Notification": "Huoneilmoitus", "Call Failed": "Puhelu epäonnistui", "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "Huoneessa on tuntemattomia laitteita: jos jatkat varmentamatta niitä, joku voi kuunnella puheluasi.", "Review Devices": "Näytä Laitteet", @@ -914,7 +914,7 @@ "Custom of %(powerLevel)s": "Valinnaiset %(powerLevel)s", "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Varmistaaksesi että tähän laitteeseen voidaan luottaa, ole yhteydessä omistajaan jollain muulla tavalla (henkilökohtaisesti tai puhelimitse) ja pyydä heitä varmistamaan näkyykö Käyttäjäasetuksissa laite jolla on alla oleva avain:", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Jos avain täsmää, valitse painike alla. Jos avain ei täsmää, niin joku muu salakuuntelee laitetta ja haluat todennäköisesti painaa estopainiketta.", - "Old cryptography data detected": "Vanhat salaustiedot havaittu", + "Old cryptography data detected": "Vanhaa salaustietoa havaittu", "Warning": "Varoitus", "Access Token:": "Pääsykoodi:", "Fetching third party location failed": "Kolmannen osapuolen paikan haku epäonnistui", @@ -957,14 +957,14 @@ "Messages in one-to-one chats": "Viestit kahdenkeskisissä keskusteluissa", "Unavailable": "Ei saatavilla", "Error saving email notification preferences": "Virhe tallennettaessa sähköposti-ilmoitusasetuksia", - "View Decrypted Source": "Näytä purettu lähdekoodi", + "View Decrypted Source": "Näytä purettu lähde", "Failed to update keywords": "Avainsanojen päivittäminen epäonnistui", "Notifications on the following keywords follow rules which can’t be displayed here:": "Seuraaviin avainsanoihin liittyvät ilmoitukset seuraavat sääntöjä joita ei voida näyttää tässä:", "Safari and Opera work too.": "Safari ja Opera ovat myös tuettuja.", "Please set a password!": "Ole hyvä ja aseta salasana!", - "You have successfully set a password!": "Olet onnistuneesti asettanut salasanan!", + "You have successfully set a password!": "Olet asettanut salasanan!", "Explore Room State": "Huoneen tila", - "Source URL": "Lähde URL", + "Source URL": "Lähdeosoite", "Messages sent by bot": "Bottien lähettämät viestit", "Filter results": "Suodata", "Members": "Jäsenet", @@ -972,8 +972,8 @@ "Resend": "Lähetä uudelleen", "Failed to get protocol list from Home Server": "Protokollalistan hakeminen Kotipalvelimelta ei onnistunut", "Collecting app version information": "Haetaan sovelluksen versiotietoja", - "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Poista huonetunnus %(alias)s ja poista %(name)s hakemistosta?", - "This will allow you to return to your account after signing out, and sign in on other devices.": "Tämä mahdollistaa sinut palamaan tilillesi uloskirjautumisen jälkeen sekä kirjautumaan muilla laitteilla.", + "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Poista huonealias %(alias)s ja poista %(name)s hakemistosta?", + "This will allow you to return to your account after signing out, and sign in on other devices.": "Tämä antaa sinun palata tilillesi uloskirjautumisen jälkeen sekä kirjautumaan muilla laitteilla.", "Keywords": "Avainsanat", "Enable notifications for this account": "Ota käyttöön ilmoitukset tälle tilille", "Directory": "Hakemisto", @@ -984,17 +984,17 @@ "Tuesday": "Tiistai", "Enter keywords separated by a comma:": "Anna avainsanat pilkuin eroteltuna:", "Search…": "Haku…", - "You have successfully set a password and an email address!": "Olet onnistuneesti asettanut salasanan ja sähköpostiosoitteen!", + "You have successfully set a password and an email address!": "Olet asettanut salasanan ja sähköpostiosoitteen!", "Remove %(name)s from the directory?": "Poista %(name)s hakemistosta?", - "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot käyttää monia selainominaisuuksia, joista osa selaimesi ei tue tai ne ovat kokeellisia.", + "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot käyttää monia edistyneitä ominaisuuksia, joista osaa selaimesi ei tue tai ne ovat kokeellisia.", "Developer Tools": "Kehittäjätyökalut", "Enable desktop notifications": "Ota käyttöön työpöytäilmoitukset", "Explore Account Data": "Tilitiedot", - "All messages (noisy)": "Kaikki viestit (äänekkäästi)", + "All messages (noisy)": "Kaikki viestit (meluisa)", "Saturday": "Lauantai", "Remember, you can always set an email address in user settings if you change your mind.": "Muista että voit aina asettaa sähköpostiosoitteen käyttäjäasetuksista jos muutat mielesi.", "Direct Chat": "Suora viestittely", - "The server may be unavailable or overloaded": "Palvelin saattaa olla saavuttamaton tai ylikuormitettu", + "The server may be unavailable or overloaded": "Palvelin saattaa olla tavoittamattomissa tai ylikuormitettu", "Reject": "Hylkää", "Failed to set Direct Message status of room": "Huoneen suoran viestittelyn tilan asettaminen epäonnistui", "Monday": "Maanantai", @@ -1006,7 +1006,7 @@ "Collecting logs": "Haetaan lokeja", "more": "lisää", "You must specify an event type!": "Sinun on määritettävä tapahtuman tyyppi!", - "(HTTP status %(httpStatus)s)": "(HTTP tila %(httpStatus)s)", + "(HTTP status %(httpStatus)s)": "(HTTP-tila %(httpStatus)s)", "All Rooms": "Kaikki huoneet", "Please install Chrome or Firefox for the best experience.": "Asenna Chrome tai Firefox parhaan käyttökokemuksen saavuttamiseksi.", "Failed to get public room list": "Julkisten huoneiden luettelon hakeminen epäonnistui", @@ -1025,13 +1025,13 @@ "Unable to look up room ID from server": "Huone-ID:n haku palvelimelta epäonnistui", "Couldn't find a matching Matrix room": "Vastaavaa Matrix-huonetta ei löytynyt", "Invite to this room": "Kutsu käyttäjiä", - "You cannot delete this message. (%(code)s)": "Et voi poistaa tätä viestiä. (%(code)s)", + "You cannot delete this message. (%(code)s)": "Et voi poistaa tätä viestiä. (%(code)s)", "Thursday": "Torstai", "I understand the risks and wish to continue": "Ymmärrän riskit ja haluan jatkaa", "Back": "Takaisin", "Reply": "Vastaa", "Show message in desktop notification": "Näytä viestit ilmoituskeskuksessa", - "Unhide Preview": "Näytä ennakkokatselu", + "Unhide Preview": "Näytä esikatselu", "Unable to join network": "Verkkoon liittyminen epäonnistui", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Olet saattanut muuttaa niitä muussa asiakasohjelmassa kuin Riotissa. Et voi muuttaa niitä Riotissa mutta ne pätevät silti", "Sorry, your browser is not able to run Riot.": "Valitettavasti Riot ei toimi selaimessasi.", @@ -1047,7 +1047,7 @@ "Enable audible notifications in web client": "Ota käyttöön äänelliset ilmoitukset", "remove %(name)s from the directory.": "poista %(name)s hakemistosta.", "Off": "Pois päältä", - "Riot does not know how to join a room on this network": "Riot ei tiedä miten liittya huoneeseen tässä verkossa", + "Riot does not know how to join a room on this network": "Riot ei tiedä miten liittyä huoneeseen tässä verkossa", "Mentions only": "Vain maininnat", "Failed to remove tag %(tagName)s from room": "Tagin %(tagName)s poistaminen huoneesta epäonnistui", "Wednesday": "Keskiviikko", @@ -1063,7 +1063,7 @@ "Event Content": "Tapahtuman sisältö", "Thank you!": "Kiitos!", "Collapse panel": "Piilota paneeli", - "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!": "Nykyisellä selaimellasi ohjelman ulkonäkö voi olla aivan virheellinen, ja jotkut ominaisuudet eivät saata toimia. Voit jatkaa jos haluat kokeilla mutta et voi odottaa saavasi apua mahdollisesti ilmeneviin ongelmiin!", + "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!": "Nykyisellä selaimellasi ohjelman ulkonäkö voi olla täysin virheellinen, ja jotkut tai kaikki ominaisuudet eivät vättämättä toimi. Voit jatkaa jos haluat kokeilla, mutta et voi odottaa saavasi apua mahdollisesti ilmeneviin ongelmiin!", "Checking for an update...": "Tarkistetaan päivityksen saatavuutta...", "There are advanced notifications which are not shown here": "Tässä ei näytetä edistyneitä ilmoituksia", "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Voit myös määrittää toisen identiteettipalvelimen, mutta et voi kutsua muita käyttäjiä sähköpostin perusteella, eivätkä se voi kutsua sinua.", @@ -1075,7 +1075,7 @@ "Send a message (unencrypted)…": "Lähetä viesti (salaamaton)…", "In reply to ": "Vastauksena käyttäjälle ", "This room is not public. You will not be able to rejoin without an invite.": "Tämä huone ei ole julkinen. Tarvitset kutsun liittyäksesi huoneeseen.", - "%(count)s of your messages have not been sent.|one": "Viestiäsi ei pystytty lähettämään.", + "%(count)s of your messages have not been sent.|one": "Viestiäsi ei lähetetty.", "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s asetti näyttönimekseen %(displayName)s.", "Learn more about how we use analytics.": "Lue lisää analytiikkakäytännöistämme.", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Täällä ei ole muita! Haluaisitko kutsua muita tai poistaa varoituksen tyhjästä huoneesta?", @@ -1198,7 +1198,7 @@ "Report bugs & give feedback": "Ilmoita ongelmista ja anna palautetta", "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Jos törmäsit ongelmiin tai haluat antaa palautetta, ota meihin yhteys GitHubin kautta.", "Go back": "Takaisin", - "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Luo yhteisö tuodaksesi yhteen käyttäjät ja huoneet! Luo mukautettu kotisivu merkitäksesi tilasi Matrix-universumissa.", + "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Luo yhteisö tuodaksesi yhteen käyttäjät ja huoneet! Luo mukautettu kotisivu rajataksesi paikkasi Matrix-universumissa.", "Room avatar": "Huoneen kuva", "Upload room avatar": "Lähetä huoneen kuva", "No room avatar": "Huoneella ei ole kuvaa", @@ -1337,7 +1337,7 @@ "Add an email address to configure email notifications": "Lisää sähköpostiosoite määrittääksesi sähköposti-ilmoitukset", "Chat with Riot Bot": "Keskustele Riot-botin kanssa", "You'll lose access to your encrypted messages": "Menetät pääsyn salattuihin viesteihisi", - "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Tämän huoneen päivittäminen vaatii nykyisen huoneen sulkemisen ja uuden huoneen luomisen sen paikalle. Jotta huoneen jäsenillä olisi mahdollisimman hyvä kokemus, teemme seuraavaa:", + "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Tämän huoneen päivittäminen vaatii nykyisen huoneen sulkemisen ja uuden huoneen luomisen sen paikalle. Antaaksemme huoneen jäsenille mahdollisimman hyvän kokemuksen, teemme seuraavaa:", "Create a new room with the same name, description and avatar": "luomme uuden huoneen samalla nimellä, kuvauksella ja kuvalla", "Update any local room aliases to point to the new room": "päivitämme kaikki huoneen aliakset osoittamaan uuteen huoneeseen", "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "estämme käyttäjiä puhumasta vanhassa huoneessa ja lähetämme viestin, joka ohjeistaa käyttäjiä siirtymään uuteen huoneeseen", @@ -1520,7 +1520,7 @@ "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Aliaksen poistossa tapahtui virhe. Se ei välttämättä ole enää olemassa tai kyseessä on väliaikainen virhe.", "Error updating flair": "Tyylin päivittämisessä tapahtui virhe", "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Tyylin päivittämisessä tapahtui virhe. Palveline ei välttämättä salli sitä tai kyseessä on väliaikainen virhe.", - "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.": "Salatuissa huoneissa, kuten tässä, osoitteiden esikatselut ovat oletuksena pois käytöstä, jotta kotipalvelimesi (missä osoitteiden esikatselut luodaan) eivät voi kerätä tietoa siitä, mitä osoitteita näät huoneissasi.", + "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.": "Salatuissa huoneissa, kuten tässä, osoitteiden esikatselut ovat oletuksena pois käytöstä, jotta kotipalvelimesi (missä osoitteiden esikatselut luodaan) ei voi kerätä tietoa siitä, mitä linkkejä näet tässä huoneessa.", "Please contact your service administrator to get this limit increased.": "Ota yhteyttä ylläpitäjääsi tämän rajan kasvattamiseksi.", "This homeserver has hit its Monthly Active User limit so some users will not be able to log in.": "Tämä kotipalvelin on saavuttanut kuukausittaisten aktiivisten käyttäjien rajansa, joten osa käyttäjistä ei pysty kirjautumaan sisään.", "This homeserver has exceeded one of its resource limits so some users will not be able to log in.": "Tämä kotipalvelin on ylittänyt yhden resurssirajoistaan, joten osa käyttäjistä ei pysty kirjautumaan sisään.", @@ -1559,7 +1559,7 @@ "The following users may not exist": "Seuraavat käyttäjät eivät välttämättä ole olemassa", "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Alla luetelluille Matrix ID:ille ei löytynyt profiileja. Haluaisitko kutsua ne siitä huolimatta?", "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.": "Debug-lokit sisältävät ohjelman käyttödataa, kuten käyttäjätunnuksesi, huoneiden ja ryhmien ID:t tai aliakset, joissa olet vieraillut sekä muiden käyttäjien käyttäjätunnukset. Ne eivät sisällä viestejä.", - "Before submitting logs, you must create a GitHub issue to describe your problem.": "Ennen lokien lähettämistä sinun täytyy luoda tapahtuma Githubiin, joka sisältää kuvauksen ongelmastasi.", + "Before submitting logs, you must create a GitHub issue to describe your problem.": "Ennen lokien lähettämistä sinun täytyy luoda Githubiin issue (kysymys/ongelma), joka sisältää kuvauksen ongelmastasi.", "What GitHub issue are these logs for?": "Mihin Github-issueen nämä lokit liittyvät?", "Notes:": "Huomiot:", "Unable to load commit detail: %(msg)s": "Commitin tietojen hakeminen epäonnistui: %(msg)s", @@ -1577,24 +1577,24 @@ "Nothing appearing? Not all clients support interactive verification yet. .": "Näytölle ei ilmesty mitään? Kaikki asiakasohjelmat eivät vielä tue interaktiivista varmentamista. .", "Waiting for %(userId)s to confirm...": "Odotetaan, että %(userId)s hyväksyy...", "Use two-way text verification": "Käytä kahdensuuntaista tekstivarmennusta", - "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Varmenna tämä käyttäjä merkitsemällä hänet luotetuksi. Käyttäjiin luottaminen antaa sinulle ylimääräistä mielenrauhaa käyttäessäsi osapuolten välistä salausta.", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Varmenna tämä käyttäjä merkitäksesi hänet luotetuksi. Käyttäjiin luottaminen antaa sinulle ylimääräistä mielenrauhaa käyttäessäsi osapuolten välistä salausta.", "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Tämän käyttäjän varmentaminen merkitsee heidän laitteensa luotetuiksi, sekä merkitsee sinun laitteesi luotetuiksi tälle käyttäjälle.", "Waiting for partner to confirm...": "Odotetaan, että toinen osapuoli varmistaa...", "Incoming Verification Request": "Saapuva varmennuspyyntö", - "You've previously used Riot 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, Riot needs to resync your account.": "Olet aikaisemmin käytttänyt Riotia laitteella %(host)s, jossa oli jäsenten laiska lataus käytössä. Tässä versiossa laiska lataus on pois käytöstä. Koska paikallinen välimuisti ei ole yhteensopiva näiden kahden asetuksen välillä, Riotin täytyy hakea tunnuksesi tiedot uudelleen.", - "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Jos sinulla on toinen Riotin versio edelleen auki toisessa välilehdessä, suljethan sen, koska Riotin käyttäminen samalla laitteella niin, että laiska lataus on toisessa tabissa käytössä ja toisessa ei, aiheuttaa ongelmia.", + "You've previously used Riot 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, Riot needs to resync your account.": "Olet aikaisemmin käytttänyt Riotia laitteella %(host)s, jossa oli jäsenten laiska lataus käytössä. Tässä versiossa laiska lataus on pois käytöstä. Koska paikallinen välimuisti ei ole yhteensopiva näiden kahden asetuksen välillä, Riotin täytyy hakea käyttäjätilisi tiedot uudelleen.", + "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Jos sinulla on toinen Riotin versio edelleen auki toisessa välilehdessä, suljethan sen, koska Riotin käyttäminen samalla laitteella niin, että laiska lataus on toisessa välilehdessä käytössä ja toisessa ei, aiheuttaa ongelmia.", "Incompatible local cache": "Yhteensopimaton paikallinen välimuisti", "Clear cache and resync": "Tyhjennä välimuisti ja hae tiedot uudelleen", "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot käyttää nyt 3-5 kertaa vähemmän muistia, koska se lataa tietoa muista käyttäjistä vain tarvittaessa. Odotathan, kun haemme tarvittavat tiedot palvelimelta!", "I don't want my encrypted messages": "En halua salattuja viestejäni", - "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Välttääksesi duplikaatin luomista, katsothan olemassaolevat tapahtumat ensin (ja lisää +1, mikäli löydät tapahtuman joka koskee sinuakin) tai luo uusi tapahtuma mikäli et löydä ongelmaasi.", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Välttääksesi saman ongelman ilmoittamista kahdesti, katso ensin olemassaolevat issuet (ja lisää +1, mikäli löydät issuen joka koskee sinuakin) tai luo uusi issue mikäli et löydä ongelmaasi.", "Room Settings - %(roomName)s": "Huoneen asetukset — %(roomName)s", "Clear Storage and Sign Out": "Tyhjennä varasto ja kirjaudu ulos", - "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Selaimen varaston tyhjentäminen saattaa korjata ongelman, mutta kirjaudut samalla ulos ja estää sinua lukemasta salattuja keskusteluita.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Selaimen varaston tyhjentäminen saattaa korjata ongelman, mutta kirjaa sinut samalla ulos ja estää sinua lukemasta salattuja keskusteluita.", "A username can only contain lower case letters, numbers and '=_-./'": "Käyttäjätunnus voi sisältää vain pieniä kirjaimia, numeroita ja merkkejä ”=_-./”", "COPY": "Kopioi", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Estät tällä hetkellä varmentamattomia laitteita; jotta voit lähettää viestejä näihin laitteisiin, sinun täytyy varmentaa ne.", - "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "Suosittelemme, että menet varmennusprosessin läpi jokaisella laitteella, varmistaaksesi, että ne kuuluvat oikeille omistajilleen, mutta voit lähettää viestin uudelleen varmentamatta, jos niin haluat.", + "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "Suosittelemme, että käyt varmennusprosessin läpi jokaisella laitteella varmistaaksesi, että ne kuuluvat oikeille omistajilleen, mutta voit lähettää viestin uudelleen varmentamatta, jos niin haluat.", "Unable to load backup status": "Varmuuskopioinnin tilan lataaminen epäonnistui", "Recovery Key Mismatch": "Palautusavaimet eivät täsmää", "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Varmuuskopiota ei voitu purkaa tällä avaimella. Tarkastathan, että syötit oikean palautusavaimen.", @@ -1604,7 +1604,7 @@ "Restored %(sessionCount)s session keys": "%(sessionCount)s istunnon avainta palautettu", "Enter Recovery Passphrase": "Syötä palautuksen salalause", "Warning: you should only set up key backup from a trusted computer.": "Varoitus: sinun pitäisi ottaa avainvarmuuskopio käyttöön vain luotetulta tietokoneelta.", - "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Pääse käsiksi turvattuun viestihistoriaasi ja ota käyttöön turvallinen viestintä syöttämällä palautuksen salalauseesi.", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Pääse turvattuun viestihistoriaasi ja ota käyttöön turvallinen viestintä syöttämällä palautuksen salalauseesi.", "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Jos olet unohtanut palautuksen salalauseesi, voit käyttää palautusavaintasi tai ottaa käyttöön uuden palautustavan", "Access your secure message history and set up secure messaging by entering your recovery key.": "Pääse käsiksi turvattuun viestihistoriaasi ja ota käyttöön turvallinen viestintä syöttämällä palautusavaimesi.", "If you've forgotten your recovery passphrase you can ": "Jos olet unohtanut palautuksen salalauseesi, voit ", @@ -1615,14 +1615,14 @@ "Please review and accept the policies of this homeserver:": "Tarkistathan tämän kotipalvelimen käytännöt:", "Code": "Koodi", "Your Modular server": "Modular-palvelimesi", - "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Syötä Modular-kotipalvelimesi sijainti. Se voi käyttää omaa domainiasi tai olla osoitteen modular.im alidomain.", + "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Syötä Modular-kotipalvelimesi sijainti. Se voi käyttää omaa verkkotunnustasi tai olla modular.im:n aliverkkotunnus.", "The username field must not be blank.": "Käyttäjätunnus ei voi olla tyhjä.", "Username": "Käyttäjätunnus", - "Sign in to your Matrix account": "Kirjaudu sisään Matrix-tunnukseesi", - "Sign in to your Matrix account on %(serverName)s": "Kirjaudu sisään Matrix-tunnukseesi palvelimella %(serverName)s", + "Sign in to your Matrix account": "Kirjaudu sisään Matrix-käyttäjätilillesi", + "Sign in to your Matrix account on %(serverName)s": "Kirjaudu sisään Matrix-käyttäjätilillesi palvelimella %(serverName)s", "Change": "Muuta", - "Create your Matrix account": "Luo Matrix-tunnus", - "Create your Matrix account on %(serverName)s": "Luo Matrix-tunnus palvelimelle %(serverName)s", + "Create your Matrix account": "Luo Matrix-käyttäjätili", + "Create your Matrix account on %(serverName)s": "Luo Matrix-käyttäjätili palvelimelle %(serverName)s", "Confirm": "Varmista", "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Käytä sähköpostia tunnuksesi palauttamiseen. Muut käyttäjät voivat kutsua sinut huoneisiin yhteystiedoillasi.", "Other servers": "Muut palvelimet", @@ -1644,13 +1644,46 @@ "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Epäkelpo asetus: ei voitu toimittaa oletuksena olevaa kotipalvelimen osoitetta ja oletuksena olevaa palvelimen nimeä", "Can't leave Server Notices room": "Palvelinilmoitushuonetta ei voitu jättää", "This room is used for important messages from the Homeserver, so you cannot leave it.": "Tämä huone on kotipalvelimen tärkeille viesteille, joten ei voi poistua siitä.", - "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Jatkaaksesi kotipalvelimen %(homeserverDomain)s päyttöä, sinun täytyy tarkastaa ja hyväksyä käyttöehtomme.", - "Review terms and conditions": "Tarkasta käyttöehdot", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Jatkaaksesi kotipalvelimen %(homeserverDomain)s käyttöä, sinun täytyy lukea ja hyväksyä käyttöehtomme.", + "Review terms and conditions": "Lue käyttöehdot", "You are logged in to another account": "Olet kirjautuneena sisään toisella tunnuksella", "Unknown error discovering homeserver": "Tuntematon virhe kotipalvelimen etsinnässä", "Did you know: you can use communities to filter your Riot.im experience!": "Tiesitkö: voit käyttää yhteisöjä suodattaaksesi Riot.im-kokemustasi!", - "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.": "Asettaaksesi suodattimen, raahaa yhteisön kuva vasemmalla olevan suodatinpaneelin päälle. Voit klikata suodatinpaneelissa olevaa yhteisön kuvaa, jotta näät vain huoneet ja henkilöt, jotka liittyvät kyseiseen yhteisöön.", + "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.": "Asettaaksesi suodattimen, vedä yhteisön kuva vasemmalla olevan suodatinpaneelin päälle. Voit klikata suodatinpaneelissa olevaa yhteisön kuvaa, jotta näet vain huoneet ja henkilöt, jotka liittyvät kyseiseen yhteisöön.", "Failed to get protocol list from homeserver": "Protokollalistan hakeminen kotipalvelimelta epäonnistui", "The homeserver may be too old to support third party networks": "Tämä kotipalvelin saattaa olla liian vanha tukeakseen kolmannen osapuolen verkkoja", - "Search for a room like #example": "Etsi huoneita tyyliin #esimerkki" + "Search for a room like #example": "Etsi huoneita tyyliin #esimerkki", + "Show devices, send anyway or cancel.": "Näytä laitteet, lähetä silti tai peruuta.", + "You can't send any messages until you review and agree to our terms and conditions.": "Et voi lähettää viestejä ennen kuin luet ja hyväksyt käyttöehtomme.", + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Viestiäsi ei lähetetty, koska tämä kotipalvelin on saavuttanut kuukausittaisten aktiivisten käyttäjien rajan. Ota yhteyttä palvelun ylläpitäjään jatkaaksesi palvelun käyttämistä.", + "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Viestiäsi ei lähetetty, koska tämä kotipalvelin on ylittänyt resurssirajan. Ota yhteyttä palvelun ylläpitäjään jatkaaksesi palvelun käyttämistä.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Lähetä kaikki uudelleen tai peruuta kaikki. Voit myös valita yksittäisiä viestejä uudelleenlähetettäväksi tai peruutettavaksi.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Lähetä viesti uudelleen tai peruuta viesti.", + "Could not load user profile": "Käyttäjäprofiilia ei voitu ladata", + "Your Matrix account": "Matrix-käyttäjätilisi", + "Your Matrix account on %(serverName)s": "Matrix-käyttäjätilisi palvelimella %(serverName)s", + "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Olet kirjautunut ulos kaikista laitteista etkä enää saa push-ilmoituksia. Laittaaksesi ilmoitukset uudestaan päälle, kirjaudu uudelleen kullekin laitteelle.", + "General failure": "Yleinen virhe", + "This homeserver does not support login using email address.": "Tämä kotipalvelin ei tue sähköpostiosoitteella kirjautumista.", + "Please contact your service administrator to continue using this service.": "Ota yhteyttä palvelun ylläpitäjään jatkaaksesi palvelun käyttöä.", + "Try the app first": "Kokeile ensin sovellusta", + "Registration has been disabled on this homeserver.": "Rekisteröityminen on poistettu käytöstä tällä kotipalvelimella.", + "Unable to query for supported registration methods.": "Tuettuja rekisteröitymistapoja ei voitu kysellä.", + "You need to enter a username.": "Sinun täytyy syöttää käyttäjänimi.", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Viety tiedosto suojataan salasanalla. Syötä salasana tähän purkaaksesi tiedoston salauksen.", + "Great! This passphrase looks strong enough.": "Mahtavaa! Salasana näyttää tarpeeksi vahvalta.", + "Keep going...": "Jatka...", + "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.": "Tallennamme salatun kopion avaimistasi palvelimellemme. Suojaa varmuuskopio salasanalla.", + "For maximum security, this should be different from your account password.": "Parhaan turvallisuuden takaamiseksi tämän tulisi olla eri kuin käyttäjätilisi salasana.", + "Enter a passphrase...": "Syötä salasana...", + "That matches!": "Täsmää!", + "That doesn't match.": "Ei täsmää.", + "Go back to set it again.": "Palaa asettamaan se uudelleen.", + "Repeat your passphrase...": "Toista salasana...", + "Print it and store it somewhere safe": "Tulosta se ja säilytä sitä turvallisessa paikassa", + "Save it on a USB key or backup drive": "Tallenna se muistitikulle tai varmuuskopiolevylle", + "Copy it to your personal cloud storage": "Kopioi se henkilökohtaiseen pilvitallennustilaasi", + "Your keys are being backed up (the first backup could take a few minutes).": "Avaimiasi varmuuskopioidaan (ensimmäinen varmuuskopio voi viedä muutaman minuutin).", + "Okay": "OK", + "Unable to create key backup": "Avaimen varmuuskopiota ei voi luoda" } From 8d42d6837e40031d0c51e18f728803063b7a3d6f Mon Sep 17 00:00:00 2001 From: Samu Voutilainen Date: Fri, 29 Mar 2019 06:29:02 +0000 Subject: [PATCH 160/481] Translated using Weblate (Finnish) Currently translated at 97.3% (1518 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fi/ --- src/i18n/strings/fi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index f9bb3f8861..4cbd5e577c 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -13,7 +13,7 @@ "Notifications": "Ilmoitukset", "Operation failed": "Toiminto epäonnistui", "Remove": "Poista", - "Room directory": "Huonehakemisto", + "Room directory": "Huoneluettelo", "Search": "Haku", "Settings": "Asetukset", "Start chat": "Aloita keskustelu", From 01326f10af1fd0bd5cfc3b8e8cf849cd378699e8 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Thu, 28 Mar 2019 21:55:39 +0000 Subject: [PATCH 161/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 663 +++++++++++++++++++++++++-------------- 1 file changed, 426 insertions(+), 237 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 4da2ead2a7..7f75428c16 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -15,23 +15,23 @@ "and %(count)s others...|other": "en %(count)s andere…", "and %(count)s others...|one": "en één andere…", "%(names)s and %(lastPerson)s are typing": "%(names)s en %(lastPerson)s zijn aan het typen", - "A new password must be entered.": "Er moet een nieuw wachtwoord worden ingevoerd.", + "A new password must be entered.": "Er moet een nieuw wachtwoord ingevoerd worden.", "%(senderName)s answered the call.": "%(senderName)s heeft de oproep beantwoord.", "An error has occurred.": "Er is een fout opgetreden.", "Anyone who knows the room's link, apart from guests": "Iedereen die de koppeling van de kamer kent, behalve gasten", "Anyone who knows the room's link, including guests": "Iedereen die de koppeling van de kamer kent, inclusief gasten", "Are you sure?": "Weet u het zeker?", - "Are you sure you want to reject the invitation?": "Weet je zeker dat je de uitnodiging wilt weigeren?", + "Are you sure you want to reject the invitation?": "Weet u zeker dat u de uitnodiging wilt weigeren?", "Attachment": "Bijlage", "Autoplay GIFs and videos": "GIF’s en video’s automatisch afspelen", "%(senderName)s banned %(targetName)s.": "%(senderName)s heeft %(targetName)s verbannen.", "Ban": "Verbannen", "Banned users": "Verbannen gebruikers", "Bans user with given id": "Verbant de gebruiker met de gegeven ID", - "Blacklisted": "Buitengesloten", + "Blacklisted": "Geblokkeerd", "Bulk Options": "Bulk opties", "Call Timeout": "Oproeptime-out", - "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Kan niet met de thuisserver verbinden via HTTP wanneer er een HTTPS-URL in je browser balk staat. Gebruik HTTPS of activeer onveilige scripts.", + "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Kan geen verbinding maken met de thuisserver via HTTP wanneer er een HTTPS-URL in uw browserbalk staat. Gebruik HTTPS of schakel onveilige scripts in.", "Can't load user settings": "Kan de gebruikersinstellingen niet laden", "Change Password": "Wachtwoord veranderen", "%(senderName)s changed their profile picture.": "%(senderName)s heeft een nieuwe profielfoto ingesteld.", @@ -77,16 +77,16 @@ "Hide removed messages": "Verwijderde berichten verbergen", "Alias (optional)": "Alias (optioneel)", "Anyone": "Iedereen", - "Are you sure you want to leave the room '%(roomName)s'?": "Weet u zeker dat u de ruimte '%(roomName)s' wil verlaten?", + "Are you sure you want to leave the room '%(roomName)s'?": "Weet u zeker dat u de kamer ‘%(roomName)s’ wilt verlaten?", "Are you sure you want to upload the following files?": "Weet u zeker dat u de volgende bestanden wilt uploaden?", "Click here to join the discussion!": "Klik hier om mee te doen aan het gesprek!", "Close": "Sluiten", "%(count)s new messages|one": "%(count)s nieuw bericht", - "Create new room": "Een nieuwe ruimte maken", + "Create new room": "Een nieuwe kamer aanmaken", "Custom Server Options": "Aangepaste serverinstellingen", "Dismiss": "Afwijzen", "Error": "Fout", - "Failed to forget room %(errCode)s": "Ruimte vergeten mislukt %(errCode)s", + "Failed to forget room %(errCode)s": "Vergeten van kamer is mislukt %(errCode)s", "Favourite": "Favoriet", "Mute": "Dempen", "Notifications": "Meldingen", @@ -121,13 +121,13 @@ "Passwords can't be empty": "Wachtwoorden kunnen niet leeg zijn", "People": "Personen", "Permissions": "Toestemmingen", - "Phone": "Telefoon", + "Phone": "Telefoonnummer", "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gemaakt.", "Privacy warning": "Privacywaarschuwing", "Private Chat": "Privégesprek", "Privileged Users": "Bevoorrechte gebruikers", "Profile": "Profiel", - "Public Chat": "Publiek Gesprek", + "Public Chat": "Openbaar gesprek", "Reason": "Reden", "Reason: %(reasonText)s": "Reden: %(reasonText)s", "Revoke Moderator": "Moderator degraderen", @@ -167,23 +167,23 @@ "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s %(day)s %(monthName)s, %(time)s", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s, %(time)s", "%(weekDayName)s %(time)s": "%(weekDayName)s, %(time)s", - "Set a display name:": "Weergavenaam instellen:", - "Upload an avatar:": "Een avatar uploaden:", - "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Geen verbinding met de thuisserver - controleer je verbinding. Controleer het SSL-certificaat van de thuisserver en browser-extensies die verzoeken kunnen blokkeren.", + "Set a display name:": "Stel een weergavenaam in:", + "Upload an avatar:": "Upload een avatar:", + "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Geen verbinding met de thuisserver - controleer uw verbinding, zorg ervoor dat het SSL-certificaat van de thuisserver vertrouwd is en dat er geen browserextensies verzoeken blokkeren.", "%(count)s new messages|other": "%(count)s nieuwe berichten", "Create an account": "Open een account", "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", - "Create a new chat or reuse an existing one": "Start een nieuwe chat of heropen een bestaande", - "Create Room": "Maak een ruimte aan", + "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik er een bestaand", + "Create Room": "Kamer aanmaken", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen opdracht", "Deactivate Account": "Account deactiveren", "Deactivate my account": "Mijn account deactiveren", "Decline": "Weigeren", "Decrypt %(text)s": "%(text)s ontsleutelen", - "Decryption error": "Ontsleutelfout", + "Decryption error": "Ontsleutelingsfout", "Delete": "Verwijderen", "Device already verified!": "Apparaat reeds geverifieerd!", "Device ID": "Apparaats-ID", @@ -200,10 +200,10 @@ "Download %(text)s": "%(text)s downloaden", "Drop File Here": "Versleep het bestand naar hier", "Ed25519 fingerprint": "Ed25519-vingerafdruk", - "Email": "E-mail", + "Email": "E-mailadres", "Email address": "E-mailadres", "Email address (optional)": "E-mailadres (optioneel)", - "Claimed Ed25519 fingerprint key": "Geclaimde Ed25519-sleutelvingerafdruk", + "Claimed Ed25519 fingerprint key": "Geclaimde Ed25519-vingerafdrukssleutel", "Custom": "Aangepast", "Custom level": "Aangepast niveau", "Deops user with given id": "Ontmachtigt gebruiker met de gegeven ID", @@ -211,7 +211,7 @@ "Displays action": "Geeft actie weer", "Drop here to tag %(section)s": "Versleep hierheen om %(section)s te labellen", "Email, name or matrix ID": "E-mailadres, naam of matrix-ID", - "Emoji": "Emoji", + "Emoji": "Emoticons", "Enable encryption": "Versleuteling inschakelen", "Enable Notifications": "Meldingen inschakelen", "Encrypted by a verified device": "Versleuteld door een geverifieerd apparaat", @@ -221,34 +221,34 @@ "Encryption is enabled in this room": "Versleuteling is ingeschakeld in deze ruimte", "Encryption is not enabled in this room": "Versleuteling is niet ingeschakeld in deze ruimte", "%(senderName)s ended the call.": "%(senderName)s heeft opgehangen.", - "End-to-end encryption information": "end-to-endbeveiligingsinformatie", + "End-to-end encryption information": "Informatie over eind-tot-eind-versleuteling", "End-to-end encryption is in beta and may not be reliable": "End-to-endbeveiliging is nog in bèta en kan onbetrouwbaar zijn", "Enter Code": "Voer code in", - "Enter passphrase": "Voer wachtzin in", + "Enter passphrase": "Voer wachtwoord in", "Error decrypting attachment": "Fout bij het ontsleutelen van de bijlage", - "Error: Problem communicating with the given homeserver.": "Fout: Er doet zich een probleem voor met het communiceren met de gegeven thuisserver.", - "Event information": "Gebeurtenis-informatie", + "Error: Problem communicating with the given homeserver.": "Fout: probleem bij communicatie met de gegeven thuisserver.", + "Event information": "Gebeurtenisinformatie", "Existing Call": "Bestaande oproep", "Export": "Exporteren", "Export E2E room keys": "E2E-kamersleutels exporteren", "Failed to ban user": "Verbannen van gebruiker is mislukt", "Failed to change power level": "Wijzigen van machtsniveau is mislukt", - "Failed to fetch avatar URL": "Niet gelukt de avatar-URL op te halen", + "Failed to fetch avatar URL": "Ophalen van avatar-URL is mislukt", "Failed to join room": "Toetreden van kamer is mislukt", - "Failed to leave room": "Niet gelukt de ruimte te verlaten", - "Failed to load timeline position": "Niet gelukt de tijdlijnpositie te laden", + "Failed to leave room": "Verlaten van kamer is mislukt", + "Failed to load timeline position": "Laden van tijdslijnpositie is mislukt", "Failed to mute user": "Dempen van gebruiker is mislukt", - "Failed to reject invite": "Niet gelukt de uitnodiging te weigeren", - "Failed to reject invitation": "Niet gelukt de uitnodiging te weigeren", + "Failed to reject invite": "Weigeren van uitnodiging is mislukt", + "Failed to reject invitation": "Weigeren van uitnodiging is mislukt", "Failed to save settings": "Niet gelukt om de instellingen op te slaan", - "Failed to send email": "Niet gelukt de e-mail te versturen", + "Failed to send email": "Versturen van e-mail is mislukt", "Failed to send request.": "Versturen van verzoek is mislukt.", "Failed to set avatar.": "Niet gelukt om de avatar in te stellen.", "Failed to set display name": "Instellen van weergavenaam is mislukt", "Failed to set up conference call": "Niet gelukt om een vergadergesprek te maken", "Failed to toggle moderator status": "Aanpassen van moderatorstatus is mislukt", "Failed to unban": "Ontbannen mislukt", - "Failed to upload file": "Niet gelukt het bestand te uploaden", + "Failed to upload file": "Uploaden van bestand is mislukt", "Failed to upload profile picture!": "Uploaden van profielfoto is mislukt!", "Failed to verify email address: make sure you clicked the link in the email": "Kan het e-mailadres niet verifiëren: zorg ervoor dat u de koppeling in de e-mail heeft aangeklikt", "Failure to create room": "Aanmaken van kamer is mislukt", @@ -257,7 +257,7 @@ "Filter room members": "Kamerleden filteren", "Forget room": "Kamer vergeten", "Forgot your password?": "Wachtwoord vergeten?", - "For security, this session has been signed out. Please sign in again.": "Voor veiligheidsredenen is deze sessie uitgelogd. Log alsjeblieft opnieuw in.", + "For security, this session has been signed out. Please sign in again.": "Wegens veiligheidsredenen is deze sessie afgemeld. Gelieve u opnieuw aan te melden.", "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "In verband met veiligheidsredenen zullen alle end-to-endbeveiligingsleutels van deze browser verwijderd worden. Als je je gespreksgeschiedenis van toekomstige Riot sessies wilt kunnen ontsleutelen, exporteer en bewaar dan de ruimte sleutels.", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s van %(fromPowerLevel)s naar %(toPowerLevel)s", "Guest access is disabled on this Home Server.": "Gasttoegang is uitgeschakeld op deze thuisserver.", @@ -275,7 +275,7 @@ "Incoming call from %(name)s": "Inkomende oproep van %(name)s", "Incoming video call from %(name)s": "Inkomende video-oproep van %(name)s", "Incoming voice call from %(name)s": "Inkomende spraakoproep van %(name)s", - "Incorrect username and/or password.": "Incorrecte gebruikersnaam en/of wachtwoord.", + "Incorrect username and/or password.": "Onjuiste gebruikersnaam en/of wachtwoord.", "Incorrect verification code": "Onjuiste verificatiecode", "Interface Language": "Interfacetaal", "Invalid alias format": "Ongeldig aliasformaat", @@ -290,7 +290,7 @@ "'%(alias)s' is not a valid format for an address": "'%(alias)s' is niet een geldig formaat voor een adres", "'%(alias)s' is not a valid format for an alias": "‘%(alias)s’ is geen geldig formaat voor een alias", "%(displayName)s is typing": "%(displayName)s is aan het typen", - "Sign in with": "Inloggen met", + "Sign in with": "Aanmelden met", "Join as voice or video.": "Deelnemen met spraak of video.", "Join Room": "Kamer toetreden", "%(targetName)s joined the room.": "%(targetName)s is tot de kamer toegetreden.", @@ -303,7 +303,7 @@ "Level:": "Niveau:", "Local addresses for this room:": "Lokale adressen voor deze kamer:", "Logged in as:": "Ingelogd als:", - "Logout": "Uitloggen", + "Logout": "Afmelden", "Low priority": "Lage prioriteit", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor alle kamerdeelnemers, vanaf het moment dat ze uitgenodigd zijn.", "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s heeft de toekomstige kamergeschiedenis zichtbaar gemaakt voor alle kamerdeelnemers, vanaf het moment dat ze toegetreden zijn.", @@ -314,7 +314,7 @@ "Markdown is disabled": "Markdown is uitgeschakeld", "Markdown is enabled": "Markdown is ingeschakeld", "matrix-react-sdk version:": "matrix-react-sdk-versie:", - "Message not sent due to unknown devices being present": "Bericht niet verzonden doordat er een onbekende apparaten aanwezig zijn", + "Message not sent due to unknown devices being present": "Bericht niet verstuurd doordat er een onbekende apparaten aanwezig zijn", "Missing room_id in request": "room_id ontbreekt in verzoek", "Missing user_id in request": "user_id ontbreekt in verzoek", "Mobile phone number": "Mobiele-telefoonnummer", @@ -326,7 +326,7 @@ "New passwords must match each other.": "Nieuwe wachtwoorden moeten overeenkomen.", "Once encryption is enabled for a room it cannot be turned off again (for now)": "Zodra versleuteling in een ruimte is ingeschakeld kan het niet meer worden uitgeschakeld (kan later wijzigen)", "Only people who have been invited": "Alleen personen die zijn uitgenodigd", - "Please check your email and click on the link it contains. Once this is done, click continue.": "Bekijk je e-mail en klik op de link die het bevat. Zodra dit klaar is, klik op verder gaan.", + "Please check your email and click on the link it contains. Once this is done, click continue.": "Bekijk uw e-mail en klik op de koppeling erin. Klik zodra u dit gedaan heeft op ‘Verdergaan’.", "Power level must be positive integer.": "Machtsniveau moet een positief geheel getal zijn.", "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s heeft zijn/haar weergavenaam (%(oldDisplayName)s) verwijderd.", "%(senderName)s removed their profile picture.": "%(senderName)s heeft zijn/haar profielfoto verwijderd.", @@ -336,14 +336,14 @@ "%(senderName)s requested a VoIP conference.": "%(senderName)s heeft een VoIP-vergadering aangevraagd.", "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Het wachtwoord veranderen betekent momenteel dat alle end-to-endbeveiligingssleutels op alle apparaten veranderen waardoor versleutelde gespreksgeschiedenis onleesbaar wordt, behalve als je eerst de ruimte sleutels exporteert en daarna opnieuw importeert. Dit zal in de toekomst verbeterd worden.", "Results from DuckDuckGo": "Resultaten van DuckDuckGo", - "Return to login screen": "Naar het inlogscherm terugkeren", + "Return to login screen": "Terug naar het aanmeldscherm", "Riot does not have permission to send you notifications - please check your browser settings": "Riot heeft geen toestemming om u meldingen te versturen - controleer uw browserinstellingen", "Riot was not given permission to send notifications - please try again": "Riot heeft geen toestemming gekregen om u meldingen te versturen - probeer het opnieuw", "riot-web version:": "riot-web-versie:", "Room %(roomId)s not visible": "Kamer %(roomId)s is niet zichtbaar", "Room Colour": "Kamerkleur", - "Room contains unknown devices": "De ruimte bevat onbekende apparaten", - "Room name (optional)": "Ruimtenaam (optioneel)", + "Room contains unknown devices": "De kamer bevat onbekende apparaten", + "Room name (optional)": "Kamernaam (optioneel)", "%(roomName)s does not exist.": "%(roomName)s bestaat niet.", "%(roomName)s is not accessible at this time.": "%(roomName)s is op dit moment niet toegankelijk.", "Rooms": "Kamers", @@ -354,14 +354,14 @@ "Searches DuckDuckGo for results": "Zoekt op DuckDuckGo voor resultaten", "Seen by %(userName)s at %(dateTime)s": "Gezien door %(userName)s op %(dateTime)s", "Send anyway": "Alsnog versturen", - "Sender device information": "Afzenderapparaatinformatie", - "Send Reset Email": "Stuur Reset-E-mail", + "Sender device information": "Informatie over apparaat van afzender", + "Send Reset Email": "E-mail voor opnieuw instellen versturen", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s heeft een afbeelding gestuurd.", "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s heeft %(targetDisplayName)s in de kamer uitgenodigd.", "Server error": "Serverfout", "Server may be unavailable or overloaded": "De server kan onbereikbaar of overbelast zijn", - "Server may be unavailable, overloaded, or search timed out :(": "De server is misschien onbereikbaar, overbelast of het zoeken duurde te lang :(", - "Server may be unavailable, overloaded, or the file too big": "De server is misschien onbereikbaar, overbelast of het bestand is te groot", + "Server may be unavailable, overloaded, or search timed out :(": "De server is misschien onbereikbaar of overbelast, of het zoeken duurde te lang :(", + "Server may be unavailable, overloaded, or the file too big": "De server is misschien onbereikbaar of overbelast, of het bestand is te groot", "Server may be unavailable, overloaded, or you hit a bug.": "De server is misschien onbereikbaar of overbelast, of u bent een fout tegengekomen.", "Server unavailable, overloaded, or something else went wrong.": "De server is onbereikbaar of overbelast, of er is iets anders foutgegaan.", "Session ID": "Sessie-ID", @@ -373,18 +373,18 @@ "Show panel": "Paneel weergeven", "Show Text Formatting Toolbar": "Tekstopmaakwerkbalk weergeven", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Tijd in 12-uursformaat weergeven (bv. 2:30pm)", - "Signed Out": "Uitgelogd", - "Sign in": "Inloggen", - "Sign out": "Uitloggen", - "%(count)s of your messages have not been sent.|other": "Een paar van je berichten zijn niet verstuurd.", + "Signed Out": "Afgemeld", + "Sign in": "Aanmelden", + "Sign out": "Afmelden", + "%(count)s of your messages have not been sent.|other": "Enkele van uw berichten zijn niet verstuurd.", "Someone": "Iemand", "The default role for new room members is": "De standaardrol voor nieuwe ruimteleden is", "The main address for this room is": "Het hoofdadres voor deze ruimte is", - "The phone number entered looks invalid": "Het telefoonnummer dat ingevoerd is ziet er ongeldig uit", + "The phone number entered looks invalid": "Het ingevoerde telefoonnummer ziet er ongeldig uit", "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "De versleutelingssleutel die u heeft verstrekt komt overeen met de versleutelingssleutel die u heeft ontvangen van het apparaat %(deviceId)s van %(userId)s. Het apparaat is gemarkeerd als geverifieerd.", "This email address is already in use": "Dit e-mailadres is al in gebruik", "This email address was not found": "Dit e-mailadres is niet gevonden", - "The email address linked to your account must be entered.": "Het e-mailadres dat met je account verbonden is moet worden ingevoerd.", + "The email address linked to your account must be entered.": "Het e-mailadres dat met uw account verbonden is moet ingevoerd worden.", "The file '%(fileName)s' exceeds this home server's size limit for uploads": "Het bestand '%(fileName)s' overtreft de maximale bestandsgrootte voor uploads van deze thuisserver", "The file '%(fileName)s' failed to upload": "Uploaden van bestand ‘%(fileName)s’ is mislukt", "The remote side failed to pick up": "De andere kant heeft niet opgenomen", @@ -403,8 +403,8 @@ "To link to a room it must have an address.": "Om naar een ruimte te linken moet het een adres hebben.", "To reset your password, enter the email address linked to your account": "Voer het e-mailadres dat met je account verbonden is in om je wachtwoord opnieuw in te stellen", "To use it, just wait for autocomplete results to load and tab through them.": "Om het te gebruiken, wacht u tot de automatisch aangevulde resultaten geladen zijn en tabt u erdoorheen.", - "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Je probeerde een gegeven punt in de tijdlijn van deze ruimte te laden maar je hebt geen toestemming de desbetreffende berichten te zien.", - "Tried to load a specific point in this room's timeline, but was unable to find it.": "Probeerde tevergeefs een gegeven punt in de tijdlijn van deze ruimte te laden.", + "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "U heeft geprobeerd een gegeven punt in de tijdslijn van deze kamer te laden, maar u heeft geen toestemming om het desbetreffende bericht te zien.", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "Geprobeerd een gegeven punt in de tijdslijn van deze kamer te laden, maar kon dit niet vinden.", "Turn Markdown off": "Zet Markdown uit", "Turn Markdown on": "Zet Markdown aan", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s heeft eind-tot-eind-versleuteling aangezet (%(algorithm)s-algoritme).", @@ -419,20 +419,20 @@ "Unable to load device list": "Kan lijst van apparaten niet laden", "Undecryptable": "Onontsleutelbaar", "Unencrypted room": "Ontsleutelde ruimte", - "unencrypted": "ontsleuteld", + "unencrypted": "onversleuteld", "Unencrypted message": "Onversleuteld bericht", "unknown caller": "onbekende beller", - "unknown device": "Onbekend apparaat", - "Unknown room %(roomId)s": "Onbekende ruimte %(roomId)s", + "unknown device": "onbekend apparaat", + "Unknown room %(roomId)s": "Onbekende kamer %(roomId)s", "Unknown (user, device) pair:": "Onbekend paar (gebruiker, apparaat):", "Unmute": "Niet dempen", "Unnamed Room": "Naamloze kamer", "Unrecognised command:": "Onbekende opdracht:", "Unrecognised room alias:": "Onbekende kameralias:", "Unverified": "Niet geverifieerd", - "Uploading %(filename)s and %(count)s others|zero": "Aan het uploaden %(filename)s", - "Uploading %(filename)s and %(count)s others|one": "%(filename)s en %(count)s andere aan het uploaden", - "Uploading %(filename)s and %(count)s others|other": "%(filename)s en %(count)s anderen aan het uploaden", + "Uploading %(filename)s and %(count)s others|zero": "%(filename)s wordt geüpload", + "Uploading %(filename)s and %(count)s others|one": "%(filename)s en %(count)s ander worden geüpload", + "Uploading %(filename)s and %(count)s others|other": "%(filename)s en %(count)s andere worden geüpload", "Upload avatar": "Avatar uploaden", "Upload Failed": "Uploaden mislukt", "Upload Files": "Bestanden uploaden", @@ -447,7 +447,7 @@ "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (macht %(powerLevelNumber)s)", "Username invalid: %(errMessage)s": "Gebruikersnaam ongeldig: %(errMessage)s", "Users": "Gebruikers", - "Verification Pending": "Verificatie Uitstaand", + "Verification Pending": "Verificatie in afwachting", "Verification": "Verificatie", "verified": "geverifieerd", "Verified": "Geverifieerd", @@ -470,7 +470,7 @@ "Who would you like to communicate with?": "Met wie zou u willen communiceren?", "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s heeft de uitnodiging van %(targetName)s ingetrokken.", "Would you like to accept or decline this invitation?": "Wilt u deze uitnodiging aanvaarden of afwijzen?", - "You already have existing direct chats with this user:": "Je hebt al bestaande privé-gesprekken met deze gebruiker:", + "You already have existing direct chats with this user:": "U heeft al bestaande één-op-één-gesprekken met deze gebruiker:", "You are already in a call.": "U bent al in gesprek.", "You're not in any rooms yet! Press to make a room or to browse the directory": "Je zit nog niet in een ruimte! Druk op om een ruimte te maken of om door de catalogus te bladeren", "You are trying to access %(roomName)s.": "U probeert toegang te verkrijgen tot %(roomName)s.", @@ -483,42 +483,42 @@ "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device": "Je bent op alle apparaten uitgelegd en je zal niet langer notificaties ontvangen. Om notificaties weer aan te zetten, log op elk apparaat opnieuw in", "You have disabled URL previews by default.": "U heeft URL-voorvertoningen standaard uitgeschakeld.", "You have enabled URL previews by default.": "U heeft URL-voorvertoningen standaard ingeschakeld.", - "You have no visible notifications": "Je hebt geen zichtbare notificaties", + "You have no visible notifications": "U heeft geen zichtbare meldingen", "You may wish to login with a different account, or add this email to this account.": "U kunt zich met een andere account aanmelden, of dit e-mailadres aan uw account toevoegen.", - "You must register to use this functionality": "Je moet je registreren om deze functie te gebruiken", + "You must register to use this functionality": "U dient u te registreren om deze functie te gebruiken", "You need to be able to invite users to do that.": "Om dit te kunnen doen, moet u gebruikers kunnen uitnodigen.", "You need to be logged in.": "Aanmelding is vereist.", "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat uw e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Uw wachtwoord is gewijzigd. U zult op andere apparaten geen pushmeldingen meer ontvangen totdat u zich er opnieuw op aanmeldt", - "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat je in een gesprek zit, weet je zeker dat je wilt afsluiten?", - "You seem to be uploading files, are you sure you want to quit?": "Het ziet er naar uit dat je bestanden aan het uploaden bent, weet je zeker dat je wilt afsluiten?", + "You seem to be in a call, are you sure you want to quit?": "Het ziet er naar uit dat u in gesprek bent, weet u zeker dat u wilt afsluiten?", + "You seem to be uploading files, are you sure you want to quit?": "Het ziet er naar uit dat u bestanden aan het uploaden bent, weet u zeker dat u wilt afsluiten?", "You should not yet trust it to secure data": "Je moet het nog niet vertrouwen om gegevens te beveiligen", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "U kunt deze veranderingen niet ongedaan maken aangezien u de gebruiker tot hetzelfde niveau als uzelf promoveert.", "Your home server does not support device management.": "Je thuisserver ondersteund geen apparaatbeheer.", - "This server does not support authentication with a phone number.": "Deze server ondersteunt geen authenticatie met een telefoonnummer.", - "Missing password.": "Het wachtwoord mist.", - "Passwords don't match.": "De wachtwoorden komen niet overeen.", + "This server does not support authentication with a phone number.": "Deze server biedt geen ondersteuning voor authenticatie met een telefoonnummer.", + "Missing password.": "Wachtwoord ontbreekt.", + "Passwords don't match.": "Wachtwoorden komen niet overeen.", "Password too short (min %(MIN_PASSWORD_LENGTH)s).": "Het wachtwoord is te kort (min %(MIN_PASSWORD_LENGTH)s).", - "This doesn't look like a valid email address.": "Dit ziet er niet uit als een geldig e-mailadres.", - "This doesn't look like a valid phone number.": "Dit zit er niet uit als een geldig telefoonnummer.", + "This doesn't look like a valid email address.": "Dit is geen geldig e-mailadres.", + "This doesn't look like a valid phone number.": "Dit is geen geldig telefoonnummer.", "User names may only contain letters, numbers, dots, hyphens and underscores.": "Gebruikersnamen mogen alleen letters, nummers, punten, afbreek- en lage streepjes bevatten.", - "An unknown error occurred.": "Een onbekende fout voorgevallen.", + "An unknown error occurred.": "Er is een onbekende fout opgetreden.", "I already have an account": "Ik heb al een account", - "An error occurred: %(error_string)s": "Er is een fout voorgevallen: %(error_string)s", + "An error occurred: %(error_string)s": "Er is een fout opgetreden: %(error_string)s", "Topic": "Onderwerp", "Make Moderator": "Benoemen tot moderator", "Make this room private": "Deze ruimte privé maken", "Share message history with new users": "Bericht geschiedenis met nieuwe gebruikers delen", "Encrypt room": "Ruimte versleutelen", - "There are no visible files in this room": "Er zijn geen zichtbare bestanden in deze ruimte", - "Room": "Ruimte", - "Connectivity to the server has been lost.": "De connectiviteit naar de server is verloren.", - "Sent messages will be stored until your connection has returned.": "Verstuurde berichten zullen opgeslagen worden tot je connectie weer terug is.", + "There are no visible files in this room": "Er zijn geen zichtbare bestanden in deze kamer", + "Room": "Kamer", + "Connectivity to the server has been lost.": "De verbinding met de server is verbroken.", + "Sent messages will be stored until your connection has returned.": "Verstuurde berichten zullen opgeslagen worden totdat uw verbinding hersteld is.", "(~%(count)s results)|one": "(~%(count)s resultaat)", "(~%(count)s results)|other": "(~%(count)s resultaten)", - "Active call": "Actief gesprek", + "Active call": "Actieve oproep", "bold": "vetgedrukt", "italic": "schuingedrukt", "strike": "doorgestreept", @@ -534,42 +534,42 @@ "Analytics": "Statistische gegevens", "Options": "Opties", "Riot collects anonymous analytics to allow us to improve the application.": "Riot verzamelt anonieme analysegegevens die het mogelijk maken de toepassing te verbeteren.", - "Passphrases must match": "Wachtzinnen moeten overeenkomen", - "Passphrase must not be empty": "Wachtzin mag niet leeg zijn", - "Export room keys": "Ruimtesleutels exporteren", - "Confirm passphrase": "Wachtzin bevestigen", - "Import room keys": "Ruimtesleutels importeren", - "File to import": "Het in te lezen bestand", - "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.": "Hiermee kun je de sleutels van je ontvangen berichten in versleutelde ruimten naar een lokaal bestand wegschrijven. Je kunt dan later het bestand in een ander Matrix-programma inlezen, zodat ook dat programma deze berichten kan ontsleutelen.", - "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.": "Iedereen die het weggeschreven bestand kan lezen kan daarmee alle berichten die jij kunt zien ontcijferen. Je zult dus voorzichtig moeten zijn en het bestand veilig bewaren. Daartoe kun je hieronder een wachtzin invoeren, die dan gebruikt zal worden om de geëxporteerde gegevens te versleutelen. Het is dan enkel mogelijk de gegevens in te lezen met dezelfde wachtzin.", - "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.": "Hiermee kun je eerder vanuit een ander Matrixprogramma weggeschreven versleutelingscodes inlezen, zodat je alle berichten die het andere programma kon ontcijferen ook hier zult kunnen lezen.", - "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Het weggeschreven bestand is beveiligd met een wachtzin. Voer die wachtzin hier in om het bestand te ontcijferen.", - "You must join the room to see its files": "Je moet tot de ruimte toetreden om de bestanden te kunnen zien", + "Passphrases must match": "Wachtwoorden moeten overeenkomen", + "Passphrase must not be empty": "Wachtwoord mag niet leeg zijn", + "Export room keys": "Kamersleutels exporteren", + "Confirm passphrase": "Bevestig wachtwoord", + "Import room keys": "Kamersleutels importeren", + "File to import": "Te importeren bestand", + "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.": "Hiermee kunt u de sleutels van uw ontvangen berichten in versleutelde kamers naar een lokaal bestand exporteren. U kunt dit bestand later in een andere Matrix-cliënt importeren, zodat ook die cliënt deze berichten zal kunnen ontsleutelen.", + "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.": "Iedereen die het geëxporteerde bestand kan lezen, kan daarmee alle versleutelde berichten die u kunt zien ontsleutelen. Wees dus voorzichtig en bewaar dit bestand op een veilige plaats. Daartoe kunt u hieronder een wachtwoord invoeren, dat dan gebruikt zal worden om de geëxporteerde gegevens te versleutelen. Het is dan enkel mogelijk de gegevens in te lezen met hetzelfde wachtwoord.", + "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.": "Hiermee kunt u de versleutelingssleutels die u uit een andere Matrix-cliënt had geëxporteerd importeren, zodat u alle berichten die het andere programma kon ontsleutelen ook hier zult kunnen lezen.", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Het geëxporteerde bestand is beveiligd met een wachtwoord. Voer dat wachtwoord hier in om het bestand te ontsleutelen.", + "You must join the room to see its files": "U moet tot de kamer toetreden om de bestanden te kunnen zien", "Reject all %(invitedRooms)s invites": "Alle %(invitedRooms)s-uitnodigingen weigeren", - "Start new chat": "Nieuw gesprek starten", + "Start new chat": "Nieuw gesprek beginnen", "Failed to invite": "Uitnodigen is mislukt", "Failed to invite user": "Uitnodigen van gebruiker is mislukt", "Failed to invite the following users to the %(roomName)s room:": "Uitnodigen van volgende gebruikers in kamer %(roomName)s is mislukt:", - "Confirm Removal": "Verwijdering Bevestigen", - "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Weet je zeker dat je deze gebeurtenis wilt verwijderen? Wees er wel van bewust dat als je een ruimtenaam of onderwerp verwijderd je de verandering ongedaan kunt maken.", + "Confirm Removal": "Verwijdering bevestigen", + "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Weet u zeker dat u deze gebeurtenis wilt verwijderen? Wees u er wel van bewust dat als u een kamernaam of onderwerpswijziging verwijdert, u de verandering mogelijk ongedaan maakt.", "Unknown error": "Onbekende fout", - "Incorrect password": "Incorrect wachtwoord", - "To continue, please enter your password.": "Voer om verder te gaan je wachtwoord in.", - "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Zoek op een andere manier (bijv. in levenden lijve of per telefoon) contact met de eigenaar om te controleren of dit apparaat vertrouwd kan worden, en vraag of de sleutel voor dit apparaat in hun Gebruikersinstellingen gelijk is aan onderstaande sleutel:", + "Incorrect password": "Onjuist wachtwoord", + "To continue, please enter your password.": "Voer uw wachtwoord in om verder te gaan.", + "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Neem op een andere manier (bv. persoonlijk of telefonisch) contact op met de eigenaar om te controleren of dit apparaat vertrouwd kan worden, en vraag of de sleutel voor dit apparaat in hun Gebruikersinstellingen gelijk is aan onderstaande sleutel:", "Device name": "Apparaatnaam", "Device Name": "Apparaatnaam", - "Device key": "Apparaatsleutel", - "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Komen ze overeen? Zo ja, druk dan op de knop 'verifiëren' hieronder. Zo neen, druk dan liever op de knop 'blokkeren', want dan onderschept iemand berichten naar dit apparaat.", + "Device key": "Apparaatssleutel", + "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Klik hieronder op de knop ‘Verifiëren’ als de sleutels overeenkomen. Zo niet drukt u op de knop ‘Blokkeren’, want dan onderschept iemand berichten naar dit apparaat.", "Blacklist": "Blokkeren", - "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit je ongecontroleerde apparaten uit; om berichten naar deze apparaten te versturen moet je ze controleren.", + "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit u ongeverifieerde apparaten uit; om berichten naar deze apparaten te versturen moet u ze verifiëren.", "Unblacklist": "Deblokkeren", "In future this verification process will be more sophisticated.": "In de toekomst zal dit verificatie proces meer geraffineerd zijn.", "Verify device": "Apparaat verifiëren", "I verify that the keys match": "Ik verifieer dat de sleutels overeenkomen", "Unable to restore session": "Het is niet mogelijk de sessie te herstellen", - "If you have previously used a more recent version of Riot, your session may be incompatible with this version. Close this window and return to the more recent version.": "Als je eerst gebruik hebt gemaakt van een recentere versie van Riot, dan is je sessie misschien onverenigbaar met deze versie. Sluit dit scherm en ga terug naar de recentere versie.", - "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We raden je aan ieder apparaat te controleren om te vast te stellen of ze tot de legitieme eigenaar behoren, maar je kunt het bericht desgewenst zonder controle versturen.", - "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" bevat apparaten die je nog niet eerder hebt gezien.", + "If you have previously used a more recent version of Riot, your session may be incompatible with this version. Close this window and return to the more recent version.": "Als u reeds gebruik heeft gemaakt van een recentere versie van Riot, is uw sessie misschien onverenigbaar met deze versie. Sluit dit venster en ga terug naar de recentere versie.", + "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We raden u aan ieder apparaat te verifiëren om vast te stellen of ze tot de rechtmatige eigenaar behoren, maar u kunt het bericht ook zonder verificatie versturen.", + "\"%(RoomName)s\" contains devices that you haven't seen before.": "‘%(RoomName)s’ bevat apparaten die u nog niet eerder heeft gezien.", "Unknown devices": "Onbekende apparaten", "Unknown Address": "Onbekend adres", "Unverify": "Ontverifiëren", @@ -581,10 +581,10 @@ "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.": "Je kan de alternatieve-serverinstellingen gebruiken om bij andere Matrix-servers in te loggen door een andere thuisserver-URL te specificeren.", "This allows you to use this app with an existing Matrix account on a different home server.": "Dit maakt het mogelijk om deze applicatie te gebruiken met een bestaand Matrix-account op een andere thuisserver.", "You can also set a custom identity server but this will typically prevent interaction with users based on email address.": "Je kan ook een aangepaste identiteitsserver instellen maar dit zal waarschijnlijk interactie met gebruikers gebaseerd op een e-mailadres voorkomen.", - "Please check your email to continue registration.": "Bekijk je e-mail om door te gaan met de registratie.", - "Token incorrect": "Bewijs incorrect", + "Please check your email to continue registration.": "Bekijk uw e-mail om verder te gaan met de registratie.", + "Token incorrect": "Bewijs onjuist", "Please enter the code it contains:": "Voer de code in die het bevat:", - "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Als je geen e-mailadres specificeert zul je je wachtwoord niet kunnen resetten. Weet je het zeker?", + "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Als u geen e-mailadres opgeeft, zult u uw wachtwoord niet opnieuw kunnen instellen. Weet u het zeker?", "You are registering with %(SelectedTeamName)s": "Je registreert je met %(SelectedTeamName)s", "Default server": "Standaardserver", "Custom server": "Alternatieve server", @@ -606,8 +606,8 @@ "Offline": "Offline", "Updates": "Updates", "Check for update": "Controleren op updates", - "Start chatting": "Start met praten", - "Start Chatting": "Start Met Praten", + "Start chatting": "Begin te praten", + "Start Chatting": "Begin te praten", "Click on the button below to start chatting!": "Klik op de knop hieronder om het gesprek te beginnen!", "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s heeft de kameravatar aangepast naar ", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s heeft de kameravatar verwijderd.", @@ -615,21 +615,21 @@ "Username available": "Gebruikersnaam beschikbaar", "Username not available": "Gebruikersnaam niet beschikbaar", "Something went wrong!": "Er is iets misgegaan!", - "This will be your account name on the homeserver, or you can pick a different server.": "Dit zal je account naam worden op de thuisserver, of je kunt een andere server kiezen.", - "If you already have a Matrix account you can log in instead.": "Als je al een Matrix-account hebt kun je ook meteen inloggen.", + "This will be your account name on the homeserver, or you can pick a different server.": "Dit zal uw accountnaam worden op de -thuisserver, of u kunt een andere server kiezen.", + "If you already have a Matrix account you can log in instead.": "Als u al een Matrix-account heeft, kunt u zich meteen aanmelden.", "Your browser does not support the required cryptography extensions": "Uw browser ondersteunt de benodigde cryptografie-extensies niet", "Not a valid Riot keyfile": "Geen geldig Riot-sleutelbestand", "Authentication check failed: incorrect password?": "Aanmeldingscontrole mislukt: onjuist wachtwoord?", "Disable Peer-to-Peer for 1:1 calls": "Peer-to-Peer voor 1:1 oproepen uitschakelen", "Do you want to set an email address?": "Wilt u een e-mailadres instellen?", - "This will allow you to reset your password and receive notifications.": "Hierdoor zul je je wachtwoord kunnen resetten en mededelingen ontvangen.", + "This will allow you to reset your password and receive notifications.": "Hierdoor zult u uw wachtwoord opnieuw kunnen instellen en meldingen ontvangen.", "To return to your account in future you need to set a password": "Om in de toekomst naar je account terug te gaan moet je een wachtwoord instellen", "Skip": "Overslaan", "Start verification": "Verificatie starten", "Share without verifying": "Delen zonder verificatie", "Ignore request": "Verzoek negeren", - "You added a new device '%(displayName)s', which is requesting encryption keys.": "Je hebt een nieuw apparaat '%(displayName)s' toegevoegd dat om ontcijferingssleutels vraagt.", - "Your unverified device '%(displayName)s' is requesting encryption keys.": "Je niet geverifieerde apparaat '%(displayName)s' vraagt naar versleutelingssleutels.", + "You added a new device '%(displayName)s', which is requesting encryption keys.": "U heeft een nieuw apparaat ‘%(displayName)s’ toegevoegd, dat om versleutelingssleutels vraagt.", + "Your unverified device '%(displayName)s' is requesting encryption keys.": "Uw ongeverifieerde apparaat ‘%(displayName)s’ vraagt naar versleutelingssleutels.", "Encryption key request": "Verzoek voor versleutelingssleutel", "Define the power level of a user": "Bepaal het machtsniveau van een gebruiker", "Add a widget": "Widget toevoegen", @@ -656,13 +656,13 @@ "You do not have permission to do that in this room.": "U heeft geen toestemming om dat in deze kamer te doen.", "Verifies a user, device, and pubkey tuple": "Verifieert een combinatie van gebruiker, apparaat en publieke sleutel", "Autocomplete Delay (ms):": "Automatisch-aanvullen-vertraging (ms):", - "Loading device info...": "Apparaatinformatie aan het laden...", + "Loading device info...": "Apparaatinformatie wordt geladen…", "Example": "Voorbeeld", - "Create": "Creëer", - "Featured Rooms:": "Prominente Ruimtes:", - "Featured Users:": "Prominente Gebruikers:", + "Create": "Aanmaken", + "Featured Rooms:": "Prominente kamers:", + "Featured Users:": "Prominente gebruikers:", "Automatically replace plain text Emoji": "Tekst automatisch vervangen door emoticons", - "Failed to upload image": "Kon de afbeelding niet uploaden", + "Failed to upload image": "Uploaden van afbeelding is mislukt", "Hide avatars in user and room mentions": "Avatars in gebruiker- en ruimte-vermeldingen verbergen", "%(widgetName)s widget added by %(senderName)s": "%(widgetName)s-widget toegevoegd door %(senderName)s", "%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s-widget verwijderd door %(senderName)s", @@ -791,8 +791,8 @@ "URL previews are disabled by default for participants in this room.": "URL-voorvertoningen zijn voor deelnemers in deze kamer standaard uitgeschakeld.", "Message removed by %(userId)s": "Bericht verwijderd door %(userId)s", "Message removed": "Bericht verwijderd", - "An email has been sent to %(emailAddress)s": "Een e-mail is naar %(emailAddress)s verstuurd", - "A text message has been sent to %(msisdn)s": "Een tekstbericht is naar %(msisdn)s versuurd", + "An email has been sent to %(emailAddress)s": "Er is een e-mail naar %(emailAddress)s verstuurd", + "A text message has been sent to %(msisdn)s": "Er is een sms naar %(msisdn)s verstuurd", "Username on %(hs)s": "Gebruikersnaam op %(hs)s", "Remove from community": "Verwijderen uit gemeenschap", "Disinvite this user from community?": "Uitnodiging voor deze gebruiker tot de gemeenschap intrekken?", @@ -803,8 +803,8 @@ "Flair will appear if enabled in room settings": "Badge zal worden weergeven als het aangezet is in de ruimte-instellingen", "Flair will not appear": "Badge zal niet weergeven worden", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Weet u zeker dat u ‘%(roomName)s’ uit %(groupId)s wilt verwijderen?", - "Removing a room from the community will also remove it from the community page.": "De ruimte uit de gemeenschap verwijderen zal deze ook van de gemeenschapspagina verwijderen.", - "Failed to remove room from community": "Verwijderen van ruimte uit gemeenschap is mislukt", + "Removing a room from the community will also remove it from the community page.": "De kamer uit de gemeenschap verwijderen zal deze ook van de gemeenschapspagina verwijderen.", + "Failed to remove room from community": "Verwijderen van kamer uit gemeenschap is mislukt", "Failed to remove '%(roomName)s' from %(groupId)s": "Verwijderen van ‘%(roomName)s’ uit %(groupId)s is mislukt", "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "De zichtbaarheid van ‘%(roomName)s’ in %(groupId)s kon niet bijgewerkt worden.", "Visibility in Room List": "Zichtbaarheid in kamerlijst", @@ -876,73 +876,73 @@ "email address": "e-mailadres", "Try using one of the following valid address types: %(validTypesList)s.": "Probeer één van de volgende geldige adrestypes: %(validTypesList)s.", "You have entered an invalid address.": "U heeft een ongeldig adres ingevoerd.", - "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Een gemeenschaps-ID moet uit enkel de karakters a-z, 0-9, of '=_-./' bestaan", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Een gemeenschaps-ID kan enkel uit de tekens a-z, 0-9, of ‘=_-./’ bestaan", "Community IDs cannot be empty.": "Een gemeenschaps-ID kan niet leeg zijn.", - "Something went wrong whilst creating your community": "Er is iets fout gegaan tijdens het aanmaken van je gemeenschap", - "Create Community": "Gemeenschap Aanmaken", + "Something went wrong whilst creating your community": "Er is iets fout gegaan bij het aanmaken van uw gemeenschap", + "Create Community": "Gemeenschap aanmaken", "Community Name": "Gemeenschapsnaam", - "Community ID": "Gemeenschap-ID", + "Community ID": "Gemeenschaps-ID", "example": "voorbeeld", "Advanced options": "Geavanceerde opties", - "Block users on other matrix homeservers from joining this room": "Gebruikers van andere matrix thuisservers van deze ruimte uitsluiten", - "This setting cannot be changed later!": "Deze instelling kan niet later veranderd worden!", - "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      HTML voor je gemeenschapspagina

      \n

      \n Gebruik de lange beschrijving om nieuwe leden in de gemeenschap te introduceren of om belangrijke links aan te bieden.\n

      \n

      \n Je kunt zelfs 'img' tags gebruiken.\n

      \n", - "Add rooms to the community summary": "Voeg ruimtes aan de gemeenschapssamenvatting toe", - "Which rooms would you like to add to this summary?": "Welke ruimtes zou je aan deze samenvatting willen toevoegen?", - "Add to summary": "Voeg aan samenvatting toe", - "Failed to add the following rooms to the summary of %(groupId)s:": "Kon de volgende ruimten niet aan het overzicht van %(groupId)s toevoegen:", - "Add a Room": "Voeg een ruimte toe", - "Failed to remove the room from the summary of %(groupId)s": "Kon de ruimte niet uit het overzicht van %(groupId)s verwijderen", - "The room '%(roomName)s' could not be removed from the summary.": "De ruimte '%(roomName)s' kan niet van de samenvatting verwijderd worden.", + "Block users on other matrix homeservers from joining this room": "Gebruikers van andere matrix-thuisservers uitsluiten van deze kamer", + "This setting cannot be changed later!": "Deze instelling kan later niet meer veranderd worden!", + "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      HTML voor uw gemeenschapspagina

      \n

      \n Gebruik de lange beschrijving om nieuwe leden in de gemeenschap te introduceren of om belangrijke koppelingen aan te bieden.\n

      \n

      \n U kunt zelfs ‘img’-tags gebruiken.\n

      \n", + "Add rooms to the community summary": "Voeg kamers aan de gemeenschapssamenvatting toe", + "Which rooms would you like to add to this summary?": "Welke kamers zou u aan deze samenvatting willen toevoegen?", + "Add to summary": "Toevoegen aan samenvatting", + "Failed to add the following rooms to the summary of %(groupId)s:": "Kon de volgende kamers niet aan het overzicht van %(groupId)s toevoegen:", + "Add a Room": "Voeg een kamer toe", + "Failed to remove the room from the summary of %(groupId)s": "Kon de kamer niet uit het overzicht van %(groupId)s verwijderen", + "The room '%(roomName)s' could not be removed from the summary.": "De kamer ‘%(roomName)s’ kan niet uit de samenvatting verwijderd worden.", "Add users to the community summary": "Voeg gebruikers aan de gemeenschapssamenvatting toe", - "Who would you like to add to this summary?": "Wie zou je aan de samenvatting toe willen voegen?", + "Who would you like to add to this summary?": "Wie zou u aan de samenvatting willen toevoegen?", "Failed to add the following users to the summary of %(groupId)s:": "Kon de volgende gebruikers niet aan het overzicht van %(groupId)s toevoegen:", - "Add a User": "Voeg een Gebruiker toe", - "Failed to remove a user from the summary of %(groupId)s": "Het is niet gelukt een gebruiker uit het overzicht van %(groupId)s te verwijderen", - "The user '%(displayName)s' could not be removed from the summary.": "De gebruiker '%(displayName)s' kon niet van de samenvatting verwijderd worden.", - "Failed to update community": "Kon de gemeenschap niet bijwerken", - "Unable to accept invite": "De uitnodiging kon niet geaccepteerd worden", - "Unable to reject invite": "De uitnodiging kon niet afgewezen worden", - "Leave Community": "Gemeenschap Verlaten", + "Add a User": "Voeg een gebruiker toe", + "Failed to remove a user from the summary of %(groupId)s": "Verwijderen van gebruiker uit het overzicht van %(groupId)s is mislukt", + "The user '%(displayName)s' could not be removed from the summary.": "De gebruiker ‘%(displayName)s’ kon niet uit de samenvatting verwijderd worden.", + "Failed to update community": "Bijwerken van gemeenschap is mislukt", + "Unable to accept invite": "Kan de uitnodiging niet aanvaarden", + "Unable to reject invite": "Kan de uitnodiging niet weigeren", + "Leave Community": "Gemeenschap verlaten", "Leave %(groupName)s?": "%(groupName)s verlaten?", "Leave": "Verlaten", "Community Settings": "Gemeenschapsinstellingen", - "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Deze ruimtes worden aan gemeenschapsleden getoond op de gemeenschapspagina. Gemeenschapsleden kunnen tot de ruimtes toetreden door er op te klikken.", - "%(inviter)s has invited you to join this community": "%(inviter)s heeft jou uitgenodigd tot deze gemeenschap toe te treden", - "You are an administrator of this community": "Je bent een administrator van deze gemeenschap", - "You are a member of this community": "Je bent lid van deze gemeenschap", - "Your community hasn't got a Long Description, a HTML page to show to community members.
      Click here to open settings and give it one!": "Je gemeenschap heeft geen Lange Beschrijving (een HTMLpagina die aan de gemeenschapsleden wordt getoond).
      Klik hier om de instellingen te openen en een Lange Beschrijving te maken!", - "Long Description (HTML)": "Lange Beschrijving (HTML)", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Deze kamers worden aan gemeenschapsleden getoond op de gemeenschapspagina. Gemeenschapsleden kunnen tot de kamers toetreden door er op te klikken.", + "%(inviter)s has invited you to join this community": "%(inviter)s heeft u uitgenodigd in deze gemeenschap", + "You are an administrator of this community": "U bent een beheerder van deze gemeenschap", + "You are a member of this community": "U bent lid van deze gemeenschap", + "Your community hasn't got a Long Description, a HTML page to show to community members.
      Click here to open settings and give it one!": "Uw gemeenschap heeft geen lange beschrijving (een HTML-pagina die aan de gemeenschapsleden wordt getoond).
      Klik hier om de instellingen te openen en een lange beschrijving op te geven!", + "Long Description (HTML)": "Lange beschrijving (HTML)", "Description": "Beschrijving", "Community %(groupId)s not found": "Gemeenschap %(groupId)s is niet gevonden", "This Home server does not support communities": "Deze Thuisserver ondersteunt geen gemeenschappen", - "Failed to load %(groupId)s": "Het is niet gelukt %(groupId)s te laden", - "Old cryptography data detected": "Oude cryptografie gegevens gedetecteerd", - "Data from an older version of Riot 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.": "Er zijn gegevens van een oudere versie van Riot gedetecteerd. Dit verstoorde end-to-endbeveiliging in de oude versie. End-to-endbeveiligde berichten die recent uitgewisseld zijn met de oude versie zijn wellicht niet te ontsleutelen in deze versie. Dit zou er ook voor kunnen zorgen dat berichten die zijn uitgewisseld in deze versie falen. Log opnieuw in als je problemen ervaart. Exporteer de sleutels en importeer ze achteraf weer om de berichtgeschiedenis te behouden.", - "Your Communities": "Jouw Gemeenschappen", - "Error whilst fetching joined communities": "Er is een fout opgetreden tijdens het ophalen van de gemeenschappen waar je lid van bent", + "Failed to load %(groupId)s": "Laden van %(groupId)s is mislukt", + "Old cryptography data detected": "Oude cryptografiegegevens gedetecteerd", + "Data from an older version of Riot 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.": "Er zijn gegevens van een oudere versie van Riot gedetecteerd. Dit zal problemen veroorzaakt hebben met de eind-tot-eind-versleuteling in de oude versie. Eind-tot-eind-versleutelde berichten die recent uitgewisseld zijn met de oude versie zijn mogelijk niet te ontsleutelen in deze versie. Dit zou er ook voor kunnen zorgen dat berichten die uitgewisseld zijn in deze versie falen. Meld u opnieuw aan als u problemen zou ervaren. Exporteer de sleutels en importeer ze achteraf weer om de berichtgeschiedenis te behouden.", + "Your Communities": "Uw gemeenschappen", + "Error whilst fetching joined communities": "Er is een fout opgetreden bij het ophalen van de gemeenschappen waarvan u lid bent", "Create a new community": "Maak een nieuwe gemeenschap aan", - "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Maak een gemeenschap aan om gebruikers en ruimten bijeen te brengen! Vorm met een homepagina op maat je eigen plaats in het Matrix-universum.", - "Show devices, send anyway or cancel.": "Toon apparaten, Toch versturen of annuleren.", - "%(count)s of your messages have not been sent.|one": "Je bericht was niet verstuurd.", - "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Alles nu herzenden of annuleren. Je kunt ook individuele berichten selecteren om te herzenden of te annuleren.", - "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Nu bericht opnieuw versturen of bericht annuleren.", + "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Maak een gemeenschap aan om gebruikers en kamers bijeen te brengen! Schep met een startpagina op maat uw eigen plaats in het Matrix-universum.", + "Show devices, send anyway or cancel.": "Apparaten weergeven, toch versturen of annuleren.", + "%(count)s of your messages have not been sent.|one": "Uw bericht is niet verstuurd.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Alles nu opnieuw versturen of annuleren. U kunt ook individuele berichten selecteren om opnieuw te versturen of te annuleren.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Bericht opnieuw versturen of bericht annuleren.", "Warning": "Let op", - "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Er is niemand anders hier! Wil je anderen uitnodigen of de waarschuwing over de lege ruimte stoppen?", + "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Er is niemand anders hier! Wilt u anderen uitnodigen of de waarschuwing over de lege kamer stoppen?", "Light theme": "Licht thema", "Dark theme": "Donker thema", "Status.im theme": "Status.im thema", "Ignored Users": "Genegeerde Gebruikers", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is belangrijk voor ons, dus we verzamelen geen persoonlijke of identificeerbare gegevens voor onze gegevensanalyse.", "Learn more about how we use analytics.": "Lees meer over hoe we uw gegevens gebruiken.", - "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Een e-mail is naar %(emailAddress)s verstuurd. Klik hieronder zodra je de link hebt gevolgd.", - "Please note you are logging into the %(hs)s server, not matrix.org.": "Merk op dat je aan het inloggen bent in de %(hs)s server, niet matrix.org.", - "This homeserver doesn't offer any login flows which are supported by this client.": "Deze thuisserver heeft geen inlogmethodes die bij deze client ondersteunt worden.", + "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Er is een e-mail naar %(emailAddress)s verstuurd. Klik hieronder van zodra u de koppeling erin hebt gevolgd.", + "Please note you are logging into the %(hs)s server, not matrix.org.": "Merk op dat u zich aanmeldt bij de %(hs)s-server, niet matrix.org.", + "This homeserver doesn't offer any login flows which are supported by this client.": "Deze thuisserver heeft geen aanmeldmethodes die door deze cliënt worden ondersteund.", "Sign in to get started": "Log in om te beginnen", "Ignores a user, hiding their messages from you": "Negeert een gebruiker, waardoor de berichten ervan onzichtbaar voor u worden", "Stops ignoring a user, showing their messages going forward": "Stopt het negeren van een gebruiker, hierdoor worden de berichten van de gebruiker weer zichtbaar", - "Notify the whole room": "Notificeer de gehele ruimte", - "Room Notification": "Ruimte Notificatie", + "Notify the whole room": "Laat dit aan de hele kamer weten", + "Room Notification": "Kamermelding", "The information being sent to us to help make Riot.im better includes:": "De informatie die naar ons wordt verstuurd om Riot.im te verbeteren betreft:", "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Waar deze pagina identificeerbare informatie bevat, zoals een kamer, gebruikers- of groeps-ID, zullen deze gegevens verwijderd worden voordat ze naar de server gestuurd worden.", "The platform you're on": "Het platform dat u gebruikt", @@ -954,7 +954,7 @@ "Your homeserver's URL": "De URL van uw thuisserver", "Your identity server's URL": "De URL van uw identiteitsserver", "In reply to ": "Als antwoord op ", - "This room is not public. You will not be able to rejoin without an invite.": "Deze ruimte is niet openbaar. Zonder uitnodiging zul je niet opnieuw kunnen toetreden.", + "This room is not public. You will not be able to rejoin without an invite.": "Deze kamer is niet openbaar. Zonder uitnodiging zult u niet opnieuw kunnen toetreden.", "were unbanned %(count)s times|one": "zijn ontbannen", "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s heeft zijn/haar weergavenaam gewijzigd naar %(displayName)s.", "Disable Community Filter Panel": "Gemeenschapsfilterpaneel uitzetten", @@ -964,12 +964,12 @@ "Key request sent.": "Sleutelverzoek verstuurd.", "Re-request encryption keys from your other devices.": "Versleutelingssleutels opnieuw aanvragen van uw andere apparaten.", "%(user)s is a %(userRole)s": "%(user)s is een %(userRole)s", - "Did you know: you can use communities to filter your Riot.im experience!": "Wist je dat: je gemeenschappen kan gebruiken om je Riot.im-beleving te filteren!", - "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.": "Sleep om een filter te maken een gemeenschapsavatar naar het filterpaneel helemaal links op het scherm. Je kunt daarna op de avatar in het filterpaneel klikken wanneer je je wilt beperken tot de ruimten en mensen uit die tot die gemeenschap.", - "Clear filter": "Filter vrijmaken", - "Failed to set direct chat tag": "Het is niet gelukt het label 'privégesprek' in te stellen", - "Failed to remove tag %(tagName)s from room": "Het is niet gelukt het label %(tagName)s van de ruimte te verwijderen", - "Failed to add tag %(tagName)s to room": "Het is niet gelukt het label %(tagName)s aan deze ruimte toe te voegen", + "Did you know: you can use communities to filter your Riot.im experience!": "Wist u dat: u gemeenschappen kunt gebruiken om uw Riot.im-beleving te filteren!", + "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.": "Versleep een gemeenschapsavatar naar het filterpaneel helemaal links op het scherm om een filter in te stellen. Daarna kunt u op de avatar in het filterpaneel klikken wanneer u zich wilt beperken tot de kamers en mensen uit die gemeenschap.", + "Clear filter": "Filter wissen", + "Failed to set direct chat tag": "Instellen van één-op-één-gesprekslabel is mislukt", + "Failed to remove tag %(tagName)s from room": "Verwijderen van %(tagName)s-label van kamer is mislukt", + "Failed to add tag %(tagName)s to room": "Toevoegen van %(tagName)s-label aan kamer is mislukt", "Stickerpack": "Stickerpakket", "You don't currently have any stickerpacks enabled": "U heeft momenteel geen stickerpakketten ingeschakeld", "Add a stickerpack": "Stickerpakket toevoegen", @@ -977,11 +977,11 @@ "Show Stickers": "Stickers weergeven", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Gezien door %(displayName)s (%(userName)s) op %(dateTime)s", "Code": "Code", - "Unable to join community": "Je kon niet tot de gemeenschap toetreden", - "Unable to leave community": "Je kon de gemeenschap niet verlaten", - "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "Veranderingen die aan je gemeenschap naam en avatar zijn aangebracht zullen misschien niet gezien worden door anderen tot maximaal 30 minuten.", - "Join this community": "Tot deze gemeenschap toetreden", - "Who can join this community?": "Wie kan tot deze gemeenschap toetreden?", + "Unable to join community": "Kan niet toetreden tot de gemeenschap", + "Unable to leave community": "Kan de gemeenschap niet verlaten", + "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "Veranderingen aan uw gemeenschapsnaam en -avatar zullen mogelijk niet gezien worden door anderen tot maximaal 30 minuten.", + "Join this community": "Toetreden tot deze gemeenschap", + "Who can join this community?": "Wie kan er tot deze gemeenschap toetreden?", "Everyone": "Iedereen", "Leave this community": "Deze gemeenschap verlaten", "Debug Logs Submission": "Debug Logs Indienen", @@ -990,9 +990,9 @@ "Opens the Developer Tools dialog": "Opent het dialoogvenster met ontwikkelaarsgereedschap", "Fetching third party location failed": "Het ophalen van de locatie van de derde partij is mislukt", "A new version of Riot is available.": "Er is een nieuwe versie van Riot beschikbaar.", - "I understand the risks and wish to continue": "Ik begrijp de risico's en wil graag verder gaan", + "I understand the risks and wish to continue": "Ik begrijp de risico’s en wil graag verdergaan", "Couldn't load home page": "Kon de home pagina niet laden", - "Send Account Data": "Stuur account informatie", + "Send Account Data": "Accountgegevens versturen", "All notifications are currently disabled for all targets.": "Alle meldingen zijn momenteel uitgeschakeld voor alle bestemmingen.", "Uploading report": "Rapport wordt geüpload", "Sunday": "Zondag", @@ -1007,10 +1007,10 @@ "Expand panel": "Paneel uitklappen", "On": "Aan", "%(count)s Members|other": "%(count)s Deelnemers", - "Filter room names": "Filter ruimtenamen", + "Filter room names": "Kamernamen filteren", "Changelog": "Wijzigingslogboek", "Waiting for response from server": "Wachten op antwoord van de server", - "Send Custom Event": "Verzend aangepast evenement", + "Send Custom Event": "Aangepaste gebeurtenis versturen", "Advanced notification settings": "Geavanceerde meldingsinstellingen", "delete the alias.": "verwijder de alias.", "To return to your account in future you need to set a password": "Om in de toekomst naar uw account terug te gaan is het nodig een wachtwoord in te stellen", @@ -1021,20 +1021,20 @@ "Cancel Sending": "Versturen annuleren", "This Room": "Deze kamer", "The Home Server may be too old to support third party networks": "De thuisserver is misschien te oud om netwerken van derde partijen te ondersteunen", - "Resend": "Opnieuw verzenden", + "Resend": "Opnieuw versturen", "Error saving email notification preferences": "Fout bij het opslaan van de meldingsvoorkeuren voor e-mail", "Messages containing my display name": "Berichten die mijn weergavenaam bevatten", "Messages in one-to-one chats": "Berichten in één-op-één-gesprekken", "Unavailable": "Niet beschikbaar", - "View Decrypted Source": "Bekijk ontsleutelde bron", + "View Decrypted Source": "Ontsleutelde bron bekijken", "Failed to update keywords": "Bijwerken van trefwoorden is mislukt", - "remove %(name)s from the directory.": "verwijder %(name)s uit de ruimtelijst.", + "remove %(name)s from the directory.": "verwijder %(name)s uit de catalogus.", "Notifications on the following keywords follow rules which can’t be displayed here:": "Meldingen op de volgende trefwoorden volgen regels die hier niet getoond kunnen worden:", "Safari and Opera work too.": "Safari en Opera werken ook.", "Please set a password!": "Stel een wachtwoord in!", - "You have successfully set a password!": "U heeft met succes een wachtwoord ingesteld!", + "You have successfully set a password!": "U heeft een wachtwoord ingesteld!", "An error occurred whilst saving your email notification preferences.": "Er is een fout opgetreden tijdens het opslaan van uw e-mailmeldingsvoorkeuren.", - "Explore Room State": "Verken Ruimtetoestand", + "Explore Room State": "Ruimtetoestand verkennen", "Source URL": "Bron-URL", "Messages sent by bot": "Berichten verzonden door een robot", "Filter results": "Resultaten filteren", @@ -1043,64 +1043,64 @@ "Noisy": "Lawaaierig", "Failed to get protocol list from Home Server": "Protocollijst ophalen van de homeserver mislukt", "Collecting app version information": "App-versieinformatie wordt verzameld", - "Delete the room alias %(alias)s and remove %(name)s from the directory?": "De alias %(alias)s verwijderen en %(name)s uit de ruimtelijst verwijderen?", + "Delete the room alias %(alias)s and remove %(name)s from the directory?": "De alias %(alias)s verwijderen en %(name)s uit de catalogus verwijderen?", "This will allow you to return to your account after signing out, and sign in on other devices.": "Hiermee kunt u naar uw account terugkeren nadat u zich heeft afgemeld, en u aanmelden op andere apparaten.", "Keywords": "Trefwoorden", "Enable notifications for this account": "Meldingen inschakelen voor deze account", "Directory": "Ruimtelijst", "Invite to this community": "Uitnodigen in deze gemeenschap", - "Search for a room": "Een ruimte opzoeken", + "Search for a room": "Zoek een kamer", "Messages containing keywords": "Berichten die trefwoorden bevatten", - "Room not found": "De ruimte is niet gevonden", + "Room not found": "Kamer niet gevonden", "Tuesday": "Dinsdag", "Enter keywords separated by a comma:": "Voeg trefwoorden toe, gescheiden door een komma:", "Search…": "Zoeken…", - "You have successfully set a password and an email address!": "Het instellen van een wachtwoord en e-mailadres is geslaagd!", - "Remove %(name)s from the directory?": "%(name)s uit de ruimtelijst verwijderen?", - "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot gebrukt veel geavanceerde browserfuncties, waarvan enkele niet (of experimenteel) in uw webbrowser beschikbaar zijn.", - "Developer Tools": "Ontwikkelaarsgereedschap", + "You have successfully set a password and an email address!": "U heeft een wachtwoord en e-mailadres ingesteld!", + "Remove %(name)s from the directory?": "%(name)s uit de catalogus verwijderen?", + "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot gebruikt veel geavanceerde browserfuncties, waarvan enkele niet (of slechts experimenteel) in uw browser beschikbaar zijn.", + "Developer Tools": "Ontwikkelgereedschap", "Enable desktop notifications": "Bureaubladmeldingen inschakelen", - "Explore Account Data": "Bekijk account informatie", - "Remove from Directory": "Uit de ruimtelijst verwijderen", + "Explore Account Data": "Accountgegevens verkennen", + "Remove from Directory": "Verwijderen uit catalogus", "Saturday": "Zaterdag", - "Remember, you can always set an email address in user settings if you change your mind.": "Onthoud dat u altijd een e-mailadres in kan stellen in de gebruikersinstellingen als u zich bedenkt.", - "Direct Chat": "Privégesprek", - "The server may be unavailable or overloaded": "De server is misschien niet beschikbaar of overbelast", - "Reject": "Afwijzen", - "Failed to set Direct Message status of room": "Het is niet gelukt de privéchat-status van de ruimte in te stellen", + "Remember, you can always set an email address in user settings if you change your mind.": "Onthoud dat u altijd nog een e-mailadres kunt instellen in de gebruikersinstellingen.", + "Direct Chat": "Eén-op-één-gesprek", + "The server may be unavailable or overloaded": "De server is mogelijk onbereikbaar of overbelast", + "Reject": "Weigeren", + "Failed to set Direct Message status of room": "Instellen van één-op-één-gesprekstoestand van kamer is mislukt", "Monday": "Maandag", "All messages (noisy)": "Alle berichten (luid)", "Enable them now": "Deze nu inschakelen", "Messages containing my user name": "Berichten die mijn gebruikersnaam bevatten", - "Toolbox": "Eigenschappen", + "Toolbox": "Gereedschap", "Collecting logs": "Logboeken worden verzameld", "more": "meer", - "You must specify an event type!": "Je moet een event-type specificeren!", + "You must specify an event type!": "U dient een gebeurtenistype op te geven!", "(HTTP status %(httpStatus)s)": "(HTTP-status %(httpStatus)s)", "Invite to this room": "Uitnodigen in deze kamer", "Please install Chrome or Firefox for the best experience.": "Installeer alstublieft Chrome of Firefox voor de beste gebruikerservaring.", - "Failed to get public room list": "Lijst met publieke ruimtes ophalen mislukt", + "Failed to get public room list": "Lijst met publieke kamers ophalen is mislukt", "Send logs": "Logboeken versturen", "All messages": "Alle berichten", "Call invitation": "Oproep-uitnodiging", "Downloading update...": "Update wordt gedownload…", "State Key": "Toestandssleutel", - "Failed to send custom event.": "Aangepast Event verzenden mislukt.", + "Failed to send custom event.": "Versturen van aangepaste gebeurtenis is mislukt.", "What's new?": "Wat is er nieuw?", "Notify me for anything else": "Stuur een melding voor al het andere", - "When I'm invited to a room": "Wanneer ik uitgenodigd word voor een ruimte", + "When I'm invited to a room": "Wanneer ik uitgenodigd word in een kamer", "Can't update user notification settings": "Kan de meldingsinstellingen van de gebruiker niet bijwerken", "Notify for all other messages/rooms": "Stuur een melding voor alle andere berichten/kamers", - "Unable to look up room ID from server": "Kon het ruimte-ID niet van de server ophalen", - "Couldn't find a matching Matrix room": "Kon geen bijbehorende Matrix-ruimte vinden", + "Unable to look up room ID from server": "Kon de kamer-ID niet van de server ophalen", + "Couldn't find a matching Matrix room": "Kon geen bijbehorende Matrix-kamer vinden", "All Rooms": "Alle kamers", - "You cannot delete this message. (%(code)s)": "Je kunt dit bericht niet verwijderen. (%(code)s)", + "You cannot delete this message. (%(code)s)": "U kunt dit bericht niet verwijderen. (%(code)s)", "Thursday": "Donderdag", "Forward Message": "Bericht doorsturen", "Back": "Terug", - "Reply": "Beantwoord", + "Reply": "Beantwoorden", "Show message in desktop notification": "Bericht tonen in bureaubladmelding", - "Unhide Preview": "Zichtbaar maken preview", + "Unhide Preview": "Voorvertoning weergeven", "Unable to join network": "Kon niet toetreden tot dit netwerk", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "U heeft ze mogelijk ingesteld in een andere cliënt dan Riot. U kunt ze niet aanpassen in Riot, maar ze zijn wel actief", "Sorry, your browser is not able to run Riot.": "Sorry, uw browser werkt niet met Riot.", @@ -1114,23 +1114,23 @@ "Set Password": "Wachtwoord instellen", "Enable audible notifications in web client": "Geluidsmeldingen in de webcliënt inschakelen", "Off": "Uit", - "Riot does not know how to join a room on this network": "Riot weet niet hoe het moet deelnemen in een ruimte op dit netwerk", + "Riot does not know how to join a room on this network": "Riot weet niet hoe het moet deelnemen aan een kamer op dit netwerk", "Mentions only": "Alleen vermeldingen", "Wednesday": "Woensdag", - "You can now return to your account after signing out, and sign in on other devices.": "U kunt nu terugkeren naar uw account nadat u bent afgemeld, en u aanmelden op andere apparaten.", + "You can now return to your account after signing out, and sign in on other devices.": "U kunt nu terugkeren naar uw account nadat u zich heeft afgemeld, en u aanmelden op andere apparaten.", "Enable email notifications": "E-mailmeldingen inschakelen", - "Event Type": "Event-type", + "Event Type": "Gebeurtenistype", "Download this file": "Dit bestand downloaden", - "Pin Message": "Bericht vastpinnen", + "Pin Message": "Bericht vastprikken", "Failed to change settings": "Wijzigen van instellingen mislukt", - "View Community": "Gemeenschap Weergeven", + "View Community": "Gemeenschap weergeven", "%(count)s Members|one": "%(count)s Deelnemer", - "Event sent!": "Event verstuurd!", - "View Source": "Bekijk bron", - "Event Content": "Event-inhoud", + "Event sent!": "Gebeurtenis verstuurd!", + "View Source": "Bron bekijken", + "Event Content": "Gebeurtenisinhoud", "Thank you!": "Bedankt!", "Collapse panel": "Paneel inklappen", - "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!": "Met uw huidige browser kan de applicatie er volledig incorrect uitzien. Tevens is het mogelijk dat niet alle functies naar behoren werken. U kunt doorgaan als u het toch wil proberen, maar bij problemen bent u volledig op uzelf aangewezen!", + "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!": "Met uw huidige browser kan de toepassing er volledig onjuist uitzien. Tevens is het mogelijk dat niet alle functies naar behoren werken. U kunt doorgaan als u het toch wilt proberen, maar bij problemen bent u volledig op uzelf aangewezen!", "Checking for an update...": "Bezig met controleren op updates…", "There are advanced notifications which are not shown here": "Er zijn geavanceerde meldingen die hier niet getoond worden", "Logs sent": "Logboeken verstuurd", @@ -1163,24 +1163,24 @@ "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Kan de gebeurtenis waarop gereageerd was niet laden. Wellicht bestaat die niet, of heeft u geen toestemming die te bekijken.", "Riot bugs are tracked on GitHub: create a GitHub issue.": "Riot fouten worden bijgehouden op GitHub: maak een GitHub melding.", "Failed to indicate account erasure": "Niet gelukt om de accountverwijdering aan te geven", - "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Dit zal je account voorgoed onbruikbaar maken. Je zult niet meer in kunnen loggen en niemand anders zal met dezelfde gebruikers ID kunnen registreren. Hierdoor zal je account alle ruimten waarin het deelneemt verlaten en worden de accountgegevens van de identiteitsserver verwijderd. Deze actie is onomkeerbaar.", - "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.": "Het deactiveren van je account zal er niet standaard voor zorgen dat de berichten die je verzonden hebt vergeten worden. Als je wilt dat wij de berichten vergeten, klik alsjeblieft op het vakje hieronder.", - "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.": "De zichtbaarheid van berichten in Matrix is hetzelfde als in e-mail. Het vergeten van je berichten betekent dat berichten die je hebt verstuurd niet meer gedeeld worden met nieuwe of ongeregistreerde gebruikers, maar geregistreerde gebruikers die al toegang hebben tot deze berichten zullen alsnog toegang hebben tot hun eigen kopie van het bericht.", - "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)": "Vergeet alle berichten die ik heb verstuurd wanneer mijn account gedeactiveerd is (Waarschuwing: dit zal er voor zorgen dat toekomstige gebruikers een incompleet beeld krijgen van gesprekken)", - "To continue, please enter your password:": "Om verder te gaan, vul alsjeblieft je wachtwoord in:", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Dit zal uw account voorgoed onbruikbaar maken. U zult zich niet meer kunnen aanmelden, en niemand anders zal zich met dezelfde gebruikers-ID kunnen registreren. Hierdoor zal uw account alle kamers waaraan deze deelneemt verlaten, en worden de accountgegevens verwijderd van de identiteitsserver. Deze actie is onomkeerbaar.", + "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.": "Het deactiveren van uw account zal er standaard niet voor zorgen dat de berichten die u heeft verstuurd vergeten worden. Als u wilt dat wij de berichten vergeten, vinkt u het vakje hieronder aan.", + "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.": "De zichtbaarheid van berichten in Matrix is zoals bij e-mails. Het vergeten van uw berichten betekent dat berichten die u heeft verstuurd niet meer gedeeld worden met nieuwe of ongeregistreerde gebruikers, maar geregistreerde gebruikers die al toegang hebben tot deze berichten zullen alsnog toegang hebben tot hun eigen kopie ervan.", + "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)": "Vergeet alle berichten die ik heb verstuurd wanneer mijn account gedeactiveerd is (Let op: dit zal er voor zorgen dat toekomstige gebruikers een onvolledig beeld krijgen van gesprekken)", + "To continue, please enter your password:": "Voer uw wachtwoord in om verder te gaan:", "password": "wachtwoord", - "Log out and remove encryption keys?": "Uitloggen en versleutelingssleutels verwijderen?", - "Clear Storage and Sign Out": "Leeg Opslag en Log Uit", - "Send Logs": "Logboek Versturen", + "Log out and remove encryption keys?": "Afmelden en versleutelingssleutels verwijderen?", + "Clear Storage and Sign Out": "Opslag wissen en afmelden", + "Send Logs": "Logboek versturen", "Refresh": "Herladen", - "We encountered an error trying to restore your previous session.": "Er is een fout opgetreden tijdens het herstellen van je vorige sessie.", - "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Het legen van de opslag van je browser zal het probleem misschien verhelpen, maar zal je ook uitloggen en je gehele versleutelde chatgeschiedenis onleesbaar maken.", - "Collapse Reply Thread": "Reactieketting Inklappen", - "Can't leave Server Notices room": "Kan de Server Meldingen ruimte niet verlaten", - "This room is used for important messages from the Homeserver, so you cannot leave it.": "Deze ruimte wordt gebruikt voor belangrijke berichten van de thuisserver, dus je kunt haar niet verlaten.", - "Terms and Conditions": "Voorwaarden", - "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Om de %(homeserverDomain)s thuisserver te blijven gebruiken zul je de voorwaarden moeten lezen en aanvaarden.", - "Review terms and conditions": "Voorwaarden lezen", + "We encountered an error trying to restore your previous session.": "Er is een fout opgetreden bij het herstellen van uw vorige sessie.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Het legen van de opslag van uw browser zal het probleem misschien verhelpen, maar zal u ook afmelden en uw gehele versleutelde gespreksgeschiedenis onleesbaar maken.", + "Collapse Reply Thread": "Reactieketting dichtvouwen", + "Can't leave Server Notices room": "Kan servermeldingskamer niet verlaten", + "This room is used for important messages from the Homeserver, so you cannot leave it.": "Deze kamer wordt gebruikt voor belangrijke berichten van de thuisserver, dus u kunt ze niet verlaten.", + "Terms and Conditions": "Gebruiksvoorwaarden", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Om de %(homeserverDomain)s-thuisserver te blijven gebruiken, zult u de gebruiksvoorwaarden moeten lezen en aanvaarden.", + "Review terms and conditions": "Gebruiksvoorwaarden lezen", "A conference call could not be started because the intgrations server is not available": "Een groepsgesprek kon niet gestart worden omdat de integratieserver niet beschikbaar is", "Call in Progress": "Lopend gesprek", "A call is currently being placed!": "Er wordt al een oproep gemaakt!", @@ -1212,21 +1212,21 @@ "This homeserver has hit its Monthly Active User limit. Please contact your service administrator to continue using the service.": "Deze thuisserver heeft zijn maandelijkse gebruikerslimiet bereikt. Neem contact op met de beheerder van je thuisserver om de dienst weer te kunnen gebruiken.", "Failed to remove widget": "Widget kon niet worden verwijderd", "An error ocurred whilst trying to remove the widget from the room": "Er is een fout opgetreden bij het verwijderen van de widget uit deze kamer", - "Share Room": "Ruimte delen", - "Link to most recent message": "Link naar meest recente bericht", + "Share Room": "Kamer delen", + "Link to most recent message": "Koppeling naar meest recente bericht", "Share User": "Gebruiker delen", "Share Community": "Gemeenschap delen", - "Share Room Message": "Bericht uit ruimte delen", - "Link to selected message": "Link naar geselecteerde bericht", + "Share Room Message": "Bericht uit kamer delen", + "Link to selected message": "Koppeling naar geselecteerde bericht", "COPY": "KOPIËREN", "Share Message": "Bericht delen", - "You can't send any messages until you review and agree to our terms and conditions.": "Je kunt geen berichten sturen totdat je onze algemene voorwaarden hebt gelezen en geaccepteerd.", + "You can't send any messages until you review and agree to our terms and conditions.": "U kunt geen berichten sturen totdat u onze algemene voorwaarden heeft gelezen en aanvaard.", "Your message wasn’t sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Je bericht is niet verstuurd omdat deze thuisserver zijn maandelijkse gebruikerslimiet heeft bereikt. Neem contact op met de beheerder van je thuisserver om de dienst te kunnen blijven gebruiken.", "No Audio Outputs detected": "Geen geluidsuitgangen gedetecteerd", "Audio Output": "Geluidsuitgang", "This homeserver has hit its Monthly Active User limit": "Deze thuisserver heeft zijn maandelijkse gebruikerslimiet bereikt", "Please contact your service administrator to continue using this service.": "Neem contact op met de beheerder van je thuisserver om de dienst te kunnen blijven gebruiken.", - "Try the app first": "De app eerst proberen", + "Try the app first": "Probeer de toepassing eerst uit", "Ignored users": "Genegeerde gebruikers", "Bulk options": "Bulkopties", "Registration Required": "Registratie vereist", @@ -1548,5 +1548,194 @@ "Invite anyway": "Alsnog uitnodigen", "Before submitting logs, you must create a GitHub issue to describe your problem.": "Vooraleer u logboeken indient, dient u een melding te openen op GitHub waarin u uw probleem beschrijft.", "What GitHub issue are these logs for?": "Voor welke melding op GitHub zijn deze logboeken?", - "Unable to load commit detail: %(msg)s": "Kan commitdetail niet laden: %(msg)s" + "Unable to load commit detail: %(msg)s": "Kan commitdetail niet laden: %(msg)s", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Om uw gespreksgeschiedenis niet te verliezen, moet u uw kamersleutels exporteren vooraleer u zich afmeldt. U zult moeten terugkeren naar de nieuwere versie van Riot om dit te doen", + "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "U heeft eerder een nieuwere versie van Riot op %(host)s gebruikt. Om deze versie opnieuw met eind-tot-eind-versleuteling te gebruiken, zult u zich moeten afmelden en opnieuw aanmelden. ", + "Incompatible Database": "Incompatibele database", + "Continue With Encryption Disabled": "Verdergaan met versleuteling uitgeschakeld", + "Use Legacy Verification (for older clients)": "Verouderde verificatie gebruiken (voor oudere cliënten)", + "Verify by comparing a short text string.": "Verifieer door een korte tekenreeks te vergelijken.", + "Begin Verifying": "Verificatie beginnen", + "Waiting for partner to accept...": "Aan het wachten op partner…", + "Nothing appearing? Not all clients support interactive verification yet. .": "Verschijnt er niets? Nog niet alle cliënten bieden ondersteuning voor interactieve verificatie. .", + "Waiting for %(userId)s to confirm...": "Wachten op bevestiging van %(userId)s…", + "Use two-way text verification": "Tweerichtingstekstverificatie gebruiken", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verifieer deze gebruiker om hem/haar als vertrouwd te markeren. Gebruikers vertrouwen geeft u extra gemoedsrust bij het gebruik van eind-tot-eind-versleutelde berichten.", + "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "Deze gebruiker verifiëren zal hun apparaat als vertrouwd markeren, en ook uw apparaat voor hen als vertrouwd markeren.", + "Waiting for partner to confirm...": "Wachten op bevestiging van partner…", + "Incoming Verification Request": "Inkomend verificatieverzoek", + "You've previously used Riot 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, Riot needs to resync your account.": "U heeft voorheen Riot op %(host)s gebruikt met lui laden van leden ingeschakeld. In deze versie is lui laden uitgeschakeld. Omdat de lokale cache niet compatibel is tussen deze twee instellingen, moet Riot uw account opnieuw synchroniseren.", + "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Indien de andere versie van Riot nog in een ander tabblad is geopend, sluit u dit beter, want Riot op dezelfde host gelijktijdig met lui laden ingeschakeld en uitgeschakeld gebruiken zal voor problemen zorgen.", + "Incompatible local cache": "Incompatibele lokale cache", + "Clear cache and resync": "Cache wissen en hersynchroniseren", + "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot verbruikt nu 3-5x minder geheugen, door informatie over andere gebruikers enkel te laden wanneer nodig. Even geduld, we hersynchroniseren met de server!", + "Updating Riot": "Riot wordt bijgewerkt", + "I don't want my encrypted messages": "Ik wil mijn versleutelde berichten niet", + "Manually export keys": "Sleutels handmatig exporteren", + "You'll lose access to your encrypted messages": "U zult de toegang tot uw versleutelde berichten verliezen", + "Are you sure you want to sign out?": "Weet u zeker dat u zich wilt afmelden?", + "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Als u fouten zou tegenkomen of voorstellen zou hebben, laat het ons dan weten op GitHub.", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Bekijk eerst de bestaande meldingen (en voeg een +1 toe waar u dat wenst), of maak een nieuwe melding aan indien u er geen kunt vinden, zo voorkomt u dat u een duplicate melding indient.", + "Report bugs & give feedback": "Fouten melden & feedback geven", + "Go back": "Terug", + "Room Settings - %(roomName)s": "Kamerinstellingen - %(roomName)s", + "Failed to upgrade room": "Opwaarderen van kamer is mislukt", + "The room upgrade could not be completed": "De kameropwaardering kon niet voltooid worden", + "Upgrade this room to version %(version)s": "Opwaardeer deze kamer naar versie %(version)s", + "Upgrade Room Version": "Kamerversie opwaarderen", + "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Deze kamer opwaarderen zal de huidige instantie van de kamer sluiten en er een nieuwe kamer voor in de plaats aanmaken. Om kamerleden de best mogelijke ervaring te bieden, zullen we:", + "Create a new room with the same name, description and avatar": "Een nieuwe kamer aanmaken met dezelfde naam, beschrijving en avatar", + "Update any local room aliases to point to the new room": "Alle lokale kameraliassen bijwerken om naar de nieuwe kamer te verwijzen", + "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Gebruikers verhinderen van te praten in de oude versie van de kamer, en er een bericht in plaatsen waarin de gebruikers worden aanbevolen zich naar de nieuwe kamer te begeven", + "Put a link back to the old room at the start of the new room so people can see old messages": "Een verwijzing naar de oude kamer plaatsen aan het begin van de nieuwe kamer, zodat mensen oude berichten kunnen zien", + "A username can only contain lower case letters, numbers and '=_-./'": "Een gebruikersnaam kan enkel kleine letters, cijfers en ‘=_-./’ bevatten", + "Checking...": "Bezig met controleren…", + "Unable to load backup status": "Kan back-upstatus niet laden", + "Recovery Key Mismatch": "Herstelsleutel komt niet overeen", + "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "De back-up kon met deze sleutel niet ontsleuteld worden: controleer of u de juiste herstelsleutel heeft ingevoerd.", + "Incorrect Recovery Passphrase": "Onjuist herstelwachtwoord", + "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "De back-up kon met dit wachtwoord niet ontsleuteld worden: controleer of u het juiste herstelwachtwoord heeft ingevoerd.", + "Unable to restore backup": "Kan back-up niet herstellen", + "No backup found!": "Geen back-up gevonden!", + "Backup Restored": "Back-up hersteld", + "Failed to decrypt %(failedCount)s sessions!": "Ontsleutelen van %(failedCount)s sessies is mislukt!", + "Restored %(sessionCount)s session keys": "%(sessionCount)s sessiesleutels hersteld", + "Enter Recovery Passphrase": "Voer het herstelwachtwoord in", + "Warning: you should only set up key backup from a trusted computer.": "Let op: stel sleutelback-up enkel in op een vertrouwde computer.", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Verkrijg toegang tot uw beveiligde berichtgeschiedenis en stel beveiligd chatten in door uw herstelwachtwoord in te voeren.", + "Next": "Volgende", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Als u uw herstelwachtwoord vergeten bent, kunt u uw herstelsleutel gebruiken of nieuwe herstelopties instellen", + "Enter Recovery Key": "Voer de herstelsleutel in", + "This looks like a valid recovery key!": "Dit is een geldige herstelsleutel!", + "Not a valid recovery key": "Geen geldige herstelsleutel", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Verkrijg toegang tot uw beveiligde berichtgeschiedenis en stel beveiligd chatten in door uw herstelsleutel in te voeren.", + "If you've forgotten your recovery passphrase you can ": "Als u uw herstelwachtwoord vergeten bent, kunt u ", + "Share Permalink": "Permalink delen", + "Clear status": "Status wissen", + "Update status": "Status bijwerken", + "Set status": "Status instellen", + "Set a new status...": "Stel een nieuwe status in…", + "Hide": "Verbergen", + "This homeserver would like to make sure you are not a robot.": "Deze thuisserver wil graag weten of u geen robot bent.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "U kunt de aangepaste serveropties gebruiken om u aan te melden bij andere Matrix-servers, door een andere thuisserver-URL op te geven. Dit biedt u de mogelijkheid om deze toepassing te gebruiken met een bestaande Matrix-account op een andere thuisserver.", + "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "U kunt ook een aangepaste identiteitsserver instellen, maar u zult geen gebruikers kunnen uitnodigen via e-mail, of zelf via e-mail uitgenodigd worden.", + "Please review and accept all of the homeserver's policies": "Gelieve het beleid van de thuisserver te doornemen en aanvaarden", + "Please review and accept the policies of this homeserver:": "Gelieve het beleid van deze thuisserver te doornemen en aanvaarden:", + "Your Modular server": "Uw Modular-server", + "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Voer de locatie van uw Modular-thuisserver in. Deze kan uw eigen domeinnaam gebruiken, of een subdomein van modular.im zijn.", + "Server Name": "Servernaam", + "The username field must not be blank.": "Het gebruikersnaamveld mag niet leeg zijn.", + "Username": "Gebruikersnaam", + "Not sure of your password? Set a new one": "Onzeker over uw wachtwoord? Stel er een nieuw in", + "Sign in to your Matrix account": "Aanmelden met uw Matrix-account", + "Sign in to your Matrix account on %(serverName)s": "Aanmelden met uw Matrix-account op %(serverName)s", + "Change": "Wijzigen", + "Create your Matrix account": "Maak uw Matrix-account aan", + "Create your Matrix account on %(serverName)s": "Maak uw Matrix-account aan op %(serverName)s", + "Email (optional)": "E-mailadres (optioneel)", + "Phone (optional)": "Telefoonnummer (optioneel)", + "Confirm": "Bevestigen", + "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Gebruik een e-mailadres om uw account te herstellen. Andere gebruikers kunnen u uitnodigen in kamers aan de hand van uw contactgegevens.", + "Other servers": "Andere servers", + "Enter custom server URLs What does this mean?": "Voer aangepaste server-URL’s in Wat betekent dit?", + "Homeserver URL": "Thuisserver-URL", + "Identity Server URL": "Identiteitsserver-URL", + "Free": "Gratis", + "Join millions for free on the largest public server": "Doe mee met miljoenen andere op de grootste publieke server", + "Premium": "Premium", + "Premium hosting for organisations Learn more": "Premium hosting voor organisaties Lees meer", + "Other": "Overige", + "Find other public servers or use a custom server": "Zoek andere publieke servers, of gebruik een aangepaste server", + "Please install Chrome, Firefox, or Safari for the best experience.": "Installeer Chrome, Firefox, of Safari voor de beste gebruikservaring.", + "Couldn't load page": "Kon pagina niet laden", + "You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "U bent een beheerder van deze gemeenschap. U zult niet opnieuw kunnen toetreden zonder een uitnodiging van een andere beheerder.", + "Want more than a community? Get your own server": "Wilt u meer dan een gemeenschap? Verkrijg uw eigen server", + "This homeserver does not support communities": "Deze thuisserver biedt geen ondersteuning voor gemeenschappen", + "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Ongeldige configuratie: kan geen standaard-thuisserver-URL en standaardservernaam leveren", + "You are logged in to another account": "U bent aangemeld met een andere account", + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Bedankt om uw e-mailadres te verifiëren! De account waarmee u zich hier heeft aangemeld (%(sessionUserId)s) lijkt te verschillen van de account waarvoor u een e-mailadres heeft geverifieerd (%(verifiedUserId)s). Als u zich met %(verifiedUserId2)s wilt aanmelden, gelieve u dan eerst af te melden.", + "Unknown error discovering homeserver": "Onbekende fout bij ontdekken van thuisserver", + "Failed to get protocol list from homeserver": "Ophalen van protocollijst van thuisserver is mislukt", + "The homeserver may be too old to support third party networks": "De thuisserver is mogelijk te oud om derdepartijnetwerken te ondersteunen", + "Search for a room like #example": "Zoek een kamer zoals #voorbeeld", + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Uw bericht is niet verstuurd omdat deze thuisserver zijn limiet voor maandelijks actieve gebruikers heeft bereikt. Gelieve contact op te nemen met uw dienstbeheerder om de dienst te blijven gebruiken.", + "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Uw bericht is niet verstuurd omdat deze thuisserver een systeembronlimiet heeft overschreden. Gelieve contact op te nemen met uw dienstbeheerder om de dienst te blijven gebruiken.", + "File is too big. Maximum file size is %(fileSize)s": "Bestand is te groot. Maximale bestandsgrootte is %(fileSize)s", + "Guest": "Gast", + "Could not load user profile": "Kon gebruikersprofiel niet laden", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Uw wachtwoord opnieuw instellen zal alle sleutels voor eind-tot-eind-versleuteling op al uw apparaten opnieuw instellen, waardoor uw versleutelde gesprekgeschiedenis onleesbaar wordt. Stel sleutelback-up in of exporteer uw kamersleutels vanaf een ander apparaat vooraleer u uw wachtwoord opnieuw instelt.", + "Your Matrix account": "Uw Matrix-account", + "Your Matrix account on %(serverName)s": "Uw Matrix-account op %(serverName)s", + "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.": "De thuisserver-URL %(hsUrl)s is geen geldige URL. Voer een geldige URL in inclusief het protocolvoorvoegsel.", + "A verification email will be sent to your inbox to confirm setting your new password.": "Er is een verificatie-e-mail naar u gestuurd om het instellen van uw nieuwe wachtwoord te bevestigen.", + "Sign in instead": "Aanmelden", + "Your password has been reset.": "Uw wachtwoord is opnieuw ingesteld.", + "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "U bent afgemeld op al uw apparaten en zult geen pushmeldingen meer ontvangen. Meld u op elk apparaat opnieuw aan om weer meldingen te ontvangen.", + "Set a new password": "Stel een nieuw wachtwoord in", + "Invalid homeserver discovery response": "Ongeldig thuisserverontdekkingsantwoord", + "Invalid identity server discovery response": "Ongeldig identiteitsserverontdekkingsantwoord", + "General failure": "Algemene fout", + "This homeserver does not support login using email address.": "Deze thuisserver biedt geen ondersteuning voor aanmelden met e-mailadres.", + "Please contact your service administrator to continue using this service.": "Gelieve contact op te nemen met uw dienstbeheerder om deze dienst te blijven gebruiken.", + "Guest access is disabled on this homeserver.": "Gasttoegang is uitgeschakeld op deze thuisserver.", + "Failed to perform homeserver discovery": "Ontdekken van thuisserver is mislukt", + "Unknown failure discovering homeserver": "Onbekende fout bij ontdekken van thuisserver", + "Sign in with single sign-on": "Aanmelden met enkele aanmelding", + "Create account": "Account aanmaken", + "Registration has been disabled on this homeserver.": "Registratie is uitgeschakeld op deze thuisserver.", + "Unable to query for supported registration methods.": "Kan ondersteunde registratiemethoden niet opvragen.", + "An email address is required to register on this homeserver.": "Deze thuisserver vereist een e-mailadres voor registratie.", + "A phone number is required to register on this homeserver.": "Deze thuisserver vereist een telefoonnummer voor registratie.", + "You need to enter a username.": "U moet een gebruikersnaam invoeren.", + "Create your account": "Maak uw account aan", + "Great! This passphrase looks strong enough.": "Top! Dit wachtwoord ziet er sterk genoeg uit.", + "Keep going...": "Doe verder…", + "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.": "We bewaren een versleutelde kopie van uw sleutels op onze server. Bescherm uw back-up met een wachtwoord om deze veilig te houden.", + "For maximum security, this should be different from your account password.": "Voor maximale veiligheid zou dit moeten verschillen van uw accountwachtwoord.", + "Enter a passphrase...": "Voer een wachtwoord in…", + "Set up with a Recovery Key": "Instellen met herstelsleutel", + "That matches!": "Dat komt overeen!", + "That doesn't match.": "Dat komt niet overeen.", + "Go back to set it again.": "Ga terug om het opnieuw in te stellen.", + "Please enter your passphrase a second time to confirm.": "Voer uw wachtwoord nogmaals in om te bevestigen.", + "Repeat your passphrase...": "Herhaal uw wachtwoord…", + "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Als veiligheidsnet kunt u dit gebruiken om uw versleutelde berichtgeschiedenis te herstellen indien u uw herstelwachtwoord zou vergeten.", + "As a safety net, you can use it to restore your encrypted message history.": "Als veiligheidsnet kunt u het gebruiken om uw versleutelde berichtgeschiedenis te herstellen.", + "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.": "Uw herstelsleutel is een veiligheidsnet - u kunt hem gebruiken om de toegang tot uw versleutelde berichten te herstellen indien u uw wachtwoord zou vergeten.", + "Keep your recovery key somewhere very secure, like a password manager (or a safe)": "Bewaar uw herstelsleutel op een heel veilige plaats, zoals een wachtwoordbeheerder (of een kluis)", + "Your Recovery Key": "Uw herstelsleutel", + "Copy to clipboard": "Kopiëren naar klembord", + "Download": "Downloaden", + "Your Recovery Key has been copied to your clipboard, paste it to:": "Uw herstelsleutel is gekopieerd naar uw klembord, plak hem in:", + "Your Recovery Key is in your Downloads folder.": "Uw herstelsleutel bevindt zich in uw Downloads-map.", + "Print it and store it somewhere safe": "Druk hem af en bewaar hem op een veilige plaats", + "Save it on a USB key or backup drive": "Sla hem op op een USB-stick of een back-upschijf", + "Copy it to your personal cloud storage": "Kopieer hem naar uw persoonlijke cloudopslag", + "Your keys are being backed up (the first backup could take a few minutes).": "Er wordt een back-up van uw sleutels gemaakt (de eerste back-up kan enkele minuten duren).", + "Okay": "Oké", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Zonder veilig berichtherstel in te stellen, zult u uw versleutelde berichtgeschiedenis niet kunnen herstellen indien u zich afmeldt of een ander apparaat gebruikt.", + "Set up Secure Message Recovery": "Veilig berichtherstel instellen", + "Secure your backup with a passphrase": "Beveilig uw back-up met een wachtwoord", + "Confirm your passphrase": "Bevestig uw wachtwoord", + "Recovery key": "Herstelsleutel", + "Keep it safe": "Bewaar hem op een veilige plaats", + "Starting backup...": "Back-up wordt gestart…", + "Success!": "Klaar!", + "Create Key Backup": "Sleutelback-up aanmaken", + "Unable to create key backup": "Kan sleutelback-up niet aanmaken", + "Retry": "Opnieuw proberen", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Zonder veilig berichtherstel in te stellen, zult u uw versleutelde berichtgeschiedenis verliezen wanneer u zich afmeldt.", + "If you don't want to set this up now, you can later in Settings.": "Als u dit nu niet wilt instellen, kunt u dit later doen in de instellingen.", + "Set up": "Instellen", + "Don't ask again": "Niet opnieuw vragen", + "New Recovery Method": "Nieuwe herstelmethode", + "A new recovery passphrase and key for Secure Messages have been detected.": "Er zijn een nieuw herstelwachtwoord en een nieuwe herstelsleutel voor beveiligde berichten gedetecteerd.", + "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.": "Als u deze nieuwe herstelmethode niet heeft ingesteld, is het mogelijk dat er een aanvaller toegang tot uw account probeert te verkrijgen. Wijzig onmiddellijk uw accountwachtwoord en stel een nieuwe herstelmethode in in de instellingen.", + "This device is encrypting history using the new recovery method.": "Dit apparaat versleutelt de geschiedenis met de nieuwe herstelmethode.", + "Go to Settings": "Ga naar instellingen", + "Set up Secure Messages": "Beveiligde berichten instellen", + "Recovery Method Removed": "Herstelmethode verwijderd", + "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "Dit apparaat heeft gedetecteerd dat uw herstelwachtwoord en -sleutel voor beveiligde berichten verwijderd zijn.", + "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "Als u dit per ongeluk heeft gedaan, kunt u beveiligde berichten instellen op dit apparaat, waarmee de berichtgeschiedenis van dit apparaat herversleuteld zal worden met een nieuwe herstelmethode.", + "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.": "Als u de herstelmethode niet heeft verwijderd, is het mogelijk dat er een aanvaller toegang tot uw account probeert te verkrijgen. Wijzig onmiddellijk uw accountwachtwoord en stel een nieuwe herstelmethode in in de instellingen." } From de43f78c193eca4fe7a2672d50e0494a9e85620d Mon Sep 17 00:00:00 2001 From: Nathan van Beelen Date: Fri, 29 Mar 2019 10:42:21 +0000 Subject: [PATCH 162/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 7f75428c16..c820165209 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -707,7 +707,7 @@ "Message Pinning": "Bericht vastprikken", "Disable Emoji suggestions while typing": "Emoji suggesties tijdens het typen uitzetten", "Hide avatar changes": "Avatar veranderingen verbergen", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s,%(day)s %(monthName)s %(fullYear)s", "Hide display name changes": "Weergavenaam wijzigingen verbergen", "Enable inline URL previews by default": "Inline URL-voorvertoning standaard inschakelen", "Enable URL previews for this room (only affects you)": "URL-voorvertoning in deze kamer inschakelen (geldt alleen voor u)", From cef4c8d6edf36770eb4d88a40dcb141fa5764067 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:42:42 +0000 Subject: [PATCH 163/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index c820165209..7f75428c16 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -707,7 +707,7 @@ "Message Pinning": "Bericht vastprikken", "Disable Emoji suggestions while typing": "Emoji suggesties tijdens het typen uitzetten", "Hide avatar changes": "Avatar veranderingen verbergen", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s,%(day)s %(monthName)s %(fullYear)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s %(day)s %(monthName)s %(fullYear)s", "Hide display name changes": "Weergavenaam wijzigingen verbergen", "Enable inline URL previews by default": "Inline URL-voorvertoning standaard inschakelen", "Enable URL previews for this room (only affects you)": "URL-voorvertoning in deze kamer inschakelen (geldt alleen voor u)", From 3df06fd70bf1862c9d45418a6305ba78aefa8e23 Mon Sep 17 00:00:00 2001 From: "J. A. Durieux" Date: Fri, 29 Mar 2019 10:42:58 +0000 Subject: [PATCH 164/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 7f75428c16..039187d79f 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -487,7 +487,7 @@ "You may wish to login with a different account, or add this email to this account.": "U kunt zich met een andere account aanmelden, of dit e-mailadres aan uw account toevoegen.", "You must register to use this functionality": "U dient u te registreren om deze functie te gebruiken", "You need to be able to invite users to do that.": "Om dit te kunnen doen, moet u gebruikers kunnen uitnodigen.", - "You need to be logged in.": "Aanmelding is vereist.", + "You need to be logged in.": "Hiervoor dient u ingelogd te zijn.", "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat uw e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", @@ -1236,7 +1236,7 @@ "Whether or not you're logged in (we don't record your username)": "Of u al dan niet ingelogd bent (we slaan uw gebruiksnaam niet op)", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Het bestand ‘%(fileName)s’ is groter dan de uploadlimiet van de thuisserver", "Unable to load! Check your network connectivity and try again.": "Laden mislukt! Controleer uw netwerktoegang en probeer het opnieuw.", - "Failed to invite users to the room:": "Uitnodigen van gebruikers in kamer is mislukt:", + "Failed to invite users to the room:": "Kon de volgende gebruikers hier niet uitnodigen:", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Plakt ¯\\_(ツ)_/¯ vóór een bericht zonder opmaak", "Upgrades a room to a new version": "Actualiseert de kamer tot een nieuwe versie", "Changes your display nickname in the current room only": "Stelt uw weergavenaam enkel in de huidige kamer in", From 50afdcfeff04c404e4ca57bceef828f12bd146a0 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:43:20 +0000 Subject: [PATCH 165/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 039187d79f..75aa7a9f87 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -487,7 +487,7 @@ "You may wish to login with a different account, or add this email to this account.": "U kunt zich met een andere account aanmelden, of dit e-mailadres aan uw account toevoegen.", "You must register to use this functionality": "U dient u te registreren om deze functie te gebruiken", "You need to be able to invite users to do that.": "Om dit te kunnen doen, moet u gebruikers kunnen uitnodigen.", - "You need to be logged in.": "Hiervoor dient u ingelogd te zijn.", + "You need to be logged in.": "Hiervoor dient u aangemeld te zijn.", "You need to enter a user name.": "Je moet een gebruikersnaam invoeren.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Het lijkt erop dat uw e-mailadres niet met een Matrix-ID geassocieerd is op deze thuisserver.", "Your password has been reset": "Je wachtwoord is gereset", From d4a369f5595684c0fe5feb90bbd19ebc6ecd6339 Mon Sep 17 00:00:00 2001 From: Gary Date: Fri, 29 Mar 2019 10:43:31 +0000 Subject: [PATCH 166/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 75aa7a9f87..bbe3bed084 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -174,7 +174,7 @@ "Create an account": "Open een account", "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", - "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de naam van het kanaal verwijderd.", "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik er een bestaand", "Create Room": "Kamer aanmaken", "Curve25519 identity key": "Curve25519-identiteitssleutel", From 31c2874ea81c7d088753a2358740145c57b0b0f0 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:43:37 +0000 Subject: [PATCH 167/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index bbe3bed084..75aa7a9f87 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -174,7 +174,7 @@ "Create an account": "Open een account", "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", - "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de naam van het kanaal verwijderd.", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik er een bestaand", "Create Room": "Kamer aanmaken", "Curve25519 identity key": "Curve25519-identiteitssleutel", From dd3e9a9d72bbc8703f3d95f3b029f5191ccfae9e Mon Sep 17 00:00:00 2001 From: Nathan van Beelen Date: Fri, 29 Mar 2019 10:43:44 +0000 Subject: [PATCH 168/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 75aa7a9f87..13dc1397ea 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -120,7 +120,7 @@ "Password:": "Wachtwoord:", "Passwords can't be empty": "Wachtwoorden kunnen niet leeg zijn", "People": "Personen", - "Permissions": "Toestemmingen", + "Permissions": "Permissies", "Phone": "Telefoonnummer", "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gemaakt.", "Privacy warning": "Privacywaarschuwing", From d59c388fffc50b3d5a11e250b3b58e092da4b8e7 Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:43:50 +0000 Subject: [PATCH 169/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 13dc1397ea..75aa7a9f87 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -120,7 +120,7 @@ "Password:": "Wachtwoord:", "Passwords can't be empty": "Wachtwoorden kunnen niet leeg zijn", "People": "Personen", - "Permissions": "Permissies", + "Permissions": "Toestemmingen", "Phone": "Telefoonnummer", "%(senderName)s placed a %(callType)s call.": "%(senderName)s heeft een %(callType)s-oproep gemaakt.", "Privacy warning": "Privacywaarschuwing", From f7d93acda859debb7018a8bdd380ba614c1062f5 Mon Sep 17 00:00:00 2001 From: Nathan van Beelen Date: Fri, 29 Mar 2019 10:43:58 +0000 Subject: [PATCH 170/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 75aa7a9f87..fee4a2ad29 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -130,7 +130,7 @@ "Public Chat": "Openbaar gesprek", "Reason": "Reden", "Reason: %(reasonText)s": "Reden: %(reasonText)s", - "Revoke Moderator": "Moderator degraderen", + "Revoke Moderator": "Moderator terugtrekken", "Refer a friend to Riot:": "Laat een vriend weten over Riot:", "Register": "Registreren", "%(targetName)s rejected the invitation.": "%(targetName)s heeft de uitnodiging geweigerd.", From 8784ac07ff68b683ee6ed507d573ae5a70c4478e Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:44:03 +0000 Subject: [PATCH 171/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index fee4a2ad29..75aa7a9f87 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -130,7 +130,7 @@ "Public Chat": "Openbaar gesprek", "Reason": "Reden", "Reason: %(reasonText)s": "Reden: %(reasonText)s", - "Revoke Moderator": "Moderator terugtrekken", + "Revoke Moderator": "Moderator degraderen", "Refer a friend to Riot:": "Laat een vriend weten over Riot:", "Register": "Registreren", "%(targetName)s rejected the invitation.": "%(targetName)s heeft de uitnodiging geweigerd.", From 94605995d001872cf3a6df0d52660b8951240300 Mon Sep 17 00:00:00 2001 From: Joachim Nielandt Date: Fri, 29 Mar 2019 10:44:13 +0000 Subject: [PATCH 172/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 75aa7a9f87..7548054389 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -562,7 +562,7 @@ "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Klik hieronder op de knop ‘Verifiëren’ als de sleutels overeenkomen. Zo niet drukt u op de knop ‘Blokkeren’, want dan onderschept iemand berichten naar dit apparaat.", "Blacklist": "Blokkeren", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit u ongeverifieerde apparaten uit; om berichten naar deze apparaten te versturen moet u ze verifiëren.", - "Unblacklist": "Deblokkeren", + "Unblacklist": "Van zwarte lijst halen", "In future this verification process will be more sophisticated.": "In de toekomst zal dit verificatie proces meer geraffineerd zijn.", "Verify device": "Apparaat verifiëren", "I verify that the keys match": "Ik verifieer dat de sleutels overeenkomen", From b839afdbd7472214070e3a836af83713a2d50e7a Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:44:19 +0000 Subject: [PATCH 173/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 7548054389..75aa7a9f87 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -562,7 +562,7 @@ "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Klik hieronder op de knop ‘Verifiëren’ als de sleutels overeenkomen. Zo niet drukt u op de knop ‘Blokkeren’, want dan onderschept iemand berichten naar dit apparaat.", "Blacklist": "Blokkeren", "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Momenteel sluit u ongeverifieerde apparaten uit; om berichten naar deze apparaten te versturen moet u ze verifiëren.", - "Unblacklist": "Van zwarte lijst halen", + "Unblacklist": "Deblokkeren", "In future this verification process will be more sophisticated.": "In de toekomst zal dit verificatie proces meer geraffineerd zijn.", "Verify device": "Apparaat verifiëren", "I verify that the keys match": "Ik verifieer dat de sleutels overeenkomen", From 95e829913491171c6d6d6d40b129adadcc0635fa Mon Sep 17 00:00:00 2001 From: Gary Date: Fri, 29 Mar 2019 10:44:28 +0000 Subject: [PATCH 174/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 75aa7a9f87..4a00995b02 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -176,7 +176,7 @@ "Current password": "Huidig wachtwoord", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik er een bestaand", - "Create Room": "Kamer aanmaken", + "Create Room": "Maak een Kanaal aan", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen opdracht", "Deactivate Account": "Account deactiveren", From f15783886432c1439d139ec874eeab6e24e4e0b9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 29 Mar 2019 14:32:26 +0100 Subject: [PATCH 175/481] dispatch supports async dispatching on its own --- src/components/structures/MatrixChat.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index b7a5b94373..83492c2ac5 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1702,10 +1702,7 @@ export default React.createClass({ }, _dispatchTimelineResize() { - // prevent dispatch from within dispatch error - setTimeout(() => { - dis.dispatch({ action: 'timeline_resize' }, true); - }, 0); + dis.dispatch({ action: 'timeline_resize' }); }, onRoomCreated: function(roomId) { From 6e79cbc092e48edd92fd06e66c38c26e2f796dba Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 29 Mar 2019 15:19:39 +0000 Subject: [PATCH 176/481] Delay `Notifier` check until we have push rules The `Notifier` class expects push rules to be available, so it can explode in strange ways if called too early. This changes to wait until the sync is in the `PREPARED` state (when push rules should be ready) before using the `Notifier`. Fixes https://github.com/vector-im/riot-web/issues/9323 --- src/components/structures/MatrixChat.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 8848cda303..f64d546bbb 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -198,7 +198,7 @@ export default React.createClass({ syncError: null, // If the current syncing status is ERROR, the error object, otherwise null. resizeNotifier: new ResizeNotifier(), - showNotifierToolbar: Notifier.shouldShowToolbar(), + showNotifierToolbar: false, }; return s; }, @@ -1197,8 +1197,7 @@ export default React.createClass({ * Called when a new logged in session has started */ _onLoggedIn: async function() { - this.setStateForNewView({view: VIEWS.LOGGED_IN}); - this.setState({showNotifierToolbar: Notifier.shouldShowToolbar()}); + this.setStateForNewView({ view: VIEWS.LOGGED_IN }); if (this._is_registered) { this._is_registered = false; @@ -1342,7 +1341,10 @@ export default React.createClass({ self.firstSyncPromise.resolve(); dis.dispatch({action: 'focus_composer'}); - self.setState({ready: true}); + self.setState({ + ready: true, + showNotifierToolbar: Notifier.shouldShowToolbar(), + }); }); cli.on('Call.incoming', function(call) { // we dispatch this synchronously to make sure that the event From 39355c8270c43a1d1c314ffa4d98683c40b76bd4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 29 Mar 2019 16:27:37 +0100 Subject: [PATCH 177/481] Notifier is how singleton is known outside of this module, use this inside --- src/Notifier.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Notifier.js b/src/Notifier.js index ab8009c457..6a4f9827f7 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -226,8 +226,8 @@ const Notifier = { return false; } const isGuest = client.isGuest(); - return !isGuest && Notifier.supportsDesktopNotifications() && - !Notifier.isEnabled() && !Notifier._isToolbarHidden(); + return !isGuest && this.supportsDesktopNotifications() && + !this.isEnabled() && !this._isToolbarHidden(); }, _isToolbarHidden: function() { From 8e4a06db77f22569568bcdf7a44d964ab0ff0268 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 29 Mar 2019 16:41:10 +0100 Subject: [PATCH 178/481] round scrollTop upwards to prevent never detecting bottom --- src/components/structures/ScrollPanel.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index bb01da03da..cbbca3c468 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -222,7 +222,10 @@ module.exports = React.createClass({ // whether it will stay that way when the children update. isAtBottom: function() { const sn = this._getScrollNode(); - return sn.scrollTop === sn.scrollHeight - sn.clientHeight; + // fractional values for scrollTop happen on certain browsers/platforms + // when scrolled all the way down. E.g. Chrome 72 on debian. + // so ceil everything upwards to make sure it aligns. + return Math.ceil(sn.scrollTop) === Math.ceil(sn.scrollHeight - sn.clientHeight); }, // returns the vertical height in the given direction that can be removed from From 328f0cd6bf5695f7dbf8be508f8bc655b31d6ab9 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 28 Mar 2019 16:22:17 +0000 Subject: [PATCH 179/481] Notify user when crypto data is missing If we have account data in local storage but nothing in the crypto store, it generally means the browser has evicted IndexedDB out from under us. This adds a modal to explain the situation and offer to completely clear storage to get things back to normal. Fixes https://github.com/vector-im/riot-web/issues/9109 --- .babelrc | 21 ++++- package.json | 1 + src/Lifecycle.js | 38 ++++++++- .../dialogs/SessionRestoreErrorDialog.js | 2 +- .../views/dialogs/StorageEvictedDialog.js | 77 +++++++++++++++++++ src/i18n/strings/en_EN.json | 6 +- src/utils/StorageManager.js | 6 ++ yarn.lock | 12 ++- 8 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 src/components/views/dialogs/StorageEvictedDialog.js diff --git a/.babelrc b/.babelrc index fc5bd1788f..3fb847ad18 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,21 @@ { - "presets": ["react", "es2015", "es2016"], - "plugins": ["transform-class-properties", "transform-object-rest-spread", "transform-async-to-bluebird", "transform-runtime", "add-module-exports", "syntax-dynamic-import"] + "presets": [ + "react", + "es2015", + "es2016" + ], + "plugins": [ + [ + "transform-builtin-extend", + { + "globals": ["Error"] + } + ], + "transform-class-properties", + "transform-object-rest-spread", + "transform-async-to-bluebird", + "transform-runtime", + "add-module-exports", + "syntax-dynamic-import" + ] } diff --git a/package.json b/package.json index 8997d3c2af..91a349cda9 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "babel-loader": "^7.1.5", "babel-plugin-add-module-exports": "^0.2.1", "babel-plugin-transform-async-to-bluebird": "^1.1.1", + "babel-plugin-transform-builtin-extend": "^1.1.2", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-runtime": "^6.23.0", diff --git a/src/Lifecycle.js b/src/Lifecycle.js index fbb68481ad..f65dffa006 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -103,9 +103,14 @@ export async function loadSession(opts) { return _registerAsGuest(guestHsUrl, guestIsUrl, defaultDeviceDisplayName); } - // fall back to login screen + // fall back to welcome screen return false; } catch (e) { + if (e instanceof AbortLoginAndRebuildStorage) { + // If we're aborting login because of a storage inconsistency, we don't + // need to show the general failure dialog. Instead, just go back to welcome. + return false; + } return _handleLoadSessionFailure(e); } } @@ -279,7 +284,7 @@ async function _restoreFromLocalStorage() { } function _handleLoadSessionFailure(e) { - console.log("Unable to load session", e); + console.error("Unable to load session", e); const def = Promise.defer(); const SessionRestoreErrorDialog = @@ -354,7 +359,21 @@ async function _doSetLoggedIn(credentials, clearStorage) { await _clearStorage(); } - await StorageManager.checkConsistency(); + const results = await StorageManager.checkConsistency(); + // If there's an inconsistency between account data in local storage and the + // crypto store, we'll be generally confused when handling encrypted data. + // Show a modal recommending a full reset of storage. + if (results.dataInLocalStorage && !results.dataInCryptoStore) { + const signOut = await _showStorageEvictedDialog(); + if (signOut) { + await _clearStorage(); + // This error feels a bit clunky, but we want to make sure we don't go any + // further and instead head back to sign in. + throw new AbortLoginAndRebuildStorage( + "Aborting login in progress because of storage inconsistency", + ); + } + } Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl, credentials.identityServerUrl); @@ -386,6 +405,19 @@ async function _doSetLoggedIn(credentials, clearStorage) { return MatrixClientPeg.get(); } +function _showStorageEvictedDialog() { + const StorageEvictedDialog = sdk.getComponent('views.dialogs.StorageEvictedDialog'); + return new Promise(resolve => { + Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, { + onFinished: resolve, + }); + }); +} + +// Note: Babel 6 requires the `transform-builtin-extend` plugin for this to satisfy +// `instanceof`. Babel 7 supports this natively in their class handling. +class AbortLoginAndRebuildStorage extends Error { } + function _persistCredentialsToLocalStorage(credentials) { localStorage.setItem("mx_hs_url", credentials.homeserverUrl); localStorage.setItem("mx_is_url", credentials.identityServerUrl); diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.js index 60430b995e..f7e117b31b 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.js +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.js @@ -41,7 +41,7 @@ export default React.createClass({ Modal.createTrackedDialog('Session Restore Confirm Logout', '', QuestionDialog, { title: _t("Sign out"), description: -
      { _t("Log out and remove encryption keys?") }
      , +
      { _t("Sign out and remove encryption keys?") }
      , button: _t("Sign out"), danger: true, onFinished: this.props.onFinished, diff --git a/src/components/views/dialogs/StorageEvictedDialog.js b/src/components/views/dialogs/StorageEvictedDialog.js new file mode 100644 index 0000000000..22fa3ae3ab --- /dev/null +++ b/src/components/views/dialogs/StorageEvictedDialog.js @@ -0,0 +1,77 @@ +/* +Copyright 2019 New Vector 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 sdk from '../../../index'; +import SdkConfig from '../../../SdkConfig'; +import Modal from '../../../Modal'; +import { _t } from '../../../languageHandler'; + +export default class StorageEvictedDialog extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + }; + + _sendBugReport = ev => { + ev.preventDefault(); + const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog"); + Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {}); + }; + + _onSignOutClick = () => { + this.props.onFinished(true); + }; + + render() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + let logRequest; + if (SdkConfig.get().bug_report_endpoint_url) { + logRequest = _t( + "To help us prevent this in future, please send us logs.", {}, + { + a: text => {text}, + }); + } + + return ( + +
      +

      {_t( + "Some session data, including encrypted message keys, is " + + "missing. Sign out and sign in to fix this, restoring keys " + + "from backup.", + )}

      +

      {_t( + "Your browser likely removed this data when running low on " + + "disk space.", + )} {logRequest}

      +
      + +
      + ); + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3b24f28c2c..98301c5f76 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1141,7 +1141,7 @@ "Update any local room aliases to point to the new room": "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": "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room", "Put a link back to the old room at the start of the new room so people can see old messages": "Put a link back to the old room at the start of the new room so people can see old messages", - "Log out and remove encryption keys?": "Log out and remove encryption keys?", + "Sign out and remove encryption keys?": "Sign out and remove encryption keys?", "Clear Storage and Sign Out": "Clear Storage and Sign Out", "Send Logs": "Send Logs", "Refresh": "Refresh", @@ -1177,6 +1177,10 @@ "Share Room Message": "Share Room Message", "Link to selected message": "Link to selected message", "COPY": "COPY", + "To help us prevent this in future, please send us logs.": "To help us prevent this in future, please send us logs.", + "Missing session data": "Missing session data", + "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.", + "Your browser likely removed this data when running low on disk space.": "Your browser likely removed this data when running low on disk space.", "Error showing you your room": "Error showing you your room", "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.": "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.", "Send debug logs and reload Riot": "Send debug logs and reload Riot", diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index 472e1c93d4..6184f7fde9 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -110,4 +110,10 @@ export async function checkConsistency() { error("Storage consistency checks failed"); track("Consistency checks failed"); } + + return { + dataInLocalStorage, + dataInCryptoStore, + healthy, + }; } diff --git a/yarn.lock b/yarn.lock index 893ceac0a2..470e80f85a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -902,6 +902,14 @@ babel-plugin-transform-async-to-generator@^6.24.1: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-builtin-extend@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-builtin-extend/-/babel-plugin-transform-builtin-extend-1.1.2.tgz#5e96fecf58b8fa1ed74efcad88475b2af3c9116e" + integrity sha1-Xpb+z1i4+h7XTvytiEdbKvPJEW4= + dependencies: + babel-runtime "^6.2.0" + babel-template "^6.3.0" + babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" @@ -1267,7 +1275,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -1275,7 +1283,7 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.9.0: +babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0, babel-template@^6.9.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= From 07cc640089919a228f3c5c7e7405d4f85fe63905 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 11:45:07 -0600 Subject: [PATCH 180/481] Add common utility for checking 3pid invites We just need to make sure they are structurally sound - actual validation is done by other parties. --- src/RoomInvite.js | 18 ++++++++++++++++++ src/TextForEvent.js | 3 ++- src/components/views/rooms/MemberList.js | 7 ++----- .../views/rooms/ThirdPartyMemberInfo.js | 7 ++++--- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/RoomInvite.js b/src/RoomInvite.js index 3547b9195f..b808b935a6 100644 --- a/src/RoomInvite.js +++ b/src/RoomInvite.js @@ -65,6 +65,24 @@ export function showRoomInviteDialog(roomId) { }); } +/** + * Checks if the given MatrixEvent is a valid 3rd party user invite. + * @param {MatrixEvent} event The event to check + * @returns {boolean} True if valid, false otherwise + */ +export function isValid3pidInvite(event) { + if (!event || event.getType() !== "m.room.third_party_invite") return false; + + // any events without these keys are not valid 3pid invites, so we ignore them + const requiredKeys = ['key_validity_url', 'public_key', 'display_name']; + for (let i = 0; i < requiredKeys.length; ++i) { + if (!event.getContent()[requiredKeys[i]]) return false; + } + + // Valid enough by our standards + return true; +} + function _onStartChatFinished(shouldInvite, addrs) { if (!shouldInvite) return; diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 05d83d740a..a700fe2a3c 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -17,6 +17,7 @@ import MatrixClientPeg from './MatrixClientPeg'; import CallHandler from './CallHandler'; import { _t } from './languageHandler'; import * as Roles from './Roles'; +import {isValid3pidInvite} from "./RoomInvite"; function textForMemberEvent(ev) { // XXX: SYJS-16 "sender is sometimes null for join messages" @@ -367,7 +368,7 @@ function textForCallInviteEvent(event) { function textForThreePidInviteEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); - if (!event.getContent().display_name) { + if (!isValid3pidInvite(event)) { const targetDisplayName = event.getPrevContent().display_name || _t("Someone"); return _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { senderName, diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index a8cc948f63..e79f2f21d4 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -20,6 +20,7 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher'; +import {isValid3pidInvite} from "../../../RoomInvite"; const MatrixClientPeg = require("../../../MatrixClientPeg"); const sdk = require('../../../index'); const rate_limited_func = require('../../../ratelimitedfunc'); @@ -379,11 +380,7 @@ module.exports = React.createClass({ if (room) { return room.currentState.getStateEvents("m.room.third_party_invite").filter(function(e) { - // any events without these keys are not valid 3pid invites, so we ignore them - const requiredKeys = ['key_validity_url', 'public_key', 'display_name']; - for (let i = 0; i < requiredKeys.length; ++i) { - if (e.getContent()[requiredKeys[i]] === undefined) return false; - } + if (!isValid3pidInvite(e)) return false; // discard all invites which have a m.room.member event since we've // already added them. diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.js b/src/components/views/rooms/ThirdPartyMemberInfo.js index 3fe8382251..754e32871f 100644 --- a/src/components/views/rooms/ThirdPartyMemberInfo.js +++ b/src/components/views/rooms/ThirdPartyMemberInfo.js @@ -22,6 +22,7 @@ import {_t} from "../../../languageHandler"; import dis from "../../../dispatcher"; import sdk from "../../../index"; import Modal from "../../../Modal"; +import {isValid3pidInvite} from "../../../RoomInvite"; export default class ThirdPartyMemberInfo extends React.Component { static propTypes = { @@ -64,7 +65,7 @@ export default class ThirdPartyMemberInfo extends React.Component { onRoomStateEvents = (ev) => { if (ev.getType() === "m.room.third_party_invite" && ev.getStateKey() === this.state.stateKey) { const newDisplayName = ev.getContent().display_name; - const isInvited = !!newDisplayName; // display_name indicates a valid invite + const isInvited = isValid3pidInvite(ev); const newState = {invited: isInvited}; if (newDisplayName) newState['displayName'] = newDisplayName; @@ -123,8 +124,8 @@ export default class ThirdPartyMemberInfo extends React.Component {

      {this.state.displayName}

      From 62ba7dde9487809f6589abc63ddfd3748bd61bd9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 14:12:48 -0600 Subject: [PATCH 181/481] Download PDFs as blobs to avoid empty grey screens Fixes https://github.com/vector-im/riot-web/issues/8605 The grey screen of sadness comes up when Chrome tries to open the PDF but doesn't have the right CSP headers. To avoid this, we'll just force a download of the PDF through `fetch` and `Blob`. There are a few cases where the user might still get a grey screen though: namely if they open the URL in a new tab or when the event content is lying about the file type, or the file is too large to blobify. `fetch` works in Chrome, Firefox, and our packaged Electron version. --- src/components/views/messages/MFileBody.js | 55 +++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 7960db0384..372b501558 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -294,6 +294,8 @@ module.exports = React.createClass({ const fileName = content.body && content.body.length > 0 ? content.body : _t("Attachment"); const contentUrl = this._getContentUrl(); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const fileSize = content.info ? content.info.size : null; + const fileType = content.info ? content.info.mimetype : "application/octet-stream"; if (isEncrypted) { if (this.state.decryptedBlob === null) { @@ -372,6 +374,55 @@ module.exports = React.createClass({ ); } else if (contentUrl) { + const downloadProps = { + target: "_blank", + rel: "noopener", + + // We set the href regardless of whether or not we intercept the download + // because we don't really want to convert the file to a blob eagerly, and + // still want "open in new tab" and "save link as" to work. + href: contentUrl, + }; + + // Blobs can only have up to 500mb, so if the file reports as being too large then + // we won't try and convert it. Likewise, if the file size is unknown then we'll assume + // it is too big. There is the risk of the reported file size and the actual file size + // being different, however the user shouldn't normally run into this problem. + const fileTooBig = typeof(fileSize) === 'number' ? fileSize > 524288000 : true; + + if (["application/pdf"].includes(fileType) && !fileTooBig) { + // We want to force a download on this type, so use an onClick handler. + downloadProps["onClick"] = (e) => { + console.log(`Downloading ${fileType} as blob (unencrypted)`); + + // Avoid letting the do its thing + e.preventDefault(); + e.stopPropagation(); + + // Start a fetch for the download + // Based upon https://stackoverflow.com/a/49500465 + fetch(contentUrl, { + headers: new Headers({ + 'Origin': window.location.origin, + }), + mode: 'cors', + }).then((response) => response.blob()).then((blob) => { + const blobUrl = URL.createObjectURL(blob); + + // We have to create an anchor to download the file + const tempAnchor = document.createElement('a'); + tempAnchor.download = fileName; + tempAnchor.href = blobUrl; + document.body.appendChild(tempAnchor); // for firefox: https://stackoverflow.com/a/32226068 + tempAnchor.click(); + tempAnchor.remove(); + }); + }; + } else { + // Else we are hoping the browser will do the right thing + downloadProps["download"] = fileName; + } + // If the attachment is not encrypted then we check whether we // are being displayed in the room timeline or in a list of // files in the right hand side of the screen. @@ -379,7 +430,7 @@ module.exports = React.createClass({ return (
      - + { fileName }
      @@ -392,7 +443,7 @@ module.exports = React.createClass({ return (
      - + { _t("Download %(text)s", { text: text }) } From fc28f094fef4723a40240f217e5cd9b7ff25eae7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 14:55:56 -0600 Subject: [PATCH 182/481] Set title attribute on images in lightbox Part of https://github.com/vector-im/riot-web/issues/9324 --- src/components/views/elements/ImageView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index 2c0f4a0d86..48f587b4f2 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -173,7 +173,7 @@ module.exports = React.createClass({
      - +
      { From 8d14dc4e26934235df0f430bdcb6bc5e15da2222 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 15:48:33 -0600 Subject: [PATCH 183/481] Don't send options we don't need to `fetch` --- src/components/views/messages/MFileBody.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 372b501558..7e107c1ad8 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -401,12 +401,7 @@ module.exports = React.createClass({ // Start a fetch for the download // Based upon https://stackoverflow.com/a/49500465 - fetch(contentUrl, { - headers: new Headers({ - 'Origin': window.location.origin, - }), - mode: 'cors', - }).then((response) => response.blob()).then((blob) => { + fetch(contentUrl).then((response) => response.blob()).then((blob) => { const blobUrl = URL.createObjectURL(blob); // We have to create an anchor to download the file From 5beec37c43c1765356d80ec3d55fb12f67c5f0c1 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 28 Mar 2019 20:38:15 -0600 Subject: [PATCH 184/481] Add MemberInfo for 3pid invites and support revoking those invites Fixes https://github.com/vector-im/riot-web/issues/625 Fixes https://github.com/vector-im/riot-web/issues/6411 Fixes https://github.com/vector-im/riot-web/issues/5490 --- src/TextForEvent.js | 9 ++ src/components/structures/RightPanel.js | 5 + .../views/right_panel/RoomHeaderButtons.js | 7 + src/components/views/rooms/MemberList.js | 8 + .../views/rooms/ThirdPartyMemberInfo.js | 142 ++++++++++++++++++ src/i18n/strings/en_EN.json | 5 + 6 files changed, 176 insertions(+) create mode 100644 src/components/views/rooms/ThirdPartyMemberInfo.js diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 030c346ccc..05d83d740a 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -366,6 +366,15 @@ function textForCallInviteEvent(event) { function textForThreePidInviteEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); + + if (!event.getContent().display_name) { + const targetDisplayName = event.getPrevContent().display_name || _t("Someone"); + return _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { + senderName, + targetDisplayName, + }); + } + return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', { senderName, targetDisplayName: event.getContent().display_name, diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 5c745b04cc..74820c804a 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -50,6 +50,7 @@ export default class RightPanel extends React.Component { FilePanel: 'FilePanel', NotificationPanel: 'NotificationPanel', RoomMemberInfo: 'RoomMemberInfo', + Room3pidMemberInfo: 'Room3pidMemberInfo', GroupMemberInfo: 'GroupMemberInfo', }); @@ -155,6 +156,7 @@ export default class RightPanel extends React.Component { groupRoomId: payload.groupRoomId, groupId: payload.groupId, member: payload.member, + event: payload.event, }); } } @@ -162,6 +164,7 @@ export default class RightPanel extends React.Component { render() { const MemberList = sdk.getComponent('rooms.MemberList'); const MemberInfo = sdk.getComponent('rooms.MemberInfo'); + const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo'); const NotificationPanel = sdk.getComponent('structures.NotificationPanel'); const FilePanel = sdk.getComponent('structures.FilePanel'); @@ -180,6 +183,8 @@ export default class RightPanel extends React.Component { panel = ; } else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) { panel = ; + } else if (this.state.phase === RightPanel.Phase.Room3pidMemberInfo) { + panel = ; } else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) { panel = { if (query) { @@ -408,6 +415,7 @@ module.exports = React.createClass({ return this._onPending3pidInviteClick(e)} />; })); } diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.js b/src/components/views/rooms/ThirdPartyMemberInfo.js new file mode 100644 index 0000000000..3fe8382251 --- /dev/null +++ b/src/components/views/rooms/ThirdPartyMemberInfo.js @@ -0,0 +1,142 @@ +/* +Copyright 2019 New Vector 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 MatrixClientPeg from "../../../MatrixClientPeg"; +import {MatrixEvent} from "matrix-js-sdk"; +import {_t} from "../../../languageHandler"; +import dis from "../../../dispatcher"; +import sdk from "../../../index"; +import Modal from "../../../Modal"; + +export default class ThirdPartyMemberInfo extends React.Component { + static propTypes = { + event: PropTypes.instanceOf(MatrixEvent).isRequired, + }; + + constructor(props) { + super(props); + + const room = MatrixClientPeg.get().getRoom(this.props.event.getRoomId()); + const me = room.getMember(MatrixClientPeg.get().getUserId()); + const powerLevels = room.currentState.getStateEvents("m.room.power_levels", ""); + + let kickLevel = powerLevels ? powerLevels.getContent().kick : 50; + if (typeof(kickLevel) !== 'number') kickLevel = 50; + + const sender = room.getMember(this.props.event.getSender()); + + this.state = { + stateKey: this.props.event.getStateKey(), + roomId: this.props.event.getRoomId(), + displayName: this.props.event.getContent().display_name, + invited: true, + canKick: me ? me.powerLevel > kickLevel : false, + senderName: sender ? sender.name : this.props.event.getSender(), + }; + } + + componentWillMount(): void { + MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents); + } + + componentWillUnmount(): void { + const client = MatrixClientPeg.get(); + if (client) { + client.removeListener("RoomState.events", this.onRoomStateEvents); + } + } + + onRoomStateEvents = (ev) => { + if (ev.getType() === "m.room.third_party_invite" && ev.getStateKey() === this.state.stateKey) { + const newDisplayName = ev.getContent().display_name; + const isInvited = !!newDisplayName; // display_name indicates a valid invite + + const newState = {invited: isInvited}; + if (newDisplayName) newState['displayName'] = newDisplayName; + this.setState(newState); + } + }; + + onCancel = () => { + dis.dispatch({ + action: "view_3pid_invite", + event: null, + }); + }; + + onKickClick = () => { + MatrixClientPeg.get().sendStateEvent(this.state.roomId, "m.room.third_party_invite", {}, this.state.stateKey) + .catch((err) => { + console.error(err); + + // Revert echo because of error + this.setState({invited: true}); + + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog('Revoke 3pid invite failed', '', ErrorDialog, { + title: _t("Failed to revoke invite"), + description: _t( + "Could not revoke the invite. The server may be experiencing a temporary problem or " + + "you do not have sufficient permissions to revoke the invite.", + ), + }); + }); + + // Local echo + this.setState({invited: false}); + }; + + render() { + const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); + + let adminTools = null; + if (this.state.canKick && this.state.invited) { + adminTools = ( +
      +

      {_t("Admin Tools")}

      +
      + + {_t("Revoke invite")} + +
      +
      + ); + } + + // We shamelessly rip off the MemberInfo styles here. + return ( +
      +
      + +

      {this.state.displayName}

      +
      +
      +
      +
      + {_t("Invited by %(sender)s", {sender: this.state.senderName})} +
      +
      +
      + {adminTools} +
      + ); + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 94d524d767..0f696e2893 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -223,6 +223,7 @@ "(unknown failure: %(reason)s)": "(unknown failure: %(reason)s)", "%(senderName)s ended the call.": "%(senderName)s ended the call.", "%(senderName)s placed a %(callType)s call.": "%(senderName)s placed a %(callType)s call.", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.", "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s made future room history visible to all room members, from the point they are invited.", "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s made future room history visible to all room members, from the point they joined.", @@ -823,6 +824,10 @@ "Stickerpack": "Stickerpack", "Hide Stickers": "Hide Stickers", "Show Stickers": "Show Stickers", + "Failed to revoke invite": "Failed to revoke invite", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.", + "Revoke invite": "Revoke invite", + "Invited by %(sender)s": "Invited by %(sender)s", "Jump to first unread message.": "Jump to first unread message.", "Error updating main address": "Error updating main address", "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.", From 42cfe74f700b4db0fdbdc5e8f24e373df23a6246 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 11:45:07 -0600 Subject: [PATCH 185/481] Add common utility for checking 3pid invites We just need to make sure they are structurally sound - actual validation is done by other parties. --- src/RoomInvite.js | 18 ++++++++++++++++++ src/TextForEvent.js | 3 ++- src/components/views/rooms/MemberList.js | 7 ++----- .../views/rooms/ThirdPartyMemberInfo.js | 7 ++++--- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/RoomInvite.js b/src/RoomInvite.js index 3547b9195f..b808b935a6 100644 --- a/src/RoomInvite.js +++ b/src/RoomInvite.js @@ -65,6 +65,24 @@ export function showRoomInviteDialog(roomId) { }); } +/** + * Checks if the given MatrixEvent is a valid 3rd party user invite. + * @param {MatrixEvent} event The event to check + * @returns {boolean} True if valid, false otherwise + */ +export function isValid3pidInvite(event) { + if (!event || event.getType() !== "m.room.third_party_invite") return false; + + // any events without these keys are not valid 3pid invites, so we ignore them + const requiredKeys = ['key_validity_url', 'public_key', 'display_name']; + for (let i = 0; i < requiredKeys.length; ++i) { + if (!event.getContent()[requiredKeys[i]]) return false; + } + + // Valid enough by our standards + return true; +} + function _onStartChatFinished(shouldInvite, addrs) { if (!shouldInvite) return; diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 05d83d740a..a700fe2a3c 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -17,6 +17,7 @@ import MatrixClientPeg from './MatrixClientPeg'; import CallHandler from './CallHandler'; import { _t } from './languageHandler'; import * as Roles from './Roles'; +import {isValid3pidInvite} from "./RoomInvite"; function textForMemberEvent(ev) { // XXX: SYJS-16 "sender is sometimes null for join messages" @@ -367,7 +368,7 @@ function textForCallInviteEvent(event) { function textForThreePidInviteEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); - if (!event.getContent().display_name) { + if (!isValid3pidInvite(event)) { const targetDisplayName = event.getPrevContent().display_name || _t("Someone"); return _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { senderName, diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index a8cc948f63..e79f2f21d4 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -20,6 +20,7 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher'; +import {isValid3pidInvite} from "../../../RoomInvite"; const MatrixClientPeg = require("../../../MatrixClientPeg"); const sdk = require('../../../index'); const rate_limited_func = require('../../../ratelimitedfunc'); @@ -379,11 +380,7 @@ module.exports = React.createClass({ if (room) { return room.currentState.getStateEvents("m.room.third_party_invite").filter(function(e) { - // any events without these keys are not valid 3pid invites, so we ignore them - const requiredKeys = ['key_validity_url', 'public_key', 'display_name']; - for (let i = 0; i < requiredKeys.length; ++i) { - if (e.getContent()[requiredKeys[i]] === undefined) return false; - } + if (!isValid3pidInvite(e)) return false; // discard all invites which have a m.room.member event since we've // already added them. diff --git a/src/components/views/rooms/ThirdPartyMemberInfo.js b/src/components/views/rooms/ThirdPartyMemberInfo.js index 3fe8382251..754e32871f 100644 --- a/src/components/views/rooms/ThirdPartyMemberInfo.js +++ b/src/components/views/rooms/ThirdPartyMemberInfo.js @@ -22,6 +22,7 @@ import {_t} from "../../../languageHandler"; import dis from "../../../dispatcher"; import sdk from "../../../index"; import Modal from "../../../Modal"; +import {isValid3pidInvite} from "../../../RoomInvite"; export default class ThirdPartyMemberInfo extends React.Component { static propTypes = { @@ -64,7 +65,7 @@ export default class ThirdPartyMemberInfo extends React.Component { onRoomStateEvents = (ev) => { if (ev.getType() === "m.room.third_party_invite" && ev.getStateKey() === this.state.stateKey) { const newDisplayName = ev.getContent().display_name; - const isInvited = !!newDisplayName; // display_name indicates a valid invite + const isInvited = isValid3pidInvite(ev); const newState = {invited: isInvited}; if (newDisplayName) newState['displayName'] = newDisplayName; @@ -123,8 +124,8 @@ export default class ThirdPartyMemberInfo extends React.Component {

      {this.state.displayName}

      From 662a0e4785516bf46c297a633b0c0a028c552171 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 14:12:48 -0600 Subject: [PATCH 186/481] Download PDFs as blobs to avoid empty grey screens Fixes https://github.com/vector-im/riot-web/issues/8605 The grey screen of sadness comes up when Chrome tries to open the PDF but doesn't have the right CSP headers. To avoid this, we'll just force a download of the PDF through `fetch` and `Blob`. There are a few cases where the user might still get a grey screen though: namely if they open the URL in a new tab or when the event content is lying about the file type, or the file is too large to blobify. `fetch` works in Chrome, Firefox, and our packaged Electron version. --- src/components/views/messages/MFileBody.js | 55 +++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 7960db0384..372b501558 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -294,6 +294,8 @@ module.exports = React.createClass({ const fileName = content.body && content.body.length > 0 ? content.body : _t("Attachment"); const contentUrl = this._getContentUrl(); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const fileSize = content.info ? content.info.size : null; + const fileType = content.info ? content.info.mimetype : "application/octet-stream"; if (isEncrypted) { if (this.state.decryptedBlob === null) { @@ -372,6 +374,55 @@ module.exports = React.createClass({ ); } else if (contentUrl) { + const downloadProps = { + target: "_blank", + rel: "noopener", + + // We set the href regardless of whether or not we intercept the download + // because we don't really want to convert the file to a blob eagerly, and + // still want "open in new tab" and "save link as" to work. + href: contentUrl, + }; + + // Blobs can only have up to 500mb, so if the file reports as being too large then + // we won't try and convert it. Likewise, if the file size is unknown then we'll assume + // it is too big. There is the risk of the reported file size and the actual file size + // being different, however the user shouldn't normally run into this problem. + const fileTooBig = typeof(fileSize) === 'number' ? fileSize > 524288000 : true; + + if (["application/pdf"].includes(fileType) && !fileTooBig) { + // We want to force a download on this type, so use an onClick handler. + downloadProps["onClick"] = (e) => { + console.log(`Downloading ${fileType} as blob (unencrypted)`); + + // Avoid letting the do its thing + e.preventDefault(); + e.stopPropagation(); + + // Start a fetch for the download + // Based upon https://stackoverflow.com/a/49500465 + fetch(contentUrl, { + headers: new Headers({ + 'Origin': window.location.origin, + }), + mode: 'cors', + }).then((response) => response.blob()).then((blob) => { + const blobUrl = URL.createObjectURL(blob); + + // We have to create an anchor to download the file + const tempAnchor = document.createElement('a'); + tempAnchor.download = fileName; + tempAnchor.href = blobUrl; + document.body.appendChild(tempAnchor); // for firefox: https://stackoverflow.com/a/32226068 + tempAnchor.click(); + tempAnchor.remove(); + }); + }; + } else { + // Else we are hoping the browser will do the right thing + downloadProps["download"] = fileName; + } + // If the attachment is not encrypted then we check whether we // are being displayed in the room timeline or in a list of // files in the right hand side of the screen. @@ -379,7 +430,7 @@ module.exports = React.createClass({ return (
      - + { fileName }
      @@ -392,7 +443,7 @@ module.exports = React.createClass({ return (
      - + { _t("Download %(text)s", { text: text }) } From 82bc92c326b9ef436b3ae9ea66183e53a2f43d50 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 15:48:33 -0600 Subject: [PATCH 187/481] Don't send options we don't need to `fetch` --- src/components/views/messages/MFileBody.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 372b501558..7e107c1ad8 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -401,12 +401,7 @@ module.exports = React.createClass({ // Start a fetch for the download // Based upon https://stackoverflow.com/a/49500465 - fetch(contentUrl, { - headers: new Headers({ - 'Origin': window.location.origin, - }), - mode: 'cors', - }).then((response) => response.blob()).then((blob) => { + fetch(contentUrl).then((response) => response.blob()).then((blob) => { const blobUrl = URL.createObjectURL(blob); // We have to create an anchor to download the file From 9c502fda9502887eed29495fcab79df9461ef3d2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 29 Mar 2019 14:55:56 -0600 Subject: [PATCH 188/481] Set title attribute on images in lightbox Part of https://github.com/vector-im/riot-web/issues/9324 --- src/components/views/elements/ImageView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index 2c0f4a0d86..48f587b4f2 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -173,7 +173,7 @@ module.exports = React.createClass({
      - +
      { From 4c65587469185af8ac7d0a549c7a29813e6b00ed Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 28 Mar 2019 12:27:33 +0000 Subject: [PATCH 189/481] Check the local storage fallback for crypto store This adds additional consistency checks to examine the local storage fallback for the crypto store as well as the primary IndexedDB variant. Part of https://github.com/vector-im/riot-web/issues/9309 --- src/utils/StorageManager.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index 472e1c93d4..a669ed9176 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -15,6 +15,7 @@ limitations under the License. */ import Matrix from 'matrix-js-sdk'; +import LocalStorageCryptoStore from 'matrix-js-sdk/lib/crypto/store/localStorage-crypto-store'; import Analytics from '../Analytics'; const localStorage = window.localStorage; @@ -78,15 +79,10 @@ export async function checkConsistency() { } if (indexedDB) { - try { - dataInCryptoStore = await Matrix.IndexedDBCryptoStore.exists( - indexedDB, CRYPTO_STORE_NAME, - ); - log(`Crypto store contains data? ${dataInCryptoStore}`); - } catch (e) { + const results = await checkCryptoStore(); + dataInCryptoStore = results.exists; + if (!results.healthy) { healthy = false; - error("Crypto store inaccessible", e); - track("Crypto store inaccessible"); } } else { healthy = false; @@ -111,3 +107,26 @@ export async function checkConsistency() { track("Consistency checks failed"); } } + +async function checkCryptoStore() { + let exists = false; + try { + exists = await Matrix.IndexedDBCryptoStore.exists( + indexedDB, CRYPTO_STORE_NAME, + ); + log(`Crypto store using IndexedDB contains data? ${exists}`); + return { exists, healthy: true }; + } catch (e) { + error("Crypto store using IndexedDB inaccessible", e); + track("Crypto store using IndexedDB inaccessible"); + } + try { + exists = await LocalStorageCryptoStore.exists(localStorage); + log(`Crypto store using local storage contains data? ${exists}`); + return { exists, healthy: true }; + } catch (e) { + error("Crypto store using local storage inaccessible", e); + track("Crypto store using local storage inaccessible"); + } + return { exists, healthy: false }; +} From 83931a4a4238239ce6e9ec40fd0c1027f65cdcf1 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 28 Mar 2019 12:40:38 +0000 Subject: [PATCH 190/481] Clarify when memory stores are being used This adds logging for the cases where memory only stores are being used. It also reorganises the sync store path to match the crypto store. Part of https://github.com/vector-im/riot-web/issues/9309 --- src/utils/StorageManager.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/utils/StorageManager.js b/src/utils/StorageManager.js index a669ed9176..89fa0d290b 100644 --- a/src/utils/StorageManager.js +++ b/src/utils/StorageManager.js @@ -62,15 +62,9 @@ export async function checkConsistency() { } if (indexedDB && localStorage) { - try { - const dataInSyncStore = await Matrix.IndexedDBStore.exists( - indexedDB, SYNC_STORE_NAME, - ); - log(`Sync store contains data? ${dataInSyncStore}`); - } catch (e) { + const results = await checkSyncStore(); + if (!results.healthy) { healthy = false; - error("Sync store inaccessible", e); - track("Sync store inaccessible"); } } else { healthy = false; @@ -108,6 +102,22 @@ export async function checkConsistency() { } } +async function checkSyncStore() { + let exists = false; + try { + exists = await Matrix.IndexedDBStore.exists( + indexedDB, SYNC_STORE_NAME, + ); + log(`Sync store using IndexedDB contains data? ${exists}`); + return { exists, healthy: true }; + } catch (e) { + error("Sync store using IndexedDB inaccessible", e); + track("Sync store using IndexedDB inaccessible"); + } + log("Sync store using memory only"); + return { exists, healthy: false }; +} + async function checkCryptoStore() { let exists = false; try { @@ -128,5 +138,6 @@ async function checkCryptoStore() { error("Crypto store using local storage inaccessible", e); track("Crypto store using local storage inaccessible"); } + log("Crypto store using memory only"); return { exists, healthy: false }; } From 921b83bbc3b030ee5f023bfe0e44de22b420b386 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Mon, 18 Mar 2019 10:20:08 +0000 Subject: [PATCH 191/481] Translated using Weblate (Albanian) Currently translated at 99.6% (1554 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/sq/ --- src/i18n/strings/sq.json | 57 +++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 7225b0808c..d87f370a2a 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -78,7 +78,7 @@ "Failed to invite users to %(groupId)s": "S’u arrit të ftoheshin përdorues te %(groupId)s", "Failed to add the following rooms to %(groupId)s:": "S’u arrit të shtoheshin dhomat vijuese te %(groupId)s:", "Unnamed Room": "Dhomë e Paemërtuar", - "Riot does not have permission to send you notifications - please check your browser settings": "Riot-i s’ka leje t’ju dërgojë njoftime - Ju lutemi, kontrolloni rregullimet e shfletuesit tuajPlease wait whilst we resynchronise with the server", + "Riot does not have permission to send you notifications - please check your browser settings": "Riot-i s’ka leje t’ju dërgojë njoftime - Ju lutemi, kontrolloni rregullimet e shfletuesit tuaj", "Riot was not given permission to send notifications - please try again": "Riot-it s’iu dha leje të dërgojë njoftime - ju lutemi, riprovoni", "Unable to enable Notifications": "S’arrihet të aktivizohen njoftimet", "This email address was not found": "Kjo adresë email s’u gjet", @@ -560,7 +560,7 @@ "Advanced options": "Mundësi të mëtejshme", "Unknown error": "Gabim i panjohur", "Incorrect password": "Fjalëkalim i pasaktë", - "Deactivate Account": "Mbylleni Llogarinë", + "Deactivate Account": "Çaktivizoje Llogarinë", "Device name": "Emër pajisjeje", "Device key": "Kyç pajisjeje", "Verify device": "Verifiko pajisjen", @@ -697,7 +697,7 @@ "Room Notification": "Njoftim Dhome", "Users": "Përdorues", "unknown device": "pajisje e panjohur", - "NOT verified": "JO e verifikua", + "NOT verified": "JO e verifikuar", "verified": "e verifikuar", "Verification": "Verifikim", "User ID": "ID përdoruesi", @@ -941,7 +941,7 @@ "%(oneUser)sjoined %(count)s times|other": "%(oneUser)shyri %(count)s herë", "%(oneUser)sjoined %(count)s times|one": "%(oneUser)shyri", "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)sdolën %(count)s herë", - "%(severalUsers)sleft %(count)s times|one": "Doli %(severalUsers)s", + "%(severalUsers)sleft %(count)s times|one": "Dolën %(severalUsers)s", "%(oneUser)sleft %(count)s times|other": "%(oneUser)sdoli %(count)s herë", "%(oneUser)sleft %(count)s times|one": "%(oneUser)sdoli", "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)sdolën dhe rihynë", @@ -1024,7 +1024,7 @@ "Picture": "Foto", "Failed to indicate account erasure": "S’u arrit të tregohej fshirje llogarie", "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.": "Dukshmëria e mesazheve në Matrix është e ngjashme me atë në email. Harrimi i mesazheve nga ana jonë do të thotë që mesazhet që keni dërguar nuk do të ndahen me çfarëdo përdoruesi të ri apo të paregjistruar, por përdoruesit e regjistruar, që kanë tashmë hyrje në këto mesazhe, do të kenë prapëseprapë hyrje te kopja e tyre.", - "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)": "Të lutem, harro krejt mesazhet që kamë dërguar, kur të çaktivizohet llogaria ime (Kujdes: kjo do të bëjë që përdorues të ardhshëm të shohin një pamje jo të plotë të bisedave)", + "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)": "Të lutem, harro krejt mesazhet që kamë dërguar, kur të çaktivizohet llogaria ime (Kujdes: kjo do të bëjë që përdorues të ardhshëm të shohin një pamje jo të plotë të bisedave)", "To continue, please enter your password:": "Që të vazhdohet, ju lutemi, jepni fjalëkalimin tuaj:", "password": "fjalëkalim", "Incompatible local cache": "Fshehtinë vendore e papërputhshme", @@ -1125,7 +1125,7 @@ "Changes made to your community name and avatar might not be seen by other users for up to 30 minutes.": "Ndryshimet e bëra te emri dhe avatari i bashkësisë tuaj mund të mos shihen nga përdoruesit e tjera para deri 30 minutash.", "Can't leave Server Notices room": "Dhoma Njoftime Shërbyesi, s’braktiset dot", "For security, this session has been signed out. Please sign in again.": "Për hir të sigurisë, është bërë dalja nga ky sesion. Ju lutemi, ribëni hyrjen.", - "Data from an older version of Riot 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.": "Janë pikasur të dhëna nga një version i dikurshëm i Riot-it. Kjo do të bëjë që kriptografia skaj-më-skaj te versioni i dikurshëm të mos punojë si duhet. Mesazhet e fshehtëzuar skaj-më-skaj tani së fundi teksa përdorej versioni i dikurshëm mund të mos jenë të shfshehtëzueshëm në këtë version. Kjo mund bëjë edhe që mesazhet e shkëmbyera me këtë version të dështojnë. Nëse ju dalin probleme, bëni daljen dhe rihyni në llogari. Që të ruhet historiku i mesazheve, eksportoni dhe ri-importoni kyçet tuaj.", + "Data from an older version of Riot 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.": "Janë pikasur të dhëna nga një version i dikurshëm i Riot-it. Kjo do të bëjë që kriptografia skaj-më-skaj te versioni i dikurshëm të mos punojë si duhet. Mesazhet e fshehtëzuar skaj-më-skaj tani së fundi teksa përdorej versioni i dikurshëm mund të mos jenë të shfshehtëzueshëm në këtë version. Kjo mund bëjë edhe që mesazhet e shkëmbyera me këtë version të dështojnë. Nëse ju dalin probleme, bëni daljen dhe rihyni në llogari. Që të ruhet historiku i mesazheve, eksportoni dhe riimportoni kyçet tuaj.", "Did you know: you can use communities to filter your Riot.im experience!": "E dinit se: mund t’i përdorni bashkësitë për të filtruar punimin tuaj në Riot.im?", "Error whilst fetching joined communities": "Gabim teksa silleshin bashkësitë ku merret pjesë", "Show devices, send anyway or cancel.": "Shfaq pajisje, dërgoje sido qoftë ose anuloje.", @@ -1133,7 +1133,7 @@ "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Ridërgojeni mesazhin ose anulojeni mesazhin tani.", "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "Për hir të sigurisë, dalja nga llogaria do të sjellë fshirjen në këtë shfletues të çfarëdo kyçesh fshehtëzimi skaj-më-skaj. Nëse doni të jeni në gjendje të fshehtëzoni historikun e bisedave tuaja që nga sesione të ardhshëm Riot, ju lutemi, eksportoni kyçet tuaj të dhomës, për t’i ruajtur të parrezikuar diku.", "Audio Output": "Sinjal Audio", - "Error: Problem communicating with the given homeserver.": "Gabimr: Problem komunikimi me shërbyesin e dhënë Home.", + "Error: Problem communicating with the given homeserver.": "Gabim: Problem komunikimi me shërbyesin e dhënë Home.", "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "S’lidhet dot te shërbyes Home përmes HTTP-je, kur te shtylla e shfletuesit tuaj jepet një URL HTTPS. Ose përdorni HTTPS-në, ose aktivizoni përdorimin e programtheve jo të sigurt.", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "S’lidhet dot te shërbyes Home - ju lutemi, kontrolloni lidhjen tuaj, sigurohuni që dëshmia SSL e shërbyesit tuaj Home besohet, dhe që s’ka ndonjë zgjerim shfletuesi që po bllokon kërkesat tuaja.", "Failed to remove tag %(tagName)s from room": "S’u arrit të hiqej etiketa %(tagName)s nga dhoma", @@ -1197,7 +1197,7 @@ "Your home server does not support device management.": "Shërbyesi juaj Home nuk mbulon administrim pajisjesh.", "The maximum permitted number of widgets have already been added to this room.": "Në këtë dhomë është shtuar tashmë numri maksimum i lejuar për widget-et.", "Your key share request has been sent - please check your other devices for key share requests.": "Kërkesa juaj për shkëmbim kyçesh u dërgua - ju lutemi, kontrolloni pajisjet tuaja të tjera për kërkesa shkëmbimi kyçesh.", - "Undecryptable": "I pafshehtëzueshëm", + "Undecryptable": "I pashfshehtëzueshëm", "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "S’do të jeni në gjendje ta zhbëni këtë, ngaqë po zhgradoni veten, nëse jeni përdoruesi i fundit i privilegjuar te dhoma do të jetë e pamundur të rifitoni privilegjet.", "Jump to read receipt": "Hidhuni te leximi i faturës", "Unable to reply": "S’arrihet të përgjigjet", @@ -1246,8 +1246,8 @@ "This room is used for important messages from the Homeserver, so you cannot leave it.": "Kjo dhomë përdoret për mesazhe të rëndësishëm nga shërbyesi Home, ndaj s’mund ta braktisni.", "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.": "Që të ndërtoni një filtër, tërhiqeni avatarin e një bashkësie te paneli i filtrimeve në skajin e majtë të ekranit. Për të parë vetëm dhomat dhe personat e përshoqëruar asaj bashkësie, mund të klikoni në çfarëdo kohe mbi një avatar te panelit të filtrimeve.", "You can't send any messages until you review and agree to our terms and conditions.": "S’mund të dërgoni ndonjë mesazh, përpara se të shqyrtoni dhe pajtoheni me termat dhe kushtet tona.", - "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Mesazhi juaj s’u dërgua, ngaqë ky shërbyes Home ka mbërritur në Kufirin Mujor të Përdoruesve Aktivë. Ju lutemi, që të vazhdoni ta përdorni këtë shërbim, lidhuni me përgjegjësin e shërbimit tuaj.", - "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Mesazhi juaj s’u dërgua, ngaqë ky shërbyes Home ka tejkaluar kufirin e një burimi. Ju lutemi, që të vazhdoni ta përdorni këtë shërbim, lidhuni me përgjegjësin e shërbimit tuaj.", + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Mesazhi juaj s’u dërgua, ngaqë ky shërbyes Home ka mbërritur në Kufirin Mujor të Përdoruesve Aktivë. Ju lutemi, që të vazhdoni ta përdorni këtë shërbim, lidhuni me përgjegjësin e shërbimit tuaj.", + "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Mesazhi juaj s’u dërgua, ngaqë ky shërbyes Home ka tejkaluar kufirin e një burimi. Ju lutemi, që të vazhdoni ta përdorni këtë shërbim, lidhuni me përgjegjësin e shërbimit tuaj.", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "S’ka njeri këtu! Do të donit të ftoni të tjerë apo të reshtet së njoftuari për dhomë të zbrazët?", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "U provua të ngarkohej një pikë e caktuar në kronologjinë e kësaj dhome, por nuk keni leje për ta parë mesazhin në fjalë.", "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Fjalëkalimi juaj u ndryshua me sukses. Nuk do të merrni njoftime push në pajisjet tuaja të tjera, veç në hyfshi sërish në llogarinë tuaj në to", @@ -1286,11 +1286,11 @@ "Unable to load key backup status": "S’arrihet të ngarkohet gjendje kopjeruajtjeje kyçesh", "This device is uploading keys to this backup": "Kjo pajisje po ngarkon kyçe te kjo kopjeruajtje", "This device is not uploading keys to this backup": "Kjo pajisje nuk po ngarkon kyçe te kjo kopjeruajtje", - "Backup has a valid signature from this device": "Kopjeruajtja ka një nënshkrim të vlefshëm prej kësaj pajisjeje", + "Backup has a valid signature from this device": "Kopjeruajtja ka një nënshkrim të vlefshëm prej kësaj pajisjeje", "Backup has a valid signature from verified device x": "Kopjeruajtja ka një nënshkrim të vlefshëm prej pajisjes së verifikuar x", - "Backup has a valid signature from unverified device ": "Kopjeruajtja ka një nënshkrim të vlefshëm prej pajisjes së paverifikuar ", - "Backup has an invalid signature from verified device ": "Kopjeruajtja ka një nënshkrim të pavlefshëm prej pajisjes së verifikuar ", - "Backup has an invalid signature from unverified device ": "Kopjeruajtja ka një nënshkrim të pavlefshëm prej pajisjes së paverifikuar ", + "Backup has a valid signature from unverified device ": "Kopjeruajtja ka një nënshkrim të vlefshëm prej pajisjes së paverifikuar ", + "Backup has an invalid signature from verified device ": "Kopjeruajtja ka një nënshkrim të pavlefshëm prej pajisjes së verifikuar ", + "Backup has an invalid signature from unverified device ": "Kopjeruajtja ka një nënshkrim të pavlefshëm prej pajisjes së paverifikuar ", "Backup is not signed by any of your devices": "Kopjeruajtja s’është nënshkruar nga ndonjë prej pajisjeve tuaja", "Backup version: ": "Version kopjeruajtjeje: ", "Algorithm: ": "Algoritëm: ", @@ -1345,7 +1345,7 @@ "This looks like a valid recovery key!": "Ky duket si kyç i vlefshëm rikthimesh!", "Not a valid recovery key": "Kyç rikthimesh jo i vlefshëm", "Access your secure message history and set up secure messaging by entering your recovery key.": "Hyni te historiku i mesazheve tuaj të siguruar dhe rregulloni shkëmbim mesazhesh të sigurt duke dhënë kyçin tuaj të rikthimeve.", - "If you've forgotten your recovery passphrase you can ": "Nëse keni harruar frazëkalimin tuaj të rikthimeve, mund të rregulloni mundësi të reja rikthimesh", + "If you've forgotten your recovery passphrase you can ": "Nëse keni harruar frazëkalimin tuaj të rikthimeve, mund të ", "Key Backup": "Kopjeruajtje Kyçi", "Sign in with single sign-on": "Bëni hyrjen me hyrje njëshe", "Disable Peer-to-Peer for 1:1 calls": "Çaktivizoje mekanizmin Peer-to-Peer për thirrje 1 me 1", @@ -1427,7 +1427,7 @@ "Waiting for %(userId)s to confirm...": "Po pritet që %(userId)s të bëjë ripohimin…", "Prompt before sending invites to potentially invalid matrix IDs": "Pyet, përpara se të dërgohen ftesa te ID Matrix potencialisht të pavlefshme", "The following users may not exist": "Përdoruesit vijues mund të mos ekzistojnë", - "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "S’arrihet të gjenden profile për ID-të Matrix të treguara më poshtë - do të donit të ftohe, sido qoftë?", + "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "S’arrihet të gjenden profile për ID-të Matrix të treguara më poshtë - do të donit të ftohet, sido qoftë?", "Invite anyway and never warn me again": "Ftoji sido që të jetë dhe mos më sinjalizo më kurrë", "Invite anyway": "Ftoji sido qoftë", "Whether or not you're logged in (we don't record your username)": "Nëse jeni apo jo të futur në llogarinë tuaj (nuk e regjistrojmë emrin tuaj të përdoruesit)", @@ -1465,7 +1465,7 @@ "Email Address": "Adresë Email", "This device is using key backup": "Kjo pajisje është duke përdorur kopjeruajtje kyçesh", "This device is not using key backup": "Kjo pajisje s’është duke përdorur kopjeruajtje kyçesh", - "Backing up %(sessionsRemaining)s keys...": "Po kopjeruhen kyçet për %(sessionsRemaining)s keys…", + "Backing up %(sessionsRemaining)s keys...": "Po kopjeruhen kyçet për %(sessionsRemaining)s…", "All keys backed up": "U kopjeruajtën krejt kyçet", "Backup has a signature from unknown device with ID %(deviceId)s.": "Kopjeruajtja ka nënshkrim nga pajisje e panjohur me ID %(deviceId)s.", "Add an email address to configure email notifications": "Shtoni një adresë email që të formësoni njoftime me email", @@ -1553,7 +1553,7 @@ "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "Mund të përdorni mundësitë mbi shërbyes vetjak, për të bërë hyrjen në shërbyes të tjerë Matrix, duke dhënë URL-në e një tjetër shërbyesi Home. Kjo ju lejon ta përdorni këtë aplikacion në një tjetër shërbyes Home, me një llogari ekzistuese Matrix.", "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Mundeni edhe të caktoni një shërbyes vetjak identitetesh, por s’do të jeni në gjendje të ftoni përdorues përmes adresash email, ose të ftoheni ju vetë përmes adrese email.", "Your Modular server": "Shërbyesi juaj Modular", - "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Jepni vendndodhjen e shërbyesit tuaj (Home) Modular. Mund të përdorë emrin e përkatësisë tuaj ose të jetë një nënpërkatësi e modular.im.", + "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Jepni vendndodhjen e shërbyesit tuaj Home Modular. Mund të përdorë emrin e përkatësisë tuaj ose të jetë një nënpërkatësi e modular.im.", "Server Name": "Emër Shërbyesi", "The username field must not be blank.": "Fusha e emrit të përdoruesit s’duhet të jetë e zbrazët.", "Username": "Emër përdoruesi", @@ -1594,7 +1594,7 @@ "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "Kjo pajisje ka pikasur se frazëkalimi dhe kyçi juaj i rikthimeve për Mesazhe të Sigurt janë hequr.", "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "Nëse këtë e keni bërë pa dashje, mund të ujdisni Mesazhe të Sigurt në këtë pajisje, gjë që do të sjellë rifshehtëzimin e historikut të mesazheve të pajisjes me një metodë të re rikthimesh.", "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.": "Nëse metodën e re të rikthimeve s’e keni hequr ju, dikush mund të jetë duke u rrekur të hyjë në llogarinë tuaj. Ndryshoni menjëherë fjalëkalimin e llogarisë tuaj, te Rregullimet, dhe caktoni një metodë të re rikthimesh.", - "Disinvite this user?": "nga {user}", + "Disinvite this user?": "T’i hiqet ftesa këtij përdoruesi?", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Kartela '%(fileName)s' tejkalon kufirin e këtij shërbyesi Home për madhësinë e ngarkimeve", "Gets or sets the room topic": "Merr ose cakton temën e dhomës", "This room has no topic.": "Kjo dhomë s’ka temë.", @@ -1616,7 +1616,7 @@ "Butterfly": "Flutur", "Flower": "Lule", "Tree": "Pemë", - "Cactus": "kaktus", + "Cactus": "Kaktus", "Mushroom": "Kërpudhë", "Globe": "Rruzull", "Moon": "Hëna", @@ -1633,7 +1633,7 @@ "Robot": "Robot", "Hat": "Kapë", "Glasses": "Syze", - "Spanner": "Ikona në krah të shërbimeve tuaja të lidhura duket si një çelës. Klikimi mbi të ju lejon të formësoni lidhjet tuaja me rrjete dhe shërbime ", + "Spanner": "", "Umbrella": "Ombrellë", "Clock": "Sahat", "Gift": "Dhuratë", @@ -1738,7 +1738,7 @@ "Okay": "Në rregull", "Secure your backup with a passphrase": "Sigurojeni kopjeruajtjen tuaj me një frazëkalim", "Confirm your passphrase": "Ripohoni frazëkalimin tuaj", - "Recovery key": "Kyç Rikthimesh", + "Recovery key": "Kyç rikthimesh", "Success!": "Sukses!", "Allow Peer-to-Peer for 1:1 calls": "Lejo Peer-to-Peer për thirrje tek për tek", "Default theme": "Temë parazgjedhje", @@ -1752,7 +1752,7 @@ "Order rooms in the room list by most important first instead of most recent": "Renditi dhomat te lista e dhomave sipas më të rëndësishmeve së pari, në vend se më të freskëtave", "Scissors": "Gërshërë", "Pin": "Fiksoje", - "Close button should minimize window to tray": "Butoni Mbylle do të duhej ta minimizonte dritaren te shtylla", + "Close button should minimize window to tray": "Butoni Mbylle do të duhej ta minimizonte dhe ulte dritaren te shtylla", "Error updating main address": "Gabim gjatë përditësimit të adresës kryesore", "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Pati një gabim në përditësimin e adresës kryesore të dhomës. Mund të mos lejohet nga shërbyesi ose mund të ketë ndodhur një gabim i përkohshëm.", "Error creating alias": "Gabim në krijim aliasi", @@ -1765,7 +1765,7 @@ "A username can only contain lower case letters, numbers and '=_-./'": "Emri i përdoruesit mund të përmbajë vetëm shkronja të vogla, numra dhe '=_-./'", "Share Permalink": "Permalidhje Ndarjeje Me të Tjerë", "Sign in to your Matrix account": "Bëni hyrjen te llogaria juaj Matrix", - "Sign in to your Matrix account on %(serverName)s": "Hyni në llogarinë tuaj Matrix teserverName)s", + "Sign in to your Matrix account on %(serverName)s": "Hyni në llogarinë tuaj Matrix te %(serverName)s", "Create your Matrix account": "Krijoni llogarinë tuaj matrix", "Create your Matrix account on %(serverName)s": "Krijoni llogarinë tuaj Matrix te %(serverName)s", "Could not load user profile": "S’u ngarkua dot profili i përdoruesit", @@ -1773,7 +1773,7 @@ "Your Matrix account on %(serverName)s": "Llogaria juaj Matrix te %(serverName)s", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Parashtoji ¯\\_(ツ)_/¯ një mesazhi tekst të thjeshtë", "User %(userId)s is already in the room": "Përdoruesi %(userId)s gjendet tashmë në dhomë", - "The user must be unbanned before they can be invited.": "Para se të ftohen, përdoruesve u duhet hequr dëbimi", + "The user must be unbanned before they can be invited.": "Para se të ftohen, përdoruesve u duhet hequr dëbimi.", "Upgrade to your own domain": "Kaloni një shkallë më lart me përkatësinë tuaj vetjake", "Accept all %(invitedRooms)s invites": "Prano krejt ftesat prej %(invitedRooms)s", "Change room avatar": "Ndryshoni avatar dhome", @@ -1790,12 +1790,15 @@ "Kick users": "Përzini përdoruesi", "Ban users": "Dëboni përdorues", "Remove messages": "Hiqni mesazhe", - "Notify everyone": "Njoftoni gjithëkënd", + "Notify everyone": "Njoftoni gjithkënd", "Send %(eventType)s events": "Dërgo akte %(eventType)s", "Select the roles required to change various parts of the room": "Përzgjidhni rolet e domosdoshme për të ndryshuar anë të ndryshme të dhomës", "Enable encryption?": "Të aktivizohet fshehtëzim?", "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.": "Pasi të aktivizohet, fshehtëzimi për një dhomë nuk mund të çaktivizohet. Mesazhet e dërguar në një dhomë të fshehtëzuar s’mund të shihen nga shërbyesi, vetëm nga pjesëmarrësit në dhomë. Aktivizimi i fshehtëzimit mund të pengojë funksionimin si duhet të mjaft robotëve dhe urave. Mësoni më tepër rreth fshehtëzimit.", "Want more than a community? Get your own server": "Doni më shumë se një bashkësi? Merrni një shërbyes tuajin", "You are logged in to another account": "Jeni futur në një tjetër llogari", - "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Faleminderit për verifikimin e email-it tuaj! Llogaria ku keni hyrë këtu (%(sessionUserId)s) duket të jetë tjetër nga llogaria për të cilën verifikuat një (%(verifiedUserId)s). Nëse doni të bëni hyrjen te %(verifiedUserId2)s, së pari, ju lutemi, bëni daljen." + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Faleminderit për verifikimin e email-it tuaj! Llogaria ku keni hyrë këtu (%(sessionUserId)s) duket të jetë tjetër nga llogaria për të cilën verifikuat një (%(verifiedUserId)s). Nëse doni të bëni hyrjen te %(verifiedUserId2)s, së pari, ju lutemi, bëni daljen.", + "Power level": "Shkallë pushteti", + "Please install Chrome, Firefox, or Safari for the best experience.": "Për funksionimin më të mirë, ju lutemi, instaloni Chrome, Firefox, ose Safari.", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Ndryshimi i fjalëkalimit tuaj do të sjellë ricaktim të çfarëdo kyçesh fshehtëzimi skaj-më-skaj në krejt pajisjet tuaja, duke e bërë të palexueshëm historikun e bisedave të fshehtëzuara. Ujdisni një Kopjeruajtje Kyçesh ose eksportoni kyçet e dhomës tuaj prej një tjetër pajisjeje përpara se të ricaktoni fjalëkalimin tuaj." } From 397f2e87e68835bf679efb8117f34de1c1416f89 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Tue, 19 Mar 2019 17:23:48 +0000 Subject: [PATCH 192/481] Translated using Weblate (Basque) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index d360dddc7a..5609356931 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -1749,5 +1749,59 @@ "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "Zerbitzari pertsonalizatuaren aukera erabili dezakezu beste Matrix zerbitzarietan saioa hasteko beste hasiera-zerbitzari batek URLa adieraziz. Honek aplikazio hau beste Matrix zerbitzari batean duzun Matrix kontua erabiltzea baimentzen dizu.", "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.": "Hasiera zerbitzariaren URL-a %(hsUrl)s ez ditudi baliozko URL bat. Sartu baliozko URL bat protokoloaren aurrekaria barne.", "Changes your display nickname in the current room only": "Zure pantailako izena aldatzen du gela honetan bakarrik", - "Your Matrix account on %(serverName)s": "Zure %(serverName)s zerbitzariko Matrix kontua" + "Your Matrix account on %(serverName)s": "Zure %(serverName)s zerbitzariko Matrix kontua", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "¯\\_(ツ)_/¯ jartzen du testu soileko mezu baten aurrean", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s erabiltzaileak ikurra aktibatu du %(groups)s taldeentzat gela honetan.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s erabiltzaileak ikurra desaktibatu du %(groups)s taldeentzat gela honetan.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s erabiltzaileak ikurra aktibatu du %(newGroups)s taldeentzat, eta ikurra desaktibatu du %(oldGroups)s taldeentzat gela honetan.", + "User %(userId)s is already in the room": "%(userId)s erabiltzailea gelan dago jada", + "The user must be unbanned before they can be invited.": "Erabiltzaileari debekua kendu behar zaio gonbidatu aurretik.", + "Show read receipts sent by other users": "Erakutsi beste erabiltzaileek bidalitako irakurragiriak", + "Order rooms in the room list by most important first instead of most recent": "Ordenatu gelak gelen zerrendan garrantzitsuenak hasieran jarriz, eta ez eguneratutako azkenak", + "Scissors": "Artaziak", + "Upgrade to your own domain": "Eguneratu zure domeinu propiora", + "Close button should minimize window to tray": "Itxi botoiak leihoa minimizatu beharko luke", + "Accept all %(invitedRooms)s invites": "Onartu %(invitedRooms)s gelako gonbidapen guztiak", + "Change room avatar": "Aldatu gelaren abatarra", + "Change room name": "Aldatu gelaren izena", + "Change main address for the room": "Aldatu gelaren helbide nagusia", + "Change history visibility": "Aldatu historialaren ikusgaitasuna", + "Change permissions": "Aldatu baimenak", + "Change topic": "Aldatu mintzagaia", + "Modify widgets": "Aldatu trepetak", + "Default role": "Lehenetsitako rola", + "Send messages": "Bidali mezuak", + "Invite users": "Gonbidatu erabiltzaileak", + "Change settings": "Aldatu ezarpenak", + "Kick users": "Kanporatu erabiltzaileak", + "Ban users": "Debekatu erabiltzaileak", + "Remove messages": "Kendu mezuak", + "Notify everyone": "Jakinarazi denei", + "Send %(eventType)s events": "Bidali %(eventType)s gertaerak", + "Select the roles required to change various parts of the room": "Hautatu gelaren hainbat atal aldatzeko behar diren rolak", + "Enable encryption?": "Gaitu zifratzea?", + "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.": "Behin aktibatuta, ezin zaio gelari zifratzea kendu. Zerbitzariak ezin ditu zifratutako gela batetara bidalitako mezuak ikusi, gelako partaideek besterik ezin dituzte ikusi. Zifratzea aktibatzeak bot eta zubi batzuk ongi ez funtzionatzea ekarri dezake. Ikasi gehiago zifratzeari buruz.", + "Error updating main address": "Errorea helbide nagusia eguneratzean", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Errore bat gertatu da gelaren helbide nagusia eguneratzean. Agian zerbitzariak ez du hau baimentzen, edo une bateko hutsegitea izan da.", + "Error creating alias": "Errorea aliasa sortzean", + "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "Errore bat gertatu da alias hori sortzean. Agian zerbitzariak ez du onartzen, edo une bateko hutsegitea izan da.", + "Error removing alias": "Errorea aliasa kentzean", + "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Errore bat gertatu da alias hori kentzean. Agien ez da jada existitzen edo une bateko hutsegitea izan da.", + "Error updating flair": "Errorea ikurra eguneratzean", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Errorea gertatu da gela honen ikurra eguneratzean. Agian zerbitzariak ez du baimentzen, edo une bateko hutsegitea izan da.", + "Power level": "Botere maila", + "Room Settings - %(roomName)s": "Gelaren ezarpenak - %(roomName)s", + "A username can only contain lower case letters, numbers and '=_-./'": "Erabiltzaile-izenak letra xeheak, zenbakiak eta '=_-./' karaktereak izan ditzake besterik ez", + "Share Permalink": "Partekatu esteka iraunkorra", + "Sign in to your Matrix account": "Hasi saioa zure Matrix kontuan", + "Sign in to your Matrix account on %(serverName)s": "Hasi saioa zure %(serverName)s zerbitzariko kontuan", + "Create your Matrix account": "Sortu zure Matrix kontua", + "Create your Matrix account on %(serverName)s": "Sortu zure Matrix kontua %(serverName)s zerbitzarian", + "Please install Chrome, Firefox, or Safari for the best experience.": "Instalatu Chrome, Firefox, edo Safari esperientzia hobe baterako.", + "Want more than a community? Get your own server": "Komunitate bat baino gehiago nahi duzu? Eskuratu zure zerbitzari propioa", + "You are logged in to another account": "Beste kontu batekin hasi duzu saioa", + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Eskerrik asko e-mail helbidea baieztatzeagatik! Hemen saioa hasteko erabili duzun kontua (%(sessionUserId)s) itxuraz ez da baieztatu duzun e-mail helbideari lotuta dagoena (%(verifiedUserId)s). %(verifiedUserId2)s kontuan hasi nahi baduzu saioa, amaitu saio hau.", + "Could not load user profile": "Ezin izan da erabiltzaile-profila kargatu", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Zure pasahitza aldatzeak zure gailu guztietako muturretik-muturrerako zifratzerako gakoak berrezarriko ditu, eta aurretik zifratutako mezuen historiala ezin izango da irakurri. Ezarri gakoen babes-kopia edo esportatu zure geletako gakoak beste gailu batetik pasahitza aldatu aurretik.", + "Your Matrix account": "Zure Matrix kontua" } From 49d815ad5694103e83f8706c3439107aa30e0140 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Mon, 18 Mar 2019 12:56:42 +0000 Subject: [PATCH 193/481] Translated using Weblate (Bulgarian) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 52a120d56c..aec953b40b 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -369,7 +369,7 @@ "Save": "Запази", "(~%(count)s results)|other": "(~%(count)s резултати)", "(~%(count)s results)|one": "(~%(count)s резултат)", - "Join Room": "Присъедини се към стаята", + "Join Room": "Присъединяване към стаята", "Upload avatar": "Качи профилна снимка", "Remove avatar": "Премахни профилната снимка", "Settings": "Настройки", @@ -1791,5 +1791,35 @@ "Create your Matrix account on %(serverName)s": "Създаване на Matrix акаунт в %(serverName)s", "Could not load user profile": "Неуспешно зареждане на потребителския профил", "Your Matrix account": "Вашият Matrix акаунт", - "Your Matrix account on %(serverName)s": "Вашият Matrix акаунт в %(serverName)s" + "Your Matrix account on %(serverName)s": "Вашият Matrix акаунт в %(serverName)s", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Добавя ¯\\_(ツ)_/¯ в началото на съобщението", + "User %(userId)s is already in the room": "Потребител %(userId)s вече е в стаята", + "The user must be unbanned before they can be invited.": "Трябва да се махне блокирането на потребителя преди да може да бъде поканен пак.", + "Upgrade to your own domain": "Подобрете се със собствен домейн", + "Accept all %(invitedRooms)s invites": "Приеми всички %(invitedRooms)s покани", + "Change room avatar": "Промяна на снимката на стаята", + "Change room name": "Промяна на името на стаята", + "Change main address for the room": "Промяна на основния адрес на стаята", + "Change history visibility": "Промяна на видимостта на историята", + "Change permissions": "Промяна на привилегиите", + "Change topic": "Промяна на темата", + "Modify widgets": "Промяна на приспособленията", + "Default role": "Роля по подразбиране", + "Send messages": "Изпращане на съобщения", + "Invite users": "Канене на потребители", + "Change settings": "Промяна на настройките", + "Kick users": "Изгонване на потребители", + "Ban users": "Блокиране на потребители", + "Remove messages": "Премахване на съобщения", + "Notify everyone": "Уведомяване на всички", + "Send %(eventType)s events": "Изпрати %(eventType)s събития", + "Select the roles required to change various parts of the room": "Изберете ролите необходими за промяна на различни части от стаята", + "Enable encryption?": "Включване на шифроване?", + "Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. Learn more about encryption.": "Веднъж включено, шифроването за стаята не може да бъде изключено. Съобщенията изпратени в шифрована стая не могат да бъдат прочетени от сървърът, а само от участниците в стаята. Включването на шифроване може да попречи на много ботове или мостове към други мрежи да работят правилно. Научете повече за шифроването.", + "Power level": "Ниво на достъп", + "Please install Chrome, Firefox, or Safari for the best experience.": "Инсталирайте Chrome, Firefox или Safari за най-добра работа.", + "Want more than a community? Get your own server": "Искате повече от общност? Сдобийте се със собствен сървър", + "You are logged in to another account": "Влезли сте в друг акаунт", + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Благодарим, че потвърждавате имейла си! Акаунтът, с които сте влезли тук (%(sessionUserId)s) изглежда е различен от акаунтът за който потвърждавате имейл адреса (%(verifiedUserId)s). Ако искате да влезете в акаунт %(verifiedUserId2)s, моля първо излезте.", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Промяната на паролата Ви, ще анулира всички ключове за шифроване от-край-до-край по всички Ваши устройства, правейки историята на чата нечетима. Настройте резервно копие на ключовете или експортирайте ключовете от друго устройство преди да промените паролата си." } From 0e3bfc3693899695aa7c81bcc5ebcfbee01157f5 Mon Sep 17 00:00:00 2001 From: pogback Date: Wed, 20 Mar 2019 01:15:38 +0000 Subject: [PATCH 194/481] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hans/ --- src/i18n/strings/zh_Hans.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json index 1060f8f32b..5cd7a70d84 100644 --- a/src/i18n/strings/zh_Hans.json +++ b/src/i18n/strings/zh_Hans.json @@ -1750,5 +1750,7 @@ "Power level": "权限级别", "Want more than a community? Get your own server": "想要的不只是社区? 架设您自己的服务器", "You are logged in to another account": "您已以另一个账号登入", - "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "感谢您验证电子邮件地址!您在此登入的账号(%(sessionUserId)s)似乎不同于您验证的电子邮件地址(%(verifiedUserId)s)。如果您想要登入的账号是 %(verifiedUserId2)s ,请先登出。" + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "感谢您验证电子邮件地址!您在此登入的账号(%(sessionUserId)s)似乎不同于您验证的电子邮件地址(%(verifiedUserId)s)。如果您想要登入的账号是 %(verifiedUserId2)s ,请先登出。", + "Please install Chrome, Firefox, or Safari for the best experience.": "请安装 ChromeFirefox,或 Safari 以获得最佳体验。", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "更改您的密码将会重置您所有设备上的端对端加密密钥,让已加密的聊天历史记录无法读取。在重设密码之前,请设置密钥备份或从其他设备导出您的聊天室密钥。" } From 98d3ffaebbf2bd86662c85e7599c6d545e427506 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Mon, 18 Mar 2019 12:41:54 +0000 Subject: [PATCH 195/481] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index b4599bcfae..b6509fc879 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -1826,5 +1826,7 @@ "Power level": "權力等級", "Want more than a community? Get your own server": "想要的不只是社群?架設您自己的伺服器", "You are logged in to another account": "您已登入到另一個帳號", - "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "感謝驗證您的電子郵件!您在此登入的帳號 (%(sessionUserId)s) 似乎與您驗證電子郵件的 (%(verifiedUserId)s) 不同。如果您想要登入 %(verifiedUserId2)s,請先登出。" + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "感謝驗證您的電子郵件!您在此登入的帳號 (%(sessionUserId)s) 似乎與您驗證電子郵件的 (%(verifiedUserId)s) 不同。如果您想要登入 %(verifiedUserId2)s,請先登出。", + "Please install Chrome, Firefox, or Safari for the best experience.": "請安裝 ChromeFirefoxSafari 以獲得最佳體驗。", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "變更您的密碼將會重設在您所有裝置上的端到端加密金鑰,讓已加密的聊天歷史紀錄無法讀取。在重設您的密碼前,請設定金鑰備份或從其他裝置匯出您的聊天室金鑰。" } From 10b19cbb9d43bf09d8317bc0da8c9e451cbfa65e Mon Sep 17 00:00:00 2001 From: Nathan Follens Date: Fri, 29 Mar 2019 10:44:33 +0000 Subject: [PATCH 196/481] Translated using Weblate (Dutch) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 4a00995b02..52b47ac762 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -176,7 +176,7 @@ "Current password": "Huidig wachtwoord", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de kamernaam verwijderd.", "Create a new chat or reuse an existing one": "Begin een nieuw gesprek of herbruik er een bestaand", - "Create Room": "Maak een Kanaal aan", + "Create Room": "Kamer aanmaken", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen opdracht", "Deactivate Account": "Account deactiveren", @@ -221,7 +221,7 @@ "Encryption is enabled in this room": "Versleuteling is ingeschakeld in deze ruimte", "Encryption is not enabled in this room": "Versleuteling is niet ingeschakeld in deze ruimte", "%(senderName)s ended the call.": "%(senderName)s heeft opgehangen.", - "End-to-end encryption information": "Informatie over eind-tot-eind-versleuteling", + "End-to-end encryption information": "Info over eind-tot-eind-versleuteling", "End-to-end encryption is in beta and may not be reliable": "End-to-endbeveiliging is nog in bèta en kan onbetrouwbaar zijn", "Enter Code": "Voer code in", "Enter passphrase": "Voer wachtwoord in", @@ -354,7 +354,7 @@ "Searches DuckDuckGo for results": "Zoekt op DuckDuckGo voor resultaten", "Seen by %(userName)s at %(dateTime)s": "Gezien door %(userName)s op %(dateTime)s", "Send anyway": "Alsnog versturen", - "Sender device information": "Informatie over apparaat van afzender", + "Sender device information": "Info over apparaat van afzender", "Send Reset Email": "E-mail voor opnieuw instellen versturen", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s heeft een afbeelding gestuurd.", "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s heeft %(targetDisplayName)s in de kamer uitgenodigd.", From 09034641de619ecbe853f13208f0ec4973439415 Mon Sep 17 00:00:00 2001 From: Carmen Bianca Bakker Date: Fri, 29 Mar 2019 12:29:38 +0000 Subject: [PATCH 197/481] Translated using Weblate (Esperanto) Currently translated at 78.5% (1225 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/eo/ --- src/i18n/strings/eo.json | 446 +++++++++++++++++++++++++++++---------- 1 file changed, 331 insertions(+), 115 deletions(-) diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index b912f233aa..bc19f3ba06 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -1,10 +1,10 @@ { "This email address is already in use": "Tiu ĉi retpoŝtadreso jam estas uzata", - "This phone number is already in use": "Tiu ĉi telefona numero jam estas uzata", - "Failed to verify email address: make sure you clicked the link in the email": "Kontrolo de via retpoŝtadreso malsukcesis; certigu, ke vi alklakis la ligilon en la retletero", - "Call Timeout": "Voka Tempolimo", - "The remote side failed to pick up": "Kunvokonto malsukcesis respondi", - "Unable to capture screen": "Ekrano ne registreblas", + "This phone number is already in use": "Tiu ĉi telefonnumero jam estas uzata", + "Failed to verify email address: make sure you clicked the link in the email": "Kontrolo de via retpoŝtadreso malsukcesis: certigu, ke vi alklakis la ligilon en la retmesaĝo", + "Call Timeout": "Voka tempolimo", + "The remote side failed to pick up": "La defora flanko malsukcesis respondi", + "Unable to capture screen": "Ne eblas registri ekranon", "You cannot place a call with yourself.": "Vi ne povas voki vin mem.", "Warning!": "Averto!", "Sign in with CAS": "Saluti per CAS", @@ -31,11 +31,11 @@ "Oct": "Okt", "Nov": "Nov", "Dec": "Dec", - "PM": "ptm", - "AM": "atm", + "PM": "PTM", + "AM": "ATM", "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(fullYear)s %(monthName)s %(day)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s %(time)s", "Who would you like to add to this community?": "Kiun vi volas aldoni al tiu ĉi komunumo?", "Invite new community members": "Invitu novajn komunumanojn", "Name or matrix ID": "Nomo aŭ Matrix-identigilo", @@ -49,13 +49,13 @@ "Conference calling is in development and may not be reliable.": "Grupaj vokoj ankoraŭ evoluas kaj povas malbone funkcii.", "Failed to set up conference call": "Komenco de grupa voko malsukcesis", "Conference call failed.": "Grupa voko malsukcesis.", - "The file '%(fileName)s' failed to upload": "Elŝuto de la dosiero «%(fileName)s» malsukcesis", + "The file '%(fileName)s' failed to upload": "Alŝuto de la dosiero '%(fileName)s' malsukcesis", "The file '%(fileName)s' exceeds this home server's size limit for uploads": "La dosiero «%(fileName)s» estas tro granda por la hejma servilo", "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Averto: ajna persono aldonita al komunumo estos publike videbla al iu ajn, kiu konas la identigilon de tiu komunumo", "Which rooms would you like to add to this community?": "Kiujn ĉambrojn vi volas aldoni al ĉi tiu komunumo?", - "Show these rooms to non-members on the community page and room list?": "Montri tiujn babilejojn al malanoj en la komunuma paĝo kaj listo de babilejoj?", + "Show these rooms to non-members on the community page and room list?": "Montri tiujn ĉambrojn al malanoj en la komunuma paĝo kaj ĉambrolisto?", "Add rooms to the community": "Aldoni ĉambrojn al la komunumo", - "Room name or alias": "Nomo aŭ kromnomo de babilejo", + "Room name or alias": "Nomo aŭ kromnomo de ĉambro", "Add to community": "Aldoni al komunumo", "Failed to invite the following users to %(groupId)s:": "Malsukcesis inviti jenajn uzantojn al %(groupId)s:", "Failed to invite users to community": "Malsukcesis inviti novajn uzantojn al komunumo", @@ -65,37 +65,37 @@ "Riot was not given permission to send notifications - please try again": "Riot ne ricevis permeson sendi sciigojn – bonvolu reprovi", "Unable to enable Notifications": "Sciigoj ne sendeblas", "This email address was not found": "Tiu ĉi retpoŝtadreso ne troviĝis", - "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Via retpoŝtareso ŝajne ne ligiĝas al Matrix-identigaĵo sur tiu ĉi hejmservilo.", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Via retpoŝtareso ŝajne ne ligiĝas al Matrix-identigilo sur tiu ĉi hejmservilo.", "Default": "Norma", "Restricted": "Limigita", "Moderator": "Ĉambrestro", "Admin": "Administranto", "Start a chat": "Komenci babilon", "Who would you like to communicate with?": "Kun kiu vi volas komuniki?", - "Email, name or matrix ID": "Retpoŝtadreso, nomo, aŭ Matrix-identigaĵo", + "Email, name or matrix ID": "Retpoŝtadreso, nomo, aŭ Matrix-identigilo", "Start Chat": "Komenci babilon", - "Invite new room members": "Inviti novajn babilejanojn", - "Who would you like to add to this room?": "Kiun vi ŝatus aldoni al tiu ĉi babilejo?", + "Invite new room members": "Inviti novajn ĉambranojn", + "Who would you like to add to this room?": "Kiun vi ŝatus aldoni al tiu ĉi ĉambro?", "Send Invites": "Sendi invitojn", "Failed to invite user": "Malsukcesis inviti uzanton", "Operation failed": "Ago malsukcesis", "Failed to invite": "Invito malsukcesis", - "Failed to invite the following users to the %(roomName)s room:": "Malsukcesis inviti la jenajn uzantojn al la babilejo %(roomName)s:", + "Failed to invite the following users to the %(roomName)s room:": "Malsukcesis inviti la jenajn uzantojn al la ĉambro %(roomName)s:", "You need to be logged in.": "Vi devas saluti.", "You need to be able to invite users to do that.": "Vi bezonas permeson inviti uzantojn por tio.", "Unable to create widget.": "Fenestraĵo ne kreeblas.", "Failed to send request.": "Malsukcesis sendi peton.", - "This room is not recognised.": "Ĉi tiu babilejo ne estas rekonita.", + "This room is not recognised.": "Ĉi tiu ĉambro ne estas rekonita.", "Power level must be positive integer.": "Nivelo de potenco devas esti entjero pozitiva.", - "You are not in this room.": "Vi ne estas en tiu ĉi babilejo.", - "You do not have permission to do that in this room.": "Vi ne havas permeson fari tion en tiu babilejo.", - "Missing room_id in request": "En peto mankas «room_id»", - "Room %(roomId)s not visible": "babilejo %(roomId)s ne videblas", - "Missing user_id in request": "En peto mankas «user_id»", + "You are not in this room.": "Vi ne estas en tiu ĉi ĉambro.", + "You do not have permission to do that in this room.": "Vi ne havas permeson fari tion en tiu ĉambro.", + "Missing room_id in request": "En peto mankas room_id", + "Room %(roomId)s not visible": "Ĉambro %(roomId)s ne videblas", + "Missing user_id in request": "En peto mankas user_id", "Usage": "Uzo", "/ddg is not a command": "/ddg ne estas komando", "To use it, just wait for autocomplete results to load and tab through them.": "Por uzi ĝin, atendu aperon de sugestaj rezultoj, kaj tabu tra ili.", - "Unrecognised room alias:": "Nerekonita babileja kromnomo:", + "Unrecognised room alias:": "Nerekonita ĉambra kromnomo:", "Ignored user": "Malatentata uzanto", "You are now ignoring %(userId)s": "Vi nun malatentas uzanton %(userId)s", "Unignored user": "Reatentata uzanto", @@ -103,7 +103,7 @@ "Unknown (user, device) pair:": "Nekonata duopo (uzanto, aparato):", "Device already verified!": "Aparato jam kontroliĝis!", "WARNING: Device already verified, but keys do NOT MATCH!": "AVERTO: Aparato jam kontroliĝis, sed la ŝlosiloj NE KONGRUAS!", - "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "AVERTO: KONTROLO DE ŜLOSILO MALSUKCESIS! Subskriba ŝlosilo por %(userId)s kaj aparato%(deviceId)s estas «%(fprint)s», kiu ne kongruas kun la donita ŝlosilo «%(fingerprint)s». Eble do via komuniko estas subaŭskultata!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "AVERTO: KONTROLO DE ŜLOSILO MALSUKCESIS! Subskriba ŝlosilo por %(userId)s kaj aparato%(deviceId)s estas \"%(fprint)s\", kiu ne kongruas kun la donita ŝlosilo \"%(fingerprint)s\". Eble do via komuniko estas subaŭskultata!", "Verified key": "Kontrolita ŝlosilo", "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "La donita subskriba ŝlosilo kongruas kun la ŝlosilo ricevita de %(userId)s por ĝia aparato %(deviceId)s. Aparato markita kiel kontrolita.", "Unrecognised command:": "Nerekonita komando:", @@ -119,16 +119,16 @@ "%(senderName)s changed their profile picture.": "%(senderName)s ŝanĝis sian profilbildon.", "%(senderName)s set a profile picture.": "%(senderName)s agordis profilbildon.", "VoIP conference started.": "Rettelefona voko komenciĝis.", - "%(targetName)s joined the room.": "%(targetName)s venis en la babilejo.", + "%(targetName)s joined the room.": "%(targetName)s venis en la ĉambro.", "VoIP conference finished.": "Rettelefona voko finiĝis.", "%(targetName)s rejected the invitation.": "%(targetName)s rifuzis la inviton.", - "%(targetName)s left the room.": "%(targetName)s forlasis la babilejo.", + "%(targetName)s left the room.": "%(targetName)s forlasis la ĉambro.", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s malbaris uzanton %(targetName)s.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s forpelis uzanton %(targetName)s.", "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s nuligis inviton por %(targetName)s.", - "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s ŝanĝis la temon al «%(topic)s».", - "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s forigis nomon de la babilejo.", - "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s ŝanĝis nomon de la babilejo al %(roomName)s.", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s ŝanĝis la temon al \"%(topic)s\".", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s forigis nomon de la ĉambro.", + "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s ŝanĝis nomon de la ĉambro al %(roomName)s.", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s sendis bildon.", "Someone": "Iu", "(not supported by this browser)": "(nesubtenata de tiu ĉi foliumilo)", @@ -138,16 +138,16 @@ "(unknown failure: %(reason)s)": "(nekonata eraro: %(reason)s)", "%(senderName)s ended the call.": "%(senderName)s finis la vokon.", "%(senderName)s placed a %(callType)s call.": "%(senderName)s faris vokon de speco: %(callType)s.", - "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s sendis babilejan inviton al %(targetDisplayName)s.", - "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s videbligis estontan historion de la babilejo al ĉiuj babilejanoj, ekde la tempo de invito.", - "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s videbligis estontan historion de la babilejo al ĉiuj babilejanoj, ekde la tempo de aliĝo.", - "%(senderName)s made future room history visible to all room members.": "%(senderName)s videbligis estontan historion de la babilejo al ĉiuj babilejanoj.", - "%(senderName)s made future room history visible to anyone.": "%(senderName)s videbligis estontan historion de la babilejo al ĉiuj.", - "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s videbligis estontan historion de la babilejo al nekonata (%(visibility)s).", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s sendis ĉambran inviton al %(targetDisplayName)s.", + "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s videbligis estontan historion de la ĉambro al ĉiuj ĉambranoj, ekde la tempo de invito.", + "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s videbligis estontan historion de la ĉambro al ĉiuj ĉambranoj, ekde la tempo de aliĝo.", + "%(senderName)s made future room history visible to all room members.": "%(senderName)s videbligis estontan historion de la ĉambro al ĉiuj ĉambranoj.", + "%(senderName)s made future room history visible to anyone.": "%(senderName)s videbligis estontan historion de la ĉambro al ĉiuj.", + "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s videbligis estontan historion de la ĉambro al nekonata (%(visibility)s).", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s ŝaltis ĝiscelan ĉifradon (algoritmo: %(algorithm)s).", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s de %(fromPowerLevel)s al %(toPowerLevel)s", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ŝanĝis la potencan nivelon de %(powerLevelDiffText)s.", - "%(senderName)s changed the pinned messages for the room.": "%(senderName)s ŝanĝis la fiksitajn mesaĝojn de la babilejo.", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s ŝanĝis la fiksitajn mesaĝojn de la ĉambro.", "%(widgetName)s widget modified by %(senderName)s": "Fenestraĵon %(widgetName)s ŝanĝis %(senderName)s", "%(widgetName)s widget added by %(senderName)s": "Fenestraĵon %(widgetName)s aldonis %(senderName)s", "%(widgetName)s widget removed by %(senderName)s": "Fenestraĵon %(widgetName)s forigis %(senderName)s", @@ -155,13 +155,13 @@ "%(names)s and %(count)s others are typing|other": "%(names)s kaj %(count)s aliaj tajpas", "%(names)s and %(count)s others are typing|one": "%(names)s kaj unu alia tajpas", "%(names)s and %(lastPerson)s are typing": "%(names)s kaj %(lastPerson)s tajpas", - "Failure to create room": "Malsukcesis krei babilejon", + "Failure to create room": "Malsukcesis krei ĉambron", "Server may be unavailable, overloaded, or you hit a bug.": "Servilo povas esti neatingebla, troŝarĝita, aŭ vi renkontis cimon.", - "Unnamed Room": "Sennoma Babilejo", + "Unnamed Room": "Sennoma Ĉambro", "Your browser does not support the required cryptography extensions": "Via foliumilo ne subtenas la bezonatajn ĉifrajn kromprogramojn", "Not a valid Riot keyfile": "Nevalida ŝlosila dosiero de Riot", "Authentication check failed: incorrect password?": "Aŭtentiga kontrolo malsukcesis: ĉu pro malĝusta pasvorto?", - "Failed to join room": "Malsukcesis aliĝi al babilejo", + "Failed to join room": "Malsukcesis aliĝi al ĉambro", "Message Pinning": "Fikso de mesaĝoj", "Disable Emoji suggestions while typing": "Malŝalti mienetajn sugestojn dum tajpado", "Use compact timeline layout": "Uzi densan okazordan aranĝon", @@ -174,7 +174,7 @@ "Always show message timestamps": "Ĉiam montri mesaĝajn tempindikojn", "Autoplay GIFs and videos": "Aŭtomate ludi GIF-bildojn kaj videojn", "Call Failed": "Voko malsukcesis", - "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "En la babilejo estas nekonataj aparatoj: se vi daŭrigos ne kontrolante ilin, iu povos subaŭskulti vian vokon.", + "There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "En la ĉambro estas nekonataj aparatoj: se vi daŭrigos ne kontrolante ilin, iu povos subaŭskulti vian vokon.", "Review Devices": "Kontroli aparatojn", "Call Anyway": "Tamen voki", "Answer Anyway": "Tamen respondi", @@ -190,11 +190,11 @@ "Mirror local video feed": "Speguli lokan videon", "Disable Peer-to-Peer for 1:1 calls": "Malŝalti samtavolajn duopajn vokojn", "Never send encrypted messages to unverified devices from this device": "Neniam sendi neĉifritajn mesaĝojn al nekontrolitaj aparatoj de tiu ĉi aparato", - "Never send encrypted messages to unverified devices in this room from this device": "Neniam sendi ĉifritajn mesaĝojn al nekontrolitaj aparatoj en tiu ĉi babilejo el tiu ĉi aparato", + "Never send encrypted messages to unverified devices in this room from this device": "Neniam sendi ĉifritajn mesaĝojn al nekontrolitaj aparatoj en tiu ĉi ĉambro el tiu ĉi aparato", "Enable inline URL previews by default": "Ŝalti entekstan antaŭrigardon al retadresoj", - "Enable URL previews for this room (only affects you)": "Ŝalti URL-antaŭrigardon en ĉi tiu babilejo (nur por vi)", - "Enable URL previews by default for participants in this room": "Ŝalti URL-antaŭrigardon por anoj de ĉi tiu babilejo", - "Room Colour": "Babilejo-koloro", + "Enable URL previews for this room (only affects you)": "Ŝalti URL-antaŭrigardon en ĉi tiu ĉambro (nur por vi)", + "Enable URL previews by default for participants in this room": "Ŝalti URL-antaŭrigardon por anoj de ĉi tiu ĉambro", + "Room Colour": "Koloro de ĉambro", "Active call (%(roomName)s)": "Aktiva voko (%(roomName)s)", "unknown caller": "nekonata vokanto", "Incoming voice call from %(name)s": "Envena voĉvoko de %(name)s", @@ -216,7 +216,7 @@ "New passwords don't match": "Novaj pasvortoj ne kongruas", "Passwords can't be empty": "Pasvortoj ne povas esti malplenaj", "Continue": "Daŭrigi", - "Export E2E room keys": "Elporti ĝiscele ĉifrajn ŝlosilojn de la babilejo", + "Export E2E room keys": "Elporti ĝiscele ĉifrajn ŝlosilojn de la ĉambro", "Do you want to set an email address?": "Ĉu vi volas agordi retpoŝtadreson?", "Current password": "Nuna pasvorto", "Password": "Pasvorto", @@ -228,7 +228,7 @@ "Authentication": "Aŭtentigo", "Delete %(count)s devices|other": "Forigi %(count)s aparatojn", "Delete %(count)s devices|one": "Forigi aparaton", - "Device ID": "Aparata identigaĵo", + "Device ID": "Aparata identigilo", "Device Name": "Aparata nomo", "Last seen": "Laste vidita", "Select devices": "Elekti aparatojn", @@ -236,13 +236,13 @@ "Disable Notifications": "Malŝalti sciigojn", "Enable Notifications": "Ŝalti sciigojn", "Cannot add any more widgets": "Pluaj fenestraĵoj ne aldoneblas", - "The maximum permitted number of widgets have already been added to this room.": "La maksimuma permesata nombro de fenestraĵoj jam aldoniĝis al tiu babilejo.", + "The maximum permitted number of widgets have already been added to this room.": "La maksimuma permesata nombro de fenestraĵoj jam aldoniĝis al tiu ĉambro.", "Add a widget": "Aldoni fenestraĵon", "Drop File Here": "Demetu dosieron tien ĉi", "Drop file here to upload": "Demetu dosieron tien ĉi por ĝin alŝuti", " (unsupported)": " (nesubtenata)", "Join as voice or video.": "Aliĝu al voko kun voĉovideo.", - "Ongoing conference call%(supportedText)s.": "Nuntempa voko%(supportedText)s.", + "Ongoing conference call%(supportedText)s.": "Nuntempa grupvoko%(supportedText)s.", "%(senderName)s sent an image": "%(senderName)s sendis bildon", "%(senderName)s sent a video": "%(senderName)s sendis videon", "%(senderName)s uploaded a file": "%(senderName)s alŝutis dosieron", @@ -251,11 +251,11 @@ "Encrypted by a verified device": "Ĉifrita de kontrolita aparato", "Encrypted by an unverified device": "Ĉifrita de nekontrolita aparato", "Unencrypted message": "Neĉifrita mesaĝo", - "Please select the destination room for this message": "Bonvolu elekti celan babilejon por tiu mesaĝo", + "Please select the destination room for this message": "Bonvolu elekti celan ĉambron por tiu mesaĝo", "Blacklisted": "Senpova legi ĉifritajn mesaĝojn", "Verified": "Kontrolita", "Unverified": "Nekontrolita", - "device id: ": "aparata identigaĵo: ", + "device id: ": "aparata identigilo: ", "Disinvite": "Malinviti", "Kick": "Forpeli", "Disinvite this user?": "Ĉu malinviti ĉi tiun uzanton?", @@ -275,7 +275,7 @@ "Devices": "Aparatoj", "Unignore": "Reatenti", "Ignore": "Malatenti", - "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Ŝanĝo de pasvorto nuntempe nuligos ĉiujn ĝiscele ĉifrajn ŝlosilojn sur ĉiuj viaj aparatoj. Tio igos ĉifritajn babilajn historiojn nelegeblaj, krom se vi unue elportos viajn babilejajn ŝlosilojn kaj reenportos ilin poste. Estonte tio pliboniĝos.", + "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Ŝanĝo de pasvorto nuntempe nuligos ĉiujn ĝiscele ĉifrajn ŝlosilojn sur ĉiuj viaj aparatoj. Tio igos ĉifritajn babilajn historiojn nelegeblaj, krom se vi unue elportos viajn ĉambrajn ŝlosilojn kaj reenportos ilin poste. Estonte tio pliboniĝos.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s ŝanĝis la profilbildon de %(roomName)s", "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Vi estas direktota al ekstera retejo por aŭtentigi vian konton por uzo kun %(integrationsUrl)s. Ĉu vi volas daŭrigi tion?", "Jump to read receipt": "Salti al legokonfirmo", @@ -292,9 +292,9 @@ "and %(count)s others...|other": "kaj %(count)s aliaj…", "and %(count)s others...|one": "kaj unu alia…", "Invited": "Invititaj", - "Filter room members": "Filtri babilejanojn", + "Filter room members": "Filtri ĉambranojn", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (potenco je %(powerLevelNumber)s)", - "Attachment": "Kunsendaĵo", + "Attachment": "Aldonaĵo", "Upload Files": "Alŝuti dosierojn", "Are you sure you want to upload the following files?": "Ĉu vi certe volas alŝuti la jenajn dosierojn?", "Encrypted room": "Ĉifrita babilejo", @@ -304,7 +304,7 @@ "Video call": "Vidvoko", "Upload file": "Alŝuti dosieron", "Show Text Formatting Toolbar": "Montri tekstaranĝan breton", - "You do not have permission to post to this room": "Mankas al vi permeso afiŝi en tiu babilejo", + "You do not have permission to post to this room": "Mankas al vi permeso afiŝi en tiu ĉambro", "Turn Markdown on": "Ŝalti Marksubon", "Turn Markdown off": "Malŝalti Marksubon", "Hide Text Formatting Toolbar": "Kaŝi tekstaranĝan breton", @@ -339,7 +339,7 @@ "Offline": "Eksterreta", "Unknown": "Nekonata", "Seen by %(userName)s at %(dateTime)s": "Vidita de %(userName)s je %(dateTime)s", - "Unnamed room": "Sennoma babilejo", + "Unnamed room": "Sennoma ĉambro", "World readable": "Legebla de ĉiuj", "Guests can join": "Gastoj povas aliĝi", "No rooms to show": "Neniuj ĉambroj montreblas", @@ -347,11 +347,11 @@ "Save": "Konservi", "(~%(count)s results)|other": "(~%(count)s rezultoj)", "(~%(count)s results)|one": "(~%(count)s rezulto)", - "Join Room": "Aliĝi al Babilejo", + "Join Room": "Aliĝi al ĉambro", "Upload avatar": "Alŝuti profilbildon", "Remove avatar": "Forigi profilbildon", "Settings": "Agordoj", - "Forget room": "Forgesi babilejon", + "Forget room": "Forgesi ĉambron", "Search": "Serĉi", "Show panel": "Montri panelon", "Drop here to favourite": "Demetu tien ĉi por ŝati", @@ -371,19 +371,19 @@ "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Ne certigeblas, ke la adreso, kien ĉi tiu invito sendiĝis, kongruas kun tiu rilata al via konto.", "This invitation was sent to an email address which is not associated with this account:": "Ĉi tiu invito sendiĝis al retpoŝtadreso, kiu ne rilatas al ĉi tiu konto:", "You may wish to login with a different account, or add this email to this account.": "Vi povas saluti per alia konto, aŭ aldoni ĉi tiun retpoŝtadreson al tiu ĉi konto.", - "You have been invited to join this room by %(inviterName)s": "%(inviterName)s vin invitis al ĉi tiu babilejo", + "You have been invited to join this room by %(inviterName)s": "%(inviterName)s vin invitis al ĉi tiu ĉambro", "Would you like to accept or decline this invitation?": "Ĉu vi volas akceptirifuzi ĉi tiun inviton?", "Reason: %(reasonText)s": "Kialo: %(reasonText)s", "Rejoin": "Realiĝi", "You have been kicked from %(roomName)s by %(userName)s.": "%(userName)s vin forpelis de %(roomName)s.", - "You have been kicked from this room by %(userName)s.": "%(userName)s vin forpelis de tiu babilejo.", + "You have been kicked from this room by %(userName)s.": "%(userName)s vin forpelis de tiu ĉambro.", "You have been banned from %(roomName)s by %(userName)s.": "%(userName)s vi forbaris de %(roomName)s.", - "You have been banned from this room by %(userName)s.": "%(userName)s vin forbaris de tiu babilejo.", - "This room": "Ĉi tiu babilejo", + "You have been banned from this room by %(userName)s.": "%(userName)s vin forbaris de tiu ĉambro.", + "This room": "Ĉi tiu ĉambro", "%(roomName)s does not exist.": "%(roomName)s ne ekzistas.", "%(roomName)s is not accessible at this time.": "%(roomName)s ne estas atingebla nun.", "You are trying to access %(roomName)s.": "Vi provas atingi %(roomName)s.", - "You are trying to access a room.": "Vi provas aliri babilejon.", + "You are trying to access a room.": "Vi provas aliri ĉambron.", "Click here to join the discussion!": "Klaku ĉi tie por aliĝi al la diskuto!", "This is a preview of this room. Room interactions have been disabled": "Tio ĉi estas antaŭrigardo al la ĉambro. Ĉambraj interagoj estas malŝaltitaj", "To change the room's avatar, you must be a": "Por ŝanĝi la ĉambran profilbildon, vi devas esti", @@ -413,7 +413,7 @@ "No users have specific privileges in this room": "Neniuj uzantoj havas specialajn privilegiojn en tiu ĉi ĉambro", "Banned users": "Forbaritaj uzantoj", "This room is not accessible by remote Matrix servers": "Ĉi tiu ĉambro ne atingeblas por foraj serviloj de Matrix", - "Leave room": "Eliri babilejon", + "Leave room": "Eliri ĉambron", "Favourite": "Ŝatata", "Tagged as: ": "Etikedita kiel: ", "To link to a room it must have an address.": "Por esti ligebla, ĉambro devas havi adreson.", @@ -438,7 +438,7 @@ "To ban users, you must be a": "Por forbari uzantojn, vi devas esti", "To remove other users' messages, you must be a": "Por forigi mesaĝojn de aliaj uzantoj, vi devas esti", "To send events of type , you must be a": "Por sendi okazojn de tipo , vi devas esti", - "Advanced": "Specialaj", + "Advanced": "Altnivela", "This room's internal ID is": "Interna identigaĵo de tiu ĉi ĉambro estas", "Add a topic": "Aldoni temon", "Cancel": "Nuligi", @@ -446,7 +446,7 @@ "Jump to first unread message.": "Salti al unua nelegita mesaĝo.", "Close": "Fermi", "Invalid alias format": "Malvalida formo de kromnomo", - "'%(alias)s' is not a valid format for an alias": "‹%(alias)s› ne estas valida formo de kromnomo", + "'%(alias)s' is not a valid format for an alias": "'%(alias)s' ne estas valida formo de kromnomo", "Invalid address format": "Malvalida formo de adreso", "'%(alias)s' is not a valid format for an address": "‹%(alias)s› ne estas valida formo de adreso", "not specified": "nespecifita", @@ -454,19 +454,19 @@ "Remote addresses for this room:": "Foraj adresoj de ĉi tiu ĉambro:", "Addresses": "Adresoj", "The main address for this room is": "La ĉefadreso por ĉi tiu babilejo estas", - "Local addresses for this room:": "Lokaj adresoj por ĉi tiu babilejo:", - "This room has no local addresses": "Ĉi tiu babilejo ne havas lokajn adresojn", + "Local addresses for this room:": "Lokaj adresoj por ĉi tiu ĉambro:", + "This room has no local addresses": "Ĉi tiu ĉambro ne havas lokajn adresojn", "New address (e.g. #foo:%(localDomain)s)": "Nova adreso (ekz-e #io:%(localDomain)s)", - "Invalid community ID": "Malvalida komunuma identigaĵo", - "'%(groupId)s' is not a valid community ID": "‹%(groupId)s› ne estas valida komunuma identigaĵo", - "New community ID (e.g. +foo:%(localDomain)s)": "Nova komunuma identigaĵo (ekz-e +io:%(localDomain)s)", + "Invalid community ID": "Nevalida komunuma identigilo", + "'%(groupId)s' is not a valid community ID": "'%(groupId)s' ne estas valida komunuma identigilo", + "New community ID (e.g. +foo:%(localDomain)s)": "Nova komunuma identigilo (ekz-e +io:%(localDomain)s)", "You have enabled URL previews by default.": "Vi ŝaltis implicitajn antaŭrigardojn al retpaĝoj.", "You have disabled URL previews by default.": "Vi malŝaltis implicitajn antaŭrigardojn al retpaĝoj.", - "URL previews are enabled by default for participants in this room.": "Antaŭrigardoj de URL-oj estas implicite ŝaltitaj por anoj de tiu ĉi babilejo.", - "URL previews are disabled by default for participants in this room.": "Antaŭrigardoj de URL-oj estas implicite malŝaltitaj por anoj de tiu ĉi babilejo.", + "URL previews are enabled by default for participants in this room.": "Antaŭrigardoj de URL-oj estas implicite ŝaltitaj por anoj de tiu ĉi ĉambro.", + "URL previews are disabled by default for participants in this room.": "Antaŭrigardoj de URL-oj estas implicite malŝaltitaj por anoj de tiu ĉi ĉambro.", "URL Previews": "Antaŭrigardoj al retpaĝoj", "Error decrypting audio": "Eraro malĉifrante sonon", - "Error decrypting attachment": "Eraro malĉifrante kunsendaĵon", + "Error decrypting attachment": "Eraro dum malĉifrante de aldonaĵo", "Decrypt %(text)s": "Malĉifri %(text)s", "Download %(text)s": "Elŝuti %(text)s", "Invalid file%(extra)s": "Malvalida dosiero%(extra)s", @@ -488,7 +488,7 @@ "Edit": "Redakti", "Failed to change password. Is your password correct?": "Malsukcesis ŝanĝi la pasvorton. Ĉu via pasvorto estas ĝusta?", "Leave": "Foriri", - "Register": "Registriĝi", + "Register": "Registri", "Add rooms to this community": "Aldoni ĉambrojn al ĉi tiu komunumo", "Robot check is currently unavailable on desktop - please use a web browser": "Kontrolo kontraŭ robotoj ne disponeblas sur labortablo – bonvolu uzi retan foliumilon", "This Home Server would like to make sure you are not a robot": "Tiu ĉi hejma servilo volas certigi, ke vi ne estas roboto", @@ -524,12 +524,12 @@ "Failed to withdraw invitation": "Malsukcesis malinviti", "Failed to remove user from community": "Malsukcesis forigi uzanton de komunumo", "Filter community members": "Filtri komunumanojn", - "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Ĉu vi certe volas forigi ‹%(roomName)s› de %(groupId)s?", + "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Ĉu vi certe volas forigi '%(roomName)s' de %(groupId)s?", "Removing a room from the community will also remove it from the community page.": "Per forigo de ĉambro de la komunumo vi ankaŭ forigos ĝin de la paĝo de tiu komunumo.", "Failed to remove room from community": "Malsukcesis forigi ĉambron de komunumo", - "Failed to remove '%(roomName)s' from %(groupId)s": "Malsukcesis forigi ‹%(roomName)s› de %(groupId)s", + "Failed to remove '%(roomName)s' from %(groupId)s": "Malsukcesis forigi '%(roomName)s' de %(groupId)s", "Something went wrong!": "Io misokazis!", - "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Videbleco de ‹%(roomName)s› en %(groupId)s ne ĝisdatigeblis.", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Videbleco de '%(roomName)s' en %(groupId)s ne ĝisdatigeblis.", "Visibility in Room List": "Videbleco en Listo de ĉambroj", "Visible to everyone": "Videbla al ĉiuj", "Only visible to community members": "Videbla nur al komunumanoj", @@ -608,7 +608,7 @@ "expand": "etendi", "Custom of %(powerLevel)s": "Propra nivelo %(powerLevel)s", "Custom level": "Propra nivelo", - "Room directory": "Babilejo-listo", + "Room directory": "Ĉambra dosierujo", "Username not available": "Salutnomo ne disponeblas", "Username invalid: %(errMessage)s": "Salutnomo ne validas: %(errMessage)s", "Username available": "Salutnomo disponeblas", @@ -621,7 +621,7 @@ "ex. @bob:example.com": "ekz-e @nomo:ekzemplo.net", "Add User": "Aldoni uzanton", "Matrix ID": "Identigaĵo en Matrix", - "Matrix Room ID": "Ĉambra identigaĵo en Matrix", + "Matrix Room ID": "Ĉambra identigilo en Matrix", "email address": "retpoŝtadreso", "Try using one of the following valid address types: %(validTypesList)s.": "Provu unu el la sekvaj validaj tipoj de adreso: %(validTypesList)s.", "You have entered an invalid address.": "Vi enigis malvalidan adreson.", @@ -633,12 +633,12 @@ "Start Chatting": "Komenci babilon", "Confirm Removal": "Konfirmi forigon", "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.": "Ĉu vi certe volas forigi ĉi tiun okazaĵon? Per ŝanĝo de la ĉambra nomo aŭ temo, la ŝanĝo eble malfariĝos.", - "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Komunuma identigaĵo povas enhavi nur signojn a-z, 0-9, aŭ ‹=_-./› (malinkluzive la citilojn)", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Komunuma identigilo povas enhavi nur signojn a-z, 0-9, aŭ '=_-./'", "Something went wrong whilst creating your community": "Io misokazis dum kreado de via komunumo", "Create Community": "Krei komunumon", "Community Name": "Komunuma nomo", "Example": "Ekzemplo", - "Community ID": "Komunuma identigaĵo", + "Community ID": "Komunuma identigilo", "example": "ekzemplo", "Create": "Krei", "Create Room": "Krei ĉambron", @@ -659,7 +659,7 @@ "An error has occurred.": "Eraro okazis.", "OK": "Bone", "You added a new device '%(displayName)s', which is requesting encryption keys.": "Vi aldonis novan aparaton “%(displayName)s”, kiu petas ĉifrajn ŝlosilojn.", - "Your unverified device '%(displayName)s' is requesting encryption keys.": "Via nekontrolita aparato ‹%(displayName)s› petas ĉifrajn ŝlosilojn.", + "Your unverified device '%(displayName)s' is requesting encryption keys.": "Via nekontrolita aparato '%(displayName)s' petas ĉifrajn ŝlosilojn.", "Start verification": "Komenci kontrolon", "Share without verifying": "Kunhavigi sen kontrolo", "Ignore request": "Malatenti peton", @@ -670,7 +670,7 @@ "Invalid Email Address": "Malvalida retpoŝtadreso", "This doesn't appear to be a valid email address": "Tio ĉi ne ŝajnas esti valida retpoŝtadreso", "Verification Pending": "Atendanta kontrolon", - "Please check your email and click on the link it contains. Once this is done, click continue.": "Bonvolu kontroli vian retpoŝton, kaj alklaki la ligilon enhavatan en la sendita mesaĝo. Farinte tion, klaku je «daŭrigi».", + "Please check your email and click on the link it contains. Once this is done, click continue.": "Bonvolu kontroli vian retpoŝton, kaj alklaki la ligilon enhavatan en la sendita mesaĝo. Farinte tion, klaku je 'daŭrigi'.", "Unable to add email address": "Retpoŝtadreso ne aldoneblas", "Unable to verify email address.": "Retpoŝtadreso ne kontroleblas.", "This will allow you to reset your password and receive notifications.": "Tio ĉi permesos al vi restarigi vian pasvorton kaj ricevi sciigojn.", @@ -683,7 +683,7 @@ "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "Vi nun malpermesas legadon de ĉifritaj mesaĝoj al nekontrolitaj aparatoj; por sendi mesaĝojn al tiuj, vi devas ilin kontroli.", "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "Ni rekomendas al vi bone kontroli ĉiun aparaton por certigi, ke ĝi apartenas al la verŝajna posedanto, sed vi povas resendi la mesaĝon sen kontrolo, laŭprefere.", "Room contains unknown devices": "Ĉambro enhavas nekonatajn aparatojn", - "\"%(RoomName)s\" contains devices that you haven't seen before.": "«%(RoomName)s» enhavas aparatojn, kiujn vi neniam vidis antaŭe.", + "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" enhavas aparatojn, kiujn vi neniam vidis antaŭe.", "Unknown devices": "Nekonataj aparatoj", "Private Chat": "Privata babilo", "Public Chat": "Publika babilo", @@ -697,20 +697,20 @@ "You must register to use this functionality": "Vi devas registriĝî por uzi tiun ĉi funkcion", "You must join the room to see its files": "Vi devas aliĝi al la ĉambro por vidi tie dosierojn", "There are no visible files in this room": "En ĉi tiu ĉambro estas neniaj videblaj dosieroj", - "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      HTML por la paĝo de via komunumo

      \n

      \n Uzu la longan priskribon por enkonduki novajn komunumanojn, aŭ disdoni iujn\n gravajn ligilojn\n

      \n

      \n Vi povas eĉ uzi etikedojn ‹img›\n

      \n", + "

      HTML for your community's page

      \n

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

      \n

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

      \n": "

      HTML por la paĝo de via komunumo

      \n

      \n Uzu la longan priskribon por enkonduki novajn komunumanojn, aŭ disdoni iujn\n gravajn ligilojn\n

      \n

      \n Vi povas eĉ uzi etikedojn 'img'\n

      \n", "Add rooms to the community summary": "Aldoni ĉambrojn al la komunuma superrigardo", "Which rooms would you like to add to this summary?": "Kiujn ĉambrojn vi volas aldoni al ĉi tiu superrigardo?", "Add to summary": "Aldoni al superrigardo", "Failed to add the following rooms to the summary of %(groupId)s:": "Malsukcesis aldoni la jenajn ĉambrojn al la superrigardo de %(groupId)s:", "Add a Room": "Aldoni ĉambron", "Failed to remove the room from the summary of %(groupId)s": "Malsukcesis forigi la ĉambron de la superrigardo de %(groupId)s", - "The room '%(roomName)s' could not be removed from the summary.": "Ĉambro ‹%(roomName)s› ne forigeblas de la superrigardo.", + "The room '%(roomName)s' could not be removed from the summary.": "Ĉambro ;%(roomName)s' ne forigeblas de la superrigardo.", "Add users to the community summary": "Aldoni uzantojn al la komunuma superrigardo", "Who would you like to add to this summary?": "Kiun vi ŝatus aldoni al tiu ĉi superrigardo?", "Failed to add the following users to the summary of %(groupId)s:": "Malsukcesis aldoni la jenajn uzantojn al la superrigardo de %(groupId)s:", "Add a User": "Aldoni uzanton", "Failed to remove a user from the summary of %(groupId)s": "Malsukcesis forigi uzanton de la superrigardo de %(groupId)s", - "The user '%(displayName)s' could not be removed from the summary.": "Uzanto ‹%(displayName)s› ne forigeblas de la superrigardo.", + "The user '%(displayName)s' could not be removed from the summary.": "Uzanto '%(displayName)s' ne forigeblas de la superrigardo.", "Failed to upload image": "Malsukcesis alŝuti bildon", "Failed to update community": "Malskucesis ĝisdatigi la komunumon", "Unable to accept invite": "Invito ne akcepteblas", @@ -733,7 +733,7 @@ "Reject invitation": "Rifuzi inviton", "Are you sure you want to reject the invitation?": "Ĉu vi certe volas rifuzi la inviton?", "Failed to reject invitation": "Malsukcesis rifuzi la inviton", - "Are you sure you want to leave the room '%(roomName)s'?": "Ĉu vi certe volas forlasi la ĉambron ‹%(roomName)s›?", + "Are you sure you want to leave the room '%(roomName)s'?": "Ĉu vi certe volas forlasi la ĉambron '%(roomName)s'?", "Failed to leave room": "Malsukcesis forlasi la ĉambron", "Signed Out": "Adiaŭinta", "Old cryptography data detected": "Malnovaj kriptografiaj datumoj troviĝis", @@ -870,17 +870,17 @@ "An unknown error occurred.": "Okazis nekonata eraro.", "I already have an account": "Mi jam havas konton", "Displays action": "Montras agon", - "Bans user with given id": "Forbaras uzanton kun la donita identigaĵo", - "Unbans user with given id": "Malforbaras uzanton kun la donita identigaĵo", + "Bans user with given id": "Forbaras uzanton kun la donita identigilo", + "Unbans user with given id": "Malforbaras uzanton kun la donita identigilo", "Define the power level of a user": "Difini la potencan nivelon de uzanto", - "Deops user with given id": "Senestrigas uzanton kun donita identigaĵo", - "Invites user with given id to current room": "Invitas uzanton per identigilo al la nuna babilejo", - "Joins room with given alias": "Aliĝas al babilejo per kromnomo", + "Deops user with given id": "Senestrigas uzanton kun donita identigilo", + "Invites user with given id to current room": "Invitas uzanton per identigilo al la nuna ĉambro", + "Joins room with given alias": "Aliĝas al ĉambro per kromnomo", "Sets the room topic": "Agordas la babilejan temon", - "Kicks user with given id": "Forpelas uzanton kun la donita identigaĵo", + "Kicks user with given id": "Forpelas uzanton kun la donita identigilo", "Changes your display nickname": "Ŝanĝas vian vidigan nomon", "Searches DuckDuckGo for results": "Serĉas rezultojn per DuckDuckGo", - "Changes colour scheme of current room": "Ŝanĝas kolorskemon de la nuna babilejo", + "Changes colour scheme of current room": "Ŝanĝas kolorskemon de la nuna ĉambro", "Verifies a user, device, and pubkey tuple": "Kontrolas opon de uzanto, aparato, kaj publika ŝlosilo", "Ignores a user, hiding their messages from you": "Malatentas uzanton, kaŝante ĝiajn mesaĝojn de vi", "Stops ignoring a user, showing their messages going forward": "Ĉesas malatenti uzanton, montronte ĝiajn pluajn mesaĝojn", @@ -901,7 +901,7 @@ "Algorithm": "Algoritmo", "unencrypted": "neĉifritaj", "Decryption error": "Malĉifra eraro", - "Session ID": "Seanca identigaĵo", + "Session ID": "Seanca identigilo", "End-to-end encryption information": "Informoj pri ĝiscela ĉifrado", "Event information": "Informoj pri okazaĵo", "Sender device information": "Informoj pri aparato de sendinto", @@ -930,15 +930,15 @@ "Send a reply (unencrypted)…": "Sendi respondon (neĉifritan)…", "Send an encrypted message…": "Sendi ĉifritan mesaĝon…", "Send a message (unencrypted)…": "Sendi mesaĝon (neĉifritan)…", - "Replying": "Respondanta", + "Replying": "Respondante", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privato gravas al ni, tial ni ne kolektas personajn aŭ spureblajn datumojn por nia analizo.", "Learn more about how we use analytics.": "Lernu pli pri nia uzo de analiziloj.", - "Your homeserver's URL": "URL de via servilo", + "Your homeserver's URL": "URL de via hejmservilo", "Your identity server's URL": "URL de via identiga servilo", - "The platform you're on": "Via sistemtipo", + "The platform you're on": "Via platformo", "Which officially provided instance you are using, if any": "Kiun oficiale disponeblan aperon vi uzas, se iun ajn", "Whether or not you're using the Richtext mode of the Rich Text Editor": "Ĉu vi uzas la riĉtekstan reĝimon de la riĉteksta redaktilo aŭ ne", - "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Kiam ĉi tiu paĝo enhavas identigeblajn informojn, ekzemple babilejon, uzantan aŭ grupan identigilon, ili estas formetataj antaŭ sendado al la servilo.", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Kiam ĉi tiu paĝo enhavas identigeblajn informojn, ekzemple ĉambron, uzantan aŭ grupan identigilon, ili estas formetataj antaŭ ol sendado al la servilo.", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s", "Disable Community Filter Panel": "Malŝalti komunuman filtran breton", "Failed to add tag %(tagName)s to room": "Malsukcesis aldoni etikedon %(tagName)s al ĉambro", @@ -1044,13 +1044,13 @@ "Failed to send custom event.": "Malsukcesis sendi propran okazon.", "What's new?": "Kio novas?", "Notify me for anything else": "Sciigu min pri ĉio alia", - "When I'm invited to a room": "Kiam mi estas invitita al babilejo", + "When I'm invited to a room": "Kiam mi estas invitita al ĉambro", "Keywords": "Ŝlosilvortoj", "Can't update user notification settings": "Agordoj de sciigoj al uzanto ne ĝisdatigeblas", - "Notify for all other messages/rooms": "Sciigu min por ĉiuj aliaj mesaĝoj/babilejoj", - "Unable to look up room ID from server": "Ĉambra identigaĵo ne akireblas de la servilo", + "Notify for all other messages/rooms": "Sciigu min por ĉiuj aliaj mesaĝoj/ĉambroj", + "Unable to look up room ID from server": "Ĉambra identigilo ne akireblas de la servilo", "Couldn't find a matching Matrix room": "Malsukcesis trovi kongruan ĉambron en Matrix", - "All Rooms": "Ĉiuj babilejoj", + "All Rooms": "Ĉiuj ĉambroj", "Search for a room": "Serĉi ĉambron", "Thursday": "Ĵaŭdo", "Forward Message": "Plusendi mesaĝon", @@ -1061,7 +1061,7 @@ "Unhide Preview": "Malkaŝi antaŭrigardon", "Unable to join network": "Malsukcesis konektiĝi al la reto", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Vi eble agordis ilin en alia kliento. Vi ne povas agordi ilin en Riot, sed ili ankoraŭ validas", - "Sorry, your browser is not able to run Riot.": "Pardonu, via foliumilo ne kapablas funkciigi klienton Riot.", + "Sorry, your browser is not able to run Riot.": "Pardonon, via foliumilo ne kapablas funkciigi klienton Riot.", "Uploaded on %(date)s by %(user)s": "Alŝutita je %(date)s de %(user)s", "Messages in group chats": "Mesaĝoj en grupaj babiloj", "Yesterday": "Hieraŭ", @@ -1101,7 +1101,7 @@ "Every page you use in the app": "Ĉiu paĝo kiun vi uzas en la aplikaĵo", "e.g. ": "ekz. ", "Your User Agent": "Via klienta aplikaĵo", - "Your device resolution": "La distingivo de via aparato", + "Your device resolution": "La distingo de via aparato", "Call in Progress": "Voko farata", "A call is already in progress!": "Voko estas jam farata!", "Always show encryption icons": "Ĉiam montri bildetojn de ĉifrado", @@ -1126,7 +1126,7 @@ "Pin unread rooms to the top of the room list": "Fiksi nelegitajn ĉambrojn supre de la listo", "Pin rooms I'm mentioned in to the top of the room list": "Fiksi ĉambrojn kun mencioj de mia nomo supre de la listo", "A call is currently being placed!": "Alia voko nun dumas!", - "Unable to load! Check your network connectivity and try again.": "Ne eblas enlegi! Kontrolu vian retan konekton kaj reprovu.", + "Unable to load! Check your network connectivity and try again.": "Ne eblas ŝargi! Kontrolu vian retan konekton kaj reprovu.", "Failed to invite users to the room:": "Malsukcesis inviti uzantojn al la ĉambro:", "Opens the Developer Tools dialog": "Maflermas evoluigistan interagujon", "This homeserver has hit its Monthly Active User limit.": "Tiu ĉi hejmservilo atingis sian monatan limon de aktivaj uzantoj.", @@ -1144,11 +1144,11 @@ "Capitalization doesn't help very much": "Majusklado ne helpas multe", "All-uppercase is almost as easy to guess as all-lowercase": "Plena majusklado estas preskaŭ same facile konjektebla kiel plena minusklado", "Reversed words aren't much harder to guess": "Renversitaj vortoj ne estas multe pli malfacile konjekteblaj", - "Predictable substitutions like '@' instead of 'a' don't help very much": "Facile diveneblaj anstataŭigoj, kiel ‹@› anstataŭ ‹a›, ne helpas multe", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Facile diveneblaj anstataŭigoj, kiel '@' anstataŭ 'a', ne helpas multe", "Add another word or two. Uncommon words are better.": "Aldonu alian vorton aŭ du. Maloftaj vortoj pli bonas.", - "Repeats like \"aaa\" are easy to guess": "Ripetoj kiel «aaa» estas facile diveneblaj", - "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetoj kiel «abcabcabc» estas apenaŭ pli bonaj ol nur «abc»", - "Sequences like abc or 6543 are easy to guess": "Sinsekvoj kiel «abc» aŭ «6543» estas facile diveneblaj", + "Repeats like \"aaa\" are easy to guess": "Ripetoj kiel \"aaa\" estas facile diveneblaj", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetoj kiel \"abcabcabc\" estas apenaŭ pli bonaj ol nur \"abc\"", + "Sequences like abc or 6543 are easy to guess": "Sinsekvoj kiel \"abc\" aŭ \"6543\" estas facile diveneblaj", "Recent years are easy to guess": "Freŝdataj jaroj estas facile diveneblaj", "Dates are often easy to guess": "Datoj estas ofte facile diveneblaj", "This is a top-10 common password": "Ĉi tiu pasvorto estas inter la 10 plej oftaj", @@ -1159,12 +1159,12 @@ "Names and surnames by themselves are easy to guess": "Ankaŭ nomoj familiaj kaj individiuaj estas memstare facile diveneblaj", "Common names and surnames are easy to guess": "Oftaj nomoj familiaj kaj individuaj estas facile diveneblaj", "There was an error joining the room": "Okazis eraro dum aliĝo al la ĉambro", - "Sorry, your homeserver is too old to participate in this room.": "Pardonu, via hejmservilo estas tro malnova por partoprenado en la ĉambro.", + "Sorry, your homeserver is too old to participate in this room.": "Pardonon, via hejmservilo estas tro malnova por partoprenado en la ĉambro.", "Please contact your homeserver administrator.": "Bonvolu kontakti la administranton de via hejmservilo.", "Increase performance by only loading room members on first view": "Plibonigu efikecon per nur unuafoja enlego de ĉambranoj", "Backup of encryption keys to server": "Savkopio de ĉifroŝlosiloj al servilo", "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Montri memorigilon por ŝalti Sekuran Ricevon de Mesaĝoj en ĉifrataj ĉambroj", - "Show developer tools": "Montri evolugistajn ilojn", + "Show developer tools": "Montri verkistajn ilojn", "Messages containing @room": "Mesaĝoj enhavantaj @room", "Encrypted messages in one-to-one chats": "Ĉifritaj mesaĝoj en duopaj babiloj", "Encrypted messages in group chats": "Ĉifritaj mesaĝoj en grupaj babiloj", @@ -1176,5 +1176,221 @@ "In reply to ": "Respondanta al ", "Share Message": "Diskonigi", "Search for a room like #example": "Serĉi ĉambron kiel #example", - "Show devices, send anyway or cancel.": "Montri aparatojn, tamen sendinuligi." + "Show devices, send anyway or cancel.": "Montri aparatojn, tamen sendinuligi.", + "Whether or not you're logged in (we don't record your username)": "Ĉu aŭ ne vi salutis (ni ne registras vian uzantonomon)", + "A conference call could not be started because the intgrations server is not available": "Ne eblis komenci grupvokon, ĉar la integriga servilo ne disponeblas", + "You do not have permission to start a conference call in this room": "Vi ne havas permeson komenci grupvokon en ĉi tiu ĉambro", + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "La dosiero '%(fileName)s' superas la grandecan limon de ĉi tiu hejmservilo", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Antaŭmetas ¯\\_(ツ)_/¯ al platteksta mesaĝo", + "Verified!": "Kontrolita!", + "Got It": "Komprenite", + "Dog": "Hundo", + "Cat": "Kato", + "Lion": "Leono", + "Horse": "Ĉevalo", + "Unicorn": "Unikorno", + "Pig": "Porko", + "Elephant": "Elefanto", + "Rabbit": "Kuniklo", + "Panda": "Pando", + "Rooster": "Koko", + "Penguin": "Pingvino", + "Turtle": "Testudo", + "Fish": "Fiŝo", + "Octopus": "Oktopuso", + "Butterfly": "Papilio", + "Flower": "Floro", + "Tree": "Arbo", + "Cactus": "Kakto", + "Mushroom": "Fungo", + "Globe": "Globo", + "Moon": "Luno", + "Cloud": "Nubo", + "Fire": "Fajro", + "Banana": "Banano", + "Apple": "Pomo", + "Strawberry": "Frago", + "Corn": "Greno", + "Pizza": "Pico", + "Cake": "Kuko", + "Heart": "Koro", + "Smiley": "Mieneto", + "Robot": "Roboto", + "Hat": "Ĉapelo", + "Glasses": "Okulvitroj", + "Spanner": "Ŝraŭbŝlosilo", + "Umbrella": "Ombrelo", + "Hourglass": "Sablohorloĝo", + "Clock": "Horloĝo", + "Gift": "Donaco", + "Light bulb": "Lampo", + "Book": "Libro", + "Pencil": "Grifelo", + "Scissors": "Tondilo", + "Padlock": "Penda seruro", + "Key": "Ŝlosilo", + "Hammer": "Martelo", + "Telephone": "Telefono", + "Flag": "Flago", + "Train": "Trajno", + "Bicycle": "Biciklo", + "Aeroplane": "Aeroplano", + "Rocket": "Raketo", + "Trophy": "Trofeo", + "Ball": "Pilko", + "Guitar": "Gitaro", + "Trumpet": "Trumpeto", + "Bell": "Sonilo", + "Anchor": "Ankero", + "Headphones": "Kapaŭdilo", + "Folder": "Dosierujo", + "Yes": "Jes", + "No": "Ne", + "Email Address": "Retpoŝtadreso", + "Phone Number": "Telefonnumero", + "Profile picture": "Profilbildo", + "Upload profile picture": "Alŝuti profilbildon", + "Upgrade to your own domain": "Ĝisdatigi al via propra domajno", + "Display Name": "Vidiga nomo", + "Set a new account password...": "Agordi novan kontan pasvorton...", + "Email addresses": "Retpoŝtadresoj", + "Phone numbers": "Telefonnumeroj", + "Legal": "Jura", + "Credits": "Dankoj", + "For help with using Riot, click here.": "Por helpo kun uzo de Riot, alklaku ĉi tie.", + "For help with using Riot, click here or start a chat with our bot using the button below.": "Por helpo kun uzo de Riot, alklaku ĉi tie aŭ komencu babilon kun nia roboto uzante la butonon sube.", + "Chat with Riot Bot": "Babilu kun la roboto Riot Bot", + "Help & About": "Helpo & Pri", + "Bug reporting": "Cim-raportado", + "FAQ": "Oftaj demandoj", + "Versions": "Versioj", + "Preferences": "Agordoj", + "Composer": "Komponilo", + "Room list": "Ĉambrolisto", + "Ignored users": "Malatentaj uzantoj", + "Key backup": "Sekurkopio de ŝlosilo", + "Security & Privacy": "Sekureco & Privateco", + "Voice & Video": "Voĉo & Video", + "Upgrade room to version %(ver)s": "Ĝisdatigi ĉambron al versio %(ver)s", + "Room information": "Ĉambraj informoj", + "Internal room ID:": "Ena ĉambra identigilo:", + "Room version": "Ĉambra versio", + "Room version:": "Ĉambra versio:", + "Developer options": "Verkantaj opcioj", + "Room Addresses": "Ĉambra adresoj", + "Change room avatar": "Ŝanĝi avataron de ĉambro", + "Change room name": "Ŝanĝi nomon de ĉambro", + "Change main address for the room": "Ŝanĝi ĉefan adreson de la ĉambro", + "Change history visibility": "Ŝanĝi videblecon de historio", + "Change permissions": "Ŝanĝi permesojn", + "Change topic": "Ŝanĝi temon", + "Modify widgets": "Aliigi fenestraĵojn", + "Default role": "Norma rolo", + "Send messages": "Sendi mesaĝojn", + "Invite users": "Inviti uzantojn", + "Change settings": "Ŝanĝi agordojn", + "Kick users": "Forpeli uzantojn", + "Ban users": "Forbari uzantojn", + "Remove messages": "Forigi mesaĝojn", + "Notify everyone": "Sciigi ĉiujn", + "Muted Users": "Silentigitaj uzantoj", + "Roles & Permissions": "Roloj & Permesoj", + "Enable encryption?": "Ĉu ŝalti ĉifradon?", + "Share Link to User": "Kunhavigi ligilon al uzanto", + "deleted": "forigita", + "underlined": "substrekita", + "inline-code": "enteksta-kodo", + "block-quote": "blokcito", + "bulleted-list": "bula-listo", + "numbered-list": "numerita-listo", + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Vidita de %(displayName)s (%(userName)s) je %(dateTime)s", + "Share room": "Kunhavigi ĉambron", + "System Alerts": "Sistemaj avertoj", + "Joining room...": "Aliĝante al ĉambro...", + "Not now": "Ne nun", + "Don't ask me again": "Ne demandu min denove", + "Main address": "Ĉefa adreso", + "Room avatar": "Avataro de ĉambro", + "Upload room avatar": "Alŝuti avataron de ĉambro", + "No room avatar": "Neniu avataro de ĉambro", + "Room Name": "Nomo de ĉambro", + "Room Topic": "Temo de ĉambro", + "Yes, I want to help!": "Jes. Mi volas helpi!", + "Failed to remove widget": "Malsukcesis forigi fenestraĵon", + "Reload widget": "Reŝargi fenestraĵon", + "Picture": "Bildo", + "Join": "Aliĝi", + "Invite anyway": "Tamen inviti", + "To continue, please enter your password:": "Por daŭrigi, bonvoluenigi vian pasvorton:", + "password": "pasvorto", + "Updating Riot": "Ĝisdatigante Riot", + "Go back": "Reen iri", + "Room Settings - %(roomName)s": "Ĉambraj agordoj — %(roomName)s", + "Failed to upgrade room": "Malsukcesis ĝisdatigi ĉambron", + "Refresh": "Aktualigi", + "Checking...": "Kontrolante...", + "Share Room": "Kunhavigi ĉambron", + "Share User": "Kunhavigi uzanton", + "Share Community": "Kunhavigi komunumon", + "Share Room Message": "Kunhavigi ĉambran mesaĝon", + "COPY": "KOPIO", + "Next": "Sekva", + "Clear status": "Vakigi staton", + "Update status": "Ĝisdatigi staton", + "Set status": "Agordi staton", + "Set a new status...": "Agordi novan staton...", + "Hide": "Kaŝi", + "Code": "Kodo", + "Server Name": "Nomo de servilo", + "Username": "Uzantonomo", + "Not sure of your password? Set a new one": "Ĉu vi ne certas pri via pasvorto? Agordu novan", + "Sign in to your Matrix account": "Saluti per via Matrix-konto", + "Sign in to your Matrix account on %(serverName)s": "Saluti per via Matrix- sur %(serverName)s", + "Change": "Ŝanĝi", + "Create your Matrix account": "Krei vian Matrix-konton", + "Create your Matrix account on %(serverName)s": "Krei vian Matrix-konton sur %(serverName)s", + "Email (optional)": "Retpoŝto (malnepra)", + "Phone (optional)": "Telefono (malnepra)", + "Confirm": "Konfirmi", + "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Uzu retpoŝtadreson por restaŭri vian konton. Aliaj uzantoj povas inviti vin al ĉambroj uzante viajn kontaktdetalojn.", + "Other servers": "Aliaj serviloj", + "Enter custom server URLs What does this mean?": "Enigi propran servil-URL-ojn. Kion signifas ĉi tion?", + "Homeserver URL": "Hejmservila URL", + "Identity Server URL": "Identiga servila URL", + "Free": "Senpaga", + "Other": "Alia", + "Couldn't load page": "Ne povis ŝargi paĝon", + "Unable to join community": "Ne eblas aliĝi al komunumo", + "Unable to leave community": "Ne eblas forlasi komunumon", + "Join this community": "Aliĝi al ĉi tiu komunumo", + "Leave this community": "Forlasi ĉi tiun komunumon", + "Everyone": "Ĉiuj", + "This homeserver does not support communities": "Ĉi tiu hejmservilo ne subtenas komunumojn", + "%(count)s of your messages have not been sent.|other": "Kelkaj viaj mesaĝoj ne sendiĝis.", + "%(count)s of your messages have not been sent.|one": "Via mesaĝo ne sendiĝis.", + "File is too big. Maximum file size is %(fileSize)s": "Dosiero estas tro granda. Maksimuma dosiergrandeco estas %(fileSize)s", + "Clear filter": "Vakigi filtrilon", + "Guest": "Gasto", + "Could not load user profile": "Ne povis ŝargi uzantan profilon", + "Your Matrix account": "Via Matrix-konto", + "Your Matrix account on %(serverName)s": "Via Matrix-konto sur %(serverName)s", + "A verification email will be sent to your inbox to confirm setting your new password.": "Kontrola retpoŝtmesaĝo estos sendita al via enirkesto por kontroli agordadon de via nova pasvorto.", + "Sign in instead": "Anstataŭe saluti", + "Your password has been reset.": "Vi reagordis vian pasvorton.", + "Set a new password": "Agordi novan pasvorton", + "General failure": "Ĝenerala fiasko", + "Create account": "Krei konton", + "You need to enter a username.": "Necesas, ke vi enigu uzantonomon.", + "Create your account": "Krei vian konton", + "Great! This passphrase looks strong enough.": "Bonege! Ĉi tiu pasfrazo ŝajnas sufiĉe forta.", + "Keep going...": "Daŭrigu...", + "Enter a passphrase...": "Enigu pasfrazon...", + "That matches!": "Tio kongruas!", + "That doesn't match.": "Tio ne kongruas.", + "Repeat your passphrase...": "Ripetu vian pasfrazon...", + "Download": "Elŝuti", + "Okay": "Bone", + "Success!": "Sukceso!", + "Retry": "Reprovi", + "Set up": "Agordi" } From 15bb063fa4172a02dee1393c7267124d97389e24 Mon Sep 17 00:00:00 2001 From: Samu Voutilainen Date: Fri, 29 Mar 2019 06:29:15 +0000 Subject: [PATCH 198/481] Translated using Weblate (Finnish) Currently translated at 97.4% (1519 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fi/ --- src/i18n/strings/fi.json | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index 4cbd5e577c..39889cb179 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -156,7 +156,7 @@ "Failed to unban": "Porttikiellon poistaminen epäonnistui", "Failed to upload file": "Tiedoston lataaminen epäonnistui", "Failed to upload profile picture!": "Profiilikuvan lataaminen epäonnistui!", - "Failed to verify email address: make sure you clicked the link in the email": "Sähköpostin varmennus epäonnistui: varmista että seurasit sähköpostissa olevaa linkkiä", + "Failed to verify email address: make sure you clicked the link in the email": "Sähköpostin vahvistus epäonnistui: varmista, että seurasit sähköpostissa olevaa linkkiä", "Failure to create room": "Huoneen luominen epäonnistui", "Favourites": "Suosikit", "Fill screen": "Täytä näyttö", @@ -488,7 +488,7 @@ "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "Syöttämäsi allekirjoitusavain vastaa käyttäjän %(userId)s laitteelta %(deviceId)s saamaasi allekirjoitusavainta. Laite on merkitty varmennetuksi.", "Unable to add email address": "Sähköpostiosoitteen lisääminen epäonnistui", "Unable to remove contact information": "Yhteystietojen poistaminen epäonnistui", - "Unable to verify email address.": "Sähköpostin varmentaminen epäonnistui.", + "Unable to verify email address.": "Sähköpostin vahvistaminen epäonnistui.", "Unbans user with given id": "Poistaa porttikiellon annetun ID:n omaavalta käyttäjältä", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s poisti porttikiellon käyttäjältä %(targetName)s.", "Unable to capture screen": "Ruudun kaappaus epäonnistui", @@ -912,7 +912,7 @@ "%(items)s and %(count)s others|other": "%(items)s ja %(count)s muuta", "%(items)s and %(count)s others|one": "%(items)s ja yksi toinen", "Custom of %(powerLevel)s": "Valinnaiset %(powerLevel)s", - "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Varmistaaksesi että tähän laitteeseen voidaan luottaa, ole yhteydessä omistajaan jollain muulla tavalla (henkilökohtaisesti tai puhelimitse) ja pyydä heitä varmistamaan näkyykö Käyttäjäasetuksissa laite jolla on alla oleva avain:", + "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "Varmistaaksesi, että tähän laitteeseen voidaan luottaa, ole yhteydessä laitteen haltijaan jollain muulla tavalla (esim. henkilökohtaisesti tai puhelimitse) ja pyydä heitä varmistamaan, että hänen käyttäjäasetuksissa näkyy laite, jolla on alla oleva avain:", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "Jos avain täsmää, valitse painike alla. Jos avain ei täsmää, niin joku muu salakuuntelee laitetta ja haluat todennäköisesti painaa estopainiketta.", "Old cryptography data detected": "Vanhaa salaustietoa havaittu", "Warning": "Varoitus", @@ -972,7 +972,7 @@ "Resend": "Lähetä uudelleen", "Failed to get protocol list from Home Server": "Protokollalistan hakeminen Kotipalvelimelta ei onnistunut", "Collecting app version information": "Haetaan sovelluksen versiotietoja", - "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Poista huonealias %(alias)s ja poista %(name)s hakemistosta?", + "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Poista huonealias %(alias)s ja poista %(name)s luettelosta?", "This will allow you to return to your account after signing out, and sign in on other devices.": "Tämä antaa sinun palata tilillesi uloskirjautumisen jälkeen sekä kirjautumaan muilla laitteilla.", "Keywords": "Avainsanat", "Enable notifications for this account": "Ota käyttöön ilmoitukset tälle tilille", @@ -985,7 +985,7 @@ "Enter keywords separated by a comma:": "Anna avainsanat pilkuin eroteltuna:", "Search…": "Haku…", "You have successfully set a password and an email address!": "Olet asettanut salasanan ja sähköpostiosoitteen!", - "Remove %(name)s from the directory?": "Poista %(name)s hakemistosta?", + "Remove %(name)s from the directory?": "Poista %(name)s luettelosta?", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot käyttää monia edistyneitä ominaisuuksia, joista osaa selaimesi ei tue tai ne ovat kokeellisia.", "Developer Tools": "Kehittäjätyökalut", "Enable desktop notifications": "Ota käyttöön työpöytäilmoitukset", @@ -998,7 +998,7 @@ "Reject": "Hylkää", "Failed to set Direct Message status of room": "Huoneen suoran viestittelyn tilan asettaminen epäonnistui", "Monday": "Maanantai", - "Remove from Directory": "Poista hakemistosta", + "Remove from Directory": "Poista luettelosta", "Enable them now": "Ota käyttöön nyt", "Forward Message": "Edelleenlähetä viesti", "Messages containing my user name": "Viestit joissa mainitaan käyttäjänimeni", @@ -1045,7 +1045,7 @@ "Set Password": "Aseta salasana", "An error occurred whilst saving your email notification preferences.": "Sähköposti-ilmoitusasetuksia tallettaessa tapahtui virhe.", "Enable audible notifications in web client": "Ota käyttöön äänelliset ilmoitukset", - "remove %(name)s from the directory.": "poista %(name)s hakemistosta.", + "remove %(name)s from the directory.": "poista %(name)s luettelosta.", "Off": "Pois päältä", "Riot does not know how to join a room on this network": "Riot ei tiedä miten liittyä huoneeseen tässä verkossa", "Mentions only": "Vain maininnat", @@ -1410,7 +1410,7 @@ "Messages containing @room": "Viestit, jotka sisältävät sanan ”@room”", "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Turvalliset viestit tämän käyttäjän kanssa ovat salattuja päästä päähän, eivätkä kolmannet osapuolet voi lukea niitä.", "Thumbs up": "Peukut ylös", - "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Lähetimme sinulle viestin sähköpostiosoitteesi varmentamiseksi. Noudata sähköpostissa olevia ohjeita, ja klikkaa sen jälkeen alla olevaa painiketta.", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Lähetimme sinulle sähköpostin osoitteesi vahvistamiseksi. Noudata sähköpostissa olevia ohjeita, ja klikkaa sen jälkeen alla olevaa painiketta.", "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Oletko varma? Et voi lukea salattuja viestejäsi, mikäli avaimesi eivät ole kunnolla varmuuskopioituna.", "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Salatut viestit turvataan kahdenkeskisellä salauksella. Vain sinä ja viestien vastaanottajat omistavat avaimet näiden viestien lukemiseen.", "Unable to load key backup status": "Avainten varmuuskopionnin tilan lukeminen epäonnistui", @@ -1431,7 +1431,7 @@ "Algorithm: ": "Algoritmi: ", "Your keys are not being backed up from this device.": "Avaimesi eivät ole varmuuskopioituna tästä laitteesta.", "Start using Key Backup": "Aloita avainvarmuuskopion käyttö", - "Unable to verify phone number.": "Puhelinnumeron varmentaminen epäonnistui.", + "Unable to verify phone number.": "Puhelinnumeron vahvistaminen epäonnistui.", "Verification code": "Varmennuskoodi", "Internal room ID:": "Sisäinen huoneen ID:", "Credits": "Maininnat", @@ -1685,5 +1685,6 @@ "Copy it to your personal cloud storage": "Kopioi se henkilökohtaiseen pilvitallennustilaasi", "Your keys are being backed up (the first backup could take a few minutes).": "Avaimiasi varmuuskopioidaan (ensimmäinen varmuuskopio voi viedä muutaman minuutin).", "Okay": "OK", - "Unable to create key backup": "Avaimen varmuuskopiota ei voi luoda" + "Unable to create key backup": "Avaimen varmuuskopiota ei voi luoda", + "A verification email will be sent to your inbox to confirm setting your new password.": "Ottaaksesi käyttöön uuden salasanasi, seuraa ohjeita sinulle lähetettävässä vahvistussähköpostissa." } From b27e26e5d058f31b0f1b2ff989667087e156e841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Mon, 18 Mar 2019 21:11:53 +0000 Subject: [PATCH 199/481] Translated using Weblate (French) Currently translated at 99.8% (1557 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index f6569269b6..b5d50c34d7 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1831,5 +1831,7 @@ "Power level": "Rang", "Want more than a community? Get your own server": "Vous voulez plus qu’une communauté ? Obtenez votre propre serveur", "You are logged in to another account": "Vous êtes connecté(e) avec un autre compte", - "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Merci de vérifier votre adresse e-mail ! Le compte avec lequel vous êtes connecté (%(sessionUserId)s) est différent du compte que vous avez vérifié avec cette adresse e-mail (%(verifiedUserId)s). Si vous souhaitez vous connecter avec %(verifiedUserId2)s, veuillez vous déconnecter d’abord." + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Merci de vérifier votre adresse e-mail ! Le compte avec lequel vous êtes connecté (%(sessionUserId)s) est différent du compte que vous avez vérifié avec cette adresse e-mail (%(verifiedUserId)s). Si vous souhaitez vous connecter avec %(verifiedUserId2)s, veuillez vous déconnecter d’abord.", + "Please install Chrome, Firefox, or Safari for the best experience.": "Veuillez installer Chrome, Firefox ou Safari pour une expérience optimale.", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Le changement de votre mot de passe entraînera la réinitialisation de toutes les clés de chiffrement de bout en bout sur tous vos appareils. L’historique de vos conversations chiffrées sera alors illisible. Configurez la sauvegarde des clés ou exportez vos clés de chiffrement depuis un autre appareil avant de modifier votre mot de passe." } From 7d0c996b75b4b8781d3558041530cb0c723007aa Mon Sep 17 00:00:00 2001 From: Krombel Date: Tue, 26 Mar 2019 00:31:05 +0000 Subject: [PATCH 200/481] Translated using Weblate (German) Currently translated at 96.2% (1500 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 52 +++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index a23243e9dd..3cfdb9c733 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1390,7 +1390,7 @@ "Messages containing @room": "Nachrichten die \"@room\" enthalten", "Encrypted messages in one-to-one chats": "Verschlüsselte Nachrichten in 1:1 Chats", "Encrypted messages in group chats": "Verschlüsselte Nachrichten in Gruppenchats", - "Use a longer keyboard pattern with more turns": "Nutze ein längeres Tastaturmuster mit mehr Änderungen", + "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", "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Wirklich die gesicherten Verschlüsselungs-Schlüssel vom Server löschen? Du wirst nicht länger in der Lage sein, deinen Wiederherstellungsschlüssel zu verwenden um die verschlüsselte Nachrichtenhistorie zu lesen", @@ -1759,5 +1759,53 @@ "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s deaktivierte Abzeichen der Gruppen %(groups)s in diesem Raum.", "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s aktivierte Abzeichen von %(newGroups)s und deaktivierte die Abzeichen von %(oldGroups)s in diesem Raum.", "User %(userId)s is already in the room": "Nutzer %(userId)s ist bereits im Raum", - "The user must be unbanned before they can be invited.": "Nutzer müssen entbannt werden, bevor sie eingeladen werden können." + "The user must be unbanned before they can be invited.": "Nutzer müssen entbannt werden, bevor sie eingeladen werden können.", + "Show read receipts sent by other users": "Zeige Lesebestätigungen anderer Benutzer", + "Order rooms in the room list by most important first instead of most recent": "Sortiere Räume in der Raumliste nach Wichtigkeit und nicht nach letzter Aktivität", + "Scissors": "Scheren", + "Upgrade to your own domain": "Upgrade zu deiner eigenen Domain", + "Close button should minimize window to tray": "Button zum schließen soll Fenster nur minimieren", + "Accept all %(invitedRooms)s invites": "Akzeptiere alle %(invitedRooms)s Einladungen", + "Change room avatar": "Ändere Raumbild", + "Change room name": "Ändere Raumname", + "Change main address for the room": "Ändere Hauptadresse für den Raum", + "Change history visibility": "Ändere Sichtbarkeit der Historie", + "Change permissions": "Ändere Berechtigungen", + "Change topic": "Ändere das Thema", + "Modify widgets": "Ändere Widgets", + "Default role": "Standardrolle", + "Send messages": "Sende Nachrichten", + "Invite users": "Benutzer einladen", + "Change settings": "Ändere Einstellungen", + "Kick users": "Benutzer kicken", + "Ban users": "Benutzer verbannen", + "Remove messages": "Nachrichten löschen", + "Notify everyone": "Jeden Benachrichtigen", + "Send %(eventType)s events": "Sende %(eventType)s-Ereignisse", + "Select the roles required to change various parts of the room": "Wähle Rollen die benötigt werden um einige Teile des Raumes zu ändern", + "Enable encryption?": "Verschlüsselung aktivieren?", + "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.": "Sobald aktiviert, kann die Verschlüsselung für einen Raum nicht mehr deaktiviert werden. Nachrichten in einem verschlüsselten Raum können nur noch von Teilnehmern aber nicht mehr vom Server gelesen werden. Einige Bots und Brücken werden vielleicht nicht mehr funktionieren. Lerne mehr über Verschlüsselung", + "Error updating main address": "Fehler beim Aktualisieren der Hauptadresse", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Es gab ein Problem beim Aktualisieren der Raum-Hauptadresse. Es kann sein, dass es vom Server verboten ist oder ein temporäres Problem auftrat.", + "Error creating alias": "Fehler beim Erstellen eines Aliases", + "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "Es gab einen Fehler beim Erstellen eines Aliases. Entweder ist es dir vom Server nicht erlaubt oder es gab ein temporäres Problem.", + "Error removing alias": "Fehler beim entfernen eines Aliases", + "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Es gab einen Fehler beim Entfernen eines Aliases. Er existiert vielleicht nicht mehr oder es gab ein temporäres Problem.", + "Error updating flair": "Konnte Abzeichen nicht aktualisieren", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Es gab ein Problem beim Aktualisieren des Abzeichens für diesen Raum. Es kann sein, dass der Server es nicht erlaubt oder ein temporäres Problem auftrat.", + "Power level": "Berechtigungslevel", + "Room Settings - %(roomName)s": "Raumeinstellungen - %(roomName)s", + "A username can only contain lower case letters, numbers and '=_-./'": "Ein Benutzername kann nur Kleinbuchstaben, Nummern und '=_-./' enthalten", + "Share Permalink": "Teile permanenten Link", + "Sign in to your Matrix account": "Melde dich mit deinem Matrixkonto an", + "Sign in to your Matrix account on %(serverName)s": "Melde dich mit deinem Matrixkonto auf %(serverName)s an", + "Create your Matrix account": "Erstelle ein Matrix-Konto", + "Create your Matrix account on %(serverName)s": "Erstelle ein Matrixkonto auf %(serverName)s", + "Please install Chrome, Firefox, or Safari for the best experience.": "Bitte installiere Chrome, Firefox, oder Safari für die beste Erfahrung.", + "Want more than a community? Get your own server": "Du möchtest mehr als eine Community? Hol dir deinen eigenen Server", + "You are logged in to another account": "Du bist mit einem anderen Konto angemeldet", + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Danke für das Verifizieren deiner E-Mail! Das Konto, mit dem du angemeldet bist (%(sessionUserId)s) scheint ein anderes zu sein als das wofür die die E-Mail verifizierst (%(verifiedUserId)s). Wenn du dich als %(verifiedUserId2)s anmelden willst, melde dich zuerst ab.", + "Could not load user profile": "Konnte Nutzerprofil nicht laden", + "Your Matrix account": "Dein Matrixkonto", + "Your Matrix account on %(serverName)s": "Dein Matrixkonto auf %(serverName)s" } From c60df950dd144311854bc2eb4b8756ad214e6ad8 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 19 Mar 2019 07:21:18 +0000 Subject: [PATCH 201/481] Translated using Weblate (Hungarian) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 3aef45b752..3b76a4d60d 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -1469,9 +1469,9 @@ "Sets the room name": "Szobanév beállítása", "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s frissítette a szobát.", "%(displayName)s is typing …": "%(displayName)s gépel …", - "%(names)s and %(count)s others are typing …|other": "%(names)s és %(count)s másik pötyögnek …", - "%(names)s and %(count)s others are typing …|one": "%(names)s és még valaki pötyögnek …", - "%(names)s and %(lastPerson)s are typing …": "%(names)s és %(lastPerson)s pötyögnek …", + "%(names)s and %(count)s others are typing …|other": "%(names)s és %(count)s másik gépelnek …", + "%(names)s and %(count)s others are typing …|one": "%(names)s és még valaki gépelnek …", + "%(names)s and %(lastPerson)s are typing …": "%(names)s és %(lastPerson)s gépelnek …", "Tabbed settings": "Beállítások tabokban", "Render simple counters in room header": "Egyszerű számlálók a szoba fejlécében", "Two-way device verification using short text": "Kétirányú eszköz ellenőrzés rövid szöveggel", @@ -1831,5 +1831,7 @@ "Power level": "Hozzáférési szint", "Want more than a community? Get your own server": "Többet szeretnél, mint egy közösség? Szerezz saját szervert", "You are logged in to another account": "Másik felhasználói fiókba vagy bejelentkezve", - "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Köszönjük, hogy ellenőrizted az e-mailed! A fiók ahova be vagy jelentkezve itt (%(sessionUserId)s) különbözőnek tűnik attól a fióktól amihez az e-mailedet ellenőrizted (%(verifiedUserId)s). Ha be szeretnél jelentkezni ide: %(verifiedUserId2)s, ahhoz először ki kell jelentkezned." + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Köszönjük, hogy ellenőrizted az e-mailed! A fiók ahova be vagy jelentkezve itt (%(sessionUserId)s) különbözőnek tűnik attól a fióktól amihez az e-mailedet ellenőrizted (%(verifiedUserId)s). Ha be szeretnél jelentkezni ide: %(verifiedUserId2)s, ahhoz először ki kell jelentkezned.", + "Please install Chrome, Firefox, or Safari for the best experience.": "Kérlek telepíts Chromeot, Firefoxot vagy Safarit a jegjobb élményhez.", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "A jelszóváltoztatás megváltoztatja minden eszközön az összes végponttól végpontig titkosításhoz használt kulcsodat; így a titkosított csevegések olvashatatlanok lesznek. Készíts biztonsági másolatot vagy mentsd ki a szoba kulcsaidat minden eszközödön mielőtt megváltoztatod a jelszavad." } From 3e4777ff61959c87f2b000f065d8904c51760a4a Mon Sep 17 00:00:00 2001 From: random Date: Tue, 19 Mar 2019 14:48:49 +0000 Subject: [PATCH 202/481] Translated using Weblate (Italian) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 354 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 343 insertions(+), 11 deletions(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 2bde240466..8283ce8120 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -8,7 +8,7 @@ "Search": "Cerca", "Settings": "Impostazioni", "Start chat": "Inizia una chat", - "Room directory": "Lista delle stanze", + "Room directory": "Elenco delle stanze", "unknown error code": "codice errore sconosciuto", "Cancel": "Annulla", "Close": "Chiudi", @@ -37,7 +37,7 @@ "Default Device": "Dispositivo Predefinito", "Microphone": "Microfono", "Camera": "Videocamera", - "Advanced": "Avanzate", + "Advanced": "Avanzato", "Algorithm": "Algoritmo", "Hide removed messages": "Nascondi messaggi rimossi", "Always show message timestamps": "Mostra sempre il timestamps dei messaggi", @@ -209,7 +209,7 @@ "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s ha reso visibile la futura cronologia della stanza a tutti i membri della stanza, dal momento in cui sono entrati.", "%(senderName)s made future room history visible to all room members.": "%(senderName)s ha reso visibile la futura cronologia della stanza a tutti i membri della stanza.", "%(senderName)s made future room history visible to anyone.": "%(senderName)s ha reso visibile la futura cronologia della stanza a tutti.", - "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s ha reso visibile la futura cronologia della stanza a (%(visibility)s) sconosciuto.", + "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s ha reso visibile la futura cronologia della stanza a sconosciuti (%(visibility)s).", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s ha attivato la crittografia end-to-end (algoritmo %(algorithm)s).", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s da %(fromPowerLevel)s a %(toPowerLevel)s", "%(senderName)s changed the pinned messages for the room.": "%(senderName)s ha cambiato i messaggi ancorati della stanza.", @@ -1004,7 +1004,7 @@ "Filter room names": "Filtra i nomi delle stanze", "Changelog": "Cambiamenti", "Waiting for response from server": "In attesa di una risposta dal server", - "Send Custom Event": "Invia Evento Personalizzato", + "Send Custom Event": "Invia evento personalizzato", "All notifications are currently disabled for all targets.": "Tutte le notifiche sono disabilitate per tutti gli obbiettivi.", "Failed to send logs: ": "Invio dei log fallito: ", "delete the alias.": "elimina l'alias.", @@ -1029,7 +1029,7 @@ "Please set a password!": "Imposta una password!", "You have successfully set a password!": "Hai impostato una password con successo!", "An error occurred whilst saving your email notification preferences.": "Si è verificato un errore durante il salvataggio delle tue preferenze sulle notifiche email.", - "Explore Room State": "Esplora Stato Stanza", + "Explore Room State": "Esplora stato stanza", "Source URL": "URL d'origine", "Messages sent by bot": "Messaggi inviati dai bot", "Filter results": "Filtra risultati", @@ -1044,7 +1044,7 @@ "Enable notifications for this account": "Abilita le notifiche per questo account", "Directory": "Lista", "Invite to this community": "Invita a questa comunità", - "Failed to get public room list": "Impossibile ottenere la lista delle stanze pubbliche", + "Failed to get public room list": "Impossibile ottenere l'elenco delle stanze pubbliche", "Messages containing keywords": "Messaggi contenenti parole chiave", "Room not found": "Stanza non trovata", "Tuesday": "Martedì", @@ -1053,7 +1053,7 @@ "You have successfully set a password and an email address!": "Hai impostato con successo una password e un indirizzo email!", "Remove %(name)s from the directory?": "Rimuovere %(name)s dalla lista?", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot utilizza molte funzioni avanzate del browser, alcune delle quali non sono disponibili o sono sperimentali nel tuo browser attuale.", - "Developer Tools": "Strumenti per Sviluppatori", + "Developer Tools": "Strumenti per sviluppatori", "Preparing to send logs": "Preparazione invio dei log", "Enable desktop notifications": "Abilita le notifiche desktop", "Remember, you can always set an email address in user settings if you change your mind.": "Ricorda, puoi sempre specificare un indirizzo email nelle impostazioni utente se cambi idea.", @@ -1152,9 +1152,9 @@ "Refresh": "Aggiorna", "We encountered an error trying to restore your previous session.": "Abbiamo riscontrato un errore tentando di ripristinare la tua sessione precedente.", "Send analytics data": "Invia dati statistici", - "Clear Storage and Sign Out": "Elimina lo storage e disconnetti", + "Clear Storage and Sign Out": "Elimina l'archiviazione e disconnetti", "Send Logs": "Invia i log", - "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Eliminare lo storage del browser potrebbe risolvere il problema, ma verrai disconnesso e la cronologia delle chat criptate sarà illeggibile.", + "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Eliminare l'archiviazione del browser potrebbe risolvere il problema, ma verrai disconnesso e la cronologia delle chat criptate sarà illeggibile.", "Collapse Reply Thread": "Riduci finestra di risposta", "e.g. %(exampleValue)s": "es. %(exampleValue)s", "Reload widget": "Ricarica widget", @@ -1183,7 +1183,7 @@ "Bulk Options": "Opzioni applicate in massa", "Encrypting": "Cifratura...", "Encrypted, not sent": "Cifrato, non inviato", - "Share Link to User": "Condividi link con utente", + "Share Link to User": "Condividi link utente", "Share room": "Condividi stanza", "Share Room": "Condividi stanza", "Link to most recent message": "Link al messaggio più recente", @@ -1456,5 +1456,337 @@ "The following users may not exist": "I seguenti utenti potrebbero non esistere", "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Impossibile trovare profili per gli ID Matrix elencati sotto - vuoi comunque invitarli?", "Invite anyway and never warn me again": "Invitali lo stesso e non avvisarmi più", - "Invite anyway": "Invita comunque" + "Invite anyway": "Invita comunque", + "Whether or not you're logged in (we don't record your username)": "Che tu abbia fatto l'accesso o meno (non registriamo il tuo nome utente)", + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Il file '%(fileName)s' supera la dimensione massima di invio su questo homeserver", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Aggiunge ¯\\_(ツ)_/¯ ad un messaggio di testo semplice", + "Upgrades a room to a new version": "Aggiorna una stanza ad una nuova versione", + "Changes your display nickname in the current room only": "Cambia il tuo nick visualizzato solo nella stanza attuale", + "Gets or sets the room topic": "Ottiene o imposta l'argomento della stanza", + "This room has no topic.": "Questa stanza non ha un argomento.", + "Sets the room name": "Imposta il nome della stanza", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s ha aggiornato questa stanza.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s ha reso pubblica la stanza a chiunque conosca il link.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s ha reso la stanza accessibile solo su invito.", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s ha cambiato la regola di accesso a %(rule)s", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s ha attivato l'accesso per ospiti alla stanza.", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s ha disattivato l'accesso per ospiti alla stanza.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s ha cambiato l'accesso per ospiti a %(rule)s", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s ha attivato la predisposizione per %(groups)s in questa stanza.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s ha disattivato la predisposizione per %(groups)s in questa stanza.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s ha attivato la predisposizione per %(newGroups)s e disattivato la predisposizione per %(oldGroups)s in questa stanza.", + "%(displayName)s is typing …": "%(displayName)s sta scrivendo …", + "%(names)s and %(count)s others are typing …|other": "%(names)s e altri %(count)s stanno scrivendo …", + "%(names)s and %(count)s others are typing …|one": "%(names)s ed un altro stanno scrivendo …", + "%(names)s and %(lastPerson)s are typing …": "%(names)s e %(lastPerson)s stanno scrivendo …", + "User %(userId)s is already in the room": "L'utente %(userId)s è già nella stanza", + "The user must be unbanned before they can be invited.": "L'utente non deve essere bandito per essere invitato.", + "Show recent room avatars above the room list (refresh to apply changes)": "Mostra gli avatar recenti della stanza sopra l'elenco delle stanze (ricarica per applicare le modifiche)", + "Group & filter rooms by custom tags (refresh to apply changes)": "Raggruppa e filtra le stanze per etichette personalizzate (ricarica per applicare le modifiche)", + "Render simple counters in room header": "Mostra contatori semplici nell'header della stanza", + "Enable Emoji suggestions while typing": "Attiva suggerimenti Emoji durante la digitazione", + "Show a placeholder for removed messages": "Mostra un segnaposto per i messaggi rimossi", + "Show join/leave messages (invites/kicks/bans unaffected)": "Mostra messaggi di entrata/uscita (non influenza inviti/kick/ban)", + "Show avatar changes": "Mostra i cambi di avatar", + "Show display name changes": "Mostra i cambi di nomi visualizzati", + "Show read receipts sent by other users": "Mostra ricevute di lettura inviate da altri utenti", + "Show avatars in user and room mentions": "Mostra gli avatar nelle citazioni di utenti e stanze", + "Enable big emoji in chat": "Attiva gli emoji grandi in chat", + "Send typing notifications": "Invia notifiche di scrittura", + "Enable Community Filter Panel": "Attiva il pannello dei filtri di comunità", + "Allow Peer-to-Peer for 1:1 calls": "Permetti il peer-to-peer per chiamate 1:1", + "Order rooms in the room list by most important first instead of most recent": "Ordina le stanze nell'elenco per importanza, non per più recente", + "Messages containing my username": "Messaggi contenenti il mio nome utente", + "The other party cancelled the verification.": "L'altra parte ha annullato la verifica.", + "Verified!": "Verificato!", + "You've successfully verified this user.": "Hai verificato correttamente l'utente.", + "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "I messaggi sicuri con questo utente sono criptati end-to-end e non possono essere letti da terze parti.", + "Got It": "Capito", + "Verify this user by confirming the following emoji appear on their screen.": "Verifica questo utente confermando che la seguente emoji appare sul suo schermo.", + "Verify this user by confirming the following number appears on their screen.": "Verifica questo utente confermando che il seguente numero appare sul suo schermo.", + "Unable to find a supported verification method.": "Impossibile trovare un metodo di verifica supportato.", + "For maximum security, we recommend you do this in person or use another trusted means of communication.": "Per la massima sicurezza, ti consigliamo di farlo di persona o di utilizzare un altro mezzo di comunicazione fidato.", + "Dog": "Cane", + "Cat": "Gatto", + "Lion": "Leone", + "Horse": "Cavallo", + "Unicorn": "Unicorno", + "Pig": "Maiale", + "Elephant": "Elefante", + "Rabbit": "Coniglio", + "Panda": "Panda", + "Rooster": "Gallo", + "Penguin": "Pinguino", + "Turtle": "Tartaruga", + "Fish": "Pesce", + "Octopus": "Piovra", + "Butterfly": "Farfalla", + "Flower": "Fiore", + "Tree": "Albero", + "Cactus": "Cactus", + "Mushroom": "Fungo", + "Globe": "Globo", + "Moon": "Luna", + "Cloud": "Nuvola", + "Fire": "Fuoco", + "Banana": "Banana", + "Apple": "Mela", + "Strawberry": "Fragola", + "Corn": "Mais", + "Pizza": "Pizza", + "Cake": "Torta", + "Heart": "Cuore", + "Smiley": "Sorriso", + "Robot": "Robot", + "Hat": "Cappello", + "Glasses": "Occhiali", + "Spanner": "Chiave inglese", + "Santa": "Babbo Natale", + "Thumbs up": "Pollice in su", + "Umbrella": "Ombrello", + "Hourglass": "Clessidra", + "Clock": "Orologio", + "Gift": "Regalo", + "Light bulb": "Lampadina", + "Book": "Libro", + "Pencil": "Matita", + "Paperclip": "Graffetta", + "Scissors": "Forbici", + "Padlock": "Lucchetto", + "Key": "Chiave", + "Hammer": "Martello", + "Telephone": "Telefono", + "Flag": "Bandiera", + "Train": "Treno", + "Bicycle": "Bicicletta", + "Aeroplane": "Aeroplano", + "Rocket": "Razzo", + "Trophy": "Trofeo", + "Ball": "Palla", + "Guitar": "Chitarra", + "Trumpet": "Tromba", + "Bell": "Campana", + "Anchor": "Ancora", + "Headphones": "Auricolari", + "Folder": "Cartella", + "Pin": "Spillo", + "Your homeserver does not support device management.": "Il tuo homeserver non supporta la gestione dei dispositivi.", + "Yes": "Sì", + "No": "No", + "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Ti abbiamo inviato un'email per verificare il tuo indirizzo. Segui le istruzioni contenute e poi clicca il pulsante sotto.", + "Email Address": "Indirizzo email", + "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Sei sicuro? Perderai i tuoi messaggi cifrati se non hai salvato adeguatamente le tue chiavi.", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "I messaggi criptati sono resi sicuri con una cifratura end-to-end. Solo tu e il/i destinatario/i avete le chiavi per leggere questi messaggi.", + "Restore from Backup": "Ripristina da un backup", + "This device is backing up your keys. ": "Questo dispositivo sta facendo una copia delle tue chiavi. ", + "This device is not backing up your keys.": "Questo dispositivo non sta facendo una copia delle tue chiavi.", + "Back up your keys before signing out to avoid losing them.": "Fai una copia delle tue chiavi prima di disconnetterti per evitare di perderle.", + "Use key backup": "Usa backup chiavi", + "Backing up %(sessionsRemaining)s keys...": "Copia di %(sessionsRemaining)s chiavi...", + "All keys backed up": "Tutte le chiavi sono state copiate", + "Backup has a signature from unknown device with ID %(deviceId)s.": "Il backup ha una firma dal dispositivo sconosciuto con ID %(deviceId)s.", + "This backup is trusted because it has been restored on this device": "Questo backup è fidato perchè è stato ripristinato su questo dispositivo", + "Your keys are not being backed up from this device.": "Le tue chiavi non stanno venendo copiate da questo dispositivo.", + "Start using Key Backup": "Inizia ad usare il backup chiavi", + "Add an email address to configure email notifications": "Aggiungi un indirizzo email per configurare le notifiche via email", + "Unable to verify phone number.": "Impossibile verificare il numero di telefono.", + "Verification code": "Codice di verifica", + "Phone Number": "Numero di telefono", + "Profile picture": "Immagine del profilo", + "Upload profile picture": "Invia immagine del profilo", + "Upgrade to your own domain": "Aggiorna ad un tuo dominio personale", + "Display Name": "Nome visualizzato", + "Set a new account password...": "Imposta una nuova password dell'account...", + "Email addresses": "Indirizzi email", + "Phone numbers": "Numeri di telefono", + "Language and region": "Lingua e regione", + "Theme": "Tema", + "Account management": "Gestione account", + "Deactivating your account is a permanent action - be careful!": "La disattivazione dell'account è permanente - attenzione!", + "General": "Generale", + "Credits": "Crediti", + "For help with using Riot, click here.": "Per aiuto su come usare Riot, clicca qui.", + "For help with using Riot, click here or start a chat with our bot using the button below.": "Per aiuto su come usare Riot, clicca qui o inizia una chat con il nostro bot usando il pulsante sotto.", + "Chat with Riot Bot": "Chatta con Riot Bot", + "Help & About": "Aiuto e informazioni", + "Bug reporting": "Segnalazione errori", + "FAQ": "FAQ", + "Versions": "Versioni", + "Close button should minimize window to tray": "Il pulsante di chiusura riduce la finestra nella tray", + "Preferences": "Preferenze", + "Composer": "Compositore", + "Timeline": "Linea temporale", + "Room list": "Elenco stanze", + "Autocomplete delay (ms)": "Ritardo autocompletamento (ms)", + "Ignored users": "Utenti ignorati", + "Bulk options": "Opzioni generali", + "Accept all %(invitedRooms)s invites": "Accetta tutti i %(invitedRooms)s inviti", + "Key backup": "Backup chiave", + "Security & Privacy": "Sicurezza e privacy", + "Missing media permissions, click the button below to request.": "Autorizzazione multimediale mancante, clicca il pulsante sotto per richiederla.", + "Request media permissions": "Richiedi autorizzazioni multimediali", + "Voice & Video": "Voce e video", + "Room information": "Informazioni stanza", + "Internal room ID:": "ID interno stanza:", + "Room version": "Versione stanza", + "Room version:": "Versione stanza:", + "Developer options": "Opzioni sviluppatore", + "Room Addresses": "Indirizzi stanza", + "Change room avatar": "Cambia avatar stanza", + "Change room name": "Modifica nome stanza", + "Change main address for the room": "Modifica indirizzo principale della stanza", + "Change history visibility": "Cambia visibilità cronologia", + "Change permissions": "Cambia autorizzazioni", + "Change topic": "Modifica argomento", + "Modify widgets": "Modifica i widget", + "Default role": "Ruolo predefinito", + "Send messages": "Invia messaggi", + "Invite users": "Invita utenti", + "Change settings": "Modifica impostazioni", + "Kick users": "Butta fuori utenti", + "Ban users": "Bandisci utenti", + "Remove messages": "Rimuovi messaggi", + "Notify everyone": "Notifica tutti", + "Send %(eventType)s events": "Invia eventi %(eventType)s", + "Roles & Permissions": "Ruoli e permessi", + "Select the roles required to change various parts of the room": "Seleziona i ruoli necessari per cambiare varie parti della stanza", + "Enable encryption?": "Attivare la cifratura?", + "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.": "Una volta attivata, la cifratura di una stanza non può essere disattivata. I messaggi inviati in una stanza cifrata non possono essere letti dal server, solo dai partecipanti della stanza. L'attivazione della cifratura può impedire il corretto funzionamento di bot e bridge. Maggiori informazioni sulla cifratura.", + "To link to this room, please add an alias.": "Per creare un collegamento alla stanza, aggiungi un alias.", + "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Le modifiche a chi può leggere la cronologia si applicheranno solo ai messaggi futuri in questa stanza. La visibilità della cronologia esistente rimarrà invariata.", + "Encryption": "Cifratura", + "Once enabled, encryption cannot be disabled.": "Una volta attivata, la cifratura non può essere disattivata.", + "Encrypted": "Cifrato", + "Some devices for this user are not trusted": "Alcuni dispositivi di questo utente non sono fidati", + "Some devices in this encrypted room are not trusted": "Alcuni dispositivi in questa stanza cifrata non sono fidati", + "All devices for this user are trusted": "Tutti i dispositivi di questo utente sono fidati", + "All devices in this encrypted room are trusted": "Tutti i dispositivi in questa stanza cifrata sono fidati", + "Use Key Backup": "Usa backup chiave", + "Never lose encrypted messages": "Non perdere mai i messaggi cifrati", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "I messaggi in questa stanza sono protetti con crittografia end-to-end. Solo tu e i destinatari avete le chiavi per leggere questi messaggi.", + "Securely back up your keys to avoid losing them. Learn more.": "Fai una copia sicura delle chiavi per evitare di perderle. Maggiori informazioni.", + "Not now": "Non ora", + "Don't ask me again": "Non chiedermelo più", + "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "Questa stanza sta usando una versione instabile. Se non è una cosa voluta, ti preghiamo di aggiornare la stanza.", + "Click here to upgrade to the latest room version.": "Clicca qui per aggiornare all'ultima versione della stanza.", + "Error updating main address": "Errore di aggiornamento indirizzo principale", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Si è verificato un errore aggiornando l'indirizzo principale della stanza. Potrebbe non essere permesso dal server o un problema temporaneo.", + "Error creating alias": "Errore creazione alias", + "There was an error creating that alias. It may not be allowed by the server or a temporary failure occurred.": "Si è verificato un errore nella creazione di quell'alias. Potrebbe non essere permesso dal server o si è verificato un errore temporaneo.", + "Error removing alias": "Errore rimozione alias", + "There was an error removing that alias. It may no longer exist or a temporary error occurred.": "Si è verificato un errore nella rimozione di quell'alias. Potrebbe non esistere più o si è verificato un errore temporaneo.", + "Main address": "Indirizzo principale", + "Error updating flair": "Errore aggiornamento predisposizione", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Si è verificato un errore nell'aggiornamento della predisposizione di questa stanza. Potrebbe non essere permesso dal server o si è verificato un errore temporaneo.", + "Room avatar": "Avatar della stanza", + "Upload room avatar": "Invia avatar della stanza", + "No room avatar": "Nessun avatar della stanza", + "Room Name": "Nome stanza", + "Room Topic": "Argomento stanza", + "Join": "Entra", + "Power level": "Livello poteri", + "Use Legacy Verification (for older clients)": "Usa verifica obsoleta (per i vecchi client)", + "Verify by comparing a short text string.": "Verifica confrontando una piccola porzione di testo.", + "Begin Verifying": "Inizia la verifica", + "Waiting for partner to accept...": "In attesa che il partner accetti...", + "Nothing appearing? Not all clients support interactive verification yet. .": "Non compare niente? Non tutti i client supportano ancora la verifica interattiva. .", + "Use two-way text verification": "Usa la verifica testuale bidirezionale", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verifica questo utente per contrassegnarlo come affidabile. La fiducia degli utenti offre una maggiore tranquillità quando si utilizzano messaggi cifrati end-to-end.", + "Verifying this user will mark their device as trusted, and also mark your device as trusted to them.": "La verifica di questo utente contrassegna il suo dispositivo come affidabile a te e viceversa.", + "Waiting for partner to confirm...": "In attesa che il partner confermi...", + "Incoming Verification Request": "Richiesta di verifica in arrivo", + "I don't want my encrypted messages": "Non voglio i miei messaggi cifrati", + "Manually export keys": "Esporta le chiavi manualmente", + "You'll lose access to your encrypted messages": "Perderai l'accesso ai tuoi messaggi cifrati", + "Are you sure you want to sign out?": "Sei sicuro di volerti disconnettere?", + "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Se ti imbatti in qualche errore o hai opinioni che vorresti condividere, faccelo sapere su GitHub.", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Per evitare segnalazioni doppie, prima vedi i problemi esistenti (e aggiungi un +1) o segnala un nuovo problema se non riesci a trovarlo.", + "Report bugs & give feedback": "Segnala errori e dai opinioni", + "Go back": "Torna", + "Room Settings - %(roomName)s": "Impostazioni stanza - %(roomName)s", + "A username can only contain lower case letters, numbers and '=_-./'": "Un nome utente può contenere solo minuscole, numeri e '=_-./'", + "Recovery Key Mismatch": "La chiave di ripristino non corrisponde", + "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Il backup non può essere decifrato con questa chiave: verifica di aver inserito la chiave di ripristino corretta.", + "Incorrect Recovery Passphrase": "Password di recupero sbagliata", + "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Il backup non può essere decifrato con questa password: verifica di aver inserito la password di ripristino corretta.", + "Warning: you should only set up key backup from a trusted computer.": "Attenzione: dovresti impostare il backup chiavi solo da un computer fidato.", + "Share Permalink": "Condividi permalink", + "Update status": "Stato aggiornamento", + "Set status": "Imposta stato", + "Hide": "Nascondi", + "This homeserver would like to make sure you are not a robot.": "Questo homeserver vorrebbe assicurarsi che non sei un robot.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "Puoi usare le opzioni server personalizzate per accedere ad altri server Matrix specificando un URL homeserver diverso. Ciò ti permette di usare questa app con un account Matrix esistente su un homeserver differente.", + "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Puoi anche impostare un server di identità personalizzato, ma non sarai in grado di invitare utenti via email o di essere invitato via email.", + "Your Modular server": "Il tuo server Modular", + "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Inserisci l'indirizzo del tuo homeserver Modular. Potrebbe usare il tuo nome di dominio o essere un sottodominio di modular.im.", + "Server Name": "Nome server", + "The username field must not be blank.": "Il campo nome utente non deve essere vuoto.", + "Username": "Nome utente", + "Not sure of your password? Set a new one": "Non sei sicuro della tua password? Impostane una nuova", + "Sign in to your Matrix account": "Accedi al tuo account Matrix", + "Sign in to your Matrix account on %(serverName)s": "Accedi al tuo account Matrix su %(serverName)s", + "Change": "Cambia", + "Create your Matrix account": "Crea il tuo account Matrix", + "Create your Matrix account on %(serverName)s": "Crea il tuo account Matrix su %(serverName)s", + "Email (optional)": "Email (facoltativa)", + "Phone (optional)": "Telefono (facoltativo)", + "Confirm": "Conferma", + "Use an email address to recover your account. Other users can invite you to rooms using your contact details.": "Usa un indirizzo email per recuperare il tuo account. Altri utenti possono invitarti nelle stanze usando i tuoi dettagli di contatto.", + "Other servers": "Altri server", + "Enter custom server URLs What does this mean?": "Inserisci gli URL dei server personalizzati Cosa significa?", + "Homeserver URL": "URL homeserver", + "Identity Server URL": "URL server identità", + "Free": "Gratuito", + "Join millions for free on the largest public server": "Unisciti gratis a milioni nel più grande server pubblico", + "Premium": "Premium", + "Premium hosting for organisations Learn more": "Hosting premium per organizzazioni Maggior informazioni", + "Other": "Altro", + "Find other public servers or use a custom server": "Trova altri server pubblici o usane uno personale", + "Please install Chrome, Firefox, or Safari for the best experience.": "Ti suggeriamo di installare Chrome, Firefox o Safari per la migliore esperienza.", + "Couldn't load page": "Caricamento pagina fallito", + "Want more than a community? Get your own server": "Vuoi più di una comunità? Ottieni il tuo server personale", + "This homeserver does not support communities": "Questo homeserver non supporta le comunità", + "You are logged in to another account": "Sei connesso con un altro account", + "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Grazie per avere verificato l'email! L'account con cui sei connesso qui (%(sessionUserId)s) sembra essere diverso dall'account che hai verificato per email (%(verifiedUserId)s). Se vuoi accedere con %(verifiedUserId2)s, devi prima disconnetterti.", + "Failed to get protocol list from homeserver": "Ricezione elenco protocolli dall'homeserver fallita", + "The homeserver may be too old to support third party networks": "L'homeserver potrebbe essere troppo vecchio per supportare reti di terze parti", + "Search for a room like #example": "Cerca una stanza come #esempio", + "Guest": "Ospite", + "Could not load user profile": "Impossibile caricare il profilo utente", + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "La modifica della password reimposta qualsiasi chiave di cifratura end-to-end su tutti i dispositivi, rendendo illeggibile la cronologia della chat cifrata. Imposta il backup chiavi o esporta le chiavi della stanza da un altro dispositivo prima di reimpostare la password.", + "Your Matrix account": "Il tuo account Matrix", + "Your Matrix account on %(serverName)s": "Il tuo account Matrix su %(serverName)s", + "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.": "L'URL dell'homeserver %(hsUrl)s non sembra essere un URL valido. Inseriscine uno valido incluso il prefisso del protocollo.", + "A verification email will be sent to your inbox to confirm setting your new password.": "Ti verrà inviata un'email di verifica per confermare la tua nuova password.", + "Sign in instead": "Oppure accedi", + "Your password has been reset.": "La tua password è stata reimpostata.", + "You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Sei stato disconnesso da tutti i dispositivi e non riceverai più notifiche push. Per riattivare le notifiche, accedi di nuovo su ogni dispositivo.", + "Set a new password": "Imposta un nuova password", + "This homeserver does not support login using email address.": "Questo homeserver non supporta l'accesso tramite indirizzo email.", + "Guest access is disabled on this homeserver.": "L'accesso ospite in questo homeserver è disattivato.", + "Create account": "Crea account", + "Registration has been disabled on this homeserver.": "La registrazione è stata disattivata su questo homeserver.", + "Unable to query for supported registration methods.": "Impossibile richiedere i metodi di registrazione supportati.", + "You need to enter a username.": "Devi inserire un nome utente.", + "Create your account": "Crea il tuo account", + "Keep going...": "Continua...", + "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.": "Salveremo una copia cifrata delle tue chiavi sul nostro server. Proteggi il tuo backup con una password per tenerlo al sicuro.", + "For maximum security, this should be different from your account password.": "Per la massima sicurezza, questa dovrebbe essere diversa dalla password del tuo account.", + "Set up with a Recovery Key": "Imposta con una chiave di ripristino", + "Please enter your passphrase a second time to confirm.": "Inserisci la tua password un'altra volta per confermare.", + "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.": "La tua chiave di ripristino è una rete di sicurezza - puoi usarla per recuperare l'accesso ai tuoi messaggi cifrati se dimentichi la tua password.", + "Keep your recovery key somewhere very secure, like a password manager (or a safe)": "Conserva la chiave di ripristino in un luogo molto sicuro, come un password manager (o una cassaforte)", + "Your keys are being backed up (the first backup could take a few minutes).": "Il backup delle chiavi è in corso (il primo backup potrebbe richiedere qualche minuto).", + "Okay": "Okay", + "Secure your backup with a passphrase": "Proteggi il tuo backup con una password", + "Confirm your passphrase": "Conferma la tua password", + "Recovery key": "Chiave di ripristino", + "Starting backup...": "Avvio del backup...", + "Success!": "Completato!", + "A new recovery passphrase and key for Secure Messages have been detected.": "Sono state rilevate una nuova password di ripristino e una chiave per i messaggi sicuri.", + "This device is encrypting history using the new recovery method.": "Questo dispositivo sta criptando la cronologia utilizzando il nuovo metodo di ripristino.", + "Recovery Method Removed": "Metodo di ripristino rimosso", + "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "Questo dispositivo ha rilevato che la password di ripristino e la chiave per i messaggi sicuri sono stati rimossi.", + "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "Se l'hai fatto per sbaglio, è possibile impostare Messaggi Sicuri su questo dispositivo che cripterà nuovamente la cronologia dei messaggi con un nuovo metodo di ripristino.", + "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.": "Se non hai rimosso il metodo di ripristino, è possibile che un aggressore stia cercando di accedere al tuo account. Cambia la password del tuo account e imposta immediatamente un nuovo metodo di recupero nelle impostazioni." } From 133b1340b11237856f3ba0bc7b51ab64fe0d103b Mon Sep 17 00:00:00 2001 From: tea Date: Tue, 19 Mar 2019 19:57:25 +0000 Subject: [PATCH 203/481] Translated using Weblate (Italian) Currently translated at 100.0% (1559 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/it/ --- src/i18n/strings/it.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 8283ce8120..62bfaf181f 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -1247,8 +1247,8 @@ "Update any local room aliases to point to the new room": "Aggiorneremo qualsiasi alias di stanza in modo che punti a quella nuova", "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Eviteremo che gli utenti parlino nella vecchia versione della stanza e posteremo un messaggio avvisando gli utenti di spostarsi in quella nuova", "Put a link back to the old room at the start of the new room so people can see old messages": "Inseriremo un link alla vecchia stanza all'inizio della di quella nuova in modo che la gente possa vedere i messaggi precedenti", - "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Il tuo messaggio non è stato inviato perchè questo homeserver ha raggiunto il suo limite di utenti attivi mensili. Contatta l'amministratore del servizio per continuare ad usarlo.", - "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Il tuo messaggio non è stato inviato perchè questo homeserver ha oltrepassato un limite di risorse. Contatta l'amministratore del servizio per continuare ad usarlo.", + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Il tuo messaggio non è stato inviato perché questo homeserver ha raggiunto il suo limite di utenti attivi mensili. Contatta l'amministratore del servizio per continuare ad usarlo.", + "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Il tuo messaggio non è stato inviato perché questo homeserver ha oltrepassato un limite di risorse. Contatta l'amministratore del servizio per continuare ad usarlo.", "Please contact your service administrator to continue using this service.": "Contatta l'amministratore del servizio per continuare ad usarlo.", "Increase performance by only loading room members on first view": "Aumenta le prestazioni caricando solo i membri della stanza alla prima occhiata", "Sorry, your homeserver is too old to participate in this room.": "Spiacenti, il tuo homeserver è troppo vecchio per partecipare a questa stanza.", @@ -1286,7 +1286,7 @@ "An email address is required to register on this homeserver.": "È necessario un indirizzo email per registrarsi in questo homeserver.", "A phone number is required to register on this homeserver.": "È necessario un numero di telefono per registrarsi in questo homeserver.", "You've previously used Riot 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, Riot needs to resync your account.": "Hai usato Riot precedentemente su %(host)s con il caricamento lento dei membri attivato. In questa versione il caricamento lento è disattivato. Dato che la cache locale non è compatibile tra queste due impostazioni, Riot deve risincronizzare il tuo account.", - "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Se l'altra versione di Riot è ancora aperta in un'altra scheda, chiudila perchè usare Riot nello stesso host con il caricamento lento sia attivato che disattivato può causare errori.", + "If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Se l'altra versione di Riot è ancora aperta in un'altra scheda, chiudila perché usare Riot nello stesso host con il caricamento lento sia attivato che disattivato può causare errori.", "Incompatible local cache": "Cache locale non compatibile", "Clear cache and resync": "Svuota cache e risincronizza", "Please accept all of the policies": "Si prega di accettare tutte le condizioni", From afea41288b3b2c431989464e8a8abfe6ca9b1257 Mon Sep 17 00:00:00 2001 From: csybr Date: Sun, 24 Mar 2019 11:42:01 +0000 Subject: [PATCH 204/481] Translated using Weblate (Norwegian Nynorsk) Currently translated at 67.6% (1054 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/nn/ --- src/i18n/strings/nn.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/nn.json b/src/i18n/strings/nn.json index 7a3f20d20a..df165c3422 100644 --- a/src/i18n/strings/nn.json +++ b/src/i18n/strings/nn.json @@ -172,7 +172,7 @@ "(not supported by this browser)": "(ikkje støtta av denne nettlesaren)", "%(senderName)s answered the call.": "%(senderName)s tok røret.", "(could not connect media)": "(klarte ikkje å kopla media saman)", - "(no answer)": "(inkje svar)", + "(no answer)": "(ingen svar)", "(unknown failure: %(reason)s)": "(ukjend mislukking: %(reason)s)", "%(senderName)s ended the call.": "%(senderName)s enda samtala.", "%(senderName)s placed a %(callType)s call.": "%(senderName)s starta ei %(callType)s-samtale.", @@ -257,7 +257,7 @@ "Add": "Legg til", "Failed to upload profile picture!": "Fekk ikkje til å lasta opp profilbilete!", "Upload new:": "Last opp ny:", - "No display name": "Inkje visingsnamn", + "No display name": "Ingen visingsnamn", "New passwords don't match": "Dei nye passorda samsvarar ikkje", "Passwords can't be empty": "Passordsfelta kan ikkje vera tomme", "Warning!": "Åtvaring!", @@ -422,7 +422,7 @@ "Seen by %(userName)s at %(dateTime)s": "%(userName)s såg dette %(dateTime)s", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "%(displayName)s %(userName)s såg dette %(dateTime)s", "Replying": "Svarar", - "No rooms to show": "Inkje rom å visa", + "No rooms to show": "Ingen rom å visa", "Unnamed room": "Rom utan namn", "Guests can join": "Gjester kan koma inn", "Failed to set avatar.": "Fekk ikkje til å setja avatar.", From daa79940be0a84c68a27c9e2db6b87b286dddd06 Mon Sep 17 00:00:00 2001 From: Karol Kosek Date: Sat, 23 Mar 2019 20:38:27 +0000 Subject: [PATCH 205/481] Translated using Weblate (Polish) Currently translated at 73.3% (1144 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/pl/ --- src/i18n/strings/pl.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index d7b255919f..840595c5f7 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -1335,5 +1335,7 @@ "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s zaktualizował(a) ten pokój.", "Show display name changes": "Pokaż zmiany wyświetlanej nazwy", "Show read receipts": "Wyświetl potwierdzenia odczytu", - "Send typing notifications": "Wyślij powiadomienia o pisaniu" + "Send typing notifications": "Wyślij powiadomienia o pisaniu", + "I don't want my encrypted messages": "Nie chcę moich zaszyfrowanych wiadomości", + "You'll lose access to your encrypted messages": "Utracisz dostęp do zaszyfrowanych wiadomości" } From 383f5eaa3fb38746029947617863515be5053580 Mon Sep 17 00:00:00 2001 From: sergio Date: Thu, 28 Mar 2019 22:03:55 +0000 Subject: [PATCH 206/481] Translated using Weblate (Russian) Currently translated at 88.0% (1373 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/ru/ --- src/i18n/strings/ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 38a7fbf115..17dfb1e989 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -165,7 +165,7 @@ "%(displayName)s is typing": "%(displayName)s печатает", "%(targetName)s joined the room.": "%(targetName)s вошел(-ла) в комнату.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s выгнал(а) %(targetName)s.", - "%(targetName)s left the room.": "Комнату покидает %(targetName)s.", + "%(targetName)s left the room.": "%(targetName)s покинул комнату.", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s сделал(а) историю разговора видимой для всех собеседников с момента их приглашения.", "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s сделал(а) историю разговора видимой для всех собеседников с момента их входа в комнату.", "%(senderName)s made future room history visible to all room members.": "%(senderName)s сделал(а) историю разговора видимой для всех собеседников.", From d7ee49e13e85e784bc04cc82fc7213dd2f3b7607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 26 Mar 2019 10:57:11 +0000 Subject: [PATCH 207/481] Translated using Weblate (Slovak) Currently translated at 96.6% (1507 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 1c7d00fd68..7a046d13cc 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -753,7 +753,7 @@ "User Interface": "Používateľské rozhranie", "Autocomplete Delay (ms):": "Oneskorenie automatického dokončovania (ms):", "": "", - "Import E2E room keys": "Importovať E2E kľúče miestností", + "Import E2E room keys": "Importovať E2E šifrovacie kľúče miestností", "Cryptography": "Kryptografia", "Device ID:": "ID zariadenia:", "Device key:": "Kľúč zariadenia:", @@ -1192,7 +1192,7 @@ "Link to selected message": "Odkaz na vybratú správu", "COPY": "Kopírovať", "Share Message": "Zdieľať správu", - "No Audio Outputs detected": "Neboli rozpoznané žiadne zvukové výstupy", + "No Audio Outputs detected": "Neboli rozpoznané žiadne zariadenia pre výstup zvuku", "Audio Output": "Výstup zvuku", "Try the app first": "Vyskúšať si aplikáciu", "Share Room Message": "Zdieľať správu z miestnosti", @@ -1710,7 +1710,7 @@ "Hide": "Skryť", "This homeserver would like to make sure you are not a robot.": "Tento domovský server by sa rád uistil, že nie ste robot.", "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use this app with an existing Matrix account on a different homeserver.": "Vlastné nastavenia servera môžete použiť na pripojenie k inému domovskému serveru Matrix zadaním URL adresy. Umožní vám to prihlásiť sa cez túto aplikáciu k existujúcemu Matrix účtu na inom domovskom servery.", - "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Môžete tiež nastaviť vlastnú adresu servera totožností, potom ale nebudete môcť pozývať používateľov zadaním ich emailovej adresy a ani oni nebudú môcť pozývať vás zadaním vašej emailovej adresy.", + "You can also set a custom identity server, but you won't be able to invite users by email address, or be invited by email address yourself.": "Môžete tiež nastaviť vlastnú URL adresu servera totožností, potom ale nebudete môcť pozývať používateľov zadaním ich emailovej adresy a telefónneho čísla a ani ostatní nebudú môcť pozvať vás zadaním vašej emailovej adresy a telefónneho čísla.", "Your Modular server": "Váš server Modular", "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of modular.im.": "Zadajte umiestnenie vášho domovského servera modular. Môže to byť buď vaša doména alebo subdoména modular.im.", "Server Name": "Názov servera", @@ -1770,7 +1770,7 @@ "Please enter your passphrase a second time to confirm.": "Prosím zadajte heslo obnovenia ešte raz pre potvrdenie.", "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.": "Kľúč obnovenia je bezpečnostný mechanizmus - môžete ho použiť na prístup k šifrovacím kľúčom v prípade, ak zabudnete vaše heslo obnovenia.", "Keep your recovery key somewhere very secure, like a password manager (or a safe)": "Kľúč obnovenia si bezpečne uchovajte, použite napr. správcu hesiel (alebo ho schovajte v trezore)", - "Your keys are being backed up (the first backup could take a few minutes).": "Zálohovanie kľúčov (prvé zálohovanie môže trvať niekoľko minút).", + "Your keys are being backed up (the first backup could take a few minutes).": "Zálohovanie kľúčov máte aktívne (prvé zálohovanie môže trvať niekoľko minút).", "Okay": "OK", "Secure your backup with a passphrase": "Zabezpečte si zálohu zadaním hesla obnovenia", "Confirm your passphrase": "Potvrdiť heslo obnovenia", From a8f9e92196c54a985b7a6133d90f0013de2bc8ba Mon Sep 17 00:00:00 2001 From: Kenneth Larsson Date: Thu, 21 Mar 2019 21:23:47 +0000 Subject: [PATCH 208/481] Translated using Weblate (Swedish) Currently translated at 81.0% (1264 of 1559 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/sv/ --- src/i18n/strings/sv.json | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index d07d66e022..ddb3361a85 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -1505,5 +1505,59 @@ "You need to enter a username.": "Du måste ange ett användarnamn.", "Create your account": "Skapa ditt konto", "Retry": "Försök igen", - "Don't ask again": "Fråga inte igen" + "Don't ask again": "Fråga inte igen", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Lägger till ¯\\_(ツ)_/¯ i början på ett textmeddelande", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s begränsade rummet till endast inbjudna.", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s aktiverade emblem för %(groups)s i detta rum.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s inaktiverade emblem för %(groups)s i detta rum.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s aktiverade emblem för %(newGroups)s och inaktiverade emblem för %(oldGroups)s i detta rum.", + "User %(userId)s is already in the room": "Användare %(userId)s är redan i rummet", + "The user must be unbanned before they can be invited.": "Användare behöver avbannas innan de kan bjudas in.", + "Show recent room avatars above the room list (refresh to apply changes)": "Visa senaste avatarer över rumslistan (ladda om för att visa ändringar)", + "Group & filter rooms by custom tags (refresh to apply changes)": "Gruppera och filtrera rum med anpassade taggar (ladda om för att visa ändringar)", + "Render simple counters in room header": "Rendera enkla räknare i rumsrubriken", + "Order rooms in the room list by most important first instead of most recent": "Ordna rum i rumslistan med viktigaste först i stället för senaste", + "Yes": "Ja", + "No": "Nej", + "Missing media permissions, click the button below to request.": "Saknar mediebehörigheter, klicka på knappen nedan för att begära.", + "Request media permissions": "Begär mediebehörigheter", + "Change room avatar": "Ändra rumsavatar", + "Change room name": "Ändra rumsnamn", + "Change main address for the room": "Ändra huvudadress för rummet", + "Change history visibility": "Ändra synlighet för historik", + "Change permissions": "Ändra behörigheter", + "Change topic": "Ändra ämne", + "Modify widgets": "Ändra widgets", + "Default role": "Standardroll", + "Send messages": "Skicka meddelanden", + "Invite users": "Bjud in användare", + "Change settings": "Ändra inställningar", + "Kick users": "Kicka användare", + "Ban users": "Banna användare", + "Remove messages": "Ta bort meddelanden", + "Notify everyone": "Meddela alla", + "Send %(eventType)s events": "Skicka %(eventType)s-händelser", + "Roles & Permissions": "Roller och behörigheter", + "Enable encryption?": "Aktivera kryptering?", + "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.": "När det är aktiverat kan kryptering för ett rum inte inaktiveras. Meddelanden som skickas i ett krypterat rum kan inte ses av servern, utan endast av deltagarna i rummet. Att aktivera kryptering kan förhindra att många botar och bryggor att fungera korrekt. Läs mer om kryptering.", + "To link to this room, please add an alias.": "För att länka detta rum, lägg till ett alias.", + "Encryption": "Kryptering", + "Once enabled, encryption cannot be disabled.": "Efter aktivering kan kryptering inte inaktiveras igen.", + "Encrypted": "Krypterat", + "Some devices for this user are not trusted": "Vissa enheter för den här användaren är inte betrodda", + "Some devices in this encrypted room are not trusted": "Vissa enheter i det här krypterade rummet är inte betrodda", + "All devices for this user are trusted": "Alla enheter för den här användaren är betrodda", + "All devices in this encrypted room are trusted": "Alla enheter i det här krypterade rummet är betrodda", + "The following files cannot be uploaded:": "Följande filer kan inte laddas upp:", + "Not now": "Inte nu", + "Don't ask me again": "Fråga mig inte igen", + "Error updating main address": "Ett fel uppstod vid uppdatering av huvudadress", + "Room avatar": "Rumsavatar", + "Upload room avatar": "Ladda upp rumsavatar", + "No room avatar": "Ingen rumsavatar", + "Room Name": "Rumsnamn", + "Room Topic": "Rumsämne", + "The following users may not exist": "Följande användare kanske inte existerar", + "Invite anyway and never warn me again": "Bjud in ändå och varna mig aldrig igen", + "Invite anyway": "Bjud in ändå" } From 582141941f6b50b8450d43dd7dbdb35a97c1171e Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 11:01:50 +0000 Subject: [PATCH 209/481] Deleted translation using Weblate (English (United Kingdom)) --- src/i18n/strings/en_GB.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/i18n/strings/en_GB.json diff --git a/src/i18n/strings/en_GB.json b/src/i18n/strings/en_GB.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/src/i18n/strings/en_GB.json +++ /dev/null @@ -1 +0,0 @@ -{} From 7ca17f9eff00103600fdb57936f75bcaa6d82ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Mon, 1 Apr 2019 11:40:11 +0000 Subject: [PATCH 210/481] Translated using Weblate (French) Currently translated at 99.2% (1570 of 1582 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index b5d50c34d7..5b399e91d7 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1833,5 +1833,32 @@ "You are logged in to another account": "Vous êtes connecté(e) avec un autre compte", "Thank you for verifying your email! The account you're logged into here (%(sessionUserId)s) appears to be different from the account you've verified an email for (%(verifiedUserId)s). If you would like to log in to %(verifiedUserId2)s, please log out first.": "Merci de vérifier votre adresse e-mail ! Le compte avec lequel vous êtes connecté (%(sessionUserId)s) est différent du compte que vous avez vérifié avec cette adresse e-mail (%(verifiedUserId)s). Si vous souhaitez vous connecter avec %(verifiedUserId2)s, veuillez vous déconnecter d’abord.", "Please install Chrome, Firefox, or Safari for the best experience.": "Veuillez installer Chrome, Firefox ou Safari pour une expérience optimale.", - "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Le changement de votre mot de passe entraînera la réinitialisation de toutes les clés de chiffrement de bout en bout sur tous vos appareils. L’historique de vos conversations chiffrées sera alors illisible. Configurez la sauvegarde des clés ou exportez vos clés de chiffrement depuis un autre appareil avant de modifier votre mot de passe." + "Changing your password will reset any end-to-end encryption keys on all of your devices, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another device before resetting your password.": "Le changement de votre mot de passe entraînera la réinitialisation de toutes les clés de chiffrement de bout en bout sur tous vos appareils. L’historique de vos conversations chiffrées sera alors illisible. Configurez la sauvegarde des clés ou exportez vos clés de chiffrement depuis un autre appareil avant de modifier votre mot de passe.", + "Room upgrade confirmation": "Confirmation de la mise à niveau du salon", + "Upgrading a room can be destructive and isn't always necessary.": "La mise à niveau d’un salon peut être destructive et n’est pas toujours nécessaire.", + "Room upgrades are usually recommended when a room version is considered unstable. Unstable room versions might have bugs, missing features, or security vulnerabilities.": "Les mises à niveau de salon sont généralement recommandées quand la version du salon est considérée comme instable. Les versions de salon instables peuvent produire des anomalies, avoir des fonctionnalités en moins ou contenir des failles de sécurité.", + "Room upgrades usually only affect server-side processing of the room. If you're having problems with your Riot client, please file an issue with .": "Les mises à niveau de salon n’affectent généralement que le traitement par le serveur du salon. Si vous avez un problème avec votre client Riot, créez un rapport avec .", + "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Attention : La mise à niveau du salon ne migrera pas automatiquement les membres du salon vers la nouvelle version du salon. Nous enverrons un lien vers le nouveau salon dans l’ancienne version du salon. Les participants au salon devront cliquer sur ce lien pour rejoindre le nouveau salon.", + "Please confirm that you'd like to go forward with upgrading this room from to ": "Veuillez confirmer la mise à niveau de ce salon depuis vers ", + "Upgrade": "Mise à niveau", + "Adds a custom widget by URL to the room": "Ajoute un widget personnalisé par URL au salon", + "Please supply a https:// or http:// widget URL": "Veuillez fournir une URL du widget en https:// ou http://", + "You cannot modify widgets in this room.": "Vous ne pouvez pas modifier les widgets de ce salon.", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s a révoqué l’invitation de %(targetDisplayName)s à rejoindre le salon.", + "Enable desktop notifications for this device": "Activer les notifications de bureau pour cet appareil", + "Enable audible notifications for this device": "Activer les notifications sonores pour cet appareil", + "Upgrade this room to the recommended room version": "Mettre à niveau ce salon vers la version recommandée", + "This room is running room version , which this homeserver has marked as unstable.": "Ce salon utilise la version , que ce serveur d’accueil a marqué comme instable.", + "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "La mise à niveau du salon désactivera cette instance du salon et créera un salon mis à niveau avec le même nom.", + "Failed to revoke invite": "Échec de la révocation de l’invitation", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Impossible de révoquer l’invitation. Le serveur subi peut-être un problème temporaire ou vous n’avez pas la permission de révoquer l’invitation.", + "Revoke invite": "Révoquer l’invitation", + "Invited by %(sender)s": "Invité par %(sender)s", + "Maximize apps": "Maximiser les applications", + "Error showing you your room": "Erreur lors de l’affichage de votre salon", + "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit the issue.": "Riot a rencontré un problème qui rend l’affichage de vos messages difficile pour le moment. Rien n’est perdu et recharger l’application devrait résoudre ce problème. Pour nous aider à repérer le problème, nous aimerions avoir accès à vos journaux d’anomalies. Vous n’avez pas besoin de les envoyer si vous ne le souhaitez pas, mais nous vous serons reconnaissants si vous le faites. Nous voudrions également nous excuser d’avoir dû vous montrer ce message. Nous espérons que vous journaux d’anomalies sont la clé nous permettant de résoudre ce problème définitivement. Si vous voulez plus d’informations sur cette anomalie, veuillez en visiter le rapport.", + "Send debug logs and reload Riot": "Envoyer les journaux d’anomalies et recharger Riot", + "Reload Riot without sending logs": "Recharger Riot sans envoyer les journaux", + "A widget would like to verify your identity": "Un widget voudrait vérifier votre identité", + "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.": "Un widget provenant de %(widgetUrl)s souhaite vérifier votre identité. Si vous acceptez cela, le widget pourra vérifier votre identifiant d’utilisateur mais il ne pourra rien faire en se faisant passer pour vous." } From 232d0468be2e96378256a47fe2d8ec0926c8bf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Mon, 1 Apr 2019 12:11:32 +0000 Subject: [PATCH 211/481] Translated using Weblate (French) Currently translated at 99.2% (1570 of 1582 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 5b399e91d7..89a77edd1d 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1860,5 +1860,6 @@ "Send debug logs and reload Riot": "Envoyer les journaux d’anomalies et recharger Riot", "Reload Riot without sending logs": "Recharger Riot sans envoyer les journaux", "A widget would like to verify your identity": "Un widget voudrait vérifier votre identité", - "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.": "Un widget provenant de %(widgetUrl)s souhaite vérifier votre identité. Si vous acceptez cela, le widget pourra vérifier votre identifiant d’utilisateur mais il ne pourra rien faire en se faisant passer pour vous." + "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.": "Un widget provenant de %(widgetUrl)s souhaite vérifier votre identité. Si vous acceptez cela, le widget pourra vérifier votre identifiant d’utilisateur mais il ne pourra rien faire en se faisant passer pour vous.", + "Remember my selection for this widget": "Se souvenir de mon choix pour ce widget" } From 4e81a99aa4f022a4dfe85c58a7a1003cd1118be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Mon, 1 Apr 2019 12:12:38 +0000 Subject: [PATCH 212/481] Translated using Weblate (French) Currently translated at 99.6% (1576 of 1582 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 89a77edd1d..7e70583a36 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1861,5 +1861,7 @@ "Reload Riot without sending logs": "Recharger Riot sans envoyer les journaux", "A widget would like to verify your identity": "Un widget voudrait vérifier votre identité", "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.": "Un widget provenant de %(widgetUrl)s souhaite vérifier votre identité. Si vous acceptez cela, le widget pourra vérifier votre identifiant d’utilisateur mais il ne pourra rien faire en se faisant passer pour vous.", - "Remember my selection for this widget": "Se souvenir de mon choix pour ce widget" + "Remember my selection for this widget": "Se souvenir de mon choix pour ce widget", + "Deny": "Refuser", + "Riot failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "Riot n’a pas pu récupérer la liste des protocoles depuis le serveur d’accueil. Ce serveur d’accueil est peut-être trop vieux pour prendre en charge les réseaux tiers." } From 8c05da6b72169c7fef70637c741d7c7e6cd967f5 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 1 Apr 2019 12:18:17 +0000 Subject: [PATCH 213/481] remove empty translation --- src/i18n/strings/sq.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index d87f370a2a..2b2aa862ec 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -1633,7 +1633,6 @@ "Robot": "Robot", "Hat": "Kapë", "Glasses": "Syze", - "Spanner": "", "Umbrella": "Ombrellë", "Clock": "Sahat", "Gift": "Dhuratë", From 5e423505381f06f36d61812a5aebae4c4fb23f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Mon, 1 Apr 2019 12:16:57 +0000 Subject: [PATCH 214/481] Translated using Weblate (French) Currently translated at 99.1% (1569 of 1582 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: http://translate.riot.im/projects/riot-web/matrix-react-sdk/fr/ --- src/i18n/strings/fr.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 7e70583a36..32bcc981fb 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -1863,5 +1863,9 @@ "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.": "Un widget provenant de %(widgetUrl)s souhaite vérifier votre identité. Si vous acceptez cela, le widget pourra vérifier votre identifiant d’utilisateur mais il ne pourra rien faire en se faisant passer pour vous.", "Remember my selection for this widget": "Se souvenir de mon choix pour ce widget", "Deny": "Refuser", - "Riot failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "Riot n’a pas pu récupérer la liste des protocoles depuis le serveur d’accueil. Ce serveur d’accueil est peut-être trop vieux pour prendre en charge les réseaux tiers." + "Riot failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "Riot n’a pas pu récupérer la liste des protocoles depuis le serveur d’accueil. Ce serveur d’accueil est peut-être trop vieux pour prendre en charge les réseaux tiers.", + "Riot failed to get the public room list.": "Riot n’a pas pu récupérer la liste des salons publics.", + "The homeserver may be unavailable or overloaded.": "Le serveur d’accueil est peut-être indisponible ou surchargé.", + "You have %(count)s unread notifications in a prior version of this room.|other": "Vous avez %(count)s notifications non lues dans une version précédente de ce salon.", + "You have %(count)s unread notifications in a prior version of this room.|one": "Vous avez %(count)s notification non lue dans une version précédente de ce salon." } From 6cde0eb1b25eebd089b6941a3ad40933541614c7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 13:38:06 +0100 Subject: [PATCH 215/481] released js-sdk --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a5175a9034..03136b18bb 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "^1.0.3-rc.1", + "matrix-js-sdk": "1.0.3", "optimist": "^0.6.1", "pako": "^1.0.5", "prop-types": "^15.5.8", diff --git a/yarn.lock b/yarn.lock index 5dff5cbae0..d1bed804e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4371,10 +4371,10 @@ math-random@^1.0.1: resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== -matrix-js-sdk@^1.0.3-rc.1: - version "1.0.3-rc.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-1.0.3-rc.1.tgz#61dea7fc2efd6f0a23e709443b4ac6a276890e9a" - integrity sha512-31aFwoAR9AIWhqHgJCYplXVFbaykXydm7GBvM/ffCjzN5OgAQEzUqwX18PfWKHVZHqijtj2VZOqnBVsXLX0w6Q== +matrix-js-sdk@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-1.0.3.tgz#d4cc46c4dc80278b78f8e0664741b08fcc395c79" + integrity sha512-YpF4NvnG2cttRmTPJ9yqs/KwlBXW15O7+nNMs1FKj1CqdW1Phwb0fcqvahjPgmfXyn5DFzU3Deiv9aNgDIlIog== dependencies: another-json "^0.2.0" babel-runtime "^6.26.0" From 9cba85e3f4bc57cb5b333161a3ea26a6b46d728f Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 13:43:48 +0100 Subject: [PATCH 216/481] Prepare changelog for v1.0.6 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a683d6e33..ef08c15a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +Changes in [1.0.6](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.6) (2019-04-01) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.6-rc.1...v1.0.6) + + * Handle storage fallback cases in consistency check + [\#2853](https://github.com/matrix-org/matrix-react-sdk/pull/2853) + * Set title attribute on images in lightbox + [\#2852](https://github.com/matrix-org/matrix-react-sdk/pull/2852) + * Download PDFs as blobs to avoid empty grey screens + [\#2851](https://github.com/matrix-org/matrix-react-sdk/pull/2851) + * Add MemberInfo for 3pid invites and support revoking those invites + [\#2850](https://github.com/matrix-org/matrix-react-sdk/pull/2850) + Changes in [1.0.6-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.0.6-rc.1) (2019-03-27) ============================================================================================================= [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.0.5...v1.0.6-rc.1) From 33f2401e63038e4f65d8c1e37d39c6ccd5d8fc1c Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 13:43:49 +0100 Subject: [PATCH 217/481] v1.0.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 03136b18bb..cb26a18eeb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "1.0.6-rc.1", + "version": "1.0.6", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 5b2cee2fc18cc59a92cea6b2a60ad43ae5117a7f Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 16:42:41 +0100 Subject: [PATCH 218/481] Implement redesigned upload confirmation screens Also fairly significant refactor of the uploading code: there are a number of different ways of triggerring a file upload and each went through a different code path (the media config size limit worked on one of those paths). Basically take a lot of code out of the views and put it into ContentMessages. Sorry about the size of this patch. https://github.com/vector-im/riot-web/issues/7565 --- .eslintignore.errorfiles | 1 - res/css/_components.scss | 1 + .../views/dialogs/_UploadConfirmDialog.scss | 33 ++++ src/ContentMessages.js | 164 +++++++++++++++--- src/components/structures/RoomView.js | 86 +-------- src/components/structures/UploadBar.js | 4 +- .../views/dialogs/UploadConfirmDialog.js | 106 +++++++++++ .../views/dialogs/UploadFailureDialog.js | 120 +++++++++++++ src/components/views/rooms/MessageComposer.js | 105 ++--------- .../views/rooms/MessageComposerInput.js | 9 +- src/i18n/strings/en_EN.json | 25 +-- 11 files changed, 452 insertions(+), 202 deletions(-) create mode 100644 res/css/views/dialogs/_UploadConfirmDialog.scss create mode 100644 src/components/views/dialogs/UploadConfirmDialog.js create mode 100644 src/components/views/dialogs/UploadFailureDialog.js diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index c7d5804d66..6d1874b872 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -52,7 +52,6 @@ src/components/views/settings/ChangePassword.js src/components/views/settings/DevicesPanel.js src/components/views/settings/IntegrationsManager.js src/components/views/settings/Notifications.js -src/ContentMessages.js src/GroupAddressPicker.js src/HtmlUtils.js src/ImageUtils.js diff --git a/res/css/_components.scss b/res/css/_components.scss index ec8476ee63..b7d0c7a2a5 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -70,6 +70,7 @@ @import "./views/dialogs/_SettingsDialog.scss"; @import "./views/dialogs/_ShareDialog.scss"; @import "./views/dialogs/_UnknownDeviceDialog.scss"; +@import "./views/dialogs/_UploadConfirmDialog.scss"; @import "./views/dialogs/_UserSettingsDialog.scss"; @import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss"; @import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss"; diff --git a/res/css/views/dialogs/_UploadConfirmDialog.scss b/res/css/views/dialogs/_UploadConfirmDialog.scss new file mode 100644 index 0000000000..116be798e3 --- /dev/null +++ b/res/css/views/dialogs/_UploadConfirmDialog.scss @@ -0,0 +1,33 @@ +/* +Copyright 2019 New Vector 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. +*/ + +.mx_UploadConfirmDialog_fileIcon { + margin-right: 5px; +} + +.mx_UploadConfirmDialog_previewOuter { + text-align: center; +} + +.mx_UploadConfirmDialog_previewInner { + display: inline-block; + text-align: left; +} + +.mx_UploadConfirmDialog_imagePreview { + max-height: 300px; + max-width: 100%; +} diff --git a/src/ContentMessages.js b/src/ContentMessages.js index a319118121..426a707f65 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,17 +18,18 @@ limitations under the License. 'use strict'; import Promise from 'bluebird'; -const extend = require('./extend'); -const dis = require('./dispatcher'); -const MatrixClientPeg = require('./MatrixClientPeg'); -const sdk = require('./index'); +import extend from './extend'; +import dis from './dispatcher'; +import MatrixClientPeg from './MatrixClientPeg'; +import sdk from './index'; import { _t } from './languageHandler'; -const Modal = require('./Modal'); +import Modal from './Modal'; +import RoomViewStore from './stores/RoomViewStore'; -const encrypt = require("browser-encrypt-attachment"); +import encrypt from "browser-encrypt-attachment"; // Polyfill for Canvas.toBlob API using Canvas.toDataURL -require("blueimp-canvas-to-blob"); +import "blueimp-canvas-to-blob"; const MAX_WIDTH = 800; const MAX_HEIGHT = 600; @@ -91,7 +93,7 @@ function createThumbnail(element, inputWidth, inputHeight, mimeType) { /** * Load a file into a newly created image element. * - * @param {File} file The file to load in an image element. + * @param {File} imageFile The file to load in an image element. * @return {Promise} A promise that resolves with the html image element. */ function loadImageElement(imageFile) { @@ -119,7 +121,7 @@ function loadImageElement(imageFile) { * * @param {MatrixClient} matrixClient A matrixClient to upload the thumbnail with. * @param {String} roomId The ID of the room the image will be uploaded in. - * @param {File} The image to read and thumbnail. + * @param {File} imageFile The image to read and thumbnail. * @return {Promise} A promise that resolves with the attachment info. */ function infoForImageFile(matrixClient, roomId, imageFile) { @@ -144,7 +146,7 @@ function infoForImageFile(matrixClient, roomId, imageFile) { /** * Load a file into a newly created video element. * - * @param {File} file The file to load in an video element. + * @param {File} videoFile The file to load in an video element. * @return {Promise} A promise that resolves with the video image element. */ function loadVideoElement(videoFile) { @@ -179,7 +181,7 @@ function loadVideoElement(videoFile) { * * @param {MatrixClient} matrixClient A matrixClient to upload the thumbnail with. * @param {String} roomId The ID of the room the video will be uploaded to. - * @param {File} The video to read and thumbnail. + * @param {File} videoFile The video to read and thumbnail. * @return {Promise} A promise that resolves with the attachment info. */ function infoForVideoFile(matrixClient, roomId, videoFile) { @@ -200,6 +202,7 @@ function infoForVideoFile(matrixClient, roomId, videoFile) { /** * Read the file as an ArrayBuffer. + * @param {File} file The file to read * @return {Promise} A promise that resolves with an ArrayBuffer when the file * is read. */ @@ -269,11 +272,43 @@ function uploadFile(matrixClient, roomId, file, progressHandler) { } } - -class ContentMessages { +export default class ContentMessages { constructor() { this.inprogress = []; this.nextId = 0; + this._mediaConfig = null; + } + + static sharedInstance() { + if (global.mx_ContentMessages === undefined) { + global.mx_ContentMessages = new ContentMessages(); + } + return global.mx_ContentMessages; + } + + _isFileSizeAcceptable(file) { + if (this._mediaConfig !== null && + this._mediaConfig["m.upload.size"] !== undefined && + file.size > this._mediaConfig["m.upload.size"]) { + return false; + } + return true; + } + + _ensureMediaConfigFetched() { + if (this._mediaConfig !== null) return; + + console.log("[Media Config] Fetching"); + return MatrixClientPeg.get().getMediaConfig().then((config) => { + console.log("[Media Config] Fetched config:", config); + return config; + }).catch(() => { + // Media repo can't or won't report limits, so provide an empty object (no limits). + console.log("[Media Config] Could not fetch config, so not limiting uploads."); + return {}; + }).then((config) => { + this._mediaConfig = config; + }); } sendStickerContentToRoom(url, roomId, info, text, matrixClient) { @@ -283,7 +318,88 @@ class ContentMessages { }); } - sendContentToRoom(file, roomId, matrixClient) { + getUploadLimit() { + if (this._mediaConfig !== null && this._mediaConfig["m.upload.size"] !== undefined) { + return this._mediaConfig["m.upload.size"]; + } + } + + async sendContentListToRoom(files, roomId, matrixClient) { + if (matrixClient.isGuest()) { + dis.dispatch({action: 'require_registration'}); + return; + } + + const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); + if (isQuoting) { + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const shouldUpload = await new Promise((resolve) => { + Modal.createTrackedDialog('Upload Reply Warning', '', QuestionDialog, { + title: _t('Replying With Files'), + description: ( +
      {_t( + 'At this time it is not possible to reply with a file ' + + 'so this will be sent without being a reply.', + )}
      + ), + hasCancelButton: true, + button: _t("Continue"), + onFinished: (shouldUpload) => { + resolve(shouldUpload); + }, + }); + }); + if (!shouldUpload) return; + } + + await this._ensureMediaConfigFetched(); + + const tooBigFiles = []; + const okFiles = []; + + for (let i = 0; i < files.length; ++i) { + if (this._isFileSizeAcceptable(files[i])) { + okFiles.push(files[i]); + } else { + tooBigFiles.push(files[i]); + } + } + + if (tooBigFiles.length > 0) { + const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog"); + const uploadFailureDialogPromise = new Promise((resolve) => { + Modal.createTrackedDialog('Upload Failure', '', UploadFailureDialog, { + badFiles: tooBigFiles, + totalFiles: files.length, + contentMessages: this, + onFinished: (shouldContinue) => { + resolve(shouldContinue); + }, + }); + }); + const shouldContinue = await uploadFailureDialogPromise; + if (!shouldContinue) return; + } + + const UploadConfirmDialog = sdk.getComponent("dialogs.UploadConfirmDialog"); + for (let i = 0; i < okFiles.length; ++i) { + const file = okFiles[i]; + const shouldContinue = await new Promise((resolve) => { + Modal.createTrackedDialog('Upload Files confirmation', '', UploadConfirmDialog, { + file, + currentIndex: i, + totalFiles: okFiles.length, + onFinished: (shouldContinue) => { + resolve(shouldContinue); + }, + }); + }); + if (!shouldContinue) break; + this._sendContentToRoom(file, roomId, matrixClient); + } + } + + _sendContentToRoom(file, roomId, matrixClient) { const content = { body: file.name || 'Attachment', info: { @@ -357,9 +473,12 @@ class ContentMessages { }, function(err) { error = err; if (!upload.canceled) { - let desc = _t('The file \'%(fileName)s\' failed to upload', {fileName: upload.fileName}) + '.'; + let desc = _t("The file '%(fileName)s' failed to upload.", {fileName: upload.fileName}); if (err.http_status == 413) { - desc = _t('The file \'%(fileName)s\' exceeds this homeserver\'s size limit for uploads', {fileName: upload.fileName}); + desc = _t( + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads", + {fileName: upload.fileName}, + ); } const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Upload failed', '', ErrorDialog, { @@ -377,9 +496,16 @@ class ContentMessages { } } if (error) { + // 413: File was too big or upset the server in some way: + // clear the media size limit so we fetch it again next time + // we try to upload + if (error && error.http_status === 413) { + this._mediaConfig = null; + } dis.dispatch({action: 'upload_failed', upload, error}); } else { dis.dispatch({action: 'upload_finished', upload}); + dis.dispatch({action: 'message_sent'}); } }); } @@ -404,9 +530,3 @@ class ContentMessages { } } } - -if (global.mx_ContentMessage === undefined) { - global.mx_ContentMessage = new ContentMessages(); -} - -module.exports = global.mx_ContentMessage; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 73b7545c26..7914810458 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -19,7 +19,6 @@ limitations under the License. // TODO: This component is enormous! There's several things which could stand-alone: // - Search results component // - Drag and drop -// - File uploading - uploadFile() import shouldHideEvent from "../../shouldHideEvent"; @@ -33,7 +32,7 @@ import { _t } from '../../languageHandler'; import {RoomPermalinkCreator} from "../../matrix-to"; const MatrixClientPeg = require("../../MatrixClientPeg"); -const ContentMessages = require("../../ContentMessages"); +import ContentMessages from '../../ContentMessages'; const Modal = require("../../Modal"); const sdk = require('../../index'); const CallHandler = require('../../CallHandler'); @@ -170,7 +169,6 @@ module.exports = React.createClass({ MatrixClientPeg.get().on("accountData", this.onAccountData); MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus); MatrixClientPeg.get().on("deviceVerificationChanged", this.onDeviceVerificationChanged); - this._fetchMediaConfig(); // Start listening for RoomViewStore updates this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); this._onRoomViewStoreUpdate(true); @@ -178,27 +176,6 @@ module.exports = React.createClass({ WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate); }, - _fetchMediaConfig: function(invalidateCache: boolean = false) { - /// NOTE: Using global here so we don't make repeated requests for the - /// config every time we swap room. - if(global.mediaConfig !== undefined && !invalidateCache) { - this.setState({mediaConfig: global.mediaConfig}); - return; - } - console.log("[Media Config] Fetching"); - MatrixClientPeg.get().getMediaConfig().then((config) => { - console.log("[Media Config] Fetched config:", config); - return config; - }).catch(() => { - // Media repo can't or won't report limits, so provide an empty object (no limits). - console.log("[Media Config] Could not fetch config, so not limiting uploads."); - return {}; - }).then((config) => { - global.mediaConfig = config; - this.setState({mediaConfig: config}); - }); - }, - _onRoomViewStoreUpdate: function(initial) { if (this.unmounted) { return; @@ -510,7 +487,7 @@ module.exports = React.createClass({ }, onPageUnload(event) { - if (ContentMessages.getCurrentUploads().length > 0) { + 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') { @@ -561,11 +538,6 @@ module.exports = React.createClass({ case 'picture_snapshot': this.uploadFile(payload.file); break; - case 'upload_failed': - // 413: File was too big or upset the server in some way. - if (payload.error && payload.error.http_status === 413) { - this._fetchMediaConfig(true); - } case 'notifier_enabled': case 'upload_started': case 'upload_finished': @@ -1015,9 +987,11 @@ module.exports = React.createClass({ onDrop: function(ev) { ev.stopPropagation(); ev.preventDefault(); + ContentMessages.sharedInstance().sendContentListToRoom( + ev.dataTransfer.files, this.state.room.roomId, MatrixClientPeg.get(), + ); this.setState({ draggingFile: false }); - const files = [...ev.dataTransfer.files]; - files.forEach(this.uploadFile); + dis.dispatch({action: 'focus_composer'}); }, onDragLeaveOrEnd: function(ev) { @@ -1026,55 +1000,13 @@ module.exports = React.createClass({ this.setState({ draggingFile: false }); }, - isFileUploadAllowed(file) { - if (this.state.mediaConfig !== undefined && - this.state.mediaConfig["m.upload.size"] !== undefined && - file.size > this.state.mediaConfig["m.upload.size"]) { - return _t("File is too big. Maximum file size is %(fileSize)s", {fileSize: filesize(this.state.mediaConfig["m.upload.size"])}); - } - return true; - }, - - uploadFile: async function(file) { - dis.dispatch({action: 'focus_composer'}); - - if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'require_registration'}); - return; - } - - try { - await ContentMessages.sendContentToRoom(file, this.state.room.roomId, MatrixClientPeg.get()); - } catch (error) { - if (error.name === "UnknownDeviceError") { - // Let the status bar handle this - return; - } - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - console.error("Failed to upload file " + file + " " + error); - Modal.createTrackedDialog('Failed to upload file', '', ErrorDialog, { - title: _t('Failed to upload file'), - description: ((error && error.message) - ? error.message : _t("Server may be unavailable, overloaded, or the file too big")), - }); - - // bail early to avoid calling the dispatch below - return; - } - - // Send message_sent callback, for things like _checkIfAlone because after all a file is still a message. - dis.dispatch({ - action: 'message_sent', - }); - }, - injectSticker: function(url, info, text) { if (MatrixClientPeg.get().isGuest()) { dis.dispatch({action: 'require_registration'}); return; } - ContentMessages.sendStickerContentToRoom(url, this.state.room.roomId, info, text, MatrixClientPeg.get()) + ContentMessages.sharedInstance().sendStickerContentToRoom(url, this.state.room.roomId, info, text, MatrixClientPeg.get()) .done(undefined, (error) => { if (error.name === "UnknownDeviceError") { // Let the staus bar handle this @@ -1666,7 +1598,7 @@ module.exports = React.createClass({ let statusBar; let isStatusAreaExpanded = true; - if (ContentMessages.getCurrentUploads().length > 0) { + if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) { const UploadBar = sdk.getComponent('structures.UploadBar'); statusBar = ; } else if (!this.state.searchResults) { @@ -1774,11 +1706,9 @@ module.exports = React.createClass({ messageComposer = ; diff --git a/src/components/structures/UploadBar.js b/src/components/structures/UploadBar.js index b54ea00c16..a8cb3c0b0e 100644 --- a/src/components/structures/UploadBar.js +++ b/src/components/structures/UploadBar.js @@ -47,7 +47,7 @@ module.exports = React.createClass({displayName: 'UploadBar', }, render: function() { - const uploads = ContentMessages.getCurrentUploads(); + const uploads = ContentMessages.sharedInstance().getCurrentUploads(); // for testing UI... - also fix up the ContentMessages.getCurrentUploads().length // check in RoomView @@ -93,7 +93,7 @@ module.exports = React.createClass({displayName: 'UploadBar',
      { uploadedSize } / { totalSize } diff --git a/src/components/views/dialogs/UploadConfirmDialog.js b/src/components/views/dialogs/UploadConfirmDialog.js new file mode 100644 index 0000000000..fe10f4cd29 --- /dev/null +++ b/src/components/views/dialogs/UploadConfirmDialog.js @@ -0,0 +1,106 @@ +/* +Copyright 2019 New Vector 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 sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class UploadConfirmDialog extends React.Component { + static propTypes = { + file: PropTypes.object.isRequired, + currentIndex: PropTypes.number, + totalFiles: PropTypes.number, + onFinished: PropTypes.func.isRequired, + } + + static defaultProps = { + totalFiles: 1, + } + + constructor(props) { + super(props); + + this._objectUrl = URL.createObjectURL(props.file); + } + + componentWillUnmount() { + if (this._objectUrl) URL.revokeObjectURL(this._objectUrl); + } + + _onCancelClick = () => { + this.props.onFinished(false); + } + + _onUploadClick = () => { + this.props.onFinished(true); + } + + render() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + let title; + if (this.props.totalFiles > 1 && this.props.currentIndex !== undefined) { + title = _t( + "Upload files (%(current)s of %(total)s)", + { + current: this.props.currentIndex, + total: this.props.totalFiles, + }, + ); + } else { + title = _t('Upload files'); + } + + let preview; + if (this.props.file.type.startsWith('image/')) { + preview =
      +
      +
      +
      {this.props.file.name}
      +
      +
      ; + } else { + preview =
      +
      + + {this.props.file.name} +
      +
      ; + } + + return ( + +
      + {preview} +
      + + +
      + ); + } +} diff --git a/src/components/views/dialogs/UploadFailureDialog.js b/src/components/views/dialogs/UploadFailureDialog.js new file mode 100644 index 0000000000..1669bf242c --- /dev/null +++ b/src/components/views/dialogs/UploadFailureDialog.js @@ -0,0 +1,120 @@ +/* +Copyright 2019 New Vector 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 filesize from 'filesize'; + +import React from 'react'; +import PropTypes from 'prop-types'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; +import ContentMessages from '../../../ContentMessages'; + +/* + * Tells the user about files we know cannot be uploaded before we even try uploading + * them. This is named fairly generically but the only thing we check right now is + * the size of the file. + */ +export default class UploadFailureDialog extends React.Component { + static propTypes = { + badFiles: PropTypes.arrayOf(PropTypes.object).isRequired, + totalFiles: PropTypes.number.isRequired, + contentMessages: PropTypes.instanceOf(ContentMessages).isRequired, + onFinished: PropTypes.func.isRequired, + } + + _onCancelClick = () => { + this.props.onFinished(false); + } + + _onUploadClick = () => { + this.props.onFinished(true); + } + + render() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + let message; + let preview; + let buttons; + if (this.props.totalFiles === 1 && this.props.badFiles.length === 1) { + message = _t( + "This file is too large to upload. " + + "The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.", + { + limit: filesize(this.props.contentMessages.getUploadLimit()), + sizeOfThisFile: filesize(this.props.badFiles[0].size), + }, { + b: sub => {sub}, + }, + ); + buttons = ; + } else if (this.props.totalFiles === this.props.badFiles.length) { + message = _t( + "These files are too large to upload. " + + "The file size limit is %(limit)s.", + { + limit: filesize(this.props.contentMessages.getUploadLimit()), + }, { + b: sub => {sub}, + }, + ); + buttons = ; + } else { + message = _t( + "Some files are too large to be uploaded." + + "The file size limit is %(limit)s.", + { + limit: filesize(this.props.contentMessages.getUploadLimit()), + }, { + b: sub => {sub}, + }, + ); + const howManyOthers = this.props.totalFiles - this.props.badFiles.length; + buttons = ; + } + + return ( + +
      + {message} + {preview} +
      + + {buttons} +
      + ); + } +} diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index a76a45497b..535d565d22 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -26,6 +26,7 @@ import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import Stickerpicker from './Stickerpicker'; import { makeRoomPermalink } from '../../../matrix-to'; +import ContentMessages from '../../../ContentMessages'; import classNames from 'classnames'; import E2EIcon from './E2EIcon'; @@ -47,8 +48,7 @@ export default class MessageComposer extends React.Component { this.onCallClick = this.onCallClick.bind(this); this.onHangupClick = this.onHangupClick.bind(this); this.onUploadClick = this.onUploadClick.bind(this); - this.onUploadFileSelected = this.onUploadFileSelected.bind(this); - this.uploadFiles = this.uploadFiles.bind(this); + this._onUploadFileInputChange = this._onUploadFileInputChange.bind(this); this.onVoiceCallClick = this.onVoiceCallClick.bind(this); this._onAutocompleteConfirm = this._onAutocompleteConfirm.bind(this); this.onToggleFormattingClicked = this.onToggleFormattingClicked.bind(this); @@ -145,89 +145,25 @@ export default class MessageComposer extends React.Component { this.refs.uploadInput.click(); } - onUploadFileSelected(files) { - const tfiles = files.target.files; - this.uploadFiles(tfiles); - } + _onUploadFileInputChange(ev) { + if (ev.target.files.length === 0) return; - uploadFiles(files) { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - const TintableSvg = sdk.getComponent("elements.TintableSvg"); - - const fileList = []; - const acceptedFiles = []; - const failedFiles = []; - - for (let i=0; i - { files[i].name || _t('Attachment') } - ); - fileList.push(files[i]); - } else { - failedFiles.push(
    3. - { files[i].name || _t('Attachment') }

      { _t('Reason') + ": " + fileAcceptedOrError}

      -
    4. ); - } + // take a copy so we can safely reset the value of the form control + // (Note it is a FileList: we can't use slice or sesnible iteration). + const tfiles = []; + for (let i = 0; i < ev.target.files.length; ++i) { + tfiles.push(ev.target.files[i]); } - const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); - let replyToWarning = null; - if (isQuoting) { - replyToWarning =

      { - _t('At this time it is not possible to reply with a file so this will be sent without being a reply.') - }

      ; - } - - const acceptedFilesPart = acceptedFiles.length === 0 ? null : ( -
      -

      { _t('Are you sure you want to upload the following files?') }

      -
        - { acceptedFiles } -
      -
      + ContentMessages.sharedInstance().sendContentListToRoom( + tfiles, this.props.room.roomId, MatrixClientPeg.get(), ); - const failedFilesPart = failedFiles.length === 0 ? null : ( -
      -

      { _t('The following files cannot be uploaded:') }

      -
        - { failedFiles } -
      -
      - ); - let buttonText; - if (acceptedFiles.length > 0 && failedFiles.length > 0) { - buttonText = "Upload selected" - } else if (failedFiles.length > 0) { - buttonText = "Close" - } - - Modal.createTrackedDialog('Upload Files confirmation', '', QuestionDialog, { - title: _t('Upload Files'), - description: ( -
      - { acceptedFilesPart } - { failedFilesPart } - { replyToWarning } -
      - ), - hasCancelButton: acceptedFiles.length > 0, - button: buttonText, - onFinished: (shouldUpload) => { - if (shouldUpload) { - // MessageComposer shouldn't have to rely on its parent passing in a callback to upload a file - if (fileList) { - for (let i=0; i + onChange={this._onUploadFileInputChange} /> ); @@ -414,7 +350,6 @@ export default class MessageComposer extends React.Component { key="controls_input" room={this.props.room} placeholder={placeholderText} - onFilesPasted={this.uploadFiles} onInputStateChanged={this.onInputStateChanged} permalinkCreator={this.props.permalinkCreator} />, formattingButton, @@ -510,12 +445,6 @@ MessageComposer.propTypes = { // string representing the current voip call state callState: PropTypes.string, - // callback when a file to upload is chosen - uploadFile: PropTypes.func.isRequired, - - // function to test whether a file should be allowed to be uploaded. - uploadAllowed: PropTypes.func.isRequired, - // string representing the current room app drawer state showApps: PropTypes.bool }; diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index cbea2bccb9..a0b66e40e1 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -47,6 +47,7 @@ import {Completion} from "../../../autocomplete/Autocompleter"; import Markdown from '../../../Markdown'; import ComposerHistoryManager from '../../../ComposerHistoryManager'; import MessageComposerStore from '../../../stores/MessageComposerStore'; +import ContentMessage from '../../../ContentMessages'; import {MATRIXTO_URL_PATTERN} from '../../../linkify-matrix'; @@ -1009,7 +1010,13 @@ export default class MessageComposerInput extends React.Component { switch (transfer.type) { case 'files': - return this.props.onFilesPasted(transfer.files); + // This actually not so much for 'files' as such (at time of writing + // neither chrome nor firefox let you paste a plain file copied + // from Finder) but more images copied from a different website + // / word processor etc. + return ContentMessage.sharedInstance().sendContentListToRoom( + transfer.files, this.props.room.roomId, this.client, + ); case 'html': { if (this.state.isRichTextEnabled) { // FIXME: https://github.com/ianstormtaylor/slate/issues/1497 means diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b40c6aab13..2e26771208 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -40,7 +40,10 @@ "A call is already in progress!": "A call is already in progress!", "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", - "The file '%(fileName)s' failed to upload": "The file '%(fileName)s' failed to upload", + "Replying With Files": "Replying With Files", + "At this time it is not possible to reply with a file so this will be sent without being a reply.": "At this time it is not possible to reply with a file so this will be sent without being a reply.", + "Continue": "Continue", + "The file '%(fileName)s' failed to upload.": "The file '%(fileName)s' failed to upload.", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "The file '%(fileName)s' exceeds this homeserver's size limit for uploads", "Upload Failed": "Upload Failed", "Failure to create room": "Failure to create room", @@ -353,7 +356,6 @@ "Verify this user by confirming the following number appears on their screen.": "Verify this user by confirming the following number appears on their screen.", "Unable to find a supported verification method.": "Unable to find a supported verification method.", "For maximum security, we recommend you do this in person or use another trusted means of communication.": "For maximum security, we recommend you do this in person or use another trusted means of communication.", - "Continue": "Continue", "Dog": "Dog", "Cat": "Cat", "Lion": "Lion", @@ -718,11 +720,6 @@ "block-quote": "block-quote", "bulleted-list": "bulleted-list", "numbered-list": "numbered-list", - "Attachment": "Attachment", - "At this time it is not possible to reply with a file so this will be sent without being a reply.": "At this time it is not possible to reply with a file so this will be sent without being a reply.", - "Are you sure you want to upload the following files?": "Are you sure you want to upload the following files?", - "The following files cannot be uploaded:": "The following files cannot be uploaded:", - "Upload Files": "Upload Files", "Hangup": "Hangup", "Voice call": "Voice call", "Video call": "Video call", @@ -873,6 +870,7 @@ "Today": "Today", "Yesterday": "Yesterday", "Error decrypting audio": "Error decrypting audio", + "Attachment": "Attachment", "Error decrypting attachment": "Error decrypting attachment", "Decrypt %(text)s": "Decrypt %(text)s", "Download %(text)s": "Download %(text)s", @@ -1191,6 +1189,16 @@ "Room contains unknown devices": "Room contains unknown devices", "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.", "Unknown devices": "Unknown devices", + "Upload files (%(current)s of %(total)s)": "Upload files (%(current)s of %(total)s)", + "Upload files": "Upload files", + "Upload": "Upload", + "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.", + "These files are too large to upload. The file size limit is %(limit)s.": "These files are too large to upload. The file size limit is %(limit)s.", + "Some files are too large to be uploaded.The file size limit is %(limit)s.": "Some files are too large to be uploaded.The file size limit is %(limit)s.", + "Upload %(count)s other files|other": "Upload %(count)s other files", + "Upload %(count)s other files|one": "Upload %(count)s other file", + "Cancel All": "Cancel All", + "Upload Error": "Upload Error", "A widget would like to verify your identity": "A widget would like to verify your identity", "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.": "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.", "Remember my selection for this widget": "Remember my selection for this widget", @@ -1416,9 +1424,6 @@ "There's no one else here! Would you like to invite others or stop warning about the empty room?": "There's no one else here! Would you like to invite others or stop warning about the empty room?", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", "You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?", - "File is too big. Maximum file size is %(fileSize)s": "File is too big. Maximum file size is %(fileSize)s", - "Failed to upload file": "Failed to upload file", - "Server may be unavailable, overloaded, or the file too big": "Server may be unavailable, overloaded, or the file too big", "Search failed": "Search failed", "Server may be unavailable, overloaded, or search timed out :(": "Server may be unavailable, overloaded, or search timed out :(", "No more results": "No more results", From fedd4598b5eb85d8ba8aac84e276f9218c03bf40 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 16:50:23 +0100 Subject: [PATCH 219/481] Space The final frontier --- src/components/views/dialogs/UploadFailureDialog.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/UploadFailureDialog.js b/src/components/views/dialogs/UploadFailureDialog.js index 1669bf242c..e264f1a3fb 100644 --- a/src/components/views/dialogs/UploadFailureDialog.js +++ b/src/components/views/dialogs/UploadFailureDialog.js @@ -83,7 +83,7 @@ export default class UploadFailureDialog extends React.Component { />; } else { message = _t( - "Some files are too large to be uploaded." + + "Some files are too large to be uploaded. " + "The file size limit is %(limit)s.", { limit: filesize(this.props.contentMessages.getUploadLimit()), diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2e26771208..a2f939dc81 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1194,7 +1194,7 @@ "Upload": "Upload", "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.", "These files are too large to upload. The file size limit is %(limit)s.": "These files are too large to upload. The file size limit is %(limit)s.", - "Some files are too large to be uploaded.The file size limit is %(limit)s.": "Some files are too large to be uploaded.The file size limit is %(limit)s.", + "Some files are too large to be uploaded. The file size limit is %(limit)s.": "Some files are too large to be uploaded. The file size limit is %(limit)s.", "Upload %(count)s other files|other": "Upload %(count)s other files", "Upload %(count)s other files|one": "Upload %(count)s other file", "Cancel All": "Cancel All", From 0add3d0825cf996f65716ab7984c330e73decdea Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 1 Apr 2019 16:52:06 +0100 Subject: [PATCH 220/481] Translate into peoplecounting --- src/components/views/dialogs/UploadConfirmDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/UploadConfirmDialog.js b/src/components/views/dialogs/UploadConfirmDialog.js index fe10f4cd29..f026454cea 100644 --- a/src/components/views/dialogs/UploadConfirmDialog.js +++ b/src/components/views/dialogs/UploadConfirmDialog.js @@ -58,7 +58,7 @@ export default class UploadConfirmDialog extends React.Component { title = _t( "Upload files (%(current)s of %(total)s)", { - current: this.props.currentIndex, + current: this.props.currentIndex + 1, total: this.props.totalFiles, }, ); From 3948520eaa8a627653e0d9bc24f54f862179bb77 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 1 Apr 2019 17:39:12 +0100 Subject: [PATCH 221/481] Use Field component in bug report dialog This uses the field component in the bug report dialog, which generally improves the styling to fit in more naturally with the rest of the app so that it feels more trustworthy. Fixes https://github.com/vector-im/riot-web/issues/9343 --- res/css/views/dialogs/_BugReportDialog.scss | 37 ++----------- .../views/dialogs/BugReportDialog.js | 54 +++++++++---------- src/i18n/strings/en_EN.json | 5 +- 3 files changed, 32 insertions(+), 64 deletions(-) diff --git a/res/css/views/dialogs/_BugReportDialog.scss b/res/css/views/dialogs/_BugReportDialog.scss index e00d446eda..90ef55b945 100644 --- a/res/css/views/dialogs/_BugReportDialog.scss +++ b/res/css/views/dialogs/_BugReportDialog.scss @@ -14,39 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_BugReportDialog_field_container { - display: flex; -} - -.mx_BugReportDialog_field_label { - flex-basis: 150px; - - text-align: right; - - padding-top: 9px; - padding-right: 4px; - - line-height: 18px; +.mx_BugReportDialog .mx_Field { + flex: 1; } .mx_BugReportDialog_field_input { - flex-grow: 1; - - /* taken from mx_ChatInviteDialog_inputContainer */ - border-radius: 3px; - border: solid 1px $input-border-color; - - font-size: 14px; - - padding-left: 4px; - padding-right: 4px; - padding-top: 7px; - padding-bottom: 7px; - - margin-bottom: 4px; -} - -.mx_BugReportDialog_field_input[type="text" i] { - padding-top: 9px; - padding-bottom: 9px; + // TODO: We should really apply this to all .mx_Field inputs. + // See https://github.com/vector-im/riot-web/issues/9344. + flex: 1; } diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index c874049cc6..4f9b592691 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -108,6 +108,7 @@ export default class BugReportDialog extends React.Component { const Loader = sdk.getComponent("elements.Spinner"); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const Field = sdk.getComponent('elements.Field'); let error = null; if (this.state.err) { @@ -154,36 +155,29 @@ export default class BugReportDialog extends React.Component { }, ) }

      -
      - - -
      -
      - -