From cb5c9f2c5ae34e019d34b121e1ee32ce4ab7c6c0 Mon Sep 17 00:00:00 2001 From: Stefan Parviainen Date: Wed, 29 Nov 2017 21:13:48 +0100 Subject: [PATCH 001/242] Make Dialogs more accessible Signed-off-by: Stefan Parviainen --- src/components/views/dialogs/BaseDialog.js | 8 ++++++-- src/components/views/dialogs/QuestionDialog.js | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 295bb21ea1..aec9af4e98 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -45,6 +45,10 @@ export default React.createClass({ // children should be the content of the dialog children: React.PropTypes.node, + + // Id of content element + // If provided, this is used to add a aria-describedby attribute + contentId: React.PropTypes.string }, _onKeyDown: function(e) { @@ -69,13 +73,13 @@ export default React.createClass({ const TintableSvg = sdk.getComponent("elements.TintableSvg"); return ( -
+
-
+
{ this.props.title }
{ this.props.children } diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js index 339b284e2f..db20fd00ed 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.js @@ -66,6 +66,7 @@ export default React.createClass({
{ this.props.description } From 437a440bdfa17553e83e5d7e762b7494bb803ddb Mon Sep 17 00:00:00 2001 From: Stefan Parviainen Date: Thu, 30 Nov 2017 08:32:18 +0100 Subject: [PATCH 002/242] Add missing id Signed-off-by: Stefan Parviainen --- src/components/views/dialogs/QuestionDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js index db20fd00ed..92051a0df7 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.js @@ -68,7 +68,7 @@ export default React.createClass({ title={this.props.title} contentId='mx_Dialog_content' > -
+
{ this.props.description }
From 5ccbcf02e200aa8348a7415dda40a0c73e35937d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Sun, 3 Dec 2017 21:38:21 +0100 Subject: [PATCH 003/242] Several changes improving accessibility of the dialogs - Wrapped all the modals inside a react-focus-trap component disabling keyboard navigation outside the modal dialogs - Disabled our custom key handling at dialog level. Cancelling on esc key is now handled via FocusTrap component. - Removed onEnter prop from the BaseDialog component. Dialogs that submit data all now embed a form with onSubmit handler. And since keyboard focus is now managed better via FocusTrap it no longer makes sense for the other dialog types. Fixes https://github.com/vector-im/riot-web/issues/5736 - Set aria-hidden on the matrixChat outer node when showing dialogs to disable navigating outside the modals by using screen reader specific features. --- package.json | 1 + src/Modal.js | 6 +- src/components/views/dialogs/BaseDialog.js | 26 ++++----- .../views/dialogs/ConfirmUserActionDialog.js | 4 +- .../views/dialogs/CreateGroupDialog.js | 1 - .../views/dialogs/CreateRoomDialog.js | 57 +++++++++---------- .../views/dialogs/QuestionDialog.js | 1 - .../views/dialogs/TextInputDialog.js | 29 +++++----- 8 files changed, 60 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index b443b4c72a..46517230a7 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "react": "^15.4.0", "react-addons-css-transition-group": "15.3.2", "react-dom": "^15.4.0", + "react-focus-trap": "^2.5.0", "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef", "sanitize-html": "^1.14.1", "text-encoding-utf-8": "^1.0.1", diff --git a/src/Modal.js b/src/Modal.js index 68d75d1ff1..daf66a37de 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -19,6 +19,7 @@ limitations under the License. const React = require('react'); const ReactDOM = require('react-dom'); +import FocusTrap from 'react-focus-trap'; import Analytics from './Analytics'; import sdk from './index'; @@ -164,6 +165,7 @@ class ModalManager { ); modal.onFinished = props ? props.onFinished : null; modal.className = className; + modal.closeDialog = closeDialog; this._modals.unshift(modal); @@ -194,9 +196,9 @@ class ModalManager { const modal = this._modals[0]; const dialog = (
-
+ { modal.elem } -
+
); diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index aec9af4e98..1f29f2d1f4 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -33,9 +33,6 @@ export default React.createClass({ // onFinished callback to call when Escape is pressed onFinished: React.PropTypes.func.isRequired, - // callback to call when Enter is pressed - onEnterPressed: React.PropTypes.func, - // CSS class to apply to dialog div className: React.PropTypes.string, @@ -51,17 +48,16 @@ export default React.createClass({ contentId: React.PropTypes.string }, - _onKeyDown: function(e) { - if (e.keyCode === KeyCode.ESCAPE) { - e.stopPropagation(); - e.preventDefault(); - this.props.onFinished(); - } else if (e.keyCode === KeyCode.ENTER) { - if (this.props.onEnterPressed) { - e.stopPropagation(); - e.preventDefault(); - this.props.onEnterPressed(e); - } + componentDidMount: function() { + this.applicationNode = document.getElementById('matrixchat'); + if (this.applicationNode) { + this.applicationNode.setAttribute('aria-hidden', 'true'); + } + }, + + componentWillUnmount: function() { + if (this.applicationNode) { + this.applicationNode.setAttribute('aria-hidden', 'false'); } }, @@ -73,7 +69,7 @@ export default React.createClass({ const TintableSvg = sdk.getComponent("elements.TintableSvg"); return ( -
+
diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.js b/src/components/views/dialogs/ConfirmUserActionDialog.js index 78d084b709..1c246a580b 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.js +++ b/src/components/views/dialogs/ConfirmUserActionDialog.js @@ -116,10 +116,10 @@ export default React.createClass({ return ( -
+
{ avatar }
diff --git a/src/components/views/dialogs/CreateGroupDialog.js b/src/components/views/dialogs/CreateGroupDialog.js index 168fe75947..8e262a6e51 100644 --- a/src/components/views/dialogs/CreateGroupDialog.js +++ b/src/components/views/dialogs/CreateGroupDialog.js @@ -116,7 +116,6 @@ export default React.createClass({ return (
diff --git a/src/components/views/dialogs/CreateRoomDialog.js b/src/components/views/dialogs/CreateRoomDialog.js index f7be47b3eb..f5a5f87b72 100644 --- a/src/components/views/dialogs/CreateRoomDialog.js +++ b/src/components/views/dialogs/CreateRoomDialog.js @@ -43,38 +43,37 @@ export default React.createClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( -
-
- -
-
- -
-
- -
- { _t('Advanced options') } -
- - + +
+
+
-
-
-
- - -
+
+ +
+
+ +
+ { _t('Advanced options') } +
+ + +
+
+
+
+ + +
+ ); }, diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.js index 92051a0df7..41733470a1 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.js @@ -64,7 +64,6 @@ export default React.createClass({ }); return ( diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 5ea4191e5e..907848b3b8 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -60,25 +60,24 @@ export default React.createClass({ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( -
-
- +
+
+
+ +
+
+ +
-
- +
+ +
-
-
- - -
+
); }, From 4f83f6cf25480776c04329a0463d8f6fe82f48ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 5 Dec 2017 08:50:40 +0100 Subject: [PATCH 004/242] Move keyboard focus management back to the BaseDialog rather than leaving it in the Modal manager. We are using Modal manager to load other components not just BaseDialog and its subclasses and they might require different keyboard handling. Also depend on focus-trap-react rather than react-focus-trap for locking keyboard focus inside the dialog. The experience is much nicer and even the FocusTrap element it-self no longer gains the focus. On a side note using the FocusTrap element outside the dialog (on its parent) stops it from working properly. --- package.json | 2 +- src/Modal.js | 6 ++---- src/components/views/dialogs/BaseDialog.js | 13 +++++++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 46517230a7..ee089daf29 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "file-saver": "^1.3.3", "filesize": "3.5.6", "flux": "2.1.1", + "focus-trap-react": "^3.0.5", "fuse.js": "^2.2.0", "glob": "^5.0.14", "highlight.js": "^8.9.1", @@ -78,7 +79,6 @@ "react": "^15.4.0", "react-addons-css-transition-group": "15.3.2", "react-dom": "^15.4.0", - "react-focus-trap": "^2.5.0", "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef", "sanitize-html": "^1.14.1", "text-encoding-utf-8": "^1.0.1", diff --git a/src/Modal.js b/src/Modal.js index daf66a37de..68d75d1ff1 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -19,7 +19,6 @@ limitations under the License. const React = require('react'); const ReactDOM = require('react-dom'); -import FocusTrap from 'react-focus-trap'; import Analytics from './Analytics'; import sdk from './index'; @@ -165,7 +164,6 @@ class ModalManager { ); modal.onFinished = props ? props.onFinished : null; modal.className = className; - modal.closeDialog = closeDialog; this._modals.unshift(modal); @@ -196,9 +194,9 @@ class ModalManager { const modal = this._modals[0]; const dialog = (
- +
{ modal.elem } - +
); diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 1f29f2d1f4..25909a18fa 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -15,6 +15,7 @@ limitations under the License. */ import React from 'react'; +import FocusTrap from 'focus-trap-react'; import * as KeyCode from '../../../KeyCode'; import AccessibleButton from '../elements/AccessibleButton'; @@ -61,6 +62,14 @@ export default React.createClass({ } }, + _onKeyDown: function(e) { + if (e.keyCode === KeyCode.ESCAPE) { + e.stopPropagation(); + e.preventDefault(); + this.props.onFinished(); + } + }, + _onCancelClick: function(e) { this.props.onFinished(); }, @@ -69,7 +78,7 @@ export default React.createClass({ const TintableSvg = sdk.getComponent("elements.TintableSvg"); return ( -
+ @@ -79,7 +88,7 @@ export default React.createClass({ { this.props.title }
{ this.props.children } -
+ ); }, }); From a31af39ca8af8da06462d6d2cc3dd8d20093ca64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 5 Dec 2017 13:52:20 +0100 Subject: [PATCH 005/242] Applied aria-describedby to all other dialogs that are using BaseDialog. Also added initial focus where it has not been set. --- .../views/dialogs/ChatCreateOrReuseDialog.js | 11 +++++----- src/components/views/dialogs/ErrorDialog.js | 14 +++++-------- .../views/dialogs/InteractiveAuthDialog.js | 8 +++++--- .../views/dialogs/KeyShareDialog.js | 7 ++++--- .../dialogs/SessionRestoreErrorDialog.js | 16 +++++++++++---- .../views/dialogs/SetEmailDialog.js | 5 ++++- src/components/views/dialogs/SetMxIdDialog.js | 7 ++++--- .../views/dialogs/UnknownDeviceDialog.js | 5 +++-- .../login/InteractiveAuthEntryComponents.js | 20 +++++++++++++------ 9 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/components/views/dialogs/ChatCreateOrReuseDialog.js b/src/components/views/dialogs/ChatCreateOrReuseDialog.js index e0578f3b53..0623177e1a 100644 --- a/src/components/views/dialogs/ChatCreateOrReuseDialog.js +++ b/src/components/views/dialogs/ChatCreateOrReuseDialog.js @@ -127,7 +127,7 @@ export default class ChatCreateOrReuseDialog extends React.Component {
{ _t("Start new chat") }
; - content =
+ content =
{ _t('You already have existing direct chats with this user:') }
{ this.state.tiles } @@ -144,7 +144,7 @@ export default class ChatCreateOrReuseDialog extends React.Component { if (this.state.busyProfile) { profile = ; } else if (this.state.profileError) { - profile =
+ profile =
Unable to load profile information for { this.props.userId }
; } else { @@ -160,14 +160,14 @@ export default class ChatCreateOrReuseDialog extends React.Component {
; } content =
-
+

{ _t('Click on the button below to start chatting!') }

{ profile }
-
@@ -179,6 +179,7 @@ export default class ChatCreateOrReuseDialog extends React.Component { { content } @@ -186,7 +187,7 @@ export default class ChatCreateOrReuseDialog extends React.Component { } } -ChatCreateOrReuseDialog.propTyps = { +ChatCreateOrReuseDialog.propTypes = { userId: React.PropTypes.string.isRequired, // Called when clicking outside of the dialog onFinished: React.PropTypes.func.isRequired, diff --git a/src/components/views/dialogs/ErrorDialog.js b/src/components/views/dialogs/ErrorDialog.js index 97ed47e10f..0910264cef 100644 --- a/src/components/views/dialogs/ErrorDialog.js +++ b/src/components/views/dialogs/ErrorDialog.js @@ -51,22 +51,18 @@ export default React.createClass({ }; }, - componentDidMount: function() { - if (this.props.focus) { - this.refs.button.focus(); - } - }, - render: function() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( -
+ title={this.props.title || _t('Error')} + contentId='mx_Dialog_content' + > +
{ this.props.description || _t('An error has occurred.') }
-
diff --git a/src/components/views/dialogs/InteractiveAuthDialog.js b/src/components/views/dialogs/InteractiveAuthDialog.js index 59de7c7f59..d1273849ae 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.js +++ b/src/components/views/dialogs/InteractiveAuthDialog.js @@ -72,11 +72,12 @@ export default React.createClass({ let content; if (this.state.authError) { content = ( -
-
{ this.state.authError.message || this.state.authError.toString() }
+
+
{ this.state.authError.message || this.state.authError.toString() }

{ _t("Dismiss") } @@ -84,7 +85,7 @@ export default React.createClass({ ); } else { content = ( -
+
{ content } diff --git a/src/components/views/dialogs/KeyShareDialog.js b/src/components/views/dialogs/KeyShareDialog.js index 9c8be27c89..821939ff0d 100644 --- a/src/components/views/dialogs/KeyShareDialog.js +++ b/src/components/views/dialogs/KeyShareDialog.js @@ -125,11 +125,11 @@ export default React.createClass({ text = _t(text, {displayName: displayName}); return ( -
+

{ text }

- diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.js index 2dd996953d..5a9569c1b5 100644 --- a/src/components/views/dialogs/SetEmailDialog.js +++ b/src/components/views/dialogs/SetEmailDialog.js @@ -41,6 +41,7 @@ export default React.createClass({ }, componentDidMount: function() { + this.refs.emailInputField.focus(); }, onEmailAddressChanged: function(value) { @@ -130,6 +131,7 @@ export default React.createClass({ const emailInput = this.state.emailBusy ? :
-

+

{ _t('This will allow you to reset your password and receive notifications.') }

{ emailInput } diff --git a/src/components/views/dialogs/SetMxIdDialog.js b/src/components/views/dialogs/SetMxIdDialog.js index 6fc1d77682..5ef04f5be1 100644 --- a/src/components/views/dialogs/SetMxIdDialog.js +++ b/src/components/views/dialogs/SetMxIdDialog.js @@ -234,14 +234,14 @@ export default React.createClass({ "error": Boolean(this.state.usernameError), "success": usernameAvailable, }); - usernameIndicator =
+ usernameIndicator =
{ usernameAvailable ? _t('Username available') : this.state.usernameError }
; } let authErrorIndicator = null; if (this.state.authError) { - authErrorIndicator =
+ authErrorIndicator =
{ this.state.authError }
; } @@ -253,8 +253,9 @@ export default React.createClass({ -
+
- +

{ _t('"%(RoomName)s" contains devices that you haven\'t seen before.', {RoomName: this.props.room.name}) }

@@ -161,7 +162,7 @@ export default React.createClass({ }}> { _t("Send anyway") } - - +
diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.js index e68a097e80..f018a83301 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.js +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.js @@ -54,7 +54,8 @@ export default React.createClass({ { _t( "Otherwise, click here to send a bug report.", {}, - { 'a': (sub) => { sub } }, + { 'a': (sub) => { sub } }, ) }

); diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.js index 907848b3b8..4d73752641 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.js @@ -75,7 +75,7 @@ export default React.createClass({ - +
From ab0ff9b7814240f91ba0ad03351adf26cf4a63e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 12 Dec 2017 18:55:57 +0100 Subject: [PATCH 012/242] BaseDialog: split a very long line --- src/components/views/dialogs/BaseDialog.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index fbeb35c808..db8e530fa0 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -83,7 +83,12 @@ export default React.createClass({ const TintableSvg = sdk.getComponent("elements.TintableSvg"); return ( - + From 642675c96da9fb31d191539f884872d2b7717c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Thu, 14 Dec 2017 10:31:28 +0100 Subject: [PATCH 013/242] Address review request comments --- .../views/dialogs/InteractiveAuthDialog.js | 2 +- .../dialogs/SessionRestoreErrorDialog.js | 5 +- .../login/InteractiveAuthEntryComponents.js | 51 ++++++++++++++----- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/components/views/dialogs/InteractiveAuthDialog.js b/src/components/views/dialogs/InteractiveAuthDialog.js index d1273849ae..5b0e34df2c 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.js +++ b/src/components/views/dialogs/InteractiveAuthDialog.js @@ -73,7 +73,7 @@ export default React.createClass({ if (this.state.authError) { content = (
-
{ this.state.authError.message || this.state.authError.toString() }
+
{ this.state.authError.message || this.state.authError.toString() }

); } + const shouldFocusContinueButton =!(bugreport==true); return ( -
-
diff --git a/src/components/views/login/InteractiveAuthEntryComponents.js b/src/components/views/login/InteractiveAuthEntryComponents.js index 81b84684fc..a0bb1065f2 100644 --- a/src/components/views/login/InteractiveAuthEntryComponents.js +++ b/src/components/views/login/InteractiveAuthEntryComponents.js @@ -127,6 +127,15 @@ export const PasswordAuthEntry = React.createClass({ ); } + let errorSection; + if (this.props.errorText) { + errorSection = ( +
+ { this.props.errorText } +
+ ); + } + return (

{ _t("To continue, please enter your password.") }

@@ -143,9 +152,7 @@ export const PasswordAuthEntry = React.createClass({ { submitButtonOrSpinner }
-
- { this.props.errorText } -
+ { errorSection }
); }, @@ -180,14 +187,22 @@ export const RecaptchaAuthEntry = React.createClass({ const CaptchaForm = sdk.getComponent("views.login.CaptchaForm"); const sitePublicKey = this.props.stageParams.public_key; + + let errorSection; + if (this.props.errorText) { + errorSection = ( +
+ { this.props.errorText } +
+ ); + } + return (
-
- { this.props.errorText } -
+ { errorSection }
); }, @@ -372,6 +387,14 @@ export const MsisdnAuthEntry = React.createClass({ mx_InteractiveAuthEntryComponents_msisdnSubmit: true, mx_UserSettings_button: true, // XXX button classes }); + let errorSection; + if (this.state.errorText) { + errorSection = ( +
+ { this.state.errorText } +
+ ); + } return (

{ _t("A text message has been sent to %(msisdn)s", @@ -393,9 +416,7 @@ export const MsisdnAuthEntry = React.createClass({ disabled={!enableSubmit} /> -

- { this.state.errorText } -
+ {errorSection}
); @@ -452,12 +473,18 @@ export const FallbackAuthEntry = React.createClass({ }, render: function() { + let errorSection; + if (this.props.errorText) { + errorSection = ( +
+ { this.props.errorText } +
+ ); + } return (
{ _t("Start authentication") } -
- { this.props.errorText } -
+ {errorSection}
); }, From 20c485d85e4deaae0a8090496241133902a76486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Wed, 20 Dec 2017 10:09:26 +0100 Subject: [PATCH 014/242] Move aria-hidden management from the BaseDialog component to the Modal --- src/Modal.js | 14 ++++++++++++++ src/components/views/dialogs/BaseDialog.js | 18 ------------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Modal.js b/src/Modal.js index 68d75d1ff1..69ff806045 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -186,11 +186,25 @@ class ModalManager { } _reRender() { + // Retrieve the root node of the Riot application outside the modal + let applicationNode = document.getElementById('matrixchat'); if (this._modals.length == 0) { + if (applicationNode) { + // If there is no modal to render, make all of Riot available + // to screen reader users again + applicationNode.setAttribute('aria-hidden', 'false'); + } ReactDOM.unmountComponentAtNode(this.getOrCreateContainer()); return; } + if (applicationNode) { + // Hide the content outside the modal to screen reader users + // so they won't be able to navigate into it and act on it using + // screen reader specific features + applicationNode.setAttribute('aria-hidden', 'true'); + } + const modal = this._modals[0]; const dialog = (
diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index db8e530fa0..7fb642b560 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -49,24 +49,6 @@ export default React.createClass({ contentId: React.PropTypes.string, }, - componentDidMount: function() { - // Retrieve the root node of the Riot application outside the dialog - this.applicationNode = document.getElementById('matrixchat'); - if (this.applicationNode) { - // Hide the content outside the dialog to screen reader users - // so they won't be able to navigate into it and act on it using - // screen reader specific features - this.applicationNode.setAttribute('aria-hidden', 'true'); - } - }, - - componentWillUnmount: function() { - if (this.applicationNode) { - // When dismissing the dialog, make all of Riot available to screen reader users again - this.applicationNode.setAttribute('aria-hidden', 'false'); - } - }, - _onKeyDown: function(e) { if (e.keyCode === KeyCode.ESCAPE) { e.stopPropagation(); From f2ca02eaf8aa7b4cd997526bc23396bddf25b8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Wed, 20 Dec 2017 10:13:37 +0100 Subject: [PATCH 015/242] SetEmailDialog: use autoFocus prop on the EditableText rather than using its ref inside onComponentDidMount function. This is shorter better and has been requested. --- src/components/views/dialogs/SetEmailDialog.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.js index 5a9569c1b5..ba054b0c27 100644 --- a/src/components/views/dialogs/SetEmailDialog.js +++ b/src/components/views/dialogs/SetEmailDialog.js @@ -40,10 +40,6 @@ export default React.createClass({ }; }, - componentDidMount: function() { - this.refs.emailInputField.focus(); - }, - onEmailAddressChanged: function(value) { this.setState({ emailAddress: value, @@ -131,7 +127,7 @@ export default React.createClass({ const emailInput = this.state.emailBusy ? : Date: Fri, 5 Jan 2018 11:45:45 +0100 Subject: [PATCH 016/242] Consume all combinations of space / enter, keyDown / keyUp presses and try to explain this key handling inconsistency with some additional comments as per the review discussion. --- src/components/views/elements/AccessibleButton.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/components/views/elements/AccessibleButton.js b/src/components/views/elements/AccessibleButton.js index f5254de490..ee8fd20d6f 100644 --- a/src/components/views/elements/AccessibleButton.js +++ b/src/components/views/elements/AccessibleButton.js @@ -32,12 +32,20 @@ export default function AccessibleButton(props) { // We need to consume enter onKeyDown and space onKeyUp // otherwise we are risking also activating other keyboard focusable elements // that might receive focus as a result of the AccessibleButtonClick action + // It's because we are using html buttons at a few places e.g. inside dialogs + // And divs which we report as role button to assistive technologies. + // Browsers handle space and enter keypresses differently and we are only adjusting to the + // inconsistencies here restProps.onKeyDown = function(e) { if (e.keyCode === KeyCode.ENTER) { e.stopPropagation(); e.preventDefault(); return onClick(e); } + if (e.keyCode === KeyCode.SPACE) { + e.stopPropagation(); + e.preventDefault(); + } }; restProps.onKeyUp = function(e) { if (e.keyCode === KeyCode.SPACE) { @@ -45,6 +53,10 @@ export default function AccessibleButton(props) { e.preventDefault(); return onClick(e); } + if (e.keyCode === KeyCode.ENTER) { + e.stopPropagation(); + e.preventDefault(); + } }; restProps.tabIndex = restProps.tabIndex || "0"; restProps.role = "button"; From 38de8a129bdf5359714f5721ebcfa38195cdcda4 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Thu, 25 Jan 2018 21:45:15 +0100 Subject: [PATCH 017/242] Add transaction capability to asyncActions for relating pending/success/failure actions. Particularly useful for mapping a failure to a pending action to roll back any optimistic updates. --- src/actions/actionCreators.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/actions/actionCreators.js b/src/actions/actionCreators.js index 0238eee8c0..697930414c 100644 --- a/src/actions/actionCreators.js +++ b/src/actions/actionCreators.js @@ -31,18 +31,30 @@ limitations under the License. * `${id}.pending` and either * `${id}.success` or * `${id}.failure`. + * + * The shape of each are: + * { action: '${id}.pending', request, asyncId } + * { action: '${id}.success', result, asyncId } + * { action: '${id}.failure', err, asyncId } + * + * where `request` is returned by `pendingFn`, result + * is the result of the promise returned by `fn` and + * `asyncId` is a unique ID for each dispatch of the + * asynchronous action. */ export function asyncAction(id, fn, pendingFn) { return (dispatch) => { + const asyncId = Math.random().toString(16).slice(2, 10); dispatch({ action: id + '.pending', request: typeof pendingFn === 'function' ? pendingFn() : undefined, + asyncId, }); fn().then((result) => { - dispatch({action: id + '.success', result}); + dispatch({action: id + '.success', result, asyncId}); }).catch((err) => { - dispatch({action: id + '.failure', err}); + dispatch({action: id + '.failure', err, asyncId}); }); }; } From 815f52587bd532bb916113fe205b3bbf2df6140b Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Thu, 25 Jan 2018 21:53:34 +0100 Subject: [PATCH 018/242] Move TagPanel out of LoggedInView (...and into LeftPanel in riot-web. Can we merge the projects yet?) --- src/components/structures/LoggedInView.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index e97d9dd0a1..d7fe699156 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -208,7 +208,6 @@ const LoggedInView = React.createClass({ }, render: function() { - const TagPanel = sdk.getComponent('structures.TagPanel'); const LeftPanel = sdk.getComponent('structures.LeftPanel'); const RightPanel = sdk.getComponent('structures.RightPanel'); const RoomView = sdk.getComponent('structures.RoomView'); @@ -330,7 +329,6 @@ const LoggedInView = React.createClass({
{ topBar }
- { SettingsStore.isFeatureEnabled("feature_tag_panel") ? :
} Date: Thu, 25 Jan 2018 21:58:35 +0100 Subject: [PATCH 019/242] Remove DragDropContext from TagPanel and RoomList So that we can have one context that can handle DND between the TagPanel and RoomList. --- src/components/structures/TagPanel.js | 53 ++--- src/components/views/rooms/RoomList.js | 304 ++++++++----------------- 2 files changed, 118 insertions(+), 239 deletions(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 1cd3f04f9d..8c790edc03 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -20,12 +20,11 @@ import { MatrixClient } from 'matrix-js-sdk'; import TagOrderStore from '../../stores/TagOrderStore'; import GroupActions from '../../actions/GroupActions'; -import TagOrderActions from '../../actions/TagOrderActions'; import sdk from '../../index'; import dis from '../../dispatcher'; -import { DragDropContext, Droppable } from 'react-beautiful-dnd'; +import { Droppable } from 'react-beautiful-dnd'; const TagPanel = React.createClass({ displayName: 'TagPanel', @@ -82,22 +81,6 @@ const TagPanel = React.createClass({ dis.dispatch({action: 'view_create_group'}); }, - onTagTileEndDrag(result) { - // Dragged to an invalid destination, not onto a droppable - if (!result.destination) { - return; - } - - // Dispatch synchronously so that the TagPanel receives an - // optimistic update from TagOrderStore before the previous - // state is shown. - dis.dispatch(TagOrderActions.moveTag( - this.context.matrixClient, - result.draggableId, - result.destination.index, - ), true); - }, - render() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const TintableSvg = sdk.getComponent('elements.TintableSvg'); @@ -112,24 +95,22 @@ const TagPanel = React.createClass({ />; }); return
- - - { (provided, snapshot) => ( -
- { tags } - { provided.placeholder } -
- ) } -
-
+ + { (provided, snapshot) => ( +
+ { tags } + { provided.placeholder } +
+ ) } +
diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index ca1fccd1f5..d1ef6c2f2c 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -18,7 +18,6 @@ limitations under the License. 'use strict'; const React = require("react"); const ReactDOM = require("react-dom"); -import { DragDropContext } from 'react-beautiful-dnd'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; const GeminiScrollbar = require('react-gemini-scrollbar'); @@ -33,8 +32,6 @@ const Receipt = require('../../../utils/Receipt'); import TagOrderStore from '../../../stores/TagOrderStore'; import GroupStoreCache from '../../../stores/GroupStoreCache'; -import Modal from '../../../Modal'; - const HIDE_CONFERENCE_CHANS = true; function phraseForSection(section) { @@ -278,103 +275,6 @@ module.exports = React.createClass({ this.forceUpdate(); }, - onRoomTileEndDrag: function(result) { - if (!result.destination) return; - - let newTag = result.destination.droppableId.split('_')[1]; - let prevTag = result.source.droppableId.split('_')[1]; - if (newTag === 'undefined') newTag = undefined; - if (prevTag === 'undefined') prevTag = undefined; - - const roomId = result.draggableId.split('_')[1]; - const room = MatrixClientPeg.get().getRoom(roomId); - - const newIndex = result.destination.index; - - // Evil hack to get DMs behaving - if ((prevTag === undefined && newTag === 'im.vector.fake.direct') || - (prevTag === 'im.vector.fake.direct' && newTag === undefined) - ) { - Rooms.guessAndSetDMRoom( - room, newTag === 'im.vector.fake.direct', - ).catch((err) => { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - console.error("Failed to set direct chat tag " + err); - Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, { - title: _t('Failed to set direct chat tag'), - description: ((err && err.message) ? err.message : _t('Operation failed')), - }); - }); - return; - } - - const hasChangedSubLists = result.source.droppableId !== result.destination.droppableId; - - let newOrder = null; - - // Is the tag ordered manually? - if (newTag && !newTag.match(/^(m\.lowpriority|im\.vector\.fake\.(invite|recent|direct|archived))$/)) { - const newList = Object.assign({}, this.state.lists[newTag]); - - // If the room was moved "down" (increasing index) in the same list we - // need to use the orders of the tiles with indices shifted by +1 - const offset = ( - newTag === prevTag && result.source.index < result.destination.index - ) ? 1 : 0; - - const prevOrder = newIndex === 0 ? - 0 : newList[offset + newIndex - 1].tags[newTag].order; - const nextOrder = newIndex === newList.length ? - 1 : newList[offset + newIndex].tags[newTag].order; - - newOrder = { - order: (prevOrder + nextOrder) / 2.0, - }; - } - - // More evilness: We will still be dealing with moving to favourites/low prio, - // but we avoid ever doing a request with 'im.vector.fake.direct`. - // - // if we moved lists, remove the old tag - if (prevTag && prevTag !== 'im.vector.fake.direct' && - hasChangedSubLists - ) { - // Optimistic update of what will happen to the room tags - delete room.tags[prevTag]; - - MatrixClientPeg.get().deleteRoomTag(roomId, prevTag).catch(function(err) { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - console.error("Failed to remove tag " + prevTag + " from room: " + err); - Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, { - title: _t('Failed to remove tag %(tagName)s from room', {tagName: prevTag}), - description: ((err && err.message) ? err.message : _t('Operation failed')), - }); - }); - } - - // if we moved lists or the ordering changed, add the new tag - if (newTag && newTag !== 'im.vector.fake.direct' && - (hasChangedSubLists || newOrder) - ) { - // Optimistic update of what will happen to the room tags - room.tags[newTag] = newOrder; - - MatrixClientPeg.get().setRoomTag(roomId, newTag, newOrder).catch(function(err) { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - console.error("Failed to add tag " + newTag + " to room: " + err); - Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, { - title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}), - description: ((err && err.message) ? err.message : _t('Operation failed')), - }); - }); - } - - // Refresh to display the optimistic updates - this needs to be done in the - // same tick as the drag finishing otherwise the room will pop back to its - // previous position - hence no delayed refresh - this.refreshRoomList(); - }, - _delayedRefreshRoomList: new rate_limited_func(function() { this.refreshRoomList(); }, 500), @@ -749,116 +649,114 @@ module.exports = React.createClass({ const self = this; return ( - - -
- + +
+ - + - + - + - + - { Object.keys(self.state.lists).map((tagName) => { - if (!tagName.match(/^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/)) { - return ; - } - }) } + { Object.keys(self.state.lists).map((tagName) => { + if (!tagName.match(/^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/)) { + return ; + } + }) } - + - -
-
- + +
+
); }, }); From 701abb6a219cb278dc992c4761ef58d366e29743 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Thu, 25 Jan 2018 22:16:03 +0100 Subject: [PATCH 020/242] Move management of room lists to RoomListStore this is part maintenance to make RoomList clearer and part allowing room list state to be modified via a dispatch. --- src/actions/MatrixActionCreators.js | 5 + src/actions/RoomListActions.js | 142 +++++++++++++++++ src/components/views/rooms/RoomList.js | 91 +++-------- src/stores/RoomListStore.js | 212 +++++++++++++++++++++++++ 4 files changed, 383 insertions(+), 67 deletions(-) create mode 100644 src/actions/RoomListActions.js create mode 100644 src/stores/RoomListStore.js diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index 33bdb53799..d9309d7c1c 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -62,6 +62,10 @@ function createAccountDataAction(matrixClient, accountDataEvent) { }; } +function createRoomTagsAction(matrixClient, roomTagsEvent, room) { + return { action: 'MatrixActions.Room.tags', room }; +} + /** * This object is responsible for dispatching actions when certain events are emitted by * the given MatrixClient. @@ -78,6 +82,7 @@ export default { start(matrixClient) { this._addMatrixClientListener(matrixClient, 'sync', createSyncAction); this._addMatrixClientListener(matrixClient, 'accountData', createAccountDataAction); + this._addMatrixClientListener(matrixClient, 'Room.tags', createRoomTagsAction); }, /** diff --git a/src/actions/RoomListActions.js b/src/actions/RoomListActions.js new file mode 100644 index 0000000000..3e0ea53a33 --- /dev/null +++ b/src/actions/RoomListActions.js @@ -0,0 +1,142 @@ +/* +Copyright 2018 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 { asyncAction } from './actionCreators'; +import RoomListStore from '../stores/RoomListStore'; + +import Modal from '../Modal'; +import Rooms from '../Rooms'; +import { _t } from '../languageHandler'; +import sdk from '../index'; + +const RoomListActions = {}; + +/** + * Creates an action thunk that will do an asynchronous request to + * tag room. + * + * @param {MatrixClient} matrixClient the matrix client to set the + * account data on. + * @param {Room} room the room to tag. + * @param {string} oldTag the tag to remove (unless oldTag ==== newTag) + * @param {string} newTag the tag with which to tag the room. + * @param {?number} oldIndex the previous position of the room in the + * list of rooms. + * @param {?number} newIndex the new position of the room in the list + * of rooms. + * @returns {function} an action thunk. + * @see asyncAction + */ +RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex, newIndex) { + let metaData = null; + + // Is the tag ordered manually? + if (newTag && !newTag.match(/^(m\.lowpriority|im\.vector\.fake\.(invite|recent|direct|archived))$/)) { + const lists = RoomListStore.getRoomLists(); + const newList = [...lists[newTag]]; + + newList.sort((a, b) => a.tags[newTag].order - b.tags[newTag].order); + + // If the room was moved "down" (increasing index) in the same list we + // need to use the orders of the tiles with indices shifted by +1 + const offset = ( + newTag === oldTag && oldIndex < newIndex + ) ? 1 : 0; + + const prevOrder = newIndex === 0 ? + 0 : newList[offset + newIndex - 1].tags[newTag].order; + const nextOrder = newIndex === newList.length ? + 1 : newList[offset + newIndex].tags[newTag].order; + + metaData = { + order: (prevOrder + nextOrder) / 2.0, + }; + } + + return asyncAction('RoomListActions.tagRoom', () => { + const promises = []; + const roomId = room.roomId; + + // Evil hack to get DMs behaving + if ((oldTag === undefined && newTag === 'im.vector.fake.direct') || + (oldTag === 'im.vector.fake.direct' && newTag === undefined) + ) { + return Rooms.guessAndSetDMRoom( + room, newTag === 'im.vector.fake.direct', + ).catch((err) => { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + console.error("Failed to set direct chat tag " + err); + Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, { + title: _t('Failed to set direct chat tag'), + description: ((err && err.message) ? err.message : _t('Operation failed')), + }); + }); + } + + const hasChangedSubLists = oldTag !== newTag; + + // More evilness: We will still be dealing with moving to favourites/low prio, + // but we avoid ever doing a request with 'im.vector.fake.direct`. + // + // if we moved lists, remove the old tag + if (oldTag && oldTag !== 'im.vector.fake.direct' && + hasChangedSubLists + ) { + const promiseToDelete = matrixClient.deleteRoomTag( + roomId, oldTag, + ).catch(function(err) { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + console.error("Failed to remove tag " + oldTag + " from room: " + err); + Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, { + title: _t('Failed to remove tag %(tagName)s from room', {tagName: oldTag}), + description: ((err && err.message) ? err.message : _t('Operation failed')), + }); + }); + + promises.push(promiseToDelete); + } + + // if we moved lists or the ordering changed, add the new tag + if (newTag && newTag !== 'im.vector.fake.direct' && + (hasChangedSubLists || metaData) + ) { + // Optimistic update of what will happen to the room tags + room.tags[newTag] = metaData; + + const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + console.error("Failed to add tag " + newTag + " to room: " + err); + Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, { + title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}), + description: ((err && err.message) ? err.message : _t('Operation failed')), + }); + + throw err; + }); + + promises.push(promiseToAdd); + } + + return Promise.all(promises); + }, () => { + // For an optimistic update + return { + room, oldTag, newTag, metaData, + }; + }); +}; + +export default RoomListActions; diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index d1ef6c2f2c..ad85beac12 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -26,10 +26,11 @@ const CallHandler = require('../../../CallHandler'); const dis = require("../../../dispatcher"); const sdk = require('../../../index'); const rate_limited_func = require('../../../ratelimitedfunc'); -const Rooms = require('../../../Rooms'); +import * as Rooms from '../../../Rooms'; import DMRoomMap from '../../../utils/DMRoomMap'; const Receipt = require('../../../utils/Receipt'); import TagOrderStore from '../../../stores/TagOrderStore'; +import RoomListStore from '../../../stores/RoomListStore'; import GroupStoreCache from '../../../stores/GroupStoreCache'; const HIDE_CONFERENCE_CHANS = true; @@ -77,7 +78,6 @@ module.exports = React.createClass({ cli.on("deleteRoom", this.onDeleteRoom); cli.on("Room.timeline", this.onRoomTimeline); cli.on("Room.name", this.onRoomName); - cli.on("Room.tags", this.onRoomTags); cli.on("Room.receipt", this.onRoomReceipt); cli.on("RoomState.events", this.onRoomStateEvents); cli.on("RoomMember.name", this.onRoomMemberName); @@ -115,6 +115,10 @@ module.exports = React.createClass({ this.updateVisibleRooms(); }); + this._roomListStoreToken = RoomListStore.addListener(() => { + this._delayedRefreshRoomList(); + }); + this.refreshRoomList(); // order of the sublists @@ -175,7 +179,6 @@ module.exports = React.createClass({ MatrixClientPeg.get().removeListener("deleteRoom", this.onDeleteRoom); MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); - MatrixClientPeg.get().removeListener("Room.tags", this.onRoomTags); MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); MatrixClientPeg.get().removeListener("RoomMember.name", this.onRoomMemberName); @@ -248,10 +251,6 @@ module.exports = React.createClass({ this._delayedRefreshRoomList(); }, - onRoomTags: function(event, room) { - this._delayedRefreshRoomList(); - }, - onRoomStateEvents: function(ev, state) { this._delayedRefreshRoomList(); }, @@ -338,7 +337,7 @@ module.exports = React.createClass({ totalRooms += l.length; } this.setState({ - lists: this.getRoomLists(), + lists, totalRoomCount: totalRooms, // Do this here so as to not render every time the selected tags // themselves change. @@ -349,70 +348,28 @@ module.exports = React.createClass({ }, getRoomLists: function() { - const lists = {}; - lists["im.vector.fake.invite"] = []; - lists["m.favourite"] = []; - lists["im.vector.fake.recent"] = []; - lists["im.vector.fake.direct"] = []; - lists["m.lowpriority"] = []; - lists["im.vector.fake.archived"] = []; + const lists = RoomListStore.getRoomLists(); - const dmRoomMap = DMRoomMap.shared(); + const filteredLists = {}; - this._visibleRooms.forEach((room, index) => { - const me = room.getMember(MatrixClientPeg.get().credentials.userId); - if (!me) return; - - // console.log("room = " + room.name + ", me.membership = " + me.membership + - // ", sender = " + me.events.member.getSender() + - // ", target = " + me.events.member.getStateKey() + - // ", prevMembership = " + me.events.member.getPrevContent().membership); - - if (me.membership == "invite") { - lists["im.vector.fake.invite"].push(room); - } else if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, me, this.props.ConferenceHandler)) { - // skip past this room & don't put it in any lists - } else if (me.membership == "join" || me.membership === "ban" || - (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) { - // Used to split rooms via tags - const tagNames = Object.keys(room.tags); - if (tagNames.length) { - for (let i = 0; i < tagNames.length; i++) { - const tagName = tagNames[i]; - lists[tagName] = lists[tagName] || []; - lists[tagName].push(room); - } - } else if (dmRoomMap.getUserIdForRoomId(room.roomId)) { - // "Direct Message" rooms (that we're still in and that aren't otherwise tagged) - lists["im.vector.fake.direct"].push(room); - } else { - lists["im.vector.fake.recent"].push(room); + Object.keys(lists).forEach((tagName) => { + filteredLists[tagName] = lists[tagName].filter((taggedRoom) => { + // Somewhat impossible, but guard against it anyway + if (!taggedRoom) { + return; } - } else if (me.membership === "leave") { - lists["im.vector.fake.archived"].push(room); - } else { - console.error("unrecognised membership: " + me.membership + " - this should never happen"); - } + const me = taggedRoom.getMember(MatrixClientPeg.get().credentials.userId); + if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(taggedRoom, me, this.props.ConferenceHandler)) { + return; + } + + return this._visibleRooms.some((visibleRoom) => { + return visibleRoom.roomId === taggedRoom.roomId; + }); + }); }); - // we actually apply the sorting to this when receiving the prop in RoomSubLists. - - // we'll need this when we get to iterating through lists programatically - e.g. ctrl-shift-up/down -/* - this.listOrder = [ - "im.vector.fake.invite", - "m.favourite", - "im.vector.fake.recent", - "im.vector.fake.direct", - Object.keys(otherTagNames).filter(tagName=>{ - return (!tagName.match(/^m\.(favourite|lowpriority)$/)); - }).sort(), - "m.lowpriority", - "im.vector.fake.archived" - ]; -*/ - - return lists; + return filteredLists; }, _getScrollNode: function() { diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js new file mode 100644 index 0000000000..16902ef471 --- /dev/null +++ b/src/stores/RoomListStore.js @@ -0,0 +1,212 @@ +/* +Copyright 2018 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 {Store} from 'flux/utils'; +import dis from '../dispatcher'; +import DMRoomMap from '../utils/DMRoomMap'; + +/** + * A class for storing application state for categorising rooms in + * the RoomList. + */ +class RoomListStore extends Store { + constructor() { + super(dis); + + this._init(); + this._actionHistory = []; + } + + _init() { + // Initialise state + this._state = { + lists: { + "im.vector.fake.invite": [], + "m.favourite": [], + "im.vector.fake.recent": [], + "im.vector.fake.direct": [], + "m.lowpriority": [], + "im.vector.fake.archived": [], + }, + ready: false, + }; + } + + _setState(newState) { + this._state = Object.assign(this._state, newState); + console.info(this._state); + this.__emitChange(); + } + + __onDispatch(payload) { + switch (payload.action) { + // Initialise state after initial sync + case 'MatrixActions.sync': { + if (!(payload.prevState !== 'PREPARED' && payload.state === 'PREPARED')) { + break; + } + + this._generateRoomLists(payload.matrixClient); + this._actionHistory.unshift(payload); + } + break; + case 'MatrixActions.Room.tags': { + if (!this._state.ready) break; + this._updateRoomLists(payload.room); + this._actionHistory.unshift(payload); + } + break; + case 'RoomListActions.tagRoom.pending': { + this._updateRoomListsOptimistic( + payload.request.room, + payload.request.oldTag, + payload.request.newTag, + payload.request.metaData, + ); + this._actionHistory.unshift(payload); + } + break; + case 'RoomListActions.tagRoom.failure': { + this._actionHistory = this._actionHistory.filter((action) => { + return action.asyncId !== payload.asyncId; + }); + + // don't duplicate history + const history = this._actionHistory.slice(0); + this._actionHistory = []; + this._reloadFromHistory(history); + } + break; + case 'on_logged_out': { + // Reset state without pushing an update to the view, which generally assumes that + // the matrix client isn't `null` and so causing a re-render will cause NPEs. + this._init(); + this._actionHistory.unshift(payload); + } + break; + } + } + + _reloadFromHistory(history) { + this._init(); + history.forEach((action) => this.__onDispatch(action)); + } + + _updateRoomListsOptimistic(updatedRoom, oldTag, newTag, metaData) { + const newLists = {}; + + // Remove room from oldTag + Object.keys(this._state.lists).forEach((tagName) => { + if (tagName === oldTag) { + newLists[tagName] = this._state.lists[tagName].filter((room) => { + return room.roomId !== updatedRoom.roomId; + }); + } else { + newLists[tagName] = this._state.lists[tagName]; + } + }); + + /// XXX: RoomSubList sorts by data on the room object. We + /// should sort in advance and incrementally insert new rooms + /// instead of resorting every time. + if (metaData) { + updatedRoom.tags[newTag] = metaData; + } + + newLists[newTag].push(updatedRoom); + + this._setState({ + lists: newLists, + }); + } + + _updateRoomLists(updatedRoom) { + const roomTags = Object.keys(updatedRoom.tags); + + const newLists = {}; + + // Removal of the updatedRoom from tags it no longer has + Object.keys(this._state.lists).forEach((tagName) => { + newLists[tagName] = this._state.lists[tagName].filter((room) => { + return room.roomId !== updatedRoom.roomId || roomTags.includes(tagName); + }); + }); + + roomTags.forEach((tagName) => { + if (newLists[tagName].includes(updatedRoom)) return; + newLists[tagName].push(updatedRoom); + }); + + this._setState({ + lists: newLists, + }); + } + + _generateRoomLists(matrixClient) { + const lists = { + "im.vector.fake.invite": [], + "m.favourite": [], + "im.vector.fake.recent": [], + "im.vector.fake.direct": [], + "m.lowpriority": [], + "im.vector.fake.archived": [], + }; + + const dmRoomMap = DMRoomMap.shared(); + + matrixClient.getRooms().forEach((room, index) => { + const me = room.getMember(matrixClient.credentials.userId); + if (!me) return; + + if (me.membership == "invite") { + lists["im.vector.fake.invite"].push(room); + } else if (me.membership == "join" || me.membership === "ban" || + (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) { + // Used to split rooms via tags + const tagNames = Object.keys(room.tags); + if (tagNames.length) { + for (let i = 0; i < tagNames.length; i++) { + const tagName = tagNames[i]; + lists[tagName] = lists[tagName] || []; + lists[tagName].push(room); + } + } else if (dmRoomMap.getUserIdForRoomId(room.roomId)) { + // "Direct Message" rooms (that we're still in and that aren't otherwise tagged) + lists["im.vector.fake.direct"].push(room); + } else { + lists["im.vector.fake.recent"].push(room); + } + } else if (me.membership === "leave") { + lists["im.vector.fake.archived"].push(room); + } else { + console.error("unrecognised membership: " + me.membership + " - this should never happen"); + } + }); + + this._setState({ + lists, + ready: true, // Ready to receive updates via Room.tags events + }); + } + + getRoomLists() { + return this._state.lists; + } +} + +if (global.singletonRoomListStore === undefined) { + global.singletonRoomListStore = new RoomListStore(); +} +export default global.singletonRoomListStore; From 73e3a594ac20dece69ff3f9b3aa644153703dca4 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Thu, 25 Jan 2018 22:52:19 +0100 Subject: [PATCH 021/242] Prevent TagTiles from being dragged into other droppables for the time being at least. --- src/components/structures/TagPanel.js | 5 ++++- src/components/views/elements/DNDTagTile.js | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 8c790edc03..c843c08ce9 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -95,7 +95,10 @@ const TagPanel = React.createClass({ />; }); return
- + { (provided, snapshot) => (
{ (provided, snapshot) => (
From 4820a195ab1d75f318030c4313309ab319d23a29 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Fri, 26 Jan 2018 09:15:03 +0100 Subject: [PATCH 022/242] Remove logging --- src/stores/RoomListStore.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 16902ef471..69d957f074 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -46,7 +46,6 @@ class RoomListStore extends Store { _setState(newState) { this._state = Object.assign(this._state, newState); - console.info(this._state); this.__emitChange(); } From 41c9cb1c27112ea024605a46bb62a72f773545bc Mon Sep 17 00:00:00 2001 From: Krombel Date: Thu, 1 Feb 2018 15:11:44 +0000 Subject: [PATCH 023/242] Translated using Weblate (German) Currently translated at 100.0% (984 of 984 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index d0c193bfa9..dd5ed801a3 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -974,5 +974,15 @@ "Your homeserver's URL": "Die URL deines Homeservers", "Your identity server's URL": "Die URL deines Identitätsservers", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s", - "Tag Panel": "Beschriftungsfeld" + "Tag Panel": "Beschriftungsfeld", + "Message Replies": "Antworten auf Nachrichten", + "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.": "Du wirst nicht in der Lage sein, die Änderung zurückzusetzen, da du dich degradierst. Wenn du der letze Nutzer mit Berechtigungen bist, wird es unmöglich sein die Privilegien zurückzubekommen.", + "Community IDs cannot not be empty.": "Community-IDs können nicht leer sein.", + "Show devices, send anyway or cancel.": "Geräte anzeigen, trotzdem senden oder abbrechen.", + "Learn more about how we use analytics.": "Lerne mehr darüber, wie wir die Analysedaten nutzen.", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Wenn diese Seite identifizierbare Informationen sowie Raum, Nutzer oder Gruppen-ID enthalten, werden diese Daten entfernt bevor sie an den Server gesendet werden.", + "Whether or not you're logged in (we don't record your user name)": "Ob oder ob du nicht angemeldet bist (wir zeichnen deinen Benutzernamen nicht auf)", + "Which officially provided instance you are using, if any": "Welche offiziell angebotene Instanz du nutzt, wenn es der Fall ist", + "In reply to ": "Antwort zu ", + "This room is not public. You will not be able to rejoin without an invite.": "Dies ist kein öffentlicher Raum. Du wirst diesen nicht ohne Einladung wieder beitreten können." } From d884596a1f2b770fac9bb940042ade0a1d945dff Mon Sep 17 00:00:00 2001 From: Nathan van Beelen Date: Sun, 4 Feb 2018 14:22:56 +0000 Subject: [PATCH 024/242] Translated using Weblate (Dutch) Currently translated at 100.0% (984 of 984 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/nl/ --- src/i18n/strings/nl.json | 248 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 9ad7c6d5bb..b3dcfb3a8b 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -42,7 +42,7 @@ "%(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", - "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 chat geschiedenis onleesbaar zou maken, behalve als je eerst je ruimtesleutels exporteert en achteraf opnieuw importeert. Dit zal worden verbeterd in de toekomst.", + "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": "Legen cache en herlaad", "Clear Cache": "Legen cache", "Click here to fix": "Klik hier om op te lossen", @@ -178,7 +178,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 nieuwe chat aan of ga verder met een bestaande", + "Create a new chat or reuse an existing one": "Maak een nieuw gesprek aan of hergebruik een al bestaand gesprek", "Create Room": "Maak een ruimte aan", "Curve25519 identity key": "Curve25519-identiteitssleutel", "/ddg is not a command": "/ddg is geen commando", @@ -556,7 +556,7 @@ "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", "Reject all %(invitedRooms)s invites": "Alle %(invitedRooms)s uitnodigingen afslaan", - "Start new chat": "Nieuwe chat starten", + "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:", @@ -742,5 +742,245 @@ "Disinvite this user?": "Uitnodiging van deze gebruiker intrekken?", "Kick this user?": "Deze gebruiker er uit zetten?", "Unban this user?": "Deze gebruiker ontbannen?", - "Ban this user?": "Deze gebruiker bannen?" + "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.", + "Unignore": "Niet meer negeren", + "Ignore": "Negeren", + "Jump to read receipt": "Naar het laatst gelezen bericht gaan", + "Mention": "Vermelden", + "Invite": "Uitnodigen", + "User Options": "Gebruikersopties", + "Send an encrypted reply…": "Verstuur een versleuteld antwoord…", + "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", + "%(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", + "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 ruimtes 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 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", + "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.", + "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:", + "To change the permissions in the room, you must be a": "Om de permissies in de ruimte te veranderen moet je het volgende zijn:", + "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)", + "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:", + "To kick users, you must be a": "Om gebruikers er uit te zetten moet je het volgende zijn:", + "To ban users, you must be a": "Om gebruikers te verbannen moet je het volgende zijn:", + "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", + "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.", + "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 om de uitnodiging in te trekken", + "Failed to remove user from community": "Niet gelukt om de gebruiker van 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", + "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.", + "You're not currently a member of any communities.": "Je bent momenteel niet een lid van een gemeenschap.", + "Minimize apps": "Applicaties minimaliseren", + "Communities": "Gemeenschappen", + "%(nameList)s %(transitionList)s": "%(nameList)s%(transitionList)s", + "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)s traden %(count)s keer toe", + "%(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|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", + "%(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 zijn of haar naam %(count)s keer", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s veranderde zijn of haar 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", + "%(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", + "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", + "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 cannot not 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", + "Community Name": "Gemeenschapsnaam", + "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", + "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", + "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:", + "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", + "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:", + "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", + "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", + "Unable to accept invite": "De uitnodiging kon niet geaccepteerd worden", + "Unable to reject invite": "De uitnodiging kon niet afgewezen worden", + "Leave Community": "Gemeenschap Verlaten", + "Leave %(groupName)s?": "%(groupName)s verlaten?", + "Leave": "Verlaten", + "Unable to leave room": "De ruimte kon niet verlaten worden", + "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", + "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!", + "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", + "Cryptography data migrated": "Cryptografie gegevens zijn gemigreerd", + "A one-off migration of cryptography data has been performed. End-to-end encryption will not work if you go back to an older version of Riot. If you need to use end-to-end cryptography on an older version, log out of Riot first. To retain message history, export and re-import your keys.": "Een eenmalige migratie van cryptografie gegevens heeft plaatsgevonden. Eind-tot-eind versleuteling zal niet werken als je terug gaat naar een oudere versie van Riot. Log eerst uit op Riot als je eind-tot-eind versleuteling wil gebruiken op een oudere versie. Exporteer je sleutels en importeer ze achteraf weer als je de berichtgeschiedenis wilt behouden.", + "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 zal eind-tot-eind versleuteling laten storen in de oudere versie. Eind-tot-eind berichten dat recent zijn uitgewisseld zal misschien niet ontsleutelbaar zijn in deze versie. Dit zou er misschien ook voor kunnen zorgen dat berichten die zijn uitgewisseld in deze versie falen. Indien je problemen ervaart, log opnieuw in. Om de berichtgeschiedenis te behouden, exporteer de sleutels en importeer ze achteraf weer.", + "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.", + "Join an existing community": "Treed tot een bestaande gemeenschap toe", + "To join an existing community you'll have to know its community identifier; this will look something like +example:matrix.org.": "Je moet het gemeenschaps-ID weten om tot de gemeenschap toe te treden; dit zal er uitzien zoals +voorbeeld:matrix.org.", + "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.|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?", + "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 collecteren geen persoonlijke of identificeerbare gegevens voor onze gegevensanalyse.", + "Learn more about how we use analytics.": "Leer meer over hoe we gegevensanalyse 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.", + "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", + "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:", + "We also record each page you use in the app (currently ), your User Agent () and your device resolution ().": "We nemen ook elke pagina die je in de applicatie gebruikt (momenteel ), je User Agent () en de resolutie van je apparaat () op.", + "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 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.", + "were unbanned %(count)s times|one": "waren ontbant" } From 03b137d42555781b62baeb88d55f3e18bbc03470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sim=C3=B3=20Albert=20i=20Beltran?= Date: Sat, 3 Feb 2018 15:38:29 +0000 Subject: [PATCH 025/242] Translated using Weblate (Catalan) Currently translated at 88.5% (871 of 984 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ca/ --- src/i18n/strings/ca.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json index eb4ac76d05..49c2c6ed9b 100644 --- a/src/i18n/strings/ca.json +++ b/src/i18n/strings/ca.json @@ -317,7 +317,7 @@ "Unignore": "Deixa de ignorar", "Ignore": "Ignora", "Jump to read receipt": "Vés a l'últim missatge llegit", - "Mention": "Menció", + "Mention": "Menciona", "Invite": "Convida", "User Options": "Opcions d'usuari", "Direct chats": "Xats directes", From 41338013909f130fd5071b979220a2b63c862e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=BA=D0=BE=20=D0=9C=2E=20=D0=9A=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=9B?= Date: Sat, 3 Feb 2018 11:51:18 +0000 Subject: [PATCH 026/242] Translated using Weblate (Serbian) Currently translated at 78.4% (772 of 984 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sr/ --- src/i18n/strings/sr.json | 179 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index 6396455f9d..5d31879b2e 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -1,7 +1,7 @@ { "This email address is already in use": "Ова мејл адреса се већ користи", "This phone number is already in use": "Овај број телефона се већ користи", - "Failed to verify email address: make sure you clicked the link in the email": "Нисам успео да потврдим мејл адресу, постарајте се да сте кликнули на везу у мејлу", + "Failed to verify email address: make sure you clicked the link in the email": "Нисам успео да проверим мејл адресу, постарајте се да сте кликнули на везу у мејлу", "The remote side failed to pick up": "Друга страна није подигла слушалицу", "Unable to capture screen": "Не могу да ухватим садржај екрана", "Existing Call": "Постојећи позив", @@ -569,7 +569,7 @@ "Unblacklist": "Скини са црног списка", "Blacklist": "Стави на црни списак", "Unverify": "Скини потврду", - "Verify...": "Потврди...", + "Verify...": "Провери...", "No results": "Нема резултата", "Delete": "Обриши", "Communities": "Заједнице", @@ -597,5 +597,178 @@ "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s је одбило њихове позивнице %(count)s пута", "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s је одбило њихове позивнице", "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s је одбио позивницу %(count)s пута", - "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s је одбио позивницу" + "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s је одбио позивницу", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "Корисницима %(severalUsers)s су позивнице повучене %(count)s пута", + "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "Корисницима %(severalUsers)s су позивнице повучене", + "%(oneUser)shad their invitation withdrawn %(count)s times|other": "Кориснику %(oneUser)s је позивница повучена %(count)s пута", + "%(oneUser)shad their invitation withdrawn %(count)s times|one": "Кориснику %(oneUser)s је позивница повучена", + "were invited %(count)s times|other": "су позвани %(count)s пута", + "were invited %(count)s times|one": "су позвани", + "was invited %(count)s times|other": "је позван %(count)s пута", + "was invited %(count)s times|one": "је позван", + "were banned %(count)s times|other": "забрањен приступ %(count)s пута", + "were banned %(count)s times|one": "забрањен приступ", + "was banned %(count)s times|other": "забрањен приступ %(count)s пута", + "was banned %(count)s times|one": "забрањен приступ", + "were unbanned %(count)s times|other": "дозвољен приступ %(count)s пута", + "were unbanned %(count)s times|one": "дозвољен приступ", + "was unbanned %(count)s times|other": "дозвољен приступ %(count)s пута", + "was unbanned %(count)s times|one": "дозвољен приступ", + "were kicked %(count)s times|other": "избачен %(count)s пута", + "were kicked %(count)s times|one": "избачен", + "was kicked %(count)s times|other": "избачен %(count)s пута", + "was kicked %(count)s times|one": "избачен", + "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s је променило своје име %(count)s пута", + "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s је променило своје име", + "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s је променило своје име %(count)s пута", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s је променило своје име", + "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s је променило свој аватар %(count)s пута", + "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s је променило свој аватар", + "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)s је променило свој аватар %(count)s пута", + "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s је променило свој аватар", + "%(items)s and %(count)s others|other": "%(items)s и %(count)s других", + "%(items)s and %(count)s others|one": "%(items)s и још један", + "%(items)s and %(lastItem)s": "%(items)s и %(lastItem)s", + "collapse": "скупи", + "expand": "рашири", + "Custom of %(powerLevel)s": "Прилагођени ниво %(powerLevel)s", + "Custom level": "Прилагођени ниво", + "Quote": "Цитат", + "Room directory": "Фасцикла са собама", + "Start chat": "Започни ћаскање", + "And %(count)s more...|other": "И %(count)s других...", + "ex. @bob:example.com": "нпр.: @pera:domen.rs", + "Add User": "Додај корисника", + "Matrix ID": "Матрикс ИБ", + "Matrix Room ID": "ИБ Матрикс собе", + "email address": "мејл адреса", + "Try using one of the following valid address types: %(validTypesList)s.": "Пробајте са једним од следећих исправних типова адреса: %(validTypesList)s.", + "You have entered an invalid address.": "Унели сте неисправну адресу.", + "Create a new chat or reuse an existing one": "Започните ново ћаскање или искористите постојеће", + "Start new chat": "Започни ново ћаскање", + "You already have existing direct chats with this user:": "Већ имате постојећа директна ћаскања са овим корисником:", + "Start chatting": "Започни ћаскање", + "Click on the button below to start chatting!": "Кликните на дугме испод да бисте започели ћаскање!", + "Start Chatting": "Започни ћаскање", + "Confirm Removal": "Потврди уклањање", + "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Да ли сте сигурни да желите уклонити (обрисати) овај догађај? Знајте да брисање назива собе или мењање теме може опозвати измену.", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "ИБ-јеви заједнице могу садржати само знакове a-z, 0-9, или '=_-./'", + "Community IDs cannot not be empty.": "ИБ-јеви заједнице не могу бити празни.", + "Something went wrong whilst creating your community": "Нешто је пошло наопако приликом стварања ваше заједнице", + "Create Community": "Направи заједницу", + "Community Name": "Назив заједнице", + "Example": "Пример", + "Community ID": "ИБ заједнице", + "example": "пример", + "Create": "Направи", + "Create Room": "Направи собу", + "Room name (optional)": "Назив собе (изборно)", + "Advanced options": "Напредне опције", + "Block users on other matrix homeservers from joining this room": "Блокирај приступ соби корисницима са других матрикс кућних сервера", + "This setting cannot be changed later!": "Ово подешавање се не може променити касније!", + "Unknown error": "Непозната грешка", + "Incorrect password": "Нетачна лозинка", + "Deactivate Account": "Угаси налог", + "This will make your account permanently unusable. You will not be able to re-register the same user ID.": "Ово ће учинити ваш налог трајно неупотребљивим. Нећете моћи да се поново региструјете са истим корисничким ИБ-јем.", + "This action is irreversible.": "Ова радња се не може поништити.", + "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:": "Да бисте проверили да се овом уређају може веровати, контактирајте власника користећи друге начине (нпр.: лично или преко телефонског позива) и питајте га да ли се кључ који види у корисничким подешавањима подудара са кључем испод:", + "Device name": "Назив уређаја", + "Device key": "Кључ уређаја", + "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.": "Ако се подудара, притисните дугме за потврду провере испод. Ако се не подудара, неко други прислушкује овај уређај и вероватно желите да притиснете дугме за стављање на црни списак.", + "In future this verification process will be more sophisticated.": "У будућности ће овај поступак потврђивања бити напреднији.", + "Verify device": "Провери уређај", + "I verify that the keys match": "Потврђујем да се кључеви подударају", + "An error has occurred.": "Догодила се грешка.", + "OK": "У реду", + "You added a new device '%(displayName)s', which is requesting encryption keys.": "Додали сте нови уређај „%(displayName)s“ који захтева кључеве за шифровање.", + "Your unverified device '%(displayName)s' is requesting encryption keys.": "Ваш непотврђени уређај „%(displayName)s“ захтева кључеве за шифровање.", + "Start verification": "Започни потврђивање", + "Share without verifying": "Подели без потврђивања", + "Ignore request": "Занемари захтев", + "Loading device info...": "Учитавам податке о уређају...", + "Encryption key request": "Захтев за кључ шифровања", + "Otherwise, click here to send a bug report.": "У супротном, кликните овде да бисте послали извештај о грешци.", + "Unable to restore session": "Не могу да повратим сесију", + "We encountered an error trying to restore your previous session. If you continue, you will need to log in again, and encrypted chat history will be unreadable.": "Наишли смо на грешку приликом опоравка ваше претходне сесије. Ако наставите, мораћете да се пријавите поново и ваш шифровани историјат ћаскања неће бити читљив.", + "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.": "Ако сте претходно користили новије издање Riot-а, ваша сесија може бити некомпатибилна са овим издањем. Затворите овај прозор и вратите се на новије издање.", + "Continue anyway": "Ипак настави", + "Invalid Email Address": "Неисправна мејл адреса", + "This doesn't appear to be a valid email address": "Изгледа да ово није исправна мејл адреса", + "Verification Pending": "Чека се на потврду", + "Please check your email and click on the link it contains. Once this is done, click continue.": "Проверите ваш мејл и кликните на везу унутар њега. Када ово урадите, кликните на дугме „настави“.", + "Unable to add email address": "Не могу да додам мејл адресу", + "Unable to verify email address.": "Не могу да проверим мејл адресу.", + "This will allow you to reset your password and receive notifications.": "Ово омогућава поновно постављање лозинке и примање обавештења.", + "Skip": "Прескочи", + "User names may only contain letters, numbers, dots, hyphens and underscores.": "Корисничка имена могу садржати само слова, бројеве, тачке, повлаке и доње црте.", + "Username not available": "Корисничко име није доступно", + "Username invalid: %(errMessage)s": "Корисничко име није исправно: %(errMessage)s", + "An error occurred: %(error_string)s": "Догодила се грешка: %(error_string)s", + "Username available": "Корисничко име је доступно", + "To get started, please pick a username!": "Да бисте кренули, изаберите корисничко име!", + "This will be your account name on the homeserver, or you can pick a different server.": "Ово ће бити назив вашег налога на кућном серверу, или можете изабрати други сервер.", + "If you already have a Matrix account you can log in instead.": "Ако већ имате Матрикс налог, можете се већ пријавити.", + "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.": "Предлажемо да прођете кроз поступак провере сваког уређаја да бисте потврдили да они припадају њиховим стварним власницима али можете поново послати поруку без провере, ако то желите.", + "Room contains unknown devices": "Соба садржи непознате уређаје", + "\"%(RoomName)s\" contains devices that you haven't seen before.": "Соба „%(RoomName)s“ садржи уређаје које нисте видели пре.", + "Unknown devices": "Непознати уређаји", + "Private Chat": "Приватно ћаскање", + "Public Chat": "Јавно ћаскање", + "Custom": "Прилагођено", + "Alias (optional)": "Алијас (изборно)", + "Name": "Име", + "Topic": "Тема", + "Make this room private": "Учини ову собу приватном", + "Share message history with new users": "Подели историјат порука са новим корисницима", + "Encrypt room": "Шифруј собу", + "You must register to use this functionality": "Морате се регистровати да бисте користили ову могућност", + "You must join the room to see its files": "Морате приступити соби да бисте видели њене датотеке", + "There are no visible files in this room": "Нема видљивих датотека у овој соби", + "

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 за страницу ваше заједнице

\n

\n Користите дужи опис да бисте упознали нове чланове са заједницом, или поделили\n неке важне везе\n

\n

\n Можете чак користити \"img\" ознаке\n

\n", + "Add rooms to the community summary": "Додај собе у кратак опис заједнице", + "Which rooms would you like to add to this summary?": "Које собе желите додати у овај кратак опис?", + "Add to summary": "Додај у кратак опис", + "Failed to add the following rooms to the summary of %(groupId)s:": "Нисам успео да додам следеће собе у кратак опис групе %(groupId)s:", + "Add a Room": "Додај собу", + "Failed to remove the room from the summary of %(groupId)s": "Нисам успео да уклоним собу из кратког описа групе %(groupId)s", + "The room '%(roomName)s' could not be removed from the summary.": "Соба „%(roomName)s“ се не може уклонити из кратког описа.", + "Add users to the community summary": "Додај кориснике у кратак опис заједнице", + "Who would you like to add to this summary?": "Да ли желите да додате у овај кратак опис?", + "Failed to add the following users to the summary of %(groupId)s:": "Нисам успео да додам следеће кориснике у кратак опис групе %(groupId)s:", + "Add a User": "Додај корисника", + "Failed to remove a user from the summary of %(groupId)s": "Нисам успео да уклоним корисника из кратког описа групе %(groupId)s", + "The user '%(displayName)s' could not be removed from the summary.": "Корисник „%(displayName)s“ се не може уклонити из кратког описа.", + "Failed to upload image": "Нисам успео да отпремим слику", + "Failed to update community": "Нисам успео да ажурирам заједницу", + "Unable to accept invite": "Не могу да прихватим позивницу", + "Unable to reject invite": "Не могу да одбијем позивницу", + "Leave Community": "Напусти заједницу", + "Leave %(groupName)s?": "Напустити %(groupName)s?", + "Leave": "Напусти", + "Unable to leave room": "Не могу да напустим собу", + "Community Settings": "Подешавања заједнице", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Ове собе су приказане члановима заједнице на страници заједнице. Чланови заједнице могу приступити собама кликом на њих.", + "Add rooms to this community": "Додај собе у ову заједницу", + "Featured Rooms:": "Издвојене собе:", + "Featured Users:": "Издвојени корисници:", + "%(inviter)s has invited you to join this community": "Корисник %(inviter)s вас је позвао у ову заједницу", + "You are an administrator of this community": "Ви сте администратор ове заједнице", + "You are a member of this community": "Ви сте члан ове заједнице", + "Your community hasn't got a Long Description, a HTML page to show to community members.
Click here to open settings and give it one!": "Ваша заједница нема дуги опис, HTML страницу на којој су приказани чланови заједнице.
Кликните овде да бисте отворили подешавања и направили страницу!", + "Long Description (HTML)": "Дуги опис (HTML)", + "Description": "Опис", + "Community %(groupId)s not found": "Заједница %(groupId)s није нађена", + "This Home server does not support communities": "Овај кућни сервер не подржава заједнице", + "Failed to load %(groupId)s": "Нисам успео да учитам %(groupId)s", + "Reject invitation": "Одбиј позивницу", + "Are you sure you want to reject the invitation?": "Да ли сте сигурни да желите одбити позивницу?", + "Failed to reject invitation": "Нисам успео да одбијем позивницу", + "Are you sure you want to leave the room '%(roomName)s'?": "Да ли сте сигурни да желите напустити собу „%(roomName)s“?", + "Failed to leave room": "Нисам успео да напустим собу", + "Signed Out": "Одјављен", + "For security, this session has been signed out. Please sign in again.": "Зарад безбедности, одјављени сте из ове сесије. Пријавите се поново.", + "Cryptography data migrated": "Криптографски подаци су пренесени", + "A one-off migration of cryptography data has been performed. End-to-end encryption will not work if you go back to an older version of Riot. If you need to use end-to-end cryptography on an older version, log out of Riot first. To retain message history, export and re-import your keys.": "Једноструко преношење криптографских података је обављено. Шифровање с краја на крај неће радити ако се вратите на старије издање Riot-а. Ако вам треба шифровање с краја на крај на старијем издању, прво се одјавите из Riot-а. Да бисте задржали историјат порука, извезите па поново увезите ваше кључеве.", + "Old cryptography data detected": "Нађени су стари криптографски подаци" } From 330ce0f02e31a7be7195624718fb3caf5ad1d11a Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Mon, 5 Feb 2018 17:29:22 +0000 Subject: [PATCH 027/242] On failure, regenerate state from sdk Instead of using history, which could be unpredictable --- src/stores/RoomListStore.js | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 69d957f074..e48eacaa6a 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -26,7 +26,6 @@ class RoomListStore extends Store { super(dis); this._init(); - this._actionHistory = []; } _init() { @@ -57,14 +56,13 @@ class RoomListStore extends Store { break; } - this._generateRoomLists(payload.matrixClient); - this._actionHistory.unshift(payload); + this._matrixClient = payload.matrixClient; + this._generateRoomLists(); } break; case 'MatrixActions.Room.tags': { if (!this._state.ready) break; this._updateRoomLists(payload.room); - this._actionHistory.unshift(payload); } break; case 'RoomListActions.tagRoom.pending': { @@ -74,35 +72,22 @@ class RoomListStore extends Store { payload.request.newTag, payload.request.metaData, ); - this._actionHistory.unshift(payload); } break; case 'RoomListActions.tagRoom.failure': { - this._actionHistory = this._actionHistory.filter((action) => { - return action.asyncId !== payload.asyncId; - }); - - // don't duplicate history - const history = this._actionHistory.slice(0); - this._actionHistory = []; - this._reloadFromHistory(history); + // Reset state according to js-sdk + this._generateRoomLists(); } break; case 'on_logged_out': { // Reset state without pushing an update to the view, which generally assumes that // the matrix client isn't `null` and so causing a re-render will cause NPEs. this._init(); - this._actionHistory.unshift(payload); } break; } } - _reloadFromHistory(history) { - this._init(); - history.forEach((action) => this.__onDispatch(action)); - } - _updateRoomListsOptimistic(updatedRoom, oldTag, newTag, metaData) { const newLists = {}; @@ -153,7 +138,7 @@ class RoomListStore extends Store { }); } - _generateRoomLists(matrixClient) { + _generateRoomLists() { const lists = { "im.vector.fake.invite": [], "m.favourite": [], @@ -163,10 +148,14 @@ class RoomListStore extends Store { "im.vector.fake.archived": [], }; + const dmRoomMap = DMRoomMap.shared(); - matrixClient.getRooms().forEach((room, index) => { - const me = room.getMember(matrixClient.credentials.userId); + // If somehow we dispatched a RoomListActions.tagRoom.failure before a MatrixActions.sync + if (!this._matrixClient) return; + + this._matrixClient.getRooms().forEach((room, index) => { + const me = room.getMember(this._matrixClient.credentials.userId); if (!me) return; if (me.membership == "invite") { From 9982efbd8f61b75c4d4c688ce0124b47fb6c9deb Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Mon, 5 Feb 2018 18:06:29 +0000 Subject: [PATCH 028/242] Regenerate room lists when we get m.direct --- src/stores/RoomListStore.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index e48eacaa6a..6a9217eab4 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -65,6 +65,11 @@ class RoomListStore extends Store { this._updateRoomLists(payload.room); } break; + case 'MatrixActions.accountData': { + if (payload.event_type !== 'm.direct') break; + this._generateRoomLists(); + } + break; case 'RoomListActions.tagRoom.pending': { this._updateRoomListsOptimistic( payload.request.room, From c665c1170b419ec8b6e6b4b5fe7e7e06a792d0bd Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Mon, 5 Feb 2018 18:27:50 +0000 Subject: [PATCH 029/242] Regenerate room lists when we get RoomMember.membership --- src/actions/MatrixActionCreators.js | 5 +++++ src/stores/RoomListStore.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index d9309d7c1c..f4d6c34ff5 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -66,6 +66,10 @@ function createRoomTagsAction(matrixClient, roomTagsEvent, room) { return { action: 'MatrixActions.Room.tags', room }; } +function createRoomMembershipAction(matrixClient, membershipEvent, member, oldMembership) { + return { action: 'MatrixActions.RoomMember.membership', member }; +} + /** * This object is responsible for dispatching actions when certain events are emitted by * the given MatrixClient. @@ -83,6 +87,7 @@ export default { this._addMatrixClientListener(matrixClient, 'sync', createSyncAction); this._addMatrixClientListener(matrixClient, 'accountData', createAccountDataAction); this._addMatrixClientListener(matrixClient, 'Room.tags', createRoomTagsAction); + this._addMatrixClientListener(matrixClient, 'RoomMember.membership', createRoomMembershipAction); }, /** diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 6a9217eab4..28ffee99d2 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -70,6 +70,11 @@ class RoomListStore extends Store { this._generateRoomLists(); } break; + case 'MatrixActions.RoomMember.membership': { + if (!this._matrixClient || payload.member.userId !== this._matrixClient.credentials.userId) break; + this._generateRoomLists(); + } + break; case 'RoomListActions.tagRoom.pending': { this._updateRoomListsOptimistic( payload.request.room, From 0f2ca3bd95ea68401482152c36291bfa1553802d Mon Sep 17 00:00:00 2001 From: "Robert A. Viana" Date: Tue, 6 Feb 2018 09:07:38 +0000 Subject: [PATCH 030/242] Translated using Weblate (Portuguese (Brazil)) Currently translated at 66.9% (659 of 984 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 817d094422..5a9c4d7d65 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -656,5 +656,7 @@ "You are not in this room.": "Você não está nesta sala.", "You do not have permission to do that in this room.": "Você não tem permissão para fazer isto nesta sala.", "Ignored user": "Usuário ignorado", - "You are no longer ignoring %(userId)s": "Você parou de ignorar %(userId)s" + "You are no longer ignoring %(userId)s": "Você parou de ignorar %(userId)s", + "Edit": "Editar", + "Unpin Message": "Desafixar Mensagem" } From feca1707f119bab11c836a810ec9566df7de6498 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Tue, 6 Feb 2018 09:55:58 +0000 Subject: [PATCH 031/242] Remove a factor n complexity during room visibility calc --- src/components/views/rooms/RoomList.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index ad85beac12..269f04c963 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -352,6 +352,14 @@ module.exports = React.createClass({ const filteredLists = {}; + const isRoomVisible = { + // $roomId: true, + }; + + this._visibleRooms.forEach((r) => { + isRoomVisible[r.roomId] = true; + }); + Object.keys(lists).forEach((tagName) => { filteredLists[tagName] = lists[tagName].filter((taggedRoom) => { // Somewhat impossible, but guard against it anyway @@ -363,9 +371,7 @@ module.exports = React.createClass({ return; } - return this._visibleRooms.some((visibleRoom) => { - return visibleRoom.roomId === taggedRoom.roomId; - }); + return isRoomVisible[taggedRoom.roomId]; }); }); From 623cc10ab073a0d90254b00b5de02616460e979a Mon Sep 17 00:00:00 2001 From: "Robert A. Viana" Date: Tue, 6 Feb 2018 09:15:50 +0000 Subject: [PATCH 032/242] Translated using Weblate (Portuguese (Brazil)) Currently translated at 67.0% (660 of 984 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 5a9c4d7d65..f2bd95185e 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -658,5 +658,6 @@ "Ignored user": "Usuário ignorado", "You are no longer ignoring %(userId)s": "Você parou de ignorar %(userId)s", "Edit": "Editar", - "Unpin Message": "Desafixar Mensagem" + "Unpin Message": "Desafixar Mensagem", + "Add rooms to this community": "Adicionar salas na comunidade" } From b744dbaab7d7feb3008f144a369d7f7cb4309eea Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Tue, 6 Feb 2018 11:56:55 +0000 Subject: [PATCH 033/242] Handle setting a newTag without metaData metaData is actually the request body for the PUT that adds the tag so we need to send {} for e.g. m.lowpriority, which is not manually ordered. --- src/actions/RoomListActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/RoomListActions.js b/src/actions/RoomListActions.js index 3e0ea53a33..5802dbcaed 100644 --- a/src/actions/RoomListActions.js +++ b/src/actions/RoomListActions.js @@ -114,7 +114,7 @@ RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex, (hasChangedSubLists || metaData) ) { // Optimistic update of what will happen to the room tags - room.tags[newTag] = metaData; + room.tags[newTag] = metaData || {}; const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); From 8d0d0b43ffa6440bf98577c2246d6ec78fa3ab76 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Tue, 6 Feb 2018 12:00:06 +0000 Subject: [PATCH 034/242] Handle first tag added/last tag removed This is a special case because untagged rooms should appear in im.vector.fake.recent and tagged rooms should not. --- src/stores/RoomListStore.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 28ffee99d2..32aab47009 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -101,6 +101,16 @@ class RoomListStore extends Store { _updateRoomListsOptimistic(updatedRoom, oldTag, newTag, metaData) { const newLists = {}; + // Adding a tag to an untagged room - need to remove it from recents + if (newTag && Object.keys(updatedRoom.tags).length === 0) { + oldTag = 'im.vector.fake.recent'; + } + + // Removing a tag from a room with one tag left - need to add it to recents + if (oldTag && Object.keys(updatedRoom.tags).length === 1) { + newTag = 'im.vector.fake.recent'; + } + // Remove room from oldTag Object.keys(this._state.lists).forEach((tagName) => { if (tagName === oldTag) { From dd0e981d728e9cb9974ed49d0cc46b48f1dea7ae Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Tue, 6 Feb 2018 12:00:23 +0000 Subject: [PATCH 035/242] Handle indication from server that a room has no more tags --- src/stores/RoomListStore.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 32aab47009..42c77d5237 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -153,6 +153,10 @@ class RoomListStore extends Store { newLists[tagName].push(updatedRoom); }); + if (roomTags.length === 0) { + newLists['im.vector.fake.recent'].unshift(updatedRoom); + } + this._setState({ lists: newLists, }); From 6a858863fcf8b49382b6a442dffca7bb53c0ec74 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 6 Feb 2018 12:41:13 +0000 Subject: [PATCH 036/242] Translated using Weblate (Russian) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ru/ --- src/i18n/strings/ru.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 5f82177a2f..e7cc2f2319 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -980,5 +980,9 @@ "This room is not public. You will not be able to rejoin without an invite.": "Эта комната не является публичной. Вы не сможете войти без приглашения.", "Show devices, send anyway or cancel.": "Показать устройства, отправить в любом случае или отменить.", "Community IDs cannot not be empty.": "ID сообществ не могут быть пустыми.", - "In reply to ": "В ответ на " + "In reply to ": "В ответ на ", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s изменил отображаемое имя на %(displayName)s.", + "Failed to set direct chat tag": "Не удалось установить тег прямого чата", + "Failed to remove tag %(tagName)s from room": "Не удалось удалить тег %(tagName)s из комнаты", + "Failed to add tag %(tagName)s to room": "Не удалось добавить тег %(tagName)s в комнату" } From 1ea6301ecaf7154acc4b862f2d7f7639ea32e711 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Tue, 6 Feb 2018 14:25:33 +0000 Subject: [PATCH 037/242] Add index fix again This was changed on /develop to fix an issue where the incorrect index was being used in a condition to handle literal edge cases of dragging room tiles to start or end of an ordered sublist. --- src/actions/RoomListActions.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/actions/RoomListActions.js b/src/actions/RoomListActions.js index 5802dbcaed..f59e9953ee 100644 --- a/src/actions/RoomListActions.js +++ b/src/actions/RoomListActions.js @@ -56,10 +56,13 @@ RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex, newTag === oldTag && oldIndex < newIndex ) ? 1 : 0; - const prevOrder = newIndex === 0 ? - 0 : newList[offset + newIndex - 1].tags[newTag].order; - const nextOrder = newIndex === newList.length ? - 1 : newList[offset + newIndex].tags[newTag].order; + const indexBefore = offset + newIndex - 1; + const indexAfter = offset + newIndex; + + const prevOrder = indexBefore <= 0 ? + 0 : newList[indexBefore].tags[newTag].order; + const nextOrder = indexAfter >= newList.length ? + 1 : newList[indexAfter].tags[newTag].order; metaData = { order: (prevOrder + nextOrder) / 2.0, From ab88c1cf58b4d9b08362b1eca2cdb892bffc3338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Tue, 6 Feb 2018 19:11:22 +0000 Subject: [PATCH 038/242] Translated using Weblate (French) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://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 36620c2894..f0f9b2dae9 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -980,5 +980,9 @@ "This room is not public. You will not be able to rejoin without an invite.": "Ce salon n'est pas public. Vous ne pourrez pas y revenir sans invitation.", "Community IDs cannot not be empty.": "Les identifiants de communauté ne peuvent pas être vides.", "Show devices, send anyway or cancel.": "Afficher les appareils, envoyer quand même ou annuler.", - "In reply to ": "En réponse à " + "In reply to ": "En réponse à ", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s a changé son nom affiché en %(displayName)s.", + "Failed to set direct chat tag": "Échec de l'ajout de l'étiquette discussion directe", + "Failed to remove tag %(tagName)s from room": "Échec de la suppression de l'étiquette %(tagName)s du salon", + "Failed to add tag %(tagName)s to room": "Échec de l'ajout de l'étiquette %(tagName)s au salon" } From 1b196655fa0767391f59383e699b86cc9a82e3c8 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 6 Feb 2018 21:11:17 +0000 Subject: [PATCH 039/242] Translated using Weblate (Hungarian) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 29067f0bb4..4f06bbfc4e 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -980,5 +980,9 @@ "This room is not public. You will not be able to rejoin without an invite.": "Ez a szoba nem nyilvános. Kilépés után csak újabb meghívóval tudsz újra belépni a szobába.", "Show devices, send anyway or cancel.": "Eszközök listája, mindenképpen küld vagy szakítsd meg.", "Community IDs cannot not be empty.": "A közösségi azonosító nem lehet üres.", - "In reply to ": "Válaszolva neki " + "In reply to ": "Válaszolva neki ", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s megváltoztatta a nevét erre: %(displayName)s.", + "Failed to set direct chat tag": "Nem sikerült a közvetlen beszélgetés jelzést beállítani", + "Failed to remove tag %(tagName)s from room": "Nem sikerült a szobáról eltávolítani ezt: %(tagName)s", + "Failed to add tag %(tagName)s to room": "Nem sikerült hozzáadni a szobához ezt: %(tagName)s" } From 054849bc18c304b042ad1a0e5e8ecbea9268a207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Wed, 7 Feb 2018 08:52:37 +0000 Subject: [PATCH 040/242] Translated using Weblate (Slovak) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sk/ --- src/i18n/strings/sk.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index fa118beca4..959a18270a 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -977,5 +977,12 @@ "Whether or not you're using the Richtext mode of the Rich Text Editor": "Či pri písaní správ používate rozbalenú lištu formátovania textu", "Your homeserver's URL": "URL adresa vami používaného domovského servera", "Your identity server's URL": "URL adresa vami používaného servera totožností", - "This room is not public. You will not be able to rejoin without an invite.": "Toto nie je verejne dostupná miestnosť. Bez pozvánky nebudete do nej môcť vstúpiť znovu." + "This room is not public. You will not be able to rejoin without an invite.": "Toto nie je verejne dostupná miestnosť. Bez pozvánky nebudete do nej môcť vstúpiť znovu.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s si zmenil zobrazované meno na %(displayName)s.", + "Failed to set direct chat tag": "Nepodarilo sa nastaviť značku priama konverzácia", + "Failed to remove tag %(tagName)s from room": "Z miestnosti sa nepodarilo odstrániť značku %(tagName)s", + "Failed to add tag %(tagName)s to room": "Miestnosti sa nepodarilo pridať značku %(tagName)s", + "In reply to ": "Odpoveď na ", + "Community IDs cannot not be empty.": "ID komunity nemôže ostať prázdne.", + "Show devices, send anyway or cancel.": "Zobraziť zariadenia, napriek tomu odoslať alebo zrušiť." } From ae094bebe576a58b8c0b6ca893b2e4c650a0d87a Mon Sep 17 00:00:00 2001 From: Krombel Date: Wed, 7 Feb 2018 09:40:21 +0000 Subject: [PATCH 041/242] Translated using Weblate (German) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index 05745932b9..a1687858d1 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -980,5 +980,9 @@ "Whether or not you're logged in (we don't record your user name)": "Ob oder ob du nicht angemeldet bist (wir zeichnen deinen Benutzernamen nicht auf)", "Which officially provided instance you are using, if any": "Welche offiziell angebotene Instanz du nutzt, wenn es der Fall ist", "In reply to ": "Antwort zu ", - "This room is not public. You will not be able to rejoin without an invite.": "Dies ist kein öffentlicher Raum. Du wirst diesen nicht ohne Einladung wieder beitreten können." + "This room is not public. You will not be able to rejoin without an invite.": "Dies ist kein öffentlicher Raum. Du wirst diesen nicht ohne Einladung wieder beitreten können.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s änderte den Anzeigenamen auf %(displayName)s.", + "Failed to set direct chat tag": "Fehler beim Setzen der Direkt-Chat-Markierung", + "Failed to remove tag %(tagName)s from room": "Fehler beim Entfernen des \"%(tagName)s\"-Tags von dem Raum", + "Failed to add tag %(tagName)s to room": "Fehler beim Hinzufügen des \"%(tagName)s\"-Tags von dem Raum" } From 74a28a749661e2e742bac2085f2b517081ae8397 Mon Sep 17 00:00:00 2001 From: Krombel Date: Wed, 7 Feb 2018 09:41:35 +0000 Subject: [PATCH 042/242] Translated using Weblate (German) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/de/ --- src/i18n/strings/de_DE.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index a1687858d1..f92b7b479a 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -984,5 +984,5 @@ "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s änderte den Anzeigenamen auf %(displayName)s.", "Failed to set direct chat tag": "Fehler beim Setzen der Direkt-Chat-Markierung", "Failed to remove tag %(tagName)s from room": "Fehler beim Entfernen des \"%(tagName)s\"-Tags von dem Raum", - "Failed to add tag %(tagName)s to room": "Fehler beim Hinzufügen des \"%(tagName)s\"-Tags von dem Raum" + "Failed to add tag %(tagName)s to room": "Fehler beim Hinzufügen des \"%(tagName)s\"-Tags an dem Raum" } From 443c19c6e149aa7667f8f4b162911eabe34eb006 Mon Sep 17 00:00:00 2001 From: Szimszon Date: Tue, 6 Feb 2018 21:13:13 +0000 Subject: [PATCH 043/242] Translated using Weblate (Hungarian) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/hu/ --- src/i18n/strings/hu.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 4f06bbfc4e..48132200a3 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -890,7 +890,7 @@ "%(items)s and %(count)s others|other": "%(items)s és még %(count)s másik", "%(items)s and %(count)s others|one": "%(items)s és még egy másik", "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Az e-mail leküldésre került ide: %(emailAddress)s. Ha követte a levélben lévő linket kattints alább.", - "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "%(roomName)s szoba láthatóságát nem lehet frissíteni ebben a közösségben: %(groupId)s", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "%(roomName)s szoba láthatóságát nem lehet frissíteni ebben a közösségben: %(groupId)s.", "Visibility in Room List": "Láthatóság a szoba listában", "Visible to everyone": "Mindenki számára látható", "Only visible to community members": "Csak a közösség számára látható", From b65e80fa53b49ae2f5802a2521be868b219ac965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=BA=D0=BE=20=D0=9C=2E=20=D0=9A=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=9B?= Date: Tue, 6 Feb 2018 21:40:24 +0000 Subject: [PATCH 044/242] Translated using Weblate (Serbian) Currently translated at 80.4% (793 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sr/ --- src/i18n/strings/sr.json | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index 1a6da54baa..9d5c08046a 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -769,5 +769,28 @@ "For security, this session has been signed out. Please sign in again.": "Зарад безбедности, одјављени сте из ове сесије. Пријавите се поново.", "Cryptography data migrated": "Криптографски подаци су пренесени", "A one-off migration of cryptography data has been performed. End-to-end encryption will not work if you go back to an older version of Riot. If you need to use end-to-end cryptography on an older version, log out of Riot first. To retain message history, export and re-import your keys.": "Једноструко преношење криптографских података је обављено. Шифровање с краја на крај неће радити ако се вратите на старије издање Riot-а. Ако вам треба шифровање с краја на крај на старијем издању, прво се одјавите из Riot-а. Да бисте задржали историјат порука, извезите па поново увезите ваше кључеве.", - "Old cryptography data detected": "Нађени су стари криптографски подаци" + "Old cryptography data detected": "Нађени су стари криптографски подаци", + "The platform you're on": "Платформа коју користите", + "The version of Riot.im": "Riot.im издање", + "Whether or not you're logged in (we don't record your user name)": "Стање ваше пријављености (не памтимо ваше корисничко име)", + "Your language of choice": "Ваш жељени језик", + "Which officially provided instance you are using, if any": "Коју званичну инстанцу користите, ако користите", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Да ли користите режим богатог текста у уређивачу богатог текста", + "Your homeserver's URL": "Адреса вашег кућног сервера", + "Your identity server's URL": "Адреса вашег идентитеског сервера", + "Analytics": "Аналитика", + "The information being sent to us to help make Riot.im better includes:": "У податке које нам шаљете зарад побољшавања Riot.im-а спадају:", + "We also record each page you use in the app (currently ), your User Agent () and your device resolution ().": "Такође бележимо сваку страницу коју користите у апликацији (тренутно ), ваш кориснички агент () и резолуцију вашег уређаја ().", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Ако страница садржи поверљиве податке (као што је назив собе, корисника или ИБ-ја групе), ти подаци се уклањају пре слања на сервер.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "Корисник %(oldDisplayName)s је променио приказно име у %(displayName)s.", + "Failed to set direct chat tag": "Нисам успео да поставим ознаку директног ћаскања", + "Failed to remove tag %(tagName)s from room": "Нисам успео да скинем ознаку %(tagName)s са собе", + "Failed to add tag %(tagName)s to room": "Нисам успео да додам ознаку %(tagName)s на собу", + "In reply to ": "Као одговор за ", + "This room is not public. You will not be able to rejoin without an invite.": "Ова соба није јавна. Нећете моћи да поново приступите без позивнице.", + "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.": "Подаци из старијег издања Riot-а су нађени. Ово ће узроковати лош рад шифровања с краја на крај у старијем издању. Размењене поруке које су шифроване с краја на крај у старијем издању је можда немогуће дешифровати у овом издању. Такође, ово може узроковати неуспешно размењивање порука са овим издањем. Ако доживите проблеме, одјавите се и пријавите се поново. Да бисте задржали историјат поруке, извезите па поново увезите ваше кључеве.", + "Logout": "Одјава", + "Your Communities": "Ваше заједнице", + "Error whilst fetching joined communities": "Грешка приликом добављања списка са приступљеним заједницама", + "Create a new community": "Направи нову заједницу" } From 8d21803df5c9b36b93d06fcc996db552bc819a2d Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Wed, 7 Feb 2018 11:57:06 +0000 Subject: [PATCH 045/242] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/zh_Hant/ --- src/i18n/strings/zh_Hant.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 93a324aba0..8ea32cf99c 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -980,5 +980,9 @@ "This room is not public. You will not be able to rejoin without an invite.": "這個聊天室並未公開。您在沒有邀請的情況下將無法重新加入。", "Community IDs cannot not be empty.": "社群 ID 不能為空。", "Show devices, send anyway or cancel.": "顯示裝置無論如何都要傳送取消。", - "In reply to ": "回覆給 " + "In reply to ": "回覆給 ", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s 變更了他們的顯示名稱為 %(displayName)s 。", + "Failed to set direct chat tag": "設定直接聊天標籤失敗", + "Failed to remove tag %(tagName)s from room": "從聊天室移除標籤 %(tagName)s 失敗", + "Failed to add tag %(tagName)s to room": "新增標籤 %(tagName)s 到聊天室失敗" } From 34eae0fbde1b59b8a1a37feadd7658694b72ccbe Mon Sep 17 00:00:00 2001 From: "Robert A. Viana" Date: Wed, 7 Feb 2018 11:19:03 +0000 Subject: [PATCH 046/242] Translated using Weblate (Portuguese (Brazil)) Currently translated at 67.0% (661 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/pt_BR/ --- src/i18n/strings/pt_BR.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 023294db22..8c7b6ffbd6 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -658,5 +658,7 @@ "You are no longer ignoring %(userId)s": "Você parou de ignorar %(userId)s", "Edit": "Editar", "Unpin Message": "Desafixar Mensagem", - "Add rooms to this community": "Adicionar salas na comunidade" + "Add rooms to this community": "Adicionar salas na comunidade", + "The version of Riot.im": "A Versão do Riot.im", + "Whether or not you're logged in (we don't record your user name)": "Se você está ou não conectado (Nos não Gravaremos seu nome de usuário)" } From 5cf3d3176fd7b31eeb197982fe41e7852ee096b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=BA=D0=BE=20=D0=9C=2E=20=D0=9A=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=9B?= Date: Wed, 7 Feb 2018 20:35:20 +0000 Subject: [PATCH 047/242] Translated using Weblate (Serbian) Currently translated at 91.1% (899 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sr/ --- src/i18n/strings/sr.json | 108 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index 9d5c08046a..9a38d6fac8 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -792,5 +792,111 @@ "Logout": "Одјава", "Your Communities": "Ваше заједнице", "Error whilst fetching joined communities": "Грешка приликом добављања списка са приступљеним заједницама", - "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.": "Направите заједницу да бисте спојили кориснике и собе! Направите прилагођену почетну страницу да бисте означили ваш кутак у Матрикс универзуму.", + "Join an existing community": "Приступи већ постојећој заједници", + "To join an existing community you'll have to know its community identifier; this will look something like +example:matrix.org.": "Да бисте приступили већ постојећој заједници, морате знати њен идентификатор заједнице. Ово изгледа нешто као +primer:matrix.org.", + "You have no visible notifications": "Немате видљивих обавештења", + "Scroll to bottom of page": "Превуци на дно странице", + "Message not sent due to unknown devices being present": "Порука се неће послати због присутности непознатих уређаја", + "Show devices, send anyway or cancel.": "Прикажи уређаје, ипак пошаљи или откажи.", + "%(count)s of your messages have not been sent.|other": "Неке ваше поруке нису послате.", + "%(count)s of your messages have not been sent.|one": "Ваша порука није послата.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|other": "Пошаљи поново или откажи све сада. Такође можете изабрати појединачне поруке за поновно слање или отказивање.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Поново пошаљи поруку или откажи поруку сада.", + "Warning": "Упозорење", + "Connectivity to the server has been lost.": "Веза ка серверу је прекинута.", + "Sent messages will be stored until your connection has returned.": "Послате поруке биће сачуване док се веза не успостави поново.", + "%(count)s new messages|other": "%(count)s нових порука", + "%(count)s new messages|one": "%(count)s нова порука", + "Active call": "Текући позив", + "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 in a call, are you sure you want to quit?": "Изгледа да сте у позиву. Да ли сте сигурни да желите изаћи?", + "Failed to upload file": "Нисам успео да отпремим датотеку", + "Server may be unavailable, overloaded, or the file too big": "Сервер је можда недоступан, преоптерећен или је датотека сувише велика", + "Search failed": "Претрага је неуспешна", + "Server may be unavailable, overloaded, or search timed out :(": "Сервер је можда недоступан, преоптерећен или је истекло време претраживања :(", + "No more results": "Нема више резултата", + "Unknown room %(roomId)s": "Непозната соба %(roomId)s", + "Room": "Соба", + "Failed to save settings": "Нисам успео да сачувам подешавања", + "Failed to reject invite": "Нисам успео да одбацим позивницу", + "Fill screen": "Испуни екран", + "Click to unmute video": "Кликни да појачаш видео", + "Click to mute video": "Кликни да утишаш видео", + "Click to unmute audio": "Кликни да појачаш звук", + "Click to mute audio": "Кликни да утишаш звук", + "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Покушао сам да учитам одређену тачку у временској линији ове собе али ви немате овлашћења за преглед наведене поруке.", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "Покушао сам да учитам одређену тачку у временској линији ове собе али нисам могао да је нађем.", + "Failed to load timeline position": "Нисам могао да учитам позицију у временској линији", + "Uploading %(filename)s and %(count)s others|other": "Отпремам датотеку %(filename)s и још %(count)s других", + "Uploading %(filename)s and %(count)s others|zero": "Отпремам датотеку %(filename)s", + "Uploading %(filename)s and %(count)s others|one": "Отпремам датотеку %(filename)s и %(count)s других датотека", + "Light theme": "Светла тема", + "Dark theme": "Тамна тема", + "Status.im theme": "Status.im тема", + "Can't load user settings": "Не могу да учитам корисничка подешавања", + "Server may be unavailable or overloaded": "Сервер је недоступан или је преоптерећен", + "Sign out": "Одјави ме", + "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.": "Зарад безбедности, одјава ће обрисати све кључеве за шифровање с краја на крај, на овом прегледачу. Ако желите да дешифрујете историјат вашег ћаскања из будућих Riot сесија, извезите ваше кључеве и чувајте их.", + "Failed to change password. Is your password correct?": "Нисам успео да променим лозинку. Да ли је ваша лозинка тачна?", + "Success": "Успех", + "Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them": "Ваша лозинка је успешно промењена. Нећете добијати пуш обавештења на вашим другим уређајима док се поново не пријавите на њима", + "Remove Contact Information?": "Уклонити контакт податке?", + "Remove %(threePid)s?": "Уклонити %(threePid)s?", + "Unable to remove contact information": "Не могу да уклоним контакт податке", + "Refer a friend to Riot:": "Кажите пријатељу за Riot:", + "Interface Language": "Језик интерфејса", + "User Interface": "Кориснички интерфејс", + "Autocomplete Delay (ms):": "Застој самодопуњавања (мс):", + "": "<није подржано>", + "Import E2E room keys": "Увези E2E кључеве собе", + "Cryptography": "Криптографија", + "Device ID:": "ИБ уређаја:", + "Device key:": "Кључ уређаја:", + "Ignored Users": "Занемарени корисници", + "Bug Report": "Извештај о грешци", + "Found a bug?": "Нашли сте грешку?", + "Report it": "Пријавите је", + "Riot collects anonymous analytics to allow us to improve the application.": "Riot прикупља анонимне податке о коришћењу да бисмо побољшали апликацију.", + "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Приватност је веома важна нама те не сакупљамо било какве податке личне природе у нашој аналитици.", + "Learn more about how we use analytics.": "Сазнајте више о нашем начину употребе аналитике.", + "Labs": "Лабораторије", + "These are experimental features that may break in unexpected ways": "Ово су пробне могућности које се могу поломити на непредвидљиве начине", + "Use with caution": "Опрезно користите", + "Deactivate my account": "Деактивирај мој налог", + "Clear Cache": "Очисти кеш", + "Clear Cache and Reload": "Очисти кеш и поново учитај", + "Updates": "Ажурирања", + "Check for update": "Провери да ли има ажурирања", + "Reject all %(invitedRooms)s invites": "Одбиј све позивнице за собе %(invitedRooms)s", + "Bulk Options": "Вишеструке опције", + "Desktop specific": "Само за стоне уређаје", + "Start automatically after system login": "Самостално покрећи након пријаве на систем", + "No media permissions": "Нема овлашћења за медије", + "You may need to manually permit Riot to access your microphone/webcam": "Можда ћете морати да ручно доделите овлашћења Riot-у за приступ микрофону/веб камери", + "Missing Media Permissions, click here to request.": "Недостају овлашћења за медије, кликните овде да затражите.", + "No Microphones detected": "Нема уочених микрофона", + "No Webcams detected": "Нема уочених веб камера", + "Default Device": "Подразумевани уређај", + "Microphone": "Микрофон", + "Camera": "Камера", + "VoIP": "VoIP", + "Email": "Мејл", + "Add email address": "Додај мејл адресу", + "Notifications": "Обавештења", + "Profile": "Профил", + "Display name": "Приказно име", + "Account": "Налог", + "To return to your account in future you need to set a password": "Да бисте се вратили у ваш налог у будућности, морате поставити лозинку", + "Logged in as:": "Пријављени као:", + "Access Token:": "Приступни жетон:", + "click to reveal": "кликни за приказ", + "Homeserver is": "Кућни сервер је", + "Identity Server is": "Идентитетски сервер је", + "matrix-react-sdk version:": "matrix-react-sdk издање:", + "riot-web version:": "riot-web издање:", + "olm version:": "olm издање:", + "Failed to send email": "Нисам успео да пошаљем мејл" } From 7a594ce08dbcb1b0248ecfe39acab5b8ce60a607 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 8 Feb 2018 17:58:53 +0200 Subject: [PATCH 048/242] Add seconds to formatFullDate() Fixes vector-im/riot-web#6055 Signed-off-by: Tulir Asokan --- src/DateUtils.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/DateUtils.js b/src/DateUtils.js index 986525eec8..108697238c 100644 --- a/src/DateUtils.js +++ b/src/DateUtils.js @@ -50,11 +50,15 @@ function pad(n) { return (n < 10 ? '0' : '') + n; } -function twelveHourTime(date) { +function twelveHourTime(date, showSeconds=false) { let hours = date.getHours() % 12; const minutes = pad(date.getMinutes()); const ampm = date.getHours() >= 12 ? _t('PM') : _t('AM'); hours = hours ? hours : 12; // convert 0 -> 12 + if (showSeconds) { + const seconds = pad(date.getSeconds()); + return `${hours}:${minutes}:${seconds}${ampm}`; + } return `${hours}:${minutes}${ampm}`; } @@ -101,10 +105,17 @@ export function formatFullDate(date, showTwelveHour=false) { monthName: months[date.getMonth()], day: date.getDate(), fullYear: date.getFullYear(), - time: formatTime(date, showTwelveHour), + time: formatFullTime(date, showTwelveHour), }); } +export function formatFullTime(date, showTwelveHour=false) { + if (showTwelveHour) { + return twelveHourTime(date, true); + } + return pad(date.getHours()) + ':' + pad(date.getMinutes()) + ':' + pad(date.getSeconds()); +} + export function formatTime(date, showTwelveHour=false) { if (showTwelveHour) { return twelveHourTime(date); From 21d70125e4e21d40320c793186527d96c9b9358c Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 8 Feb 2018 14:48:29 +0000 Subject: [PATCH 049/242] Dispatch MatrixActions synchronously Otherwise we risk blocking the dispatches on other work, and they do not need to be done asynchronously. This emerged as a bug where the room list appeared empty until MatrixActions.sync dispatches all occured in one big lump, well after the sync events being emitted by the js-sdk. --- src/actions/MatrixActionCreators.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index f4d6c34ff5..dbfe910533 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -101,7 +101,7 @@ export default { */ _addMatrixClientListener(matrixClient, eventName, actionCreator) { const listener = (...args) => { - dis.dispatch(actionCreator(matrixClient, ...args)); + dis.dispatch(actionCreator(matrixClient, ...args), true); }; matrixClient.on(eventName, listener); this._matrixClientListenersStop.push(() => { From 9b0df1914953223cbbf31b33231585d1ba6f5afb Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Tue, 6 Feb 2018 15:15:47 +0000 Subject: [PATCH 050/242] Make RoomListStore aware of sub list orderings so that it can do optimistic updates of ordered lists. --- src/actions/RoomListActions.js | 5 +- src/stores/RoomListStore.js | 173 +++++++++++++++++++-------------- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/src/actions/RoomListActions.js b/src/actions/RoomListActions.js index f59e9953ee..a92bd1ebaf 100644 --- a/src/actions/RoomListActions.js +++ b/src/actions/RoomListActions.js @@ -116,8 +116,9 @@ RoomListActions.tagRoom = function(matrixClient, room, oldTag, newTag, oldIndex, if (newTag && newTag !== 'im.vector.fake.direct' && (hasChangedSubLists || metaData) ) { - // Optimistic update of what will happen to the room tags - room.tags[newTag] = metaData || {}; + // metaData is the body of the PUT to set the tag, so it must + // at least be an empty object. + metaData = metaData || {}; const promiseToAdd = matrixClient.setRoomTag(roomId, newTag, metaData).catch(function(err) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 42c77d5237..193784811c 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -16,6 +16,7 @@ limitations under the License. import {Store} from 'flux/utils'; import dis from '../dispatcher'; import DMRoomMap from '../utils/DMRoomMap'; +import Unread from '../Unread'; /** * A class for storing application state for categorising rooms in @@ -26,6 +27,8 @@ class RoomListStore extends Store { super(dis); this._init(); + this._getManualComparator = this._getManualComparator.bind(this); + this._recentsComparator = this._recentsComparator.bind(this); } _init() { @@ -62,7 +65,7 @@ class RoomListStore extends Store { break; case 'MatrixActions.Room.tags': { if (!this._state.ready) break; - this._updateRoomLists(payload.room); + this._generateRoomLists(); } break; case 'MatrixActions.accountData': { @@ -76,12 +79,7 @@ class RoomListStore extends Store { } break; case 'RoomListActions.tagRoom.pending': { - this._updateRoomListsOptimistic( - payload.request.room, - payload.request.oldTag, - payload.request.newTag, - payload.request.metaData, - ); + this._generateRoomLists(payload.request); } break; case 'RoomListActions.tagRoom.failure': { @@ -93,76 +91,13 @@ class RoomListStore extends Store { // Reset state without pushing an update to the view, which generally assumes that // the matrix client isn't `null` and so causing a re-render will cause NPEs. this._init(); + this._matrixClient = null; } break; } } - _updateRoomListsOptimistic(updatedRoom, oldTag, newTag, metaData) { - const newLists = {}; - - // Adding a tag to an untagged room - need to remove it from recents - if (newTag && Object.keys(updatedRoom.tags).length === 0) { - oldTag = 'im.vector.fake.recent'; - } - - // Removing a tag from a room with one tag left - need to add it to recents - if (oldTag && Object.keys(updatedRoom.tags).length === 1) { - newTag = 'im.vector.fake.recent'; - } - - // Remove room from oldTag - Object.keys(this._state.lists).forEach((tagName) => { - if (tagName === oldTag) { - newLists[tagName] = this._state.lists[tagName].filter((room) => { - return room.roomId !== updatedRoom.roomId; - }); - } else { - newLists[tagName] = this._state.lists[tagName]; - } - }); - - /// XXX: RoomSubList sorts by data on the room object. We - /// should sort in advance and incrementally insert new rooms - /// instead of resorting every time. - if (metaData) { - updatedRoom.tags[newTag] = metaData; - } - - newLists[newTag].push(updatedRoom); - - this._setState({ - lists: newLists, - }); - } - - _updateRoomLists(updatedRoom) { - const roomTags = Object.keys(updatedRoom.tags); - - const newLists = {}; - - // Removal of the updatedRoom from tags it no longer has - Object.keys(this._state.lists).forEach((tagName) => { - newLists[tagName] = this._state.lists[tagName].filter((room) => { - return room.roomId !== updatedRoom.roomId || roomTags.includes(tagName); - }); - }); - - roomTags.forEach((tagName) => { - if (newLists[tagName].includes(updatedRoom)) return; - newLists[tagName].push(updatedRoom); - }); - - if (roomTags.length === 0) { - newLists['im.vector.fake.recent'].unshift(updatedRoom); - } - - this._setState({ - lists: newLists, - }); - } - - _generateRoomLists() { + _generateRoomLists(optimisticRequest) { const lists = { "im.vector.fake.invite": [], "m.favourite": [], @@ -187,7 +122,19 @@ class RoomListStore extends Store { } else if (me.membership == "join" || me.membership === "ban" || (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) { // Used to split rooms via tags - const tagNames = Object.keys(room.tags); + let tagNames = Object.keys(room.tags); + + if (optimisticRequest && optimisticRequest.room === room) { + // Remove old tag + tagNames = tagNames.filter((tagName) => tagName !== optimisticRequest.oldTag); + // Add new tag + if (optimisticRequest.newTag && + !tagNames.includes(optimisticRequest.newTag) + ) { + tagNames.push(optimisticRequest.newTag); + } + } + if (tagNames.length) { for (let i = 0; i < tagNames.length; i++) { const tagName = tagNames[i]; @@ -207,12 +154,92 @@ class RoomListStore extends Store { } }); + const listOrders = { + "manual": [ + "m.favourite", + ], + "recent": [ + "im.vector.fake.invite", + "im.vector.fake.recent", + "im.vector.fake.direct", + "m.lowpriority", + "im.vector.fake.archived", + ], + }; + + Object.keys(listOrders).forEach((order) => { + listOrders[order].forEach((listKey) => { + let comparator; + switch (order) { + case "manual": + comparator = this._getManualComparator(listKey, optimisticRequest); + break; + case "recent": + comparator = this._recentsComparator; + break; + } + lists[listKey].sort(comparator); + }); + }); + this._setState({ lists, ready: true, // Ready to receive updates via Room.tags events }); } + _tsOfNewestEvent(room) { + for (let i = room.timeline.length - 1; i >= 0; --i) { + const ev = room.timeline[i]; + if (ev.getTs() && + (Unread.eventTriggersUnreadCount(ev) || + (ev.getSender() === this._matrixClient.credentials.userId)) + ) { + return ev.getTs(); + } + } + + // we might only have events that don't trigger the unread indicator, + // in which case use the oldest event even if normally it wouldn't count. + // This is better than just assuming the last event was forever ago. + if (room.timeline.length && room.timeline[0].getTs()) { + return room.timeline[0].getTs(); + } else { + return Number.MAX_SAFE_INTEGER; + } + } + + _recentsComparator(roomA, roomB) { + return this._tsOfNewestEvent(roomB) - this._tsOfNewestEvent(roomA); + } + + _lexicographicalComparator(roomA, roomB) { + return roomA.name > roomB.name ? 1 : -1; + } + + _getManualComparator(tagName, optimisticRequest) { + return (roomA, roomB) => { + let metaA = roomA.tags[tagName]; + let metaB = roomB.tags[tagName]; + + if (optimisticRequest && roomA === optimisticRequest.room) metaA = optimisticRequest.metaData; + if (optimisticRequest && roomB === optimisticRequest.room) metaB = optimisticRequest.metaData; + + // Make sure the room tag has an order element, if not set it to be the bottom + const a = metaA.order; + const b = metaB.order; + + // Order undefined room tag orders to the bottom + if (a === undefined && b !== undefined) { + return 1; + } else if (a !== undefined && b === undefined) { + return -1; + } + + return a == b ? this._lexicographicalComparator(roomA, roomB) : ( a > b ? 1 : -1); + }; + } + getRoomLists() { return this._state.lists; } From 015477278914b38d559e6bd77cabea16c8aee2bb Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 8 Feb 2018 18:18:57 +0000 Subject: [PATCH 051/242] Change wording of debug log submission Fixes https://github.com/vector-im/riot-web/issues/5985 --- src/components/structures/UserSettings.js | 6 +++--- src/i18n/strings/en_EN.json | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index b1eedd1a90..4237cd78eb 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -794,11 +794,11 @@ module.exports = React.createClass({ } return (
-

{ _t("Bug Report") }

+

{ _t("Debug Logs Submission") }

-

{ _t("Found a bug?") }

+

{ _t("Want to send logs?") }

diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6139ac2a91..d51f20dbd0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -500,8 +500,8 @@ "Download %(text)s": "Download %(text)s", "Invalid file%(extra)s": "Invalid file%(extra)s", "Error decrypting image": "Error decrypting image", - "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", "This image cannot be displayed.": "This image cannot be displayed.", + "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", "Error decrypting video": "Error decrypting video", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.", @@ -855,9 +855,9 @@ "Device ID:": "Device ID:", "Device key:": "Device key:", "Ignored Users": "Ignored Users", - "Bug Report": "Bug Report", - "Found a bug?": "Found a bug?", - "Report it": "Report it", + "Debug Logs Submission": "Debug Logs Submission", + "Want to send logs?": "Want to send logs?", + "Submit debug logs": "Submit debug logs", "Riot collects anonymous analytics to allow us to improve the application.": "Riot collects anonymous analytics to allow us to improve the application.", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.", "Learn more about how we use analytics.": "Learn more about how we use analytics.", From 8f97e9479d3be395d9855f17fb093629b1cd4ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Thu, 8 Feb 2018 21:16:57 +0100 Subject: [PATCH 052/242] Ooops, restore a bit of RoomCreateDialog content I have accidentally removed while trying to solve merge conflicts (thx @dbkr) --- src/components/views/dialogs/CreateRoomDialog.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/components/views/dialogs/CreateRoomDialog.js b/src/components/views/dialogs/CreateRoomDialog.js index 7a8852bc00..51693a19c9 100644 --- a/src/components/views/dialogs/CreateRoomDialog.js +++ b/src/components/views/dialogs/CreateRoomDialog.js @@ -55,6 +55,19 @@ export default React.createClass({
+
+ +
+ { _t('Advanced options') } +
+ + +
+
Date: Thu, 8 Feb 2018 21:16:25 +0000 Subject: [PATCH 053/242] Translated using Weblate (Serbian) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sr/ --- src/i18n/strings/sr.json | 89 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index 9a38d6fac8..39a1f1cf20 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -898,5 +898,92 @@ "matrix-react-sdk version:": "matrix-react-sdk издање:", "riot-web version:": "riot-web издање:", "olm version:": "olm издање:", - "Failed to send email": "Нисам успео да пошаљем мејл" + "Failed to send email": "Нисам успео да пошаљем мејл", + "The email address linked to your account must be entered.": "Морате унети мејл адресу која је везана за ваш налог.", + "A new password must be entered.": "Морате унети нову лозинку.", + "New passwords must match each other.": "Нове лозинке се морају подударати.", + "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.": "Опоравак ваше лозинке ће тренутно поново поставити кључеве за шифровање с краја на крај, на свим вашим уређајима. Ово ће учинити шифровани историјат ћаскања нечитљивим осим ако прво не извезете ваше кључеве собе па их онда увезете касније. Ово ће бити побољшано у будућности.", + "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Мејл је послат на адресу %(emailAddress)s. Када будете испратили везу у њему, кликните испод.", + "I have verified my email address": "Потврдио сам своју мејл адресу", + "Your password has been reset": "Ваша лозинка је опорављена", + "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": "Одјављени сте са свих ваших уређаја и више нећете примати пуш обавештења. Да бисте поново омогућили обавештења, одјавите се и пријавите поново на сваком вашем уређају", + "Return to login screen": "Врати ме на екран за пријаву", + "To reset your password, enter the email address linked to your account": "Да бисте опоравили вашу лозинку, унесите мејл адресу повезану са вашим налогом", + "New password": "Нова лозинка", + "Confirm your new password": "Потврдите вашу нову лозинку", + "Send Reset Email": "Пошаљи мејл за опоравак", + "Create an account": "Направи налог", + "This Home Server does not support login using email address.": "Овај кућни сервер не подржава пријављивање преко мејл адресе.", + "Incorrect username and/or password.": "Нетачно корисничко име и/или лозинка.", + "Please note you are logging into the %(hs)s server, not matrix.org.": "Знајте да се пријављујете на сервер %(hs)s, не на matrix.org.", + "Guest access is disabled on this Home Server.": "Гостински приступ је онемогућен на овом кућном серверу.", + "The phone number entered looks invalid": "Унети број телефона не изгледа исправно", + "This homeserver doesn't offer any login flows which are supported by this client.": "Овај кућни сервер не пружа било који начин пријаве унутар овог клијента.", + "Error: Problem communicating with the given homeserver.": "Грешка: проблем у комуницирању са датим кућним сервером.", + "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Не могу да се повежем на кућни сервер преко HTTP-а када се користи HTTPS адреса у траци вашег прегледача. Или користите HTTPS или омогућите небезбедне скрипте.", + "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Не могу да се повежем на кућни сервер. Проверите вашу интернет везу, постарајте се да верујете SSL сертификату кућног сервера и да проширење прегледача не блокира захтеве.", + "Login as guest": "Пријави се као гост", + "Sign in to get started": "Пријави се да почнеш", + "Failed to fetch avatar URL": "Нисам успео да добавим адресу аватара", + "Set a display name:": "Постави приказно име:", + "Upload an avatar:": "Отпреми аватар:", + "This server does not support authentication with a phone number.": "Овај сервер не подржава идентификацију преко броја мобилног.", + "Missing password.": "Недостаје лозинка.", + "Passwords don't match.": "Лозинке се не подударају.", + "Password too short (min %(MIN_PASSWORD_LENGTH)s).": "Лозинка је сувише кратка (најмање %(MIN_PASSWORD_LENGTH)s).", + "This doesn't look like a valid email address.": "Мејл адреса не изгледа исправно.", + "This doesn't look like a valid phone number.": "Број телефона не изгледа исправно.", + "You need to enter a user name.": "Морате унети корисничко име.", + "An unknown error occurred.": "Непозната грешка се догодила.", + "I already have an account": "Већ имам налог", + "Displays action": "Приказује радњу", + "Bans user with given id": "Забрањује приступ кориснику са датим иб-јем", + "Unbans user with given id": "Скида забрану приступа кориснику са датим иб-јем", + "Define the power level of a user": "Дефинише ниво моћи корисника", + "Deops user with given id": "Укида админа за корисника са датим иб-јем", + "Invites user with given id to current room": "Позива корисника са датим иб-јем у тренутну собу", + "Joins room with given alias": "Приступа соби са датим алијасем", + "Sets the room topic": "Поставља тему собе", + "Kicks user with given id": "Избацује корисника са датим иб-јем", + "Changes your display nickname": "Мења ваш приказни надимак", + "Searches DuckDuckGo for results": "Претражује DuckDuckGo за резултате", + "Changes colour scheme of current room": "Мења шему боје у тренутној соби", + "Verifies a user, device, and pubkey tuple": "Проверава корисника, уређај и торку јавног кључа", + "Ignores a user, hiding their messages from you": "Занемарује корисника и тиме скрива њихове поруке од вас", + "Stops ignoring a user, showing their messages going forward": "Престаје са занемаривањем корисника и тиме приказује њихове поруке одсад", + "Commands": "Наредбе", + "Results from DuckDuckGo": "Резултати са DuckDuckGo-а", + "Emoji": "Емоџи", + "Notify the whole room": "Обавести све у соби", + "Room Notification": "Собно обавештење", + "Users": "Корисници", + "unknown device": "непознати уређај", + "NOT verified": "НИЈЕ проверен", + "verified": "проверен", + "Verification": "Провера", + "Ed25519 fingerprint": "Ed25519 отисак прста", + "User ID": "Кориснички ИБ", + "Curve25519 identity key": "Curve25519 идентитески кључ", + "none": "ништа", + "Claimed Ed25519 fingerprint key": "Наводни Ed25519 кључ отиска прста", + "Algorithm": "Алгоритам", + "unencrypted": "нешифрован", + "Decryption error": "Грешка дешифровања", + "Session ID": "ИБ сесије", + "End-to-end encryption information": "Подаци о шифровању с краја на крај", + "Event information": "Подаци о догађају", + "Sender device information": "Подаци о уређају пошиљаоца", + "Passphrases must match": "Фразе се морају подударати", + "Passphrase must not be empty": "Фразе не смеју бити празне", + "Export room keys": "Извези кључеве собе", + "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "Ова радња вам омогућава да извезете кључеве за примљене поруке у шифрованим собама у локалну датотеку. Онда ћете моћи да увезете датотеку у други Матрикс клијент, у будућности, тако да ће тај клијент моћи да дешифрује ове поруке.", + "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "Извезена датотека ће дозволити свима који је могу прочитати да дешифрују било које шифроване поруке које можете видети те бисте требали да будете пажљиви и да је осигурате. Да бисмо вам помогли са тиме, требало би да унесете фразу испод са којом ће извезени подаци бити шифровани. Поновни увоз података ће бити могућ само уз коришћење исте фразе.", + "Enter passphrase": "Унеси фразу", + "Confirm passphrase": "Потврди фразу", + "Export": "Извези", + "Import room keys": "Увези кључеве собе", + "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "Ова радња вам омогућава да увезете кључеве за шифровање које сте претходно извезли из другог Матрикс клијента. Након тога ћете моћи да дешифрујете било коју поруку коју је други клијент могао да дешифрује.", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Извезена датотека ће бити заштићена са фразом. Требало би да унесете фразу овде, да бисте дешифровали датотеку.", + "File to import": "Датотека за увоз", + "Import": "Увези" } From 410570936a6e301b2eff5591f99bf75a6f838337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Thu, 8 Feb 2018 22:51:07 +0100 Subject: [PATCH 054/242] Reimplement setting aria-hidden on the main app node by dispatching actions rather than assuming we can find and manipulate the node directly --- src/Modal.js | 25 +++++++++++------------ src/components/structures/LoggedInView.js | 2 +- src/components/structures/MatrixChat.js | 14 +++++++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/Modal.js b/src/Modal.js index 8e3b394f87..2565d5c73b 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -22,6 +22,7 @@ const ReactDOM = require('react-dom'); import PropTypes from 'prop-types'; import Analytics from './Analytics'; import sdk from './index'; +import dis from './dispatcher'; const DIALOG_CONTAINER_ID = "mx_Dialog_Container"; @@ -187,24 +188,22 @@ class ModalManager { } _reRender() { - // Retrieve the root node of the Riot application outside the modal - let applicationNode = document.getElementById('matrixchat'); if (this._modals.length == 0) { - if (applicationNode) { - // If there is no modal to render, make all of Riot available - // to screen reader users again - applicationNode.setAttribute('aria-hidden', 'false'); - } + // If there is no modal to render, make all of Riot available + // to screen reader users again + dis.dispatch({ + action: 'aria_unhide_main_app', + }); ReactDOM.unmountComponentAtNode(this.getOrCreateContainer()); return; } - if (applicationNode) { - // Hide the content outside the modal to screen reader users - // so they won't be able to navigate into it and act on it using - // screen reader specific features - applicationNode.setAttribute('aria-hidden', 'true'); - } + // Hide the content outside the modal to screen reader users + // so they won't be able to navigate into it and act on it using + // screen reader specific features + dis.dispatch({ + action: 'aria_hide_main_app', + }); const modal = this._modals[0]; const dialog = ( diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index e97d9dd0a1..211340f5a8 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -327,7 +327,7 @@ const LoggedInView = React.createClass({ } return ( -
+
{ topBar }
{ SettingsStore.isFeatureEnabled("feature_tag_panel") ? :
} diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index d6d0b00c84..380cc697e1 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -171,6 +171,10 @@ export default React.createClass({ register_hs_url: null, register_is_url: null, register_id_sid: null, + + // When showing Modal dialogs we need to set aria-hidden on the root app element + // and disable it when there are no dialogs + hideToSRUsers: false, }; return s; }, @@ -608,6 +612,16 @@ export default React.createClass({ case 'send_event': this.onSendEvent(payload.room_id, payload.event); break; + case 'aria_hide_main_app': + this.setState({ + hideToSRUsers: true, + }); + break; + case 'aria_unhide_main_app': + this.setState({ + hideToSRUsers: false, + }); + break; } }, From cf0d45a65bd0082bc3ce0b9890b61a08a78bfa68 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Fri, 9 Feb 2018 10:28:32 +0000 Subject: [PATCH 055/242] Translated using Weblate (Basque) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eu/ --- src/i18n/strings/eu.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 8ec181d879..7592eb0708 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -980,5 +980,9 @@ "This room is not public. You will not be able to rejoin without an invite.": "Gela hau ez da publikoa. Ezin izango zara berriro elkartu gonbidapenik gabe.", "Community IDs cannot not be empty.": "Komunitate ID-ak ezin dira hutsik egon.", "Show devices, send anyway or cancel.": "Erakutsi gailuak, bidali hala ere edo ezeztatu.", - "In reply to ": "honi erantzunez: " + "In reply to ": "honi erantzunez: ", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s erabiltzaileak bere pantaila izena aldatu du %(displayName)s izatera.", + "Failed to set direct chat tag": "Huts egin du txat zuzenarenaren etiketa jartzean", + "Failed to remove tag %(tagName)s from room": "Huts egin du %(tagName)s etiketa gelatik kentzean", + "Failed to add tag %(tagName)s to room": "Huts egin du %(tagName)s etiketa gelara gehitzean" } From 52181fde9550192e88a548cbb257ae2c2f631651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sim=C3=B3=20Albert=20i=20Beltran?= Date: Thu, 8 Feb 2018 19:20:09 +0000 Subject: [PATCH 056/242] Translated using Weblate (Catalan) Currently translated at 88.3% (871 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ca/ --- src/i18n/strings/ca.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json index 691da985f2..1ff3e7f8e9 100644 --- a/src/i18n/strings/ca.json +++ b/src/i18n/strings/ca.json @@ -867,5 +867,7 @@ "Import": "Importa", "The version of Riot.im": "La versió de Riot.im", "Email": "Correu electrònic", - "Add email address": "Afegeix correu electrònic" + "Add email address": "Afegeix correu electrònic", + "I have verified my email address": "He verificat l'adreça de correu electrònic", + "Send Reset Email": "Envia email de reinici" } From 22aedb6075259cf1e58745dc7825c6aca9d78533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=BA=D0=BE=20=D0=9C=2E=20=D0=9A=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=9B?= Date: Thu, 8 Feb 2018 21:19:42 +0000 Subject: [PATCH 057/242] Translated using Weblate (Serbian) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/sr/ --- src/i18n/strings/sr.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index 39a1f1cf20..6f1958094a 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -117,7 +117,7 @@ "%(senderName)s requested a VoIP conference.": "%(senderName)s је затражио VoIP конференцију.", "%(senderName)s invited %(targetName)s.": "%(senderName)s је позвао %(targetName)s.", "%(senderName)s banned %(targetName)s.": "%(senderName)s је бановао %(targetName)s.", - "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!": "УПОЗОРЕЊЕ: ПОТВРДА КЉУЧА НИЈЕ УСПЕЛА! Кључ потписивања за корисника %(userId)s и уређај %(deviceId)s је „%(fprint)s“ а то се не подудара са достављеним кључем „%(fingerprint)s“. Ово можда значи да се ваши разговори прате!", + "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!": "УПОЗОРЕЊЕ: ПРОВЕРА КЉУЧА НИЈЕ УСПЕЛА! Кључ потписивања за корисника %(userId)s и уређај %(deviceId)s је „%(fprint)s“ а то се не подудара са достављеним кључем „%(fingerprint)s“. Ово можда значи да се ваши разговори прате!", "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "Кључ за потписивање који сте доставили се подудара са кључем за потписивање од корисника %(userId)s и уређаја %(deviceId)s. Уређај је означен као проверен.", "%(senderName)s set their display name to %(displayName)s.": "Корисник %(senderName)s је себи поставио приказно име %(displayName)s.", "%(senderName)s removed their display name (%(oldDisplayName)s).": "Корисник %(senderName)s је себи уклонио приказно име %(oldDisplayName)s.", @@ -567,7 +567,7 @@ "Create new room": "Направи нову собу", "Unblacklist": "Скини са црног списка", "Blacklist": "Стави на црни списак", - "Unverify": "Скини потврду", + "Unverify": "Означи непровереним", "Verify...": "Провери...", "No results": "Нема резултата", "Delete": "Обриши", @@ -674,15 +674,15 @@ "Device name": "Назив уређаја", "Device key": "Кључ уређаја", "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.": "Ако се подудара, притисните дугме за потврду провере испод. Ако се не подудара, неко други прислушкује овај уређај и вероватно желите да притиснете дугме за стављање на црни списак.", - "In future this verification process will be more sophisticated.": "У будућности ће овај поступак потврђивања бити напреднији.", + "In future this verification process will be more sophisticated.": "У будућности ће овај поступак провере бити напреднији.", "Verify device": "Провери уређај", "I verify that the keys match": "Потврђујем да се кључеви подударају", "An error has occurred.": "Догодила се грешка.", "OK": "У реду", "You added a new device '%(displayName)s', which is requesting encryption keys.": "Додали сте нови уређај „%(displayName)s“ који захтева кључеве за шифровање.", - "Your unverified device '%(displayName)s' is requesting encryption keys.": "Ваш непотврђени уређај „%(displayName)s“ захтева кључеве за шифровање.", - "Start verification": "Започни потврђивање", - "Share without verifying": "Подели без потврђивања", + "Your unverified device '%(displayName)s' is requesting encryption keys.": "Ваш непроверени уређај „%(displayName)s“ захтева кључеве за шифровање.", + "Start verification": "Започни проверу", + "Share without verifying": "Подели без провере", "Ignore request": "Занемари захтев", "Loading device info...": "Учитавам податке о уређају...", "Encryption key request": "Захтев за кључ шифровања", @@ -693,7 +693,7 @@ "Continue anyway": "Ипак настави", "Invalid Email Address": "Неисправна мејл адреса", "This doesn't appear to be a valid email address": "Изгледа да ово није исправна мејл адреса", - "Verification Pending": "Чека се на потврду", + "Verification Pending": "Чека се на проверу", "Please check your email and click on the link it contains. Once this is done, click continue.": "Проверите ваш мејл и кликните на везу унутар њега. Када ово урадите, кликните на дугме „настави“.", "Unable to add email address": "Не могу да додам мејл адресу", "Unable to verify email address.": "Не могу да проверим мејл адресу.", From 9dba4ab569e050dd28492ba633889f392546c0b7 Mon Sep 17 00:00:00 2001 From: Tirifto Date: Fri, 9 Feb 2018 12:30:53 +0000 Subject: [PATCH 058/242] Translated using Weblate (Esperanto) Currently translated at 97.1% (958 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/eo/ --- src/i18n/strings/eo.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index a50d16a2b3..c6a4b81740 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -944,5 +944,17 @@ "Import": "Enporti", "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Forigo de fenestraĵo efektiviĝos por ĉiuj uzantoj en ĉi tiu ĉambro. Ĉu vi certe volas ĝin forigi?", "Unblacklist": "Repermesi legadon de ĉifritaj mesaĝoj", - "none": "neniu" + "none": "neniu", + "The version of Riot.im": "Tiu ĉi versio de Riot.im", + "Whether or not you're logged in (we don't record your user name)": "Ĉu vi salutis aŭ ne (ni ne registras vian salutnomon)", + "Your language of choice": "Via preferata lingvo", + "The information being sent to us to help make Riot.im better includes:": "Informoj sendataj al ni por plibonigi la servon Riot.im inkluzivas:", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s ŝanĝis sian vidigan nomon al %(displayName)s.", + "Send an encrypted reply…": "Sendi ĉifritan respondon…", + "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", + "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." } From e1410755600b4a3f94400cace45aae3ea2c84406 Mon Sep 17 00:00:00 2001 From: Oskars Date: Sat, 10 Feb 2018 16:38:14 +0000 Subject: [PATCH 059/242] Translated using Weblate (Latvian) Currently translated at 90.3% (891 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/lv/ --- src/i18n/strings/lv.json | 296 +++++++++++++++++++++++++++++++++------ 1 file changed, 251 insertions(+), 45 deletions(-) diff --git a/src/i18n/strings/lv.json b/src/i18n/strings/lv.json index ae290d4d5f..50416f0318 100644 --- a/src/i18n/strings/lv.json +++ b/src/i18n/strings/lv.json @@ -21,7 +21,7 @@ "Default Device": "Noklusējuma ierīce", "Microphone": "Mikrofons", "Camera": "Kamera", - "Advanced": "Īpašie", + "Advanced": "Papildus", "Algorithm": "Algoritms", "Hide removed messages": "Slēpt dzēstos ziņojumus", "Always show message timestamps": "Vienmēr rādīt ziņojumu laika zīmogu", @@ -35,7 +35,7 @@ "Anyone": "Ikviens", "Anyone who knows the room's link, apart from guests": "Ikviens, kurš zina adreses saiti uz istabu, izņemot viesus", "Anyone who knows the room's link, including guests": "Ikviens, kurš zina adreses saiti uz istabu, tai skaitā arī viesi", - "Are you sure?": "Esi pārliecināts/a?", + "Are you sure?": "Vai tiešām to vēlies?", "Are you sure you want to leave the room '%(roomName)s'?": "Vai tiešām vēlies pamest istabas: '%(roomName)s'?", "Are you sure you want to reject the invitation?": "Vai tiešām vēlies noraidīt šo uzaicinājumu?", "Are you sure you want to upload the following files?": "Vai tiešām vēlies augšuplādēt sekojošos failus?", @@ -48,7 +48,7 @@ "Blacklisted": "Melnajā sarakstā iekļautie", "Bug Report": "Paziņojums par kļūdu", "Bulk Options": "Lielapjoma darbības", - "Call Timeout": "Zvana noilgums", + "Call Timeout": "Zvana gaidīšanas noilgums", "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.": "Neizdevās savienoties ar serveri. Lūdzu pārbaudi savu tīkla savienējumu un pārliecinies, ka tava servera SSL sertifikāts ir uzticams, kā arī pārlūkā instalētie paplašinājumi nebloķē pieprasījumus.", "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Neizdevās savienoties ar serveri izmantojot HTTP protokolu, kad tava pārlūka adreses laukā ir HTTPS saite. Tā vietā izmanto HTTPS savienojumu vai iespējo nedrošos skriptus.", "Can't load user settings": "Neizdevās ielādēt lietotāja uzstādījumus", @@ -77,21 +77,21 @@ "Conference call failed.": "Konferences zvans neizdevās.", "Conference calling is in development and may not be reliable.": "Konferences zvans šobrīd atrodas izstrādes stadijā un var būt nestabils.", "Conference calls are not supported in encrypted rooms": "Konferences zvani nav iespējami istabās, kurās tiek izmantota šifrēšana", - "Conference calls are not supported in this client": "Konferences zvani netiek atbalstīti šajā programmā", + "Conference calls are not supported in this client": "Konferences zvani šajā klienta programmā netiek atbalstīti", "Confirm password": "Apstiprini paroli", "Confirm your new password": "Apstiprini jauno paroli", "Continue": "Turpināt", "Could not connect to the integration server": "Neizdevās savienoties ar integrācijas serveri", "%(count)s new messages|one": "jaunu ziņu skaits: %(count)s", "%(count)s new messages|other": "%(count)s jaunas ziņas", - "Create a new chat or reuse an existing one": "Izveidot jaunu čatu vai izmantot eksistējošu", + "Create a new chat or reuse an existing one": "Izveidot jaunu čalu vai izmantot jau esošu", "Create an account": "Reģistrēt kontu", "Create Room": "Izveidot istabu", "Cryptography": "Kriptogrāfija", "Current password": "Pašreizējā parole", "Curve25519 identity key": "Curve25519 identifikācijas atslēga", "Custom": "Pielāgots", - "Custom level": "Speciāls līmenis", + "Custom level": "Īpašais līmenis", "/ddg is not a command": "/ddg nav komanda", "Deactivate Account": "Deaktivizēt kontu", "Deactivate my account": "Deaktivizēt manu kontu", @@ -116,7 +116,7 @@ "Don't send typing notifications": "Nesūtīt paziņojumus", "Download %(text)s": "Lejupielādēt tekstu: %(text)s", "Drop File Here": "Ievelc failu šeit", - "Drop here to tag %(section)s": "Ievelc šeit uz birkas %(section)s", + "Drop here to tag %(section)s": "Nomest šeit, lai birkotu %(section)s", "Ed25519 fingerprint": "Ed25519 identificējošā zīmju virkne", "Email": "Epasts", "Email address": "Epasta adrese", @@ -140,11 +140,11 @@ "Error decrypting attachment": "Kļūda atšifrējot pielikumu", "Error: Problem communicating with the given homeserver.": "Kļūda: Radās komunikācijas problēma ar norādīto serveri.", "Event information": "Notikuma informācija", - "Existing Call": "Eksistējošs zvans", + "Existing Call": "Pašreizējā saruna (zvans)", "Export": "Eksportēt", "Export E2E room keys": "Eksportēt E2E istabas atslēgas", - "Failed to ban user": "Neizdevās liegt pieeju lietotājam", - "Failed to change password. Is your password correct?": "Neizdevās mainīt paroli. Vai tava parole ir pareiza?", + "Failed to ban user": "Neizdevās bloķēt (liegt pieeju) lietotāju", + "Failed to change password. Is your password correct?": "Neizdevās nomainīt paroli. Vai tā ir pareiza?", "Failed to change power level": "Neizdevās mainīt statusa līmeni", "Power level must be positive integer.": "Statusa līmenim ir jābūt pozitīvam skaitlim.", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Tu nevarēsi atcelt šo darbību, jo šim lietotājam piešķir tādu pašu statusa līmeni, kāds ir Tev.", @@ -170,12 +170,12 @@ "Failed to upload profile picture!": "Neizdevās augšuplādēt profila attēlu!", "Failed to verify email address: make sure you clicked the link in the email": "Neizdevās apstiprināt epasta adresi. Pārbaudi, vai Tu esi noklikšķinājis/usi saiti epasta ziņā", "Failure to create room": "Neizdevās izveidot istabu", - "Favourite": "Favorīts", + "Favourite": "Tava izlase (favorīti)", "Favourites": "Favorīti", "Fill screen": "Aizpildīt ekrānu", "Filter room members": "Filtrēt istabas biedrus", "Forget room": "\"Aizmirst\" istabu", - "Forgot your password?": "Aizmirsi savu paroli?", + "Forgot your password?": "Aizmirsi paroli?", "For security, this session has been signed out. Please sign in again.": "Drošības nolūkos, šī sesija ir beigusies. Lūdzu, pieraksties par jaunu.", "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.": "Drošības nolūkos, izrakstīšanās dzēsīs jebkādas ierīce-ierīce šifrēšanas atslēgas no šī pārlūka. Ja Tu vēlies saglabāt iespēju atšifrēt tavu saziņas vēsturi no Riot nākotnes sesijām, lūdzu eksportē tavas istabas atslēgas, saglabājot tās drošā vietā.", "Found a bug?": "Pamanīji kļūdu?", @@ -198,7 +198,7 @@ "Incorrect username and/or password.": "Nepareizs lietotājvārds un/vai parole.", "Incorrect verification code": "Nepareizs verifikācijas kods", "Interface Language": "Saskarnes valoda", - "Invalid alias format": "Nepareizs aizstājējvārda formāts", + "Invalid alias format": "Nepareizs aizstājējvārda (aliases) formāts", "Invalid address format": "Nepareizs adreses formāts", "Invalid Email Address": "Nepareiza epasta adrese", "Invalid file%(extra)s": "Nepareizs faila %(extra)s", @@ -215,7 +215,7 @@ "Join Room": "Pievienoties istabai", "%(targetName)s joined the room.": "%(targetName)s pievienojās istabai.", "Joins room with given alias": "Pievieno istabai ar uzdoto aizstājējvārdu", - "Jump to first unread message.": "Pārlekt uz pirmo neizlasīto ziņu.", + "Jump to first unread message.": "Pāriet uz pirmo neizlasīto ziņu.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s iespēra (kick) %(targetName)s.", "Kick": "Iespert (kick)", "Kicks user with given id": "Iesper (kick) lietotājam pēc norādītā id", @@ -240,7 +240,7 @@ "Turn Markdown off": "Izslēgt formatēšanas iespēju", "Turn Markdown on": "Ieslēgt formatēšanas iespēju", "matrix-react-sdk version:": "matrix-react-sdk versija:", - "The default role for new room members is": "Noklusējuma loma jaunam istabas biedram ir", + "The default role for new room members is": "Jauna istabas biedra statuss pēc noklusējuma ir", "Message not sent due to unknown devices being present": "Ziņa nav nosūtīta, jo tika konstatēta nezināmu ierīču klātbūtne", "Missing room_id in request": "Iztrūkstošs room_id pieprasījumā", "Missing user_id in request": "Iztrūkstošs user_id pieprasījumā", @@ -248,7 +248,7 @@ "Mobile phone number (optional)": "Mobilā telefona numurs (nav obligāts)", "Moderator": "Moderators", "Must be viewing a room": "Jāapskata istaba", - "Mute": "Apklusināt", + "Mute": "Kluss (noklusināt)", "%(serverName)s Matrix ID": "%(serverName)s Matrix ID", "Name": "Vārds", "Never send encrypted messages to unverified devices from this device": "Nekad nesūti no šīs ierīces šifrētas ziņas uz neverificētām ierīcēm", @@ -269,7 +269,7 @@ "No more results": "Nav tālāko rezultātu", "No results": "Nav rezultātu", "No users have specific privileges in this room": "Nav lietotāju ar īpašām privilēģijām šajā istabā", - "OK": "LABI", + "OK": "Labs ir", "olm version:": "olm versija:", "Once encryption is enabled for a room it cannot be turned off again (for now)": "Tiklīdz istabai tiks iespējota šifrēšana, tā vairs nebūs atslēdzama (pašlaik)", "Only people who have been invited": "Vienīgi personas, kuras ir tikušas uzaicinātas", @@ -283,7 +283,7 @@ "Phone": "Telefons", "%(senderName)s placed a %(callType)s call.": "%(senderName)s nolika %(callType)s zvanu.", "Please check your email and click on the link it contains. Once this is done, click continue.": "Lūdzu pārbaudi savu epastu un noklikšķini tajā esošo saiti. Tiklīdz tas ir izdarīts, klikšķini \"turpināt\".", - "Press to start a chat with someone": "Nospied , lai uzsāktu čatu ar kādu", + "Press to start a chat with someone": "Nospied , lai ar kādu uzsāktu čalošanu", "Privacy warning": "Privātuma brīdinājums", "Private Chat": "Privātais čats", "Privileged Users": "Priviliģētie lietotāji", @@ -308,8 +308,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.": "Paroles atiestatīšana atiestatīs visas ierīce-ierīce šifrēšanas atslēgas visās ierīcēs, padarot čata šifrēto ziņu vēsturi nelasāmu, ja vien Tu pirms tam neesi eksportējis savas istabas atslēgas un atkārtoti importējis tās atpakaļ. Nākotnē šo ir plānots uzlabot.", "Results from DuckDuckGo": "Rezultāti no DuckDuckGo", "Return to login screen": "Atgriezties uz pierakstīšanās lapu", - "Riot does not have permission to send you notifications - please check your browser settings": "Riot nav atļauts nosūtīt Tev paziņojumus. Lūdzu pārbaudi sava pārlūka uzstādījumus", - "Riot was not given permission to send notifications - please try again": "Riot nav atļauts nosūtīt paziņojumus. Lūdzu mēģini vēlreiz.", + "Riot does not have permission to send you notifications - please check your browser settings": "Riot nav atļauts nosūtīt Tev paziņojumus. Lūdzu pārbaudi sava pārlūka iestatījumus", + "Riot was not given permission to send notifications - please try again": "Riot nav piešķirta atļauja nosūtīt paziņojumus. Lūdzu mēģini vēlreiz", "riot-web version:": "riot-web versija:", "Unable to enable Notifications": "Nav iespējams iespējot paziņojumus", "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": "Tu izrakstījies no visām ierīcēm un vairs nesaņemsi pašpiegādes (push) paziņojumus. Lai iespējotu paziņojumus, pieraksties atkārtoti katrā no ierīcēm", @@ -319,14 +319,14 @@ "Room %(roomId)s not visible": "Istaba %(roomId)s nav redzama", "%(roomName)s does not exist.": "%(roomName)s neeksistē.", "%(roomName)s is not accessible at this time.": "%(roomName)s šobrīd nav pieejama.", - "Seen by %(userName)s at %(dateTime)s": "Redzams %(userName)s %(dateTime)s", + "Seen by %(userName)s at %(dateTime)s": "Redzējis %(userName)s %(dateTime)s", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s nosūtīja attēlu.", "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s nosūtīja uzaicinājumu %(targetDisplayName)s pievienoties istabai.", "%(senderName)s set a profile picture.": "%(senderName)s uzstādīja profila attēlu.", "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s uzstādīja redzamo vārdu uz: %(displayName)s.", "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "Tevis uzdotā pierakstīšanās atslēga sakrīt ar atslēgu, kuru Tu saņēmi no %(userId)s ierīces %(deviceId)s. Ierīce tika atzīmēta kā verificēta.", "The file '%(fileName)s' exceeds this home server's size limit for uploads": "Faila '%(fileName)s' izmērs pārsniedz šī mājas servera augšupielādes lieluma ierobežojumu", - "The file '%(fileName)s' failed to upload": "Failu '%(fileName)s' neizdevās augšuplādēt", + "The file '%(fileName)s' failed to upload": "Failu '%(fileName)s' neizdevās nosūtīt (augšuplādēt)", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s ieslēdza ierīce-ierīce šifrēšanu (algorithm %(algorithm)s).", "%(senderName)s unbanned %(targetName)s.": "%(senderName)s atcēla pieejas ierobežojumu (atbanoja) %(targetName)s.", "Unknown room %(roomId)s": "Nezināma istaba %(roomId)s", @@ -402,7 +402,7 @@ "This email address is already in use": "Šī epasta adrese jau tiek izmantota", "This email address was not found": "Šāda epasta adrese nav atrasta", "The email address linked to your account must be entered.": "Ir jāievada tavam kontam piesaistītā epasta adrese.", - "The remote side failed to pick up": "Neizdevās uzņemt attālināto pusi", + "The remote side failed to pick up": "Zvana adresāts neatbild", "This Home Server does not support login using email address.": "Šis serveris neatbalsta pierakstīšanos ar epasta adresi.", "This invitation was sent to an email address which is not associated with this account:": "Šis uzaicinājums tika nosūtīts uz epasta adresi, kura nav piesaistīta šim kontam:", "This room has no local addresses": "Šai istabai nav lokālo adrešu", @@ -425,7 +425,7 @@ "Unable to verify email address.": "Nav iespējams apstiprināt epasta adresi.", "Unban": "Atbanot", "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Nav iespējams pārliecināties, ka šis uzaicinājums tika nosūtīts uz to pašu adresi, kura ir piesaistīta tavam kontam.", - "Unable to capture screen": "Nav iespējams uzņemt ekrānattēlu", + "Unable to capture screen": "Neizdevās uzņemt ekrānattēlu", "Unable to load device list": "Nav iespējams ielādēt ierīču sarakstu", "Undecryptable": "Neatšifrējams", "Unencrypted room": "Nešifrēta istaba", @@ -439,14 +439,14 @@ "Unnamed Room": "Istaba bez nosaukuma", "Cancel": "Atcelt", "Create new room": "Izveidot jaunu istabu", - "Custom Server Options": "Īpaši servera uzstādījumi", - "Dismiss": "Noņemt", + "Custom Server Options": "Iestatāmie servera uzstādījumi", + "Dismiss": "Atteikums", "You have enabled URL previews by default.": "Tev ir pēc noklusējuma iespējots URL adrešu priekšskatījums.", "Unrecognised command:": "Neatpazīta komanda:", "Unrecognised room alias:": "Neatpazīts istabas aizstājējvārds:", "Unverified": "Neverificēts", "Upload avatar": "Augšuplādē profila attēlu", - "Upload Failed": "Augšupielāde neizdevās", + "Upload Failed": "Nosūtīšana (augšupielāde) neizdevās", "Upload Files": "Augšuplādē failus", "Upload file": "Augšuplādē failu", "Upload new:": "Augšuplādē jaunu:", @@ -481,11 +481,11 @@ "Who would you like to add to this room?": "Kuru vēlies pievienot šai istabai?", "Who would you like to communicate with?": "Ar kuru vēlies komunicēt?", "Would you like to accept or decline this invitation?": "Vai vēlies apstiprināt vai noraidīt šo uzaicinājumu?", - "You already have existing direct chats with this user:": "Tev jau ir eksistējošs tiešais čats ar šo lietotāju:", - "You are already in a call.": "Tu jau šobrīd atrodies zvanā.", + "You already have existing direct chats with this user:": "Tev jau ir viens tiešais čats ar šo lietotāju:", + "You are already in a call.": "Tu jau šobrīd esi sarunā.", "You're not in any rooms yet! Press to make a room or to browse the directory": "Šobrīd Tu vēl neatrodies nevienā istabā! Klikšķini lai izveidotu istabu, vai , lai skatītu istabu katalogu", - "You cannot place a call with yourself.": "Tu nevari veikt zvanu sev.", - "You cannot place VoIP calls in this browser.": "Tu nevari veikt VoIP zvanus šajā pārlūkā.", + "You cannot place a call with yourself.": "Nav iespējams piezvanīt sev.", + "You cannot place VoIP calls in this browser.": "VoIP zvani šajā pārlūkā netiek atbalstīti.", "You do not have permission to post to this room": "Tev nav vajadzīgās atļaujas pievienot ziņas šajā istabā", "You have disabled URL previews by default.": "URL priekšskatījums pēc noklusējuma Tev ir atspējots.", "You may wish to login with a different account, or add this email to this account.": "Tu varētu, iespējams, vēlēties pierakstīties no cita konta vai piesaistīt šo epastu šim kontam.", @@ -531,7 +531,7 @@ "An unknown error occurred.": "Notikusi neparedzēta kļūda.", "I already have an account": "Man jau ir konts", "Topic": "Tēma", - "Make Moderator": "Piešķirt moderatora līmeni", + "Make Moderator": "Piešķirt moderatora statusu", "Make this room private": "Padarīt šo istabu privātu", "Share message history with new users": "Kopīgot ziņu vēsturi ar jauniem lietotājiem", "Encrypt room": "Šifrēt istabu", @@ -550,7 +550,7 @@ "numbullet": "lode ar numuru", "Please select the destination room for this message": "Lūdzu izvēlies šīs ziņas mērķa istabu", "Room directory": "Istabu katalogs", - "Start chat": "Uzsākt čatu", + "Start chat": "Uzsākt čalošanu", "New Password": "Jauna parole", "Start automatically after system login": "Uzsākt automātiski pēc pierakstīšanās sistēmā", "Desktop specific": "Darbvirsmai specifiski", @@ -569,7 +569,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.": "Šis process ļauj Tev importēt tās šifrēšanas atslēgas, kuras Tu iepriekš eksportēji no citas Matrix klienta aplikācijas. Importētās atslēgas ļaus vajadzīgajā klienta aplikācijā lasīt atšifrētās ziņas.", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Eksporta fails būs aizsargāts ar paroles frāzi. Tā ir jāievada šeit, lai atšifrētu failu.", "You must join the room to see its files": "Tev ir jāpievienojas istabai, lai redzētu tās failus", - "Start new chat": "Uzsākt jaunu čatu", + "Start new chat": "Uzsākt jaunu čalu", "Failed to invite": "Neizdevās uzaicināt", "Failed to invite user": "Neizdevās uzaicināt lietotāju", "Confirm Removal": "Apstiprini dzēšanu", @@ -596,7 +596,7 @@ "Blacklist": "Melnais saraksts", "Unverify": "Atverificēt", "Verify...": "Verificē...", - "ex. @bob:example.com": "piemēram, @janis:majaslapa.lv", + "ex. @bob:example.com": "piemēram, @valters:smaidu.lv", "Add User": "Pievienot lietotāju", "This Home Server would like to make sure you are not a robot": "Šis mājas serveris vēlas pārliecināties, ka Tu neesi robots", "Sign in with CAS": "Pierakstīties ar CAS", @@ -606,7 +606,7 @@ "Please check your email to continue registration.": "Lūdzu pārbaudi savu epastu lai turpinātu reģistrāciju.", "Token incorrect": "Nepareizs autentifikācijas kods", "Please enter the code it contains:": "Lūdzu ievadi tajā ietverto kodu:", - "powered by Matrix": "spēcināts ar Matrix", + "powered by Matrix": "Tiek darbināts ar Matrix", "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Ja Tu nenorādīsi epasta adresi, tev nebūs iespējams izmantot paroles atiestatīšanu. Vai esi pārliecināts/a?", "Default server": "Noklusējuma serveris", "Custom server": "Īpašs serveris", @@ -617,18 +617,18 @@ "Error decrypting image": "Kļūda atšifrējot attēlu", "Error decrypting video": "Kļūda atšifrējot video", "Add an Integration": "Pievienot integrāciju", - "Removed or unknown message type": "Dzēsts vai nezināms ziņas veids", + "Removed or unknown message type": "Dzēsts vai nezināms ziņas tips", "URL Previews": "URL adrešu priekšskatījumi", "Drop file here to upload": "Ievelc failu šeit lai augšuplādētu", " (unsupported)": " (netiek atbalstīts)", - "Online": "Tiešsaistē", + "Online": "Tiešsaistē (pieslēgumā)", "Idle": "Dīkstāve", - "Offline": "Nav tiešsaistē", + "Offline": "Atsaistē (ārpus tīkla)", "Updates": "Atjauninājumi", "Check for update": "Pārbaudīt, vai ir atjauninājumi", - "Start chatting": "Sākt čatošanu", - "Start Chatting": "Sākt čatošanu", - "Click on the button below to start chatting!": "Klikšķini uz zemāk esošās pogas, lai uzsāktu čatošanu!", + "Start chatting": "Sākt čalošanu", + "Start Chatting": "Sākt čalošanu", + "Click on the button below to start chatting!": "Klikšķini uz zemāk esošās pogas, lai uzsāktu čalošanu!", "Username available": "Lietotājvārds ir pieejams", "Username not available": "Lietotājvārds nav pieejams", "Something went wrong!": "Kaut kas nogāja greizi!", @@ -653,14 +653,14 @@ "Delete widget": "Dzēst widžetu", "Define the power level of a user": "Definēt lietotāja pakāpes līmeni", "Do you want to load widget from URL:": "Vai vēlies ielādēt widžetu no URL:", - "Edit": "Labot", + "Edit": "Rediģēt", "Enable automatic language detection for syntax highlighting": "Iespējot automātisko valodas noteikšanu sintakses iezīmējumiem", "Hide Apps": "Slēpt aplikācijas", "Hide join/leave messages (invites/kicks/bans unaffected)": "Slēpt pievienoties/pamest ziņas (tas neietekmē uzaicinājumus, vai kick/bana darbības)", "Integrations Error": "Integrācijas kļūda", "Publish this room to the public in %(domain)s's room directory?": "Publicēt šo istabu publiskajā %(domain)s katalogā?", "AM": "AM", - "PM": "PZ", + "PM": "PM", "NOTE: Apps are not end-to-end encrypted": "PIEZĪME: Aplikācijās nav ierīce-ierīce šifrēšanas", "Sets the room topic": "Uzstāda istabas tēmas nosaukumu", "Show Apps": "Rādīt aplikācijas", @@ -683,5 +683,211 @@ "%(widgetName)s widget added by %(senderName)s": "%(senderName)s pievienoja %(widgetName)s vidžetu", "%(widgetName)s widget removed by %(senderName)s": "%(senderName)s dzēsa vidžetu %(widgetName)s", "Robot check is currently unavailable on desktop - please use a web browser": "Robotu pārbaude šobrīd nav pieejama darbvirsmas versijā. Lūdzu izmanto web pārlūku", - "Revoke widget access": "Atsaukt vidžeta piekļuvi" + "Revoke widget access": "Atsaukt vidžeta piekļuvi", + "Unpin Message": "Atkabināt ziņu", + "Add rooms to this community": "Pievienot istabas šai komūnai", + "Failed to set direct chat tag": "Neizdevās tiešajam čatam uzstādīt birku", + "Warning": "Brīdinājums", + "Send": "Sūtīt", + "Leave": "Pamest", + "Unnamed room": "Nenosaukta istaba", + "Guests can join": "Var pievienoties viesi", + "The platform you're on": "Izmantotā operētājsistēma", + "The version of Riot.im": "Riot.im versija", + "Whether or not you're logged in (we don't record your user name)": "Neatkarīgi no tā, vai esi vai neesi iegājis sistēmā (netiek fiksēts Tavs lietotājvārds)", + "Your language of choice": "Izvēlētā valoda", + "Which officially provided instance you are using, if any": "Kuru oficiāli izlaisto versiju izmantojat (ja to darat)", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Neatkarīgi no tā, vai izmantojat Richtext režīmu redaktorā Rich Text Editor", + "Your homeserver's URL": "Mājasservera URL adrese", + "Your identity server's URL": "Tava identitātes servera URL adrese", + "The information being sent to us to help make Riot.im better includes:": "Informācija, kura mums tiek nosūtīta, lai ļautu padarīt Riot.im labāku, ietver:", + "We also record each page you use in the app (currently ), your User Agent () and your device resolution ().": "Mēs arī fiksējam katru lapu, kuru tu izmanto programmā (currently ), Tavu lietotāja aģentu () un Tavas ierīces ekrāna izšķirtspēju ().", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Ja šī lapa ietver identificējamu informāciju, tādu kā istaba, lietotājs, grupas ID, šie dati tiek noņemti pirms nosūtīšanas uz serveri.", + "Call Failed": "Zvans neizdevā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.": "Šajā istabā ir nepazīstamas ierīces: ja Tu turpināsi bez to pārbaudes, ir iespējams, ka kāda nepiederoša persona var noklausīties Tavas sarunas.", + "Review Devices": "Ierīču pārskats", + "Call Anyway": "Vienalga zvanīt", + "Answer Anyway": "Vienalga atbildēt", + "Call": "Zvans", + "Answer": "Atbildēt", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s", + "Who would you like to add to this community?": "Kurus cilvēkus Tu vēlētos pievienot šai komūnai?", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Brīdinājums: ikviens, kurš tiek pievienots komūnai būs publiski redzams visiem, kuri zin komūnas ID", + "Invite new community members": "Uzaicināt jaunus komūnas biedrus", + "Name or matrix ID": "Vārds vai Matrix ID", + "Invite to Community": "Uzaicināt komūnā", + "Which rooms would you like to add to this community?": "Kuras istabas vēlies pievienot šai komūnai?", + "Show these rooms to non-members on the community page and room list?": "Vai ne-biedriem rādīt komūnas lapā un istabu sarakstā šīs istabas?", + "Add rooms to the community": "Istabu pievienošana komūnai", + "Room name or alias": "Istabas nosaukums vai aliase", + "Add to community": "Pievienot komūnai", + "Failed to invite the following users to %(groupId)s:": "Neizdevās uzaicināt sekojošus lietotājus grupā %(groupId)s:", + "Failed to invite users to community": "Neizdevās uzaicināt lietotājus komūnā", + "Failed to invite users to %(groupId)s": "Neizdevās uzaicināt lietotājus grupā %(groupId)s:", + "Failed to add the following rooms to %(groupId)s:": "Neizdevās pievienot sekojošas istabas grupai %(groupId)s:", + "Restricted": "Ierobežots", + "Ignored user": "Ignorējams lietotājs", + "You are now ignoring %(userId)s": "Tagad Tu ignorē %(userId)s", + "Unignored user": "Neignorējams lietotājs", + "You are no longer ignoring %(userId)s": "Tu vairāk neignorē %(userId)s", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s nomainīja savu attēlojamo vārdu uz %(displayName)s.", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s šai istabai nomainīja piekabinātās ziņas.", + "%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s vidžets, kuru mainīja %(senderName)s", + "%(names)s and %(count)s others are typing|other": "%(names)s un %(count)s citi raksta", + "%(names)s and %(count)s others are typing|one": "%(names)s un vēl kāds raksta", + "Message Replies": "Atbildes uz ziņām", + "Message Pinning": "Ziņu piekabināšana", + "Presence Management": "Klātbūtnes vadība", + "Tag Panel": "Birku panelis", + "Disable Emoji suggestions while typing": "Atspējot Emoji ieteikumus teksta rakstīšanas laikā", + "Hide avatar changes": "Slēpt avatara izmaiņas", + "Hide display name changes": "Slēpt attēlojamā vārda izmaiņas", + "Disable big emoji in chat": "Atspējot čatā lielos emoji", + "Mirror local video feed": "Spoguļots vietējā video attēlojums", + "Enable inline URL previews by default": "Ieslēgt URL adrešu priekšskatījumu pēc noklusējuma", + "Enable URL previews for this room (only affects you)": "Ieslēgt URL adrešu priekšskatījumus šai istabai (ietekmē tikai Tevi pašu)", + "Enable URL previews by default for participants in this room": "Ieslēgt URL adrešu priekšskatījumus pēc noklusējuma visiem šīs istabas dalībniekiem", + "Delete %(count)s devices|other": "Dzēst %(count)s ierīces", + "Delete %(count)s devices|one": "Dzēst ierīci", + "Select devices": "Izvēlēties ierīces", + "%(senderName)s sent an image": "%(senderName)s nosūtīja bildi", + "%(senderName)s sent a video": "%(senderName)s nosūtīja video", + "%(senderName)s uploaded a file": "%(senderName)s augšupielādēja failu", + "Disinvite this user?": "Atcelt ielūgumu šim lietotājam?", + "Kick this user?": "Padzīt šo lietotāju?", + "Unban this user?": "Atbloķēt šo lietotāju (atcelt liegumu šim lietotājam)?", + "Ban this user?": "Bloķēt šo lietotāju (uzlikt liegumu šim lietotājam)?", + "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.": "Jūs nevarēsiet atcelt šīs izmaiņas pēc sava statusa pazemināšanas. Gadījumā, ja esat pēdējais priviliģētais lietotājs istabā, būs neiespējami atgūt šīs privilēģijas.", + "Unignore": "Atcelt ignorēšanu", + "Ignore": "Ignorēt", + "Jump to read receipt": "Pāriet uz izlasīšanas apstiprinājumu", + "Mention": "Atsauce (pieminējums)", + "Invite": "Uzaicināt", + "User Options": "Lietotāja uzstādījumi", + "Send an encrypted reply…": "Sūtīt šifrētu atbildi…", + "Send a reply (unencrypted)…": "Sūtīt nešifrētu atbildi…", + "Send an encrypted message…": "Sūtīt šifrētu ziņu…", + "Send a message (unencrypted)…": "Sūtīt NEšifrētu ziņu…", + "Jump to message": "Pāriet uz ziņu", + "No pinned messages.": "Nav piestiprinātu ziņu.", + "Loading...": "Ielāde...", + "Pinned Messages": "Piestiprinātās ziņas", + "%(duration)ss": "%(duration)s sek", + "%(duration)sm": "%(duration)smin", + "%(duration)sh": "%(duration)sstundas", + "%(duration)sd": "%(duration)sdienas", + "Online for %(duration)s": "Pieslēgumā %(duration)s", + "Idle for %(duration)s": "Dīkstāvē (neaktīvs) %(duration)s", + "Offline for %(duration)s": "Atslēgumā %(duration)s", + "Unknown for %(duration)s": "Neskaidrā statusā %(duration)s", + "Unknown": "Neskaidrs statuss", + "Replying": "Atbildot uz", + "No rooms to show": "Nav istabu, kuras parādīt", + "World readable": "Pieejams ikvienam no visurienes", + "Remove avatar": "Dzēst avataru", + "Drop here to favourite": "Nomest šeit (atvilt uz šejieni), lai iekļautu izlasē (favorītos)", + "Drop here to tag direct chat": "Nomest šeit, lai pievienotu atzīmi \"Tiešais čats\"", + "Drop here to restore": "Nomest šeit, lai atgrieztu", + "Drop here to demote": "Nomest šeit, lai pazeminātu", + "Failed to remove tag %(tagName)s from room": "Neizdevās istabai noņemt birku %(tagName)s", + "Failed to add tag %(tagName)s to room": "Neizdevās istabai pievienot birku %(tagName)s", + "Community Invites": "Uzaicinājums uz komūnu", + "You have been kicked from this room by %(userName)s.": "%(userName)s padzina Tevi no šīs istabas.", + "You have been banned from this room by %(userName)s.": "%(userName)s nobloķēja Tevi (liedza piekļuvi) šajā istabā.", + "You are trying to access a room.": "Tu centies gūt piekļuvi istabai.", + "To change the room's avatar, you must be a": "Lai izmainītu istabas avatāru, Tev jābūt", + "To change the room's name, you must be a": "Lai izmainītu istabas nosaukumu, Tev jābūt", + "To change the room's main address, you must be a": "Lai izmainītu istabas pamatadresi, Tev jābūt", + "To change the room's history visibility, you must be a": "Lai izmainītu istabas vēstures redzamību, Tev jābūt", + "To change the permissions in the room, you must be a": "Lai istabā izmainītu atļaujas, Tev jābūt", + "To change the topic, you must be a": "Lai izmainītu tematu, Tev jābūt", + "To modify widgets in the room, you must be a": "Lai istabā izmainītu vidžetus, Tev jābūt", + "Banned by %(displayName)s": "Nobloķējis (liedzis piekļuvi) %(displayName)s", + "Members only (since the point in time of selecting this option)": "Tikai biedri (no šī parametra iestatīšanas brīža)", + "Members only (since they were invited)": "Tikai biedri (no to uzaicināšanas brīža)", + "Members only (since they joined)": "Tikai biedri (kopš pievienošanās)", + "To send messages, you must be a": "Lai sūtītu ziņas, Tev jābūt", + "To invite users into the room, you must be a": "Lai aicinātu istabā lietotājus, ir jābūt", + "To configure the room, you must be a": "Lai konfigurētu istabu, ir jābūt", + "To kick users, you must be a": "Lai padzītu lietotājus, ir jābūt", + "To ban users, you must be a": "Lai bloķētu (liegtu pieeju) lietotājiem, ir jābūt", + "To remove other users' messages, you must be a": "Lai dzēstu citu lietotāju ziņas, ir jābūt", + "To send events of type , you must be a": "Lai sūtītu tipa notikumus, ir jābūt", + "Addresses": "Adreses", + "Invalid community ID": "Nederīgs komūnas ID", + "'%(groupId)s' is not a valid community ID": "'%(groupId)s' nav derīgs komūnas ID", + "Flair": "Gaidas (nojauta)", + "Showing flair for these communities:": "Parādīt Tavas gaidas šajās komūnās:", + "This room is not showing flair for any communities": "Šajā istabā neparādās gaidas, kas uzstādītas komūnās", + "New community ID (e.g. +foo:%(localDomain)s)": "Jaunās komūnas ID (piem. +foo:%(localDomain)s)", + "URL previews are enabled by default for participants in this room.": "URL adrešu priekšskats šīs istabas dalībniekiem ir iespējots pēc noklusējuma.", + "URL previews are disabled by default for participants in this room.": "ULR adrešu priešskats šīs istabas dalībniekiem pēc noklusējuma ir atspējots.", + "Copied!": "Nokopēts!", + "Failed to copy": "Nokopēt neizdevās", + "Message removed by %(userId)s": "Ziņu dzēsis %(userId)s", + "Message removed": "Ziņa dzēsta", + "An email has been sent to %(emailAddress)s": "Vēstule tika nosūtīta uz %(emailAddress)s", + "A text message has been sent to %(msisdn)s": "Teksta ziņa tika nosūtīts uz %(msisdn)s", + "Username on %(hs)s": "Lietotājvārds uz %(hs)s", + "Remove from community": "Izdzēst no komūnas", + "Disinvite this user from community?": "Atcelt šim lietotājam nosūtīto uzaicinājumu pievienoties komūnai?", + "Remove this user from community?": "Izdzēst šo lietotāju no kopienas?", + "Failed to withdraw invitation": "Neizdevās atcelt uzaicinājumu", + "Failed to remove user from community": "Neizdevās izdzēst lietotāju no kopienas", + "Filter community members": "Kopienas biedru filtrs", + "Flair will appear if enabled in room settings": "Gaidas parādīsies, ja tās iespējotas istabas iestatījumos", + "Flair will not appear": "Gaidas neparādīsies", + "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Vai tiešām vēlies izdzēst '%(roomName)s' no %(groupId)s?", + "Removing a room from the community will also remove it from the community page.": "Dzēšot istabu no kopienas tā tiks dzēsta arī no kopienas lapas.", + "Failed to remove room from community": "Neizdevās dzēst istabu no kopienas", + "Failed to remove '%(roomName)s' from %(groupId)s": "Neizdevās dzēst '%(roomName)s' no %(groupId)s", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Istabas '%(roomName)s' redzamību %(groupId)s nebija iespējams atjaunot.", + "Visibility in Room List": "Redzamība istabu sarakstā", + "Visible to everyone": "Redzama visiem", + "Only visible to community members": "Tikai komūnas dalībniekiem", + "Filter community rooms": "Kopienas istabu filtrs", + "Something went wrong when trying to get your communities.": "Kaut kas nogāja greizi, kad tika mēģināts attēlot Tavas kopienas.", + "Display your community flair in rooms configured to show it.": "Parādīt Tavas gaidas istabās, kurās to parādīšana iespējota.", + "You're not currently a member of any communities.": "Pašreiz Tu neesi neesi nevienas komūnas piederīgais.", + "Delete Widget": "Dzēst vidžetu", + "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Vidžeta dzēšana to dzēš visiem šīs istabas lietotājiem. Vai tiešām vēlies dzēst šo vidžetu?", + "Minimize apps": "Minimizēt lietotājprogrammas", + "Communities": "Kopienas", + "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", + "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)spievienojās %(count)s reizes", + "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)spievienojās", + "%(oneUser)sjoined %(count)s times|other": "%(oneUser)spievienojās %(count)s reizes", + "%(oneUser)sjoined %(count)s times|one": "%(oneUser)s pievienojās", + "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)s izgāja %(count)s reizes", + "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s izgāja (atvienojās)", + "%(oneUser)sleft %(count)s times|other": "%(oneUser)s izgāja (atvienojās) %(count)s reizes", + "%(oneUser)sleft %(count)s times|one": "%(oneUser)s izgāja", + "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s pievienojās un izgāja %(count)s reizes", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s pievienojās un izgāja", + "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s pievienojās un izgāja %(count)s reizes", + "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s pievienojās un izgāja", + "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s izgāja un atkalpievienojās %(count)s reizes", + "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s noraidīja uzaicinājumus %(count)s reizes", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)s atsauca izsniegtos uzaicinājumus %(count)s reizes", + "were banned %(count)s times|other": "tika bloķēti (liegta piekļuve) %(count)s reizes", + "was banned %(count)s times|other": "tika bloķēts (liegta piekļuve) %(count)s reizes", + "were unbanned %(count)s times|other": "tika atbloķēti (atgriezta pieeja) %(count)s reizes", + "were kicked %(count)s times|other": "tika padzīti %(count)s reizes", + "collapse": "sakļaut", + "expand": "izvērst", + "Custom of %(powerLevel)s": "Lietotāja līmenis %(powerLevel)s", + "In reply to ": "Atbildē uz ", + "And %(count)s more...|other": "Un par %(count)s vairāk...", + "Matrix ID": "Matrix ID", + "Matrix Room ID": "Matrix istabas ID", + "email address": "e-pasta adrese", + "Try using one of the following valid address types: %(validTypesList)s.": "Mēģiniet izmantot vienu no sekojošiem pieļautajiem adrešu tipiem: %(validTypesList)s.", + "You have entered an invalid address.": "Ievadīta nederīga adrese.", + "Community IDs cannot not be empty.": "Kopienas IDs nevar būt tukšs.", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Kopienas IDs var saturēt tikai simbolus a-z, 0-9, or '=_-./'", + "Something went wrong whilst creating your community": "Radot Tavu kopienu kaut kas nogāja greizi", + "Create Community": "Radīt kopienu", + "Community Name": "Kopienas nosaukums", + "Community ID": "Kopienas ID", + "example": "piemērs" } From 0f5dc5a7e4fa9eff05d59732389085e504225d67 Mon Sep 17 00:00:00 2001 From: Oskars Date: Mon, 12 Feb 2018 00:54:12 +0000 Subject: [PATCH 060/242] Translated using Weblate (Latvian) Currently translated at 96.5% (952 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/lv/ --- src/i18n/strings/lv.json | 177 ++++++++++++++++++++++++++------------- 1 file changed, 119 insertions(+), 58 deletions(-) diff --git a/src/i18n/strings/lv.json b/src/i18n/strings/lv.json index 50416f0318..b888050e29 100644 --- a/src/i18n/strings/lv.json +++ b/src/i18n/strings/lv.json @@ -4,19 +4,19 @@ "%(targetName)s accepted an invitation.": "%(targetName)s apstiprināja uzaicinājumu.", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s apstiprināja uzaicinājumu no %(displayName)s.", "Account": "Konts", - "Access Token:": "Pieejas atslēga:", + "Access Token:": "Pieejas tokens:", "Active call (%(roomName)s)": "Aktīvs zvans (%(roomName)s)", "Add": "Pievienot", "Add a topic": "Pievieno tematu", - "Add email address": "Pievieno Epasta adresi", + "Add email address": "Pievieno epasta adresi", "Add phone number": "Pievieno tālruņa numuru", "Admin": "Administrators", "Admin Tools": "Administratora rīki", "VoIP": "VoIP", - "Missing Media Permissions, click here to request.": "Nav pieejas medija saturam. Klikšķini šeit, lai pieprasītu.", - "No Microphones detected": "Mikrofoni nav atrasti", - "No Webcams detected": "Webkameras nav atrastas", - "No media permissions": "Nav pieejas mediju saturam", + "Missing Media Permissions, click here to request.": "Nav atļauju piekļūt ierīcei. Klikšķini šeit, lai tās pieprasītu.", + "No Microphones detected": "Nav mikrofonu", + "No Webcams detected": "Nav webkameru", + "No media permissions": "Nav datu nesēju, kuriem atļauta piekļuve", "You may need to manually permit Riot to access your microphone/webcam": "Tev varētu būt nepieciešams manuāli atļaut Riot pieslēgties tavam mikrofonam/webkamerai", "Default Device": "Noklusējuma ierīce", "Microphone": "Mikrofons", @@ -44,14 +44,14 @@ "%(senderName)s banned %(targetName)s.": "%(senderName)s liedza pieeju %(targetName)s.", "Ban": "Liegt pieeju (Bans)", "Banned users": "Lietotāji, kuriem ir liegta pieeja (banotie)", - "Bans user with given id": "Liedz pieeju lietotājam pēc uzdotā ID (Bans)", + "Bans user with given id": "Bloķē (liedz pieeju) lietotāju pēc uzdotā ID (nobano)", "Blacklisted": "Melnajā sarakstā iekļautie", "Bug Report": "Paziņojums par kļūdu", - "Bulk Options": "Lielapjoma darbības", + "Bulk Options": "Grupveida darbību parametri", "Call Timeout": "Zvana gaidīšanas noilgums", - "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.": "Neizdevās savienoties ar serveri. Lūdzu pārbaudi savu tīkla savienējumu un pārliecinies, ka tava servera SSL sertifikāts ir uzticams, kā arī pārlūkā instalētie paplašinājumi nebloķē pieprasījumus.", - "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Neizdevās savienoties ar serveri izmantojot HTTP protokolu, kad tava pārlūka adreses laukā ir HTTPS saite. Tā vietā izmanto HTTPS savienojumu vai iespējo nedrošos skriptus.", - "Can't load user settings": "Neizdevās ielādēt lietotāja uzstādījumus", + "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.": "Neizdodas savienoties ar bāzes serveri. Pārbaudi tīkla savienojumu un pārliecinies, ka bāzes servera SSL sertifikāts ir uzticams, kā arī pārlūkā instalētie paplašinājumi nebloķē pieprasījumus.", + "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Neizdodas savienoties ar bāzes serveri izmantojot HTTP protokolu, kad Tava pārlūka adreses laukā norādīts HTTPS protokols. Tā vietā izmanto HTTPS vai iespējo nedrošos skriptus.", + "Can't load user settings": "Neizdevās ielādēt lietotāja iestatījumus", "Change Password": "Paroles maiņa", "%(senderName)s changed their profile picture.": "%(senderName)s nomainīja profila attēlu.", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s nomainīja statusa līmeni %(powerLevelDiffText)s.", @@ -59,18 +59,18 @@ "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s dzēsa istabas nosaukumu.", "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s nomainīja tēmas nosaukumu uz \"%(topic)s\".", "Changes to who can read history will only apply to future messages in this room": "Izmaiņas attiecībā uz to, kurš varēs lasīt vēstures ziņas, stāsies spēkā tikai uz ziņām,kuras vēl tiks pievienotas šajā istabā", - "Changes your display nickname": "Nomaina tavu publisko segvārdu (niku)", + "Changes your display nickname": "Nomaina Tavu publisko segvārdu (niku)", "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.": "Paroles maiņa dzēsīs pašreizējās šifrēšanas atslēgas visās savstarpēji saistītajās ierīcēs, padarot čata vēsturi neizlasāmu, ja vien vien istabas atslēgas nav tikušas iepriekš eksportētas un no jauna importētas atpakaļ. Nākotnē to plānojam uzlabot.", - "Claimed Ed25519 fingerprint key": "Norādīta Ed25519 identificējošās zīmju virknes atslēga", + "Claimed Ed25519 fingerprint key": "Ed25519 pieprasītā nospieduma (fingerprint) atslēga", "Clear Cache and Reload": "Iztīri kešatmiņu un pārlādē", "Clear Cache": "Iztīri kešatmiņu", "Click here to join the discussion!": "Klikšķini šeit lai pievienotos diskusijai!", "Click here to fix": "Klikšķini šeit, lai izlabotu", - "Click to mute audio": "Klikšķini, lai izslēgtu skaņu", - "Click to mute video": "Klikšķini, lai izslēgtu video skaņu", - "click to reveal": "Klikšķini, lai atvērtu", - "Click to unmute video": "Klikšķini, lai ieslēgtu video skaņu", - "Click to unmute audio": "Klikšķini, lai ieslēgtu audio skaņu", + "Click to mute audio": "Klikšķini, lai audio skaņu izslēgtu", + "Click to mute video": "Klikšķini, lai video skaņu izslēgtu", + "click to reveal": "Klikšķini, lai atsegtu", + "Click to unmute video": "Klikšķini, lai video skaņu ieslēgtu", + "Click to unmute audio": "Klikšķini, lai audio skaņu ieslēgtu", "Close": "Aizvērt", "Command error": "Komandas kļūda", "Commands": "Komandas", @@ -93,13 +93,13 @@ "Custom": "Pielāgots", "Custom level": "Īpašais līmenis", "/ddg is not a command": "/ddg nav komanda", - "Deactivate Account": "Deaktivizēt kontu", - "Deactivate my account": "Deaktivizēt manu kontu", + "Deactivate Account": "Deaktivēt kontu", + "Deactivate my account": "Deaktivēt manu kontu", "Decline": "Noraidīt", "Decrypt %(text)s": "Atšifrēt %(text)s", "Decryption error": "Atšifrēšanas kļūda", "Delete": "Dzēst", - "Deops user with given id": "Noņemt operatora statusu lietotājam ar norādīto id", + "Deops user with given id": "Atceļ operatora statusu lietotājam ar norādīto ID", "Default": "Noklusējuma", "Device already verified!": "Ierīce ir jau verificēta!", "Device ID": "Ierīces ID", @@ -111,13 +111,13 @@ "Direct chats": "Tiešie čati", "Disable Notifications": "Atslēgt paziņojumus", "Disinvite": "Atsaukt", - "Display name": "Redzamais vārds", + "Display name": "Attēlojamais vārds", "Displays action": "Parāda darbību", "Don't send typing notifications": "Nesūtīt paziņojumus", "Download %(text)s": "Lejupielādēt tekstu: %(text)s", "Drop File Here": "Ievelc failu šeit", "Drop here to tag %(section)s": "Nomest šeit, lai birkotu %(section)s", - "Ed25519 fingerprint": "Ed25519 identificējošā zīmju virkne", + "Ed25519 fingerprint": "Ed25519 nospiedums (fingerprint), zīmju virkne", "Email": "Epasts", "Email address": "Epasta adrese", "Email address (optional)": "Epasta adrese (neobligāta)", @@ -138,7 +138,7 @@ "Enter passphrase": "Ievadi paroles frāzi", "Error": "Kļūda", "Error decrypting attachment": "Kļūda atšifrējot pielikumu", - "Error: Problem communicating with the given homeserver.": "Kļūda: Radās komunikācijas problēma ar norādīto serveri.", + "Error: Problem communicating with the given homeserver.": "Kļūda: Saziņas problēma ar norādīto bāzes serveri.", "Event information": "Notikuma informācija", "Existing Call": "Pašreizējā saruna (zvans)", "Export": "Eksportēt", @@ -166,7 +166,7 @@ "Failed to set up conference call": "Neizdevās iestatīt konferences zvanu", "Failed to toggle moderator status": "Neizdevās pārslēgt moderatora statusu", "Failed to unban": "Neizdevās atcelt pieejas liegumu (atbanot)", - "Failed to upload file": "Neizdevās augšuplādēt failu", + "Failed to upload file": "Neizdevās augšupielādēt failu", "Failed to upload profile picture!": "Neizdevās augšuplādēt profila attēlu!", "Failed to verify email address: make sure you clicked the link in the email": "Neizdevās apstiprināt epasta adresi. Pārbaudi, vai Tu esi noklikšķinājis/usi saiti epasta ziņā", "Failure to create room": "Neizdevās izveidot istabu", @@ -180,14 +180,14 @@ "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.": "Drošības nolūkos, izrakstīšanās dzēsīs jebkādas ierīce-ierīce šifrēšanas atslēgas no šī pārlūka. Ja Tu vēlies saglabāt iespēju atšifrēt tavu saziņas vēsturi no Riot nākotnes sesijām, lūdzu eksportē tavas istabas atslēgas, saglabājot tās drošā vietā.", "Found a bug?": "Pamanīji kļūdu?", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s no %(fromPowerLevel)s uz %(toPowerLevel)s", - "Guest access is disabled on this Home Server.": "Šajā serverī viesu pierakstīšanās nav iespējama.", + "Guest access is disabled on this Home Server.": "Šajā bāzes serverī viesu pierakstīšanās nav iespējama.", "Guests cannot join this room even if explicitly invited.": "Viesi nevar pievienoties šai istabai pat ja ir uzaicināti.", "Hangup": "Aizturēt", "Hide read receipts": "Slēpt izlasītās receptes", "Hide Text Formatting Toolbar": "Slēpt teksta formatēšanas rīkjoslu", "Historical": "Vēsturiskais", "Home": "Mājup", - "Homeserver is": "Serveris ir", + "Homeserver is": "Bāzes serveris ir", "Identity Server is": "Indentifikācijas serveris ir", "I have verified my email address": "Mana epasta adrese ir verificēta", "Import": "Importēt", @@ -214,11 +214,11 @@ "Join as voice or video.": "Pievienoties kā balss vai video.", "Join Room": "Pievienoties istabai", "%(targetName)s joined the room.": "%(targetName)s pievienojās istabai.", - "Joins room with given alias": "Pievieno istabai ar uzdoto aizstājējvārdu", + "Joins room with given alias": "Pievienojas istabai ar minēto aliasi (pseidonīmu)", "Jump to first unread message.": "Pāriet uz pirmo neizlasīto ziņu.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s iespēra (kick) %(targetName)s.", "Kick": "Iespert (kick)", - "Kicks user with given id": "Iesper (kick) lietotājam pēc norādītā id", + "Kicks user with given id": "Padzen (kick) lietotāju ar norādīto ID", "Labs": "Laboratorija", "Last seen": "Pēdējo reizi redzēts/a", "Leave room": "Pamest istabu", @@ -226,7 +226,7 @@ "Level:": "Līmenis:", "Local addresses for this room:": "Šīs istabas lokālās adreses:", "Logged in as:": "Pierakstījās kā:", - "Login as guest": "Pierakstīties kā viesis", + "Login as guest": "Pierakstīties kā viesim", "Logout": "Izrakstīties", "Low priority": "Zema prioritāte", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s uzstādīja nākotnes istabas ziņu vēsturi redzamu visi istabas biedri secībā, kādā tika uzaicināti.", @@ -257,7 +257,7 @@ "New password": "Jauna parole", "New passwords don't match": "Jaunās paroles nesakrīt", "New passwords must match each other.": "Jaunajām parolēm ir jāsakrīt vienai ar otru.", - "none": "nekāds", + "none": "neviens", "not set": "nav iestatījuma", "not specified": "nav noteikts", "Notifications": "Paziņojumi", @@ -292,7 +292,7 @@ "Reason": "Iemesls", "Reason: %(reasonText)s": "Iemesls: %(reasonText)s", "Revoke Moderator": "Atcelt moderatoru", - "Refer a friend to Riot:": "Nosūtīt draugu uz Riot:", + "Refer a friend to Riot:": "Rekomendēt draugam Riot:", "Register": "Reģistrēties", "%(targetName)s rejected the invitation.": "%(targetName)s noraidīja uzaicinājumu.", "Reject invitation": "Noraidīt uzaicinājumu", @@ -370,14 +370,14 @@ "Scroll to unread messages": "Aizritināt uz nelasītajām ziņām", "Search": "Meklēt", "Search failed": "Meklēšana neizdevās", - "Searches DuckDuckGo for results": "Meklē DuckDuckGo rezultātus", + "Searches DuckDuckGo for results": "Meklēšanai izmanto DuckDuckGo", "Send anyway": "Nosūtīt jebkurā gadījumā", "Sender device information": "Nosūtītāja ierīces informācija", "Send Invites": "Nosūtīt uzaicinājumus", "Send Reset Email": "Nosūtīt atiestatīšanas epastu", "Server error": "Servera kļūda", "Server may be unavailable or overloaded": "Serveris var nebūt pieejams vai ir pārslogots", - "Server may be unavailable, overloaded, or search timed out :(": "Serveris var nebūt pieejams, ir pārslogots, vai arī meklēšana beidzās ar savienojuma noilgumu :(", + "Server may be unavailable, overloaded, or search timed out :(": "Serveris izskatās nepieejams, ir pārslogots, vai arī meklēšana beidzās ar savienojuma noildzi :(", "Server may be unavailable, overloaded, or the file too big": "Serveris var nebūt pieejams, ir pārslogots, vai arī faila izmērs ir par lielu", "Server may be unavailable, overloaded, or you hit a bug.": "Serveris var nebūt pieejams, ir pārslogots, vai arī sastapi neparedzētu kļūdu.", "Server unavailable, overloaded, or something else went wrong.": "Serveris nav pieejams, ir pārslogots, vai arī ir notikusi cita, neparedzēta, kļūda.", @@ -395,19 +395,19 @@ "Start authentication": "Sākt autentifikāciju", "Start Chat": "Sākt čatu", "Submit": "Iesniegt", - "Success": "Veiksmīgi", + "Success": "Izdevās", "Tagged as: ": "Atzīmēts,kā: ", "The main address for this room is": "Galvenā šīs istabas adrese ir", "The phone number entered looks invalid": "Ievadītais telefona numurs izskatās nepareizs", "This email address is already in use": "Šī epasta adrese jau tiek izmantota", "This email address was not found": "Šāda epasta adrese nav atrasta", - "The email address linked to your account must be entered.": "Ir jāievada tavam kontam piesaistītā epasta adrese.", + "The email address linked to your account must be entered.": "Ir jāievada Tavam kontam piesaistītā epasta adrese.", "The remote side failed to pick up": "Zvana adresāts neatbild", - "This Home Server does not support login using email address.": "Šis serveris neatbalsta pierakstīšanos ar epasta adresi.", + "This Home Server does not support login using email address.": "Šis bāzes serveris neatbalsta pierakstīšanos ar epasta adresi.", "This invitation was sent to an email address which is not associated with this account:": "Šis uzaicinājums tika nosūtīts uz epasta adresi, kura nav piesaistīta šim kontam:", "This room has no local addresses": "Šai istabai nav lokālo adrešu", "This room is not recognised.": "Šī istaba netika atpazīta.", - "These are experimental features that may break in unexpected ways": "Šīs ir eksperimentālās iespējas, kuras var būt dažādos veidos nestrādājošas", + "These are experimental features that may break in unexpected ways": "Šīs ir eksperimentālas funkcijas, kuras reizēm var novest pie negaidītiem rezultātiem", "The visibility of existing history will be unchanged": "Esošās ziņu vēstures redzamība paliks nemainīga", "This doesn't appear to be a valid email address": "Šī neizskatās pēc derīgas epasta adreses", "This is a preview of this room. Room interactions have been disabled": "Šis ir esošās istabas priekšskatījums. Istabas mijiedarbība ir atspējota", @@ -416,10 +416,10 @@ "This room is not accessible by remote Matrix servers": "Šī istaba nav pieejama no attālinātajiem Matrix serveriem", "This room's internal ID is": "Šīs istabas iekšējais ID ir", "To link to a room it must have an address.": "Lai ieliktu saiti uz istabu, tai ir jābūt piešķirtai adresei.", - "To reset your password, enter the email address linked to your account": "Lai atiestatītu savu paroli, ievadi tavam kontam piesaistīto epasta adresi", + "To reset your password, enter the email address linked to your account": "Lai atiestatītu savu paroli, ievadi savam kontam piesaistīto epasta adresi", "To use it, just wait for autocomplete results to load and tab through them.": "Lai to izmantotu, vienkārši gaidi, kamēr ielādējas automātiski ieteiktie rezultāti, un pārvietojies caur tiem.", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Notika mēģinājums ielādēt šīs istabas specifisku laikpaziņojumu sadaļu, bet Tev nav atļaujas skatīt šo ziņu.", - "Tried to load a specific point in this room's timeline, but was unable to find it.": "Notika mēģinājums ielādēt šīs istabas specifisku laikpaziņojumu sadaļu, bet tā netika atrasta.", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "Mēģinājums ielādēt šīs istabas čata vēstures izvēlēto posmu neizdevās, jo tas netika atrasts.", "Unable to add email address": "Nav iespējams pievienot epasta adresi", "Unable to remove contact information": "Nav iespējams dzēst kontaktinformāciju", "Unable to verify email address.": "Nav iespējams apstiprināt epasta adresi.", @@ -518,10 +518,10 @@ "Oct": "Okt.", "Nov": "Nov.", "Dec": "Dec.", - "Set a display name:": "Iestatīt redzamo vārdu:", + "Set a display name:": "Iestatīt attēloto vārdu:", "This image cannot be displayed.": "Šo attēlu nav iespējams parādīt.", "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s nomainīja istabas attēlu uz ", - "Upload an avatar:": "Augšuplādē profila attēlu:", + "Upload an avatar:": "Augšuplādē avataru (profila attēlu):", "This server does not support authentication with a phone number.": "Šis serveris neatbalsta autentifikāciju pēc telefona numura.", "Missing password.": "Trūkst parole.", "Passwords don't match.": "Paroles nesakrīt.", @@ -530,14 +530,14 @@ "User names may only contain letters, numbers, dots, hyphens and underscores.": "Lietotājvārdi drīkst saturēt vienīgi alfabēta burtus, skaitļus, punktus, defises un apakšsvītras.", "An unknown error occurred.": "Notikusi neparedzēta kļūda.", "I already have an account": "Man jau ir konts", - "Topic": "Tēma", + "Topic": "Temats", "Make Moderator": "Piešķirt moderatora statusu", "Make this room private": "Padarīt šo istabu privātu", "Share message history with new users": "Kopīgot ziņu vēsturi ar jauniem lietotājiem", "Encrypt room": "Šifrēt istabu", "There are no visible files in this room": "Nav redzamu failu šajā istabā", "Room": "Istaba", - "Connectivity to the server has been lost.": "Savienojums ar serveri tika zaudēts.", + "Connectivity to the server has been lost.": "Savienojums ar serveri pārtrūka.", "Sent messages will be stored until your connection has returned.": "Nosūtītās ziņas tiks saglabātas tiklīdz savienojums tiks atjaunots.", "Active call": "Aktīvs zvans", "bold": "trekns", @@ -552,8 +552,8 @@ "Room directory": "Istabu katalogs", "Start chat": "Uzsākt čalošanu", "New Password": "Jauna parole", - "Start automatically after system login": "Uzsākt automātiski pēc pierakstīšanās sistēmā", - "Desktop specific": "Darbvirsmai specifiski", + "Start automatically after system login": "Palaist programmu automātiski pie sistēmas ielādes", + "Desktop specific": "Darbvirsmai specifiskie", "Analytics": "Analītika", "Opt out of analytics": "Atteikties no analītikas", "Options": "Iespējas", @@ -564,9 +564,9 @@ "Confirm passphrase": "Apstiprināt paroles frāzi", "Import room keys": "Importēt istabas atslēgas", "File to import": "Importējamais fails", - "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.": "Šī darbība atļauj Tev eksportēt lokālā failā atslēgas tām ziņām, kuras Tu saņēmi šifrētās istabās. Pēc tam nākotnē Tu varēsi importēt šo failu citā Matrix klienta aplikācijā, lai tajā būtu iespējams atšifrēt šīs ziņas.", - "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.": "Eksportētais fails atļaus ikvienam, kurš to ir nolasījis, atšifrēt jebkuras tev redzamās šifrētās ziņas, tāpēc ievēro piesardzību, un glabā šo failu drošā vietā. Lai palīdzētu to nodrošināt, Tev ir jāievada paroles frāze, kura tiks izmantota eksportēto datu šifrēšanai. Datu importēšana būs iespējama tikai izmantojot šo pašu paroles frāzi.", - "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.": "Šis process ļauj Tev importēt tās šifrēšanas atslēgas, kuras Tu iepriekš eksportēji no citas Matrix klienta aplikācijas. Importētās atslēgas ļaus vajadzīgajā klienta aplikācijā lasīt atšifrētās ziņas.", + "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.": "Šī darbība ļauj Tev uz lokālo failu eksportēt atslēgas priekš tām ziņām, kuras Tu saņēmi šifrētās istabās. Tu varēsi importēt šo failu citā Matrix klientā, lai tajā būtu iespējams lasīt šīs ziņas atšifrētas.", + "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.": "Eksportētais fails ļaus ikvienam, kurš to spēj lasīt, atšifrēt jebkuras Tavas šifrētās ziņas, tāpēc ievēro piesardzību, un glabā šo failu drošā vietā. Lai palīdzētu to nodrošināt, Tev jāievada paroles frāze, kura tiks izmantota eksportēto datu šifrēšanai. Datu importēšana būs iespējama tikai izmantojot šo pašu paroles frāzi.", + "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.": "Šis process ļaus Tev importēt šifrēšanas atslēgas, kuras Tu iepriekš eksportēji no cita Matrix klienta. Tas ļaus Tev atšifrēt čata vēsturi.", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Eksporta fails būs aizsargāts ar paroles frāzi. Tā ir jāievada šeit, lai atšifrētu failu.", "You must join the room to see its files": "Tev ir jāpievienojas istabai, lai redzētu tās failus", "Start new chat": "Uzsākt jaunu čalu", @@ -586,7 +586,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.": "Ja tā sakrīt, tad nospied zemāk esošo verifikācijas pogu . Ja nesakrīt, tad kāds cits ir piekļuvis šai ierīcei un šādā gadījumā Tu, iespējams, vēlies izmantot \"melnais saraksts\" iespēju.", "Verify device": "Verificēt ierīci", "I verify that the keys match": "Es pārbaudu, vai atslēgas sakrīt", - "We encountered an error trying to restore your previous session. If you continue, you will need to log in again, and encrypted chat history will be unreadable.": "Mēs sastapāmies ar kļūdu, mēģinot atjaunot tavu iepriekšējo sesiju. Ja vēlies turpināt, tev ir jāpierakstās par jaunu un šifrēta čata ziņu vēsture nebūs izlasāma.", + "We encountered an error trying to restore your previous session. If you continue, you will need to log in again, and encrypted chat history will be unreadable.": "Atgadījās kļūda, mēģinot atjaunot tavu iepriekšējo sesiju. Ja vēlies turpināt, Tev ir jāpierakstās no jauna, taču šifrētā čata ziņu vēsture nebūs izlasāma.", "Unable to restore session": "Nav iespējams atjaunot sesiju", "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.": "Ja Tu iepriekš izmantoji jaunāku Riot versiju, tava sesija var nebūt saderīga ar šo versiju. Aizver šo logu un atgriezies jaunākajā versijā.", "Continue anyway": "Turpināt jebkurā gadījumā", @@ -624,8 +624,8 @@ "Online": "Tiešsaistē (pieslēgumā)", "Idle": "Dīkstāve", "Offline": "Atsaistē (ārpus tīkla)", - "Updates": "Atjauninājumi", - "Check for update": "Pārbaudīt, vai ir atjauninājumi", + "Updates": "Aktualizācijas", + "Check for update": "Pārbaudīt, vai ir aktualizācijas", "Start chatting": "Sākt čalošanu", "Start Chatting": "Sākt čalošanu", "Click on the button below to start chatting!": "Klikšķini uz zemāk esošās pogas, lai uzsāktu čalošanu!", @@ -651,7 +651,7 @@ "Cannot add any more widgets": "Nav iespējams pievienot vairāk vidžetu", "Changes colour scheme of current room": "Nomaina pašreizējās istabas krāsu paleti", "Delete widget": "Dzēst widžetu", - "Define the power level of a user": "Definēt lietotāja pakāpes līmeni", + "Define the power level of a user": "Definē lietotāja statusu", "Do you want to load widget from URL:": "Vai vēlies ielādēt widžetu no URL:", "Edit": "Rediģēt", "Enable automatic language detection for syntax highlighting": "Iespējot automātisko valodas noteikšanu sintakses iezīmējumiem", @@ -662,12 +662,12 @@ "AM": "AM", "PM": "PM", "NOTE: Apps are not end-to-end encrypted": "PIEZĪME: Aplikācijās nav ierīce-ierīce šifrēšanas", - "Sets the room topic": "Uzstāda istabas tēmas nosaukumu", + "Sets the room topic": "Uzstāda istabas tematu", "Show Apps": "Rādīt aplikācijas", "The maximum permitted number of widgets have already been added to this room.": "Atļautais vidžetu skaits jau ir sasniegts šai istabai.", "To get started, please pick a username!": "Lai sāktu, lūdzu izvēlies lietotājvārdu!", "Unable to create widget.": "Nav iespējams izveidot widžetu.", - "Unbans user with given id": "Atceļ pieejas liegumu (atbano) lietotāju pēc norādītā id", + "Unbans user with given id": "Atbloķē (atceļ pieejas liegumu) lietotāju pēc norādītā ID (atbano)", "You are not in this room.": "Tu neatrodies šajā istabā.", "You do not have permission to do that in this room.": "Tev nav atļaujas šai darbībai šajā istabā.", "Verifies a user, device, and pubkey tuple": "Verificē lietotāju, ierīci, un publiskās atslēgas", @@ -685,11 +685,11 @@ "Robot check is currently unavailable on desktop - please use a web browser": "Robotu pārbaude šobrīd nav pieejama darbvirsmas versijā. Lūdzu izmanto web pārlūku", "Revoke widget access": "Atsaukt vidžeta piekļuvi", "Unpin Message": "Atkabināt ziņu", - "Add rooms to this community": "Pievienot istabas šai komūnai", + "Add rooms to this community": "Pievienot istabas šai kopienai", "Failed to set direct chat tag": "Neizdevās tiešajam čatam uzstādīt birku", "Warning": "Brīdinājums", "Send": "Sūtīt", - "Leave": "Pamest", + "Leave": "Atstāt", "Unnamed room": "Nenosaukta istaba", "Guests can join": "Var pievienoties viesi", "The platform you're on": "Izmantotā operētājsistēma", @@ -889,5 +889,66 @@ "Create Community": "Radīt kopienu", "Community Name": "Kopienas nosaukums", "Community ID": "Kopienas ID", - "example": "piemērs" + "example": "piemērs", + "Advanced options": "Papildus parametri", + "Block users on other matrix homeservers from joining this room": "Neļaut lietotājiem no citiem mājasserveriem pievienoties šai istabai", + "This setting cannot be changed later!": "Šo parametru vēlāk izmainīt nebūs iespējams!", + "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)s aizgājuši un atgriezušies", + "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)s aizgājis un atgriezies %(count)s reizes", + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s aizgājis un atgriezies", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s nepieņēma uzaicinājumus", + "were invited %(count)s times|one": "tika uzaicināti", + "was invited %(count)s times|other": "tika uzaicināta %(count)s reizes", + "was invited %(count)s times|one": "tika uzaicināts(a)", + "were unbanned %(count)s times|one": "tika atbloķēti (atcelts pieejas liegums)", + "was unbanned %(count)s times|other": "tika atbloķēts %(count)s reizes", + "was banned %(count)s times|one": "tika bloķēts", + "were banned %(count)s times|one": "tika bloķēti", + "was unbanned %(count)s times|one": "tika atbloķēts", + "were kicked %(count)s times|one": "tika padzīti", + "was kicked %(count)s times|other": "tika padzīts %(count)s reizes", + "was kicked %(count)s times|one": "tika padzīts", + "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s izmainīja savu lietotājvārdu %(count)s reizes", + "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s izmainīja savu lietotājvārdu", + "

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": "

Tavas kopienas lapas HTML

\n

\n Izmanto garāku aprakstu, lai iepazīstinātu jaunos lietoājus ar kopienu, \n vai padalies ar kādām attiecināmām web-saitēm\n

\n

\n Vari izmantot arī 'img' birkas\n

\n", + "Add rooms to the community summary": "Pievienot istabas kopienas informatīvajā kopsavilkumā", + "Which rooms would you like to add to this summary?": "Kuras istabas vēlaties pievienot šim kopsavilkumam?", + "Add to summary": "Pievienot kopsavilkumam", + "Failed to add the following rooms to the summary of %(groupId)s:": "Neizdevās sekojošās istabas pievienot %(groupId)s kopsavilkumam:", + "Add a Room": "Pievienot istabu", + "Failed to remove the room from the summary of %(groupId)s": "Neizdevās dzēst istabu no %(groupId)s kopsavilkuma", + "The room '%(roomName)s' could not be removed from the summary.": "Istabu '%(roomName)s' neizdevās dzēst no kopsavilkuma.", + "Leave Community": "Atstāt kopienu", + "Unable to leave room": "Nav iespējams atstāt istabu", + "Community Settings": "Kopienas iestatījumi", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Šīs istabas tiek rādītas kopienas dalībniekiem šīs kopienas lapā. Kopienas dalībnieki var pievienoties istabām, uzklikšķinot uz tām.", + "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!": "Jūsu kopienai nav plašāka HTML-lapas apraksta ko parādīt dalībniekiem.
Klikšķini šeit, lai atvērtu iestatījumus un to pievienotu!", + "Description": "Apraksts", + "Failed to load %(groupId)s": "Neizdevās ielādēt %(groupId)s", + "This Home server does not support communities": "Šis mitināšanas serveris neatbalsta kopienas", + "This room is not public. You will not be able to rejoin without an invite.": "Šīs istaba nav publiska. Tu nevari tajā ieiet bez uzaicinājuma.", + "Cryptography data migrated": "Sifrēšanas dati tika pārnesti", + "A one-off migration of cryptography data has been performed. End-to-end encryption will not work if you go back to an older version of Riot. If you need to use end-to-end cryptography on an older version, log out of Riot first. To retain message history, export and re-import your keys.": "Veikta vienreizēja šifrēšanas datu pārnese. Sifrēšana (end-to-end) nedarbosies, ja Tu atgriezīses pie vecākas Riot versijas. Ja nepieciešams izmantot end-to-end šifrēšanu, izmantojot vecāku versija, vispirms izraksties no Riot. Lai saglabātu ziņu vēsturi, eksportē un tad importē savas kripto-atslēgas.", + "Old cryptography data detected": "Tika uzieti novecojuši šifrēšanas dati", + "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.": "Uzieti dati no vecākas Riot versijas. Tas novedīs pie end-to-end šifrēšanas problēmām vecākajā versijā. Šajā versijā nevar tikt atšifrēti ziņojumi, kuri radīti izmantojot vecākajā versijā end-to-end šifrētas ziņas. Tas var arī novest pie ziņapmaiņas, kas veikta ar šo versiju. Ja rodas ķibeles, izraksties un par jaunu pieraksties sistēmā. Lai saglabātu ziņu vēsturi, eksportē un tad importē savas šifrēšanas atslēgas.", + "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Radi kopienu, lai apvienotu lietotājus un istabas. Izveido mājaslapu, lai iezīmētu Matrix visumā savu klātbūtni, vietu un telpu.", + "Error whilst fetching joined communities": "Ielādējot kopienas radās kļūda", + "%(count)s of your messages have not been sent.|one": "Tava ziņa netika nosūtīta.", + "Show devices, send anyway or cancel.": "Parādīt ierīces, vienalga nosūtīt vai sūtīšanu atcelt.", + "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Atkārtoti nosūtīt ziņu vai atcelt sūtīšanu.", + "There's no one else here! Would you like to invite others or stop warning about the empty room?": "Šeit neviena nav. Ja vēlies kādu uzaicināt vai atslēgt paziņojumu par tukšu istabu?", + "Light theme": "Gaiša tēma", + "Dark theme": "Tumša tēma", + "Status.im theme": "Status.im tēma", + "Ignored Users": "Ignorētie lietotāji", + "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "Privātumu augstu respektējam, tādēļ nevācam nekādus personas un identificējamus datus analītikas mērķiem.", + "Learn more about how we use analytics.": "Sīkāk par to, kā tiek izmantota analītika.", + "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "Epasts ir nosūtīts uz %(emailAddress)s. Izmantojiet epastā nosūtīto tīmekļa saiti un tad noklišķiniet šeit zemāk.", + "Please note you are logging into the %(hs)s server, not matrix.org.": "Lūdzu ņem vērā, ka Tu pieraksties %(hs)s serverī, nevis matrix.org serverī.", + "This homeserver doesn't offer any login flows which are supported by this client.": "Šis bāzes serveris neatbalsta nevienu pierakstīšanās metodi, kuru piedāvā šis Riot klients.", + "Sign in to get started": "Pierakstīties, lai sāktu", + "Ignores a user, hiding their messages from you": "Ignorē lietotāju, Tev nerādot viņa sūtītās ziņas", + "Stops ignoring a user, showing their messages going forward": "Atceļ lietotāja ignorēšanu, rādot viņa turpmāk sūtītās ziņas", + "Notify the whole room": "Paziņot visai istabai", + "Room Notification": "Istabas paziņojums" } From e3f68f12c859e23342b6f7266338d9feb2655f50 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 12 Feb 2018 18:01:08 +0000 Subject: [PATCH 061/242] Add context menu to TagTile With two options: View Community and Remove, which removes the tag from the panel. --- src/actions/TagOrderActions.js | 47 ++++++++++++++++++++++++ src/components/views/elements/TagTile.js | 35 ++++++++++++++++++ src/i18n/strings/en_EN.json | 2 +- src/stores/TagOrderStore.js | 20 +++++++++- 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/actions/TagOrderActions.js b/src/actions/TagOrderActions.js index dd4df6a9d4..3504adb09b 100644 --- a/src/actions/TagOrderActions.js +++ b/src/actions/TagOrderActions.js @@ -56,4 +56,51 @@ TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) { }); }; +/** + * Creates an action thunk that will do an asynchronous request to + * label a tag as removed in im.vector.web.tag_ordering account data. + * + * The reason this is implemented with new state `removedTags` is that + * we incrementally and initially populate `tags` with groups that + * have been joined. If we remove a group from `tags`, it will just + * get added (as it looks like a group we've recently joined). + * + * NB: If we ever support adding of tags (which is planned), we should + * take special care to remove the tag from `removedTags` when we add + * it. + * + * @param {MatrixClient} matrixClient the matrix client to set the + * account data on. + * @param {string} tag the tag to remove. + * @returns {function} an action thunk that will dispatch actions + * indicating the status of the request. + * @see asyncAction + */ +TagOrderActions.removeTag = function(matrixClient, tag) { + // Don't change tags, just removedTags + const tags = TagOrderStore.getOrderedTags(); + const removedTags = TagOrderStore.getRemovedTagsAccountData() || []; + + if (removedTags.includes(tag)) { + // Return a thunk that doesn't do anything, we don't even need + // an asynchronous action here, the tag is already removed. + return () => {}; + } + + removedTags.push(tag); + + const storeId = TagOrderStore.getStoreId(); + + return asyncAction('TagOrderActions.removeTag', () => { + Analytics.trackEvent('TagOrderActions', 'removeTag'); + return matrixClient.setAccountData( + 'im.vector.web.tag_ordering', + {tags, removedTags, _storeId: storeId}, + ); + }, () => { + // For an optimistic update + return {removedTags}; + }); +}; + export default TagOrderActions; diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js index f52f758cc0..8d801d986d 100644 --- a/src/components/views/elements/TagTile.js +++ b/src/components/views/elements/TagTile.js @@ -21,6 +21,7 @@ import { MatrixClient } from 'matrix-js-sdk'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent } from '../../../Keyboard'; +import ContextualMenu from '../../structures/ContextualMenu'; import FlairStore from '../../../stores/FlairStore'; @@ -81,6 +82,35 @@ export default React.createClass({ }); }, + onContextButtonClick: function(e) { + e.preventDefault(); + e.stopPropagation(); + + // Hide the (...) immediately + this.setState({ hover: false }); + + const TagTileContextMenu = sdk.getComponent('context_menus.TagTileContextMenu'); + const elementRect = e.target.getBoundingClientRect(); + + // The window X and Y offsets are to adjust position when zoomed in to page + const x = elementRect.right + window.pageXOffset + 3; + const chevronOffset = 12; + let y = (elementRect.top + (elementRect.height / 2) + window.pageYOffset); + y = y - (chevronOffset + 8); // where 8 is half the height of the chevron + + const self = this; + ContextualMenu.createMenu(TagTileContextMenu, { + chevronOffset: chevronOffset, + left: x, + top: y, + tag: this.props.tag, + onFinished: function() { + self.setState({ menuDisplayed: false }); + }, + }); + this.setState({ menuDisplayed: true }); + }, + onMouseOver: function() { this.setState({hover: true}); }, @@ -109,10 +139,15 @@ export default React.createClass({ const tip = this.state.hover ? :
; + const contextButton = this.state.hover || this.state.menuDisplayed ? +
+ { "\u00B7\u00B7\u00B7" } +
:
; return
{ tip } + { contextButton }
; }, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6139ac2a91..3cfbe24122 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -500,8 +500,8 @@ "Download %(text)s": "Download %(text)s", "Invalid file%(extra)s": "Invalid file%(extra)s", "Error decrypting image": "Error decrypting image", - "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", "This image cannot be displayed.": "This image cannot be displayed.", + "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", "Error decrypting video": "Error decrypting video", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.", diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js index 69b22797fb..3ec751d075 100644 --- a/src/stores/TagOrderStore.js +++ b/src/stores/TagOrderStore.js @@ -55,6 +55,7 @@ class TagOrderStore extends Store { const tagOrderingEventContent = tagOrderingEvent ? tagOrderingEvent.getContent() : {}; this._setState({ orderedTagsAccountData: tagOrderingEventContent.tags || null, + removedTagsAccountData: tagOrderingEventContent.removedTags || null, hasSynced: true, }); this._updateOrderedTags(); @@ -70,6 +71,7 @@ class TagOrderStore extends Store { this._setState({ orderedTagsAccountData: payload.event_content ? payload.event_content.tags : null, + removedTagsAccountData: payload.event_content ? payload.event_content.removedTags : null, }); this._updateOrderedTags(); break; @@ -90,6 +92,14 @@ class TagOrderStore extends Store { }); break; } + case 'TagOrderActions.removeTag.pending': { + // Optimistic update of a removed tag + this._setState({ + removedTagsAccountData: payload.request.removedTags, + }); + this._updateOrderedTags(); + break; + } case 'select_tag': { let newTags = []; // Shift-click semantics @@ -165,13 +175,15 @@ class TagOrderStore extends Store { _mergeGroupsAndTags() { const groupIds = this._state.joinedGroupIds || []; const tags = this._state.orderedTagsAccountData || []; + const removedTags = this._state.removedTagsAccountData || []; + const tagsToKeep = tags.filter( - (t) => t[0] !== '+' || groupIds.includes(t), + (t) => (t[0] !== '+' || groupIds.includes(t)) && !removedTags.includes(t), ); const groupIdsToAdd = groupIds.filter( - (groupId) => !tags.includes(groupId), + (groupId) => !tags.includes(groupId) && !removedTags.includes(groupId), ); return tagsToKeep.concat(groupIdsToAdd); @@ -181,6 +193,10 @@ class TagOrderStore extends Store { return this._state.orderedTags; } + getRemovedTagsAccountData() { + return this._state.removedTagsAccountData; + } + getStoreId() { // Generate a random ID to prevent this store from clobbering its // state with redundant remote echos. From 7a4c1994c327e4616a801c0a5d4aa1495fbdbb67 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 12 Feb 2018 18:35:13 +0000 Subject: [PATCH 062/242] Use Boolean() instead of assuming filter is based on truthiness --- src/components/views/rooms/RoomList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 269f04c963..4a491c8a03 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -371,7 +371,7 @@ module.exports = React.createClass({ return; } - return isRoomVisible[taggedRoom.roomId]; + return Boolean(isRoomVisible[taggedRoom.roomId]); }); }); From 3eeef064bf5e7abaca367f2c62dce174d9707644 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 12 Feb 2018 18:37:54 +0000 Subject: [PATCH 063/242] Remove unused asyncId --- src/actions/actionCreators.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/actions/actionCreators.js b/src/actions/actionCreators.js index 697930414c..967ce609e7 100644 --- a/src/actions/actionCreators.js +++ b/src/actions/actionCreators.js @@ -33,28 +33,25 @@ limitations under the License. * `${id}.failure`. * * The shape of each are: - * { action: '${id}.pending', request, asyncId } - * { action: '${id}.success', result, asyncId } - * { action: '${id}.failure', err, asyncId } + * { action: '${id}.pending', request } + * { action: '${id}.success', result } + * { action: '${id}.failure', err } * - * where `request` is returned by `pendingFn`, result - * is the result of the promise returned by `fn` and - * `asyncId` is a unique ID for each dispatch of the - * asynchronous action. + * where `request` is returned by `pendingFn` and + * result is the result of the promise returned by + * `fn`. */ export function asyncAction(id, fn, pendingFn) { return (dispatch) => { - const asyncId = Math.random().toString(16).slice(2, 10); dispatch({ action: id + '.pending', request: typeof pendingFn === 'function' ? pendingFn() : undefined, - asyncId, }); fn().then((result) => { - dispatch({action: id + '.success', result, asyncId}); + dispatch({action: id + '.success', result}); }).catch((err) => { - dispatch({action: id + '.failure', err, asyncId}); + dispatch({action: id + '.failure', err}); }); }; } From 322012cf889c00fe5b2bc790a01c52e6ca1e689e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 12 Feb 2018 18:46:36 +0000 Subject: [PATCH 064/242] Add comment to explain hacky optimism --- src/stores/RoomListStore.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 193784811c..b71e1c5cc1 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -79,6 +79,11 @@ class RoomListStore extends Store { } break; case 'RoomListActions.tagRoom.pending': { + // XXX: we only show one optimistic update at any one time. + // Ideally we should be making a list of in-flight requests + // that are backed by transaction IDs. Until the js-sdk + // supports this, we're stuck with only being able to use + // the most recent optimistic update. this._generateRoomLists(payload.request); } break; From 5e9368e794eac546569d93ae2738bd24566cdc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Mon, 12 Feb 2018 21:13:53 +0100 Subject: [PATCH 065/242] Add comments explaining our non standard usage of aria-described-by --- src/components/views/dialogs/BaseDialog.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 08fd972621..053aef66c3 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -76,6 +76,12 @@ export default React.createClass({ className={this.props.className} role="dialog" aria-labelledby='mx_BaseDialog_title' + // This should point to a node describing the dialog. + // If we were about to completelly follow this recommendation we'd need to + // make all the components relying on BaseDialog to be aware of it. + // So instead we will use the whole content as the description. + // Description comes first and if the content contains more text, + // AT users can skip its presentation. aria-describedby={this.props.contentId} > Date: Tue, 13 Feb 2018 09:44:00 +0000 Subject: [PATCH 066/242] Move groups button to TagPanel --- src/components/structures/TagPanel.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 49a7a4020a..f10936e802 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -111,8 +111,7 @@ const TagPanel = React.createClass({ }, render() { - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - const TintableSvg = sdk.getComponent('elements.TintableSvg'); + const GroupsButton = sdk.getComponent('elements.GroupsButton'); const DNDTagTile = sdk.getComponent('elements.DNDTagTile'); const tags = this.state.orderedTags.map((tag, index) => { @@ -142,9 +141,9 @@ const TagPanel = React.createClass({ ) } - - - +
+ +
; }, }); From 493116b17e57d56036a896ef60ab9886ebb97112 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 13 Feb 2018 11:43:22 +0000 Subject: [PATCH 067/242] Give the login page its spinner back --- src/components/structures/login/Login.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js index 5042ca1fd0..7f4aa0325a 100644 --- a/src/components/structures/login/Login.js +++ b/src/components/structures/login/Login.js @@ -431,10 +431,10 @@ module.exports = React.createClass({ // FIXME: remove status.im theme tweaks const theme = SettingsStore.getValue("theme"); if (theme !== "status") { - header =

{ _t('Sign in') }

; + header =

{ _t('Sign in') } { loader }

; } else { if (!this.state.errorText) { - header =

{ _t('Sign in to get started') }

; + header =

{ _t('Sign in to get started') } { loader }

; } } From 8377abcd1987a34cecbb3b363f807731f5dd861e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 13 Feb 2018 11:49:59 +0000 Subject: [PATCH 068/242] Store component state for editors to prevent a forceUpdate from /sync causing the editors to revert before the user had a chance to hit "Save". Part of fixing https://github.com/vector-im/riot-web/issues/6019 --- src/components/views/rooms/RoomNameEditor.js | 21 ++++++++++++++--- src/components/views/rooms/RoomTopicEditor.js | 23 +++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/RoomNameEditor.js b/src/components/views/rooms/RoomNameEditor.js index 5c224d79c0..d073a0be25 100644 --- a/src/components/views/rooms/RoomNameEditor.js +++ b/src/components/views/rooms/RoomNameEditor.js @@ -29,13 +29,21 @@ module.exports = React.createClass({ room: PropTypes.object.isRequired, }, + getInitialState: function() { + return { + name: null, + }; + }, + componentWillMount: function() { const room = this.props.room; const name = room.currentState.getStateEvents('m.room.name', ''); const myId = MatrixClientPeg.get().credentials.userId; const defaultName = room.getDefaultRoomName(myId); - this._initialName = name ? name.getContent().name : ''; + this.setState({ + name: name ? name.getContent().name : '', + }); this._placeholderName = _t("Unnamed Room"); if (defaultName && defaultName !== 'Empty room') { // default name from JS SDK, needs no translation as we don't ever show it. @@ -44,7 +52,13 @@ module.exports = React.createClass({ }, getRoomName: function() { - return this.refs.editor.getValue(); + return this.state.name; + }, + + _onValueChanged: function(value, shouldSubmit) { + this.setState({ + name: value, + }); }, render: function() { @@ -57,7 +71,8 @@ module.exports = React.createClass({ placeholderClassName="mx_RoomHeader_placeholder" placeholder={this._placeholderName} blurToCancel={false} - initialValue={this._initialName} + initialValue={this.state.name} + onValueChanged={this._onValueChanged} dir="auto" />
); diff --git a/src/components/views/rooms/RoomTopicEditor.js b/src/components/views/rooms/RoomTopicEditor.js index 8f950d625c..7ad02f264c 100644 --- a/src/components/views/rooms/RoomTopicEditor.js +++ b/src/components/views/rooms/RoomTopicEditor.js @@ -28,26 +28,41 @@ module.exports = React.createClass({ room: PropTypes.object.isRequired, }, + getInitialState: function() { + return { + topic: null, + }; + }, + componentWillMount: function() { const room = this.props.room; const topic = room.currentState.getStateEvents('m.room.topic', ''); - this._initialTopic = topic ? topic.getContent().topic : ''; + this.setState({ + topic: topic ? topic.getContent().topic : '', + }); }, getTopic: function() { - return this.refs.editor.getValue(); + return this.state.topic; + }, + + _onValueChanged: function(value) { + this.setState({ + topic: value, + }); }, render: function() { const EditableText = sdk.getComponent("elements.EditableText"); return ( - ); }, From 36e8bf1f20661c380bec1ad5a2337f914480cd0a Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 13 Feb 2018 14:13:47 +0000 Subject: [PATCH 069/242] Change CSS class for message panel spinner to stop scrollbars appearing when we - jump to a message or, - permalink that is to an not paginated in event --- src/components/structures/TimelinePanel.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 4ade78af85..12f745146e 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -1121,9 +1121,9 @@ var TimelinePanel = React.createClass({ // exist. if (this.state.timelineLoading) { return ( -
- -
+
+ +
); } From 5af560f625ef48000063c1a5b9ee3b060bf6d46e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 13 Feb 2018 14:43:34 +0000 Subject: [PATCH 070/242] Make removedTags a Set for perf --- src/stores/TagOrderStore.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js index 3ec751d075..78e4a6e95d 100644 --- a/src/stores/TagOrderStore.js +++ b/src/stores/TagOrderStore.js @@ -175,15 +175,15 @@ class TagOrderStore extends Store { _mergeGroupsAndTags() { const groupIds = this._state.joinedGroupIds || []; const tags = this._state.orderedTagsAccountData || []; - const removedTags = this._state.removedTagsAccountData || []; + const removedTags = new Set(this._state.removedTagsAccountData || []); const tagsToKeep = tags.filter( - (t) => (t[0] !== '+' || groupIds.includes(t)) && !removedTags.includes(t), + (t) => (t[0] !== '+' || groupIds.includes(t)) && !removedTags.has(t), ); const groupIdsToAdd = groupIds.filter( - (groupId) => !tags.includes(groupId) && !removedTags.includes(groupId), + (groupId) => !tags.includes(groupId) && !removedTags.has(groupId), ); return tagsToKeep.concat(groupIdsToAdd); From f16bc93fee1c46dddf90f323d82e1646fab4b5a4 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 13 Feb 2018 16:09:17 +0000 Subject: [PATCH 071/242] If a tag is unrecognised, assume manual ordering (as we did previously) Fixes https://github.com/vector-im/riot-web/issues/6135 --- src/stores/RoomListStore.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index b71e1c5cc1..693275952b 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -176,12 +176,13 @@ class RoomListStore extends Store { listOrders[order].forEach((listKey) => { let comparator; switch (order) { - case "manual": - comparator = this._getManualComparator(listKey, optimisticRequest); - break; case "recent": comparator = this._recentsComparator; break; + case "manual": + default: + comparator = this._getManualComparator(listKey, optimisticRequest); + break; } lists[listKey].sort(comparator); }); From 06b18dda1856b45b9d17a2f7c1707cbcbddbcb78 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Tue, 13 Feb 2018 17:23:42 +0000 Subject: [PATCH 072/242] Added translation using Weblate (Bulgarian) --- src/i18n/strings/bg.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/i18n/strings/bg.json diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/src/i18n/strings/bg.json @@ -0,0 +1 @@ +{} From bee0a952c37c1d7c6abc3b2092430f4fc815affa Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Tue, 13 Feb 2018 18:57:09 +0000 Subject: [PATCH 073/242] Translated using Weblate (Bulgarian) Currently translated at 0.2% (2 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 0967ef424b..1300a32895 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1 +1,4 @@ -{} +{ + "OK": "ОК", + "Operation failed": "Операцията е неуспешна" +} From 02e0663409b965bcc165dcf8703aadbc8ae80c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sim=C3=B3=20Albert=20i=20Beltran?= Date: Tue, 13 Feb 2018 18:44:58 +0000 Subject: [PATCH 074/242] Translated using Weblate (Catalan) Currently translated at 88.3% (871 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ca/ --- src/i18n/strings/ca.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json index 1ff3e7f8e9..0b1a7b10ef 100644 --- a/src/i18n/strings/ca.json +++ b/src/i18n/strings/ca.json @@ -376,7 +376,7 @@ "Idle for %(duration)s": "Inactiu durant %(duration)s", "Offline for %(duration)s": "Desconnectat durant %(duration)s", "Unknown for %(duration)s": "Desconegut durant %(duration)s", - "Online": "En línia", + "Online": "Conectat", "Idle": "Inactiu", "Offline": "Desconnectat", "Unknown": "Desconegut", From ed871cbd83987e6f2492327f8df7d6a308e17293 Mon Sep 17 00:00:00 2001 From: Walter Date: Tue, 13 Feb 2018 18:55:45 +0000 Subject: [PATCH 075/242] Translated using Weblate (Russian) Currently translated at 100.0% (986 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://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 e7cc2f2319..d24ee71de1 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -536,7 +536,7 @@ "Drop file here to upload": "Перетащите файл сюда для отправки", " (unsupported)": " (не поддерживается)", "Ongoing conference call%(supportedText)s.": "Установлен групповой вызов %(supportedText)s.", - "Online": "В сети", + "Online": "Онлайн", "Idle": "Неактивен", "Offline": "Не в сети", "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s сменил аватар комнаты на ", From db2f6f863a8c63ec434c4cd11b7fa52cae846ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sim=C3=B3=20Albert=20i=20Beltran?= Date: Tue, 13 Feb 2018 18:00:22 +0000 Subject: [PATCH 076/242] Translated using Weblate (Spanish) Currently translated at 58.1% (573 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/es/ --- src/i18n/strings/es.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/es.json b/src/i18n/strings/es.json index 1b513cc51f..ccfd6f7761 100644 --- a/src/i18n/strings/es.json +++ b/src/i18n/strings/es.json @@ -571,5 +571,6 @@ "Nov": "Nov", "Dec": "Dic", "Warning": "Advertencia", - "Unpin Message": "Desmarcar Mensaje" + "Unpin Message": "Desmarcar Mensaje", + "Online": "Conectado" } From 3020c8cd94a08210070a7633bfa35a93a049c367 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 11:23:29 +0000 Subject: [PATCH 077/242] Fix custom tags not being ordered manually Actually fixes vector-im/riot-web#6135 unlike #1748, which incorrectly assumed that custom tags would be included in listOrders. This fix makes sure that the `default` case in the `switch` is actually used. --- src/stores/RoomListStore.js | 42 ++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 693275952b..fdd9ca6692 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -160,32 +160,26 @@ class RoomListStore extends Store { }); const listOrders = { - "manual": [ - "m.favourite", - ], - "recent": [ - "im.vector.fake.invite", - "im.vector.fake.recent", - "im.vector.fake.direct", - "m.lowpriority", - "im.vector.fake.archived", - ], + "m.favourite": "manual", + "im.vector.fake.invite": "recent", + "im.vector.fake.recent": "recent", + "im.vector.fake.direct": "recent", + "m.lowpriority": "recent", + "im.vector.fake.archived": "recent", }; - Object.keys(listOrders).forEach((order) => { - listOrders[order].forEach((listKey) => { - let comparator; - switch (order) { - case "recent": - comparator = this._recentsComparator; - break; - case "manual": - default: - comparator = this._getManualComparator(listKey, optimisticRequest); - break; - } - lists[listKey].sort(comparator); - }); + Object.keys(lists).forEach((listKey) => { + let comparator; + switch (listOrders[listKey]) { + case "recent": + comparator = this._recentsComparator; + break; + case "manual": + default: + comparator = this._getManualComparator(listKey, optimisticRequest); + break; + } + lists[listKey].sort(comparator); }); this._setState({ From db4f0cb0bffc091df477899f00eded9c265bedc7 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 16:40:24 +0000 Subject: [PATCH 078/242] Handle adding previously removed tags --- src/actions/TagOrderActions.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/actions/TagOrderActions.js b/src/actions/TagOrderActions.js index 3504adb09b..38bada2228 100644 --- a/src/actions/TagOrderActions.js +++ b/src/actions/TagOrderActions.js @@ -35,6 +35,7 @@ const TagOrderActions = {}; TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) { // Only commit tags if the state is ready, i.e. not null let tags = TagOrderStore.getOrderedTags(); + let removedTags = TagOrderStore.getRemovedTagsAccountData(); if (!tags) { return; } @@ -42,17 +43,19 @@ TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) { tags = tags.filter((t) => t !== tag); tags = [...tags.slice(0, destinationIx), tag, ...tags.slice(destinationIx)]; + removedTags = removedTags.filter((t) => t !== tag); + const storeId = TagOrderStore.getStoreId(); return asyncAction('TagOrderActions.moveTag', () => { Analytics.trackEvent('TagOrderActions', 'commitTagOrdering'); return matrixClient.setAccountData( 'im.vector.web.tag_ordering', - {tags, _storeId: storeId}, + {tags, removedTags, _storeId: storeId}, ); }, () => { // For an optimistic update - return {tags}; + return {tags, removedTags}; }); }; From b626420eb93e4f25333cd5c98758d7d3cc586265 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 16:40:58 +0000 Subject: [PATCH 079/242] Move DND context to LoggedInView so that we can drag things from any part of the logged in app to another. (Specifically GroupView and TagPanel). --- src/components/structures/LoggedInView.js | 70 +++++++++++++++++++---- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index d7fe699156..f6bbfd247b 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -19,6 +19,7 @@ limitations under the License. import * as Matrix from 'matrix-js-sdk'; import React from 'react'; import PropTypes from 'prop-types'; +import { DragDropContext } from 'react-beautiful-dnd'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard'; import Notifier from '../../Notifier'; @@ -30,6 +31,9 @@ import sessionStore from '../../stores/SessionStore'; import MatrixClientPeg from '../../MatrixClientPeg'; import SettingsStore from "../../settings/SettingsStore"; +import TagOrderActions from '../../actions/TagOrderActions'; +import RoomListActions from '../../actions/RoomListActions'; + /** * This is what our MatrixChat shows when we are logged in. The precise view is * determined by the page_type property. @@ -207,6 +211,50 @@ const LoggedInView = React.createClass({ } }, + _onDragEnd: function(result) { + // Dragged to an invalid destination, not onto a droppable + if (!result.destination) { + return; + } + + const dest = result.destination.droppableId; + + if (dest === 'tag-panel-droppable') { + // Could be "GroupTile +groupId:domain" + const draggableId = result.draggableId.split(' ').pop(); + + // Dispatch synchronously so that the TagPanel receives an + // optimistic update from TagOrderStore before the previous + // state is shown. + dis.dispatch(TagOrderActions.moveTag( + this._matrixClient, + draggableId, + result.destination.index, + ), true); + } else if (dest.startsWith('room-sub-list-droppable_')) { + this._onRoomTileEndDrag(result); + } + }, + + _onRoomTileEndDrag: function(result) { + let newTag = result.destination.droppableId.split('_')[1]; + let prevTag = result.source.droppableId.split('_')[1]; + if (newTag === 'undefined') newTag = undefined; + if (prevTag === 'undefined') prevTag = undefined; + + const roomId = result.draggableId.split('_')[1]; + + const oldIndex = result.source.index; + const newIndex = result.destination.index; + + dis.dispatch(RoomListActions.tagRoom( + this._matrixClient, + this._matrixClient.getRoom(roomId), + prevTag, newTag, + oldIndex, newIndex, + ), true); + }, + render: function() { const LeftPanel = sdk.getComponent('structures.LeftPanel'); const RightPanel = sdk.getComponent('structures.RightPanel'); @@ -328,16 +376,18 @@ const LoggedInView = React.createClass({ return (
{ topBar } -
- -
- { page_element } -
- { right_panel } -
+ +
+ +
+ { page_element } +
+ { right_panel } +
+
); }, From 74c8a74e7d2106057b9c1e368914146c8d2ad8d3 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 16:43:01 +0000 Subject: [PATCH 080/242] Add Droppable to GroupView to contain the GroupTiles as Draggables --- src/components/structures/MyGroups.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index 22157beaca..4c9229a2ea 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import GeminiScrollbar from 'react-gemini-scrollbar'; +import { Droppable } from 'react-beautiful-dnd'; import sdk from '../../index'; import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; @@ -74,7 +75,13 @@ export default withMatrixClient(React.createClass({ contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

:
; content = groupNodes.length > 0 ? - { groupNodes } + + { (provided, snapshot) => ( +
+ { groupNodes } +
+ ) } +
:
{ _t( From 3850b552a5bddb753d21da3634d30914ed1f520f Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 16:46:06 +0000 Subject: [PATCH 081/242] Make GroupTile avatar draggable --- src/components/views/groups/GroupTile.js | 32 +++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js index ce426a9b78..70947afa65 100644 --- a/src/components/views/groups/GroupTile.js +++ b/src/components/views/groups/GroupTile.js @@ -17,10 +17,12 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {MatrixClient} from 'matrix-js-sdk'; +import { Draggable } from 'react-beautiful-dnd'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import FlairStore from '../../../stores/FlairStore'; + const GroupTile = React.createClass({ displayName: 'GroupTile', @@ -78,9 +80,33 @@ const GroupTile = React.createClass({ profile.avatarUrl, avatarHeight, avatarHeight, "crop", ) : null; return -
- -
+ + { (provided, snapshot) => ( +
+
+
+ +
+
+ { /* Instead of a blank placeholder, use a copy of the avatar itself. */ } + { provided.placeholder ? +
+ +
: +
+ } +
+ ) } +
{ name }
{ descElement } From 389d96bc46047bf2791b2fc6bf8200d68f7673ed Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 16:47:29 +0000 Subject: [PATCH 082/242] Use optimistic removedTagsAccountData state in TagOrderStore when receiving TagOrderActions.moveTag.pending, which now exposes this state. --- src/stores/TagOrderStore.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stores/TagOrderStore.js b/src/stores/TagOrderStore.js index 78e4a6e95d..eef078d8da 100644 --- a/src/stores/TagOrderStore.js +++ b/src/stores/TagOrderStore.js @@ -89,6 +89,7 @@ class TagOrderStore extends Store { // Optimistic update of a moved tag this._setState({ orderedTags: payload.request.tags, + removedTagsAccountData: payload.request.removedTags, }); break; } From 3948ee8ca14d5f00f2a0163a692569f303be9811 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 14 Feb 2018 17:53:54 +0000 Subject: [PATCH 083/242] Give each GroupTile avatar its own droppable so that they can be dragged and dropped without interacting with each other, as they would do if GroupView contained one droppable to contain them all. --- src/components/structures/MyGroups.js | 13 ++---- src/components/views/groups/GroupTile.js | 56 +++++++++++++----------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index 4c9229a2ea..116607fb08 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -17,7 +17,6 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import GeminiScrollbar from 'react-gemini-scrollbar'; -import { Droppable } from 'react-beautiful-dnd'; import sdk from '../../index'; import { _t } from '../../languageHandler'; import dis from '../../dispatcher'; @@ -74,14 +73,10 @@ export default withMatrixClient(React.createClass({ }); contentHeader = groupNodes.length > 0 ?

{ _t('Your Communities') }

:
; content = groupNodes.length > 0 ? - - - { (provided, snapshot) => ( -
- { groupNodes } -
- ) } -
+ +
+ { groupNodes } +
:
{ _t( diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js index 70947afa65..f1dbb75988 100644 --- a/src/components/views/groups/GroupTile.js +++ b/src/components/views/groups/GroupTile.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {MatrixClient} from 'matrix-js-sdk'; -import { Draggable } from 'react-beautiful-dnd'; +import { Draggable, Droppable } from 'react-beautiful-dnd'; import sdk from '../../../index'; import dis from '../../../dispatcher'; import FlairStore from '../../../stores/FlairStore'; @@ -80,33 +80,39 @@ const GroupTile = React.createClass({ profile.avatarUrl, avatarHeight, avatarHeight, "crop", ) : null; return - - { (provided, snapshot) => ( -
-
+ { (droppableProvided, droppableSnapshot) => ( +
+ -
- -
-
- { /* Instead of a blank placeholder, use a copy of the avatar itself. */ } - { provided.placeholder ? -
- -
: -
- } + { (provided, snapshot) => ( +
+
+
+ +
+
+ { /* Instead of a blank placeholder, use a copy of the avatar itself. */ } + { provided.placeholder ? +
+ +
: +
+ } +
+ ) } +
) } - +
{ name }
{ descElement } From a4c7da63afe4a58551a8497c221e91e1d97fdeec Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Thu, 15 Feb 2018 10:47:20 +0000 Subject: [PATCH 084/242] Translated using Weblate (Bulgarian) Currently translated at 4.6% (46 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 46 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 1300a32895..a05100dd3f 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -1,4 +1,48 @@ { "OK": "ОК", - "Operation failed": "Операцията е неуспешна" + "Operation failed": "Операцията е неуспешна", + "Search": "Търсене", + "Custom Server Options": "Потребителски опции за сървър", + "Dismiss": "Отказ", + "powered by Matrix": "базирано на Matrix", + "Warning": "Предупреждение", + "Error": "Грешка", + "Remove": "Премахни", + "Close": "Затвори", + "Cancel": "Отказ", + "Send": "Изпрати", + "Edit": "Редактирай", + "Continue": "Продължи", + "Failed to change password. Is your password correct?": "Неуспешна промяна. Правилно ли сте въвели Вашата парола?", + "Unpin Message": "Откачи съобщението", + "Sun": "нд.", + "Mon": "пн.", + "Tue": "вт.", + "Wed": "ср.", + "Thu": "чт.", + "Fri": "пт.", + "Sat": "сб.", + "Jan": "ян.", + "Feb": "февр.", + "Mar": "март", + "Apr": "апр.", + "May": "май", + "Jun": "юни", + "Jul": "юли", + "Aug": "авг.", + "Sep": "септ.", + "Oct": "окт.", + "Nov": "ноем.", + "Dec": "дек.", + "%(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": "%(day)s %(monthName)s %(fullYear)s, %(weekDayName)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s %(time)s", + "Online": "Онлайн", + "Failed to remove tag %(tagName)s from room": "Неуспешно премахване на %(tagName)s етикет от стаята", + "unknown error code": "неизвестен код за грешка", + "Failed to forget room %(errCode)s": "Не успешно забравяне на стаята %(errCode)s", + "Mute": "Заглуши", + "Leave": "Напусни", + "Favourite": "Любим" } From ceec40551908db8b35a0bd33d9fff6aa01b83b87 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 15 Feb 2018 11:23:00 +0000 Subject: [PATCH 085/242] Remove RoomListStore listener This caused the the RoomList component to leak (although in practice only accross logins because that's the only time it's unmounted) --- package.json | 2 +- src/components/views/rooms/RoomList.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bb8db64d28..9d5013de28 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "require-json": "0.0.1", "rimraf": "^2.4.3", "sinon": "^1.17.3", - "source-map-loader": "^0.1.5", + "source-map-loader": "^0.1.6", "walk": "^2.3.9", "webpack": "^1.12.14" } diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 4a491c8a03..41a200420d 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -191,6 +191,10 @@ module.exports = React.createClass({ this._tagStoreToken.remove(); } + if (this._roomListStoreToken) { + this._roomListStoreToken.remove(); + } + if (this._groupStoreTokens.length > 0) { // NB: GroupStore is not a Flux.Store this._groupStoreTokens.forEach((token) => token.unregister()); From 44964e80a9c3f8974be669b9bf453375649ea986 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 15 Feb 2018 11:25:40 +0000 Subject: [PATCH 086/242] undo unintentional commit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d5013de28..bb8db64d28 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "require-json": "0.0.1", "rimraf": "^2.4.3", "sinon": "^1.17.3", - "source-map-loader": "^0.1.6", + "source-map-loader": "^0.1.5", "walk": "^2.3.9", "webpack": "^1.12.14" } From 39af04f09048d872beef7c0059148aa7cd978d2c Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Thu, 15 Feb 2018 13:18:15 +0000 Subject: [PATCH 087/242] Translated using Weblate (Bulgarian) Currently translated at 5.5% (55 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index a05100dd3f..6ce4acf267 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -44,5 +44,14 @@ "Failed to forget room %(errCode)s": "Не успешно забравяне на стаята %(errCode)s", "Mute": "Заглуши", "Leave": "Напусни", - "Favourite": "Любим" + "Favourite": "Любим", + "Register": "Регистрация", + "Notifications": "Известия", + "Rooms": "Стаи", + "Add rooms to this community": "Добави стаи в това общество", + "Unnamed room": "Ненаименувана стая", + "World readable": "Четимо за всички", + "Guests can join": "Гости могат да се присъединят", + "No rooms to show": "Няма стаи, които да бъдат показани", + "Failed to add tag %(tagName)s to room": "Неуспешно добавяне на %(tagName)s етикет в стаята" } From 57419a7f8d485c621b6de0a85467a499874c3c45 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Thu, 15 Feb 2018 14:11:45 +0000 Subject: [PATCH 088/242] Give emptySubListTip a container for correct bg colour --- src/components/views/rooms/RoomList.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 4a491c8a03..e53b7b6536 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -544,17 +544,20 @@ module.exports = React.createClass({ const RoomDirectoryButton = sdk.getComponent('elements.RoomDirectoryButton'); const CreateRoomButton = sdk.getComponent('elements.CreateRoomButton'); + let tip = null; + switch (section) { case 'im.vector.fake.direct': - return
+ tip =
{ _t( "Press to start a chat with someone", {}, { 'StartChatButton': }, ) }
; + break; case 'im.vector.fake.recent': - return
+ tip =
{ _t( "You're not in any rooms yet! Press to make a room or"+ " to browse the directory", @@ -565,6 +568,13 @@ module.exports = React.createClass({ }, ) }
; + break; + } + + if (tip) { + return
+ { tip } +
; } // We don't want to display drop targets if there are no room tiles to drag'n'drop From 19b6684089e7a50e5bb80ed2bc8ba4c7d6e6961e Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Thu, 15 Feb 2018 14:50:16 +0000 Subject: [PATCH 089/242] Translated using Weblate (Bulgarian) Currently translated at 7.0% (70 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 6ce4acf267..7574c0278f 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -53,5 +53,20 @@ "World readable": "Четимо за всички", "Guests can join": "Гости могат да се присъединят", "No rooms to show": "Няма стаи, които да бъдат показани", - "Failed to add tag %(tagName)s to room": "Неуспешно добавяне на %(tagName)s етикет в стаята" + "Failed to add tag %(tagName)s to room": "Неуспешно добавяне на %(tagName)s етикет в стаята", + "This email address is already in use": "Този имейл адрес е вече зает", + "This phone number is already in use": "Този телефонен номер е вече зает", + "Failed to verify email address: make sure you clicked the link in the email": "Неуспешно потвърждаване на имейл адреса: уверете се, че сте кликнали върху връзката в имейла", + "The platform you're on": "Платформата, която използвате", + "The version of Riot.im": "Версията на Riot.im", + "Whether or not you're logged in (we don't record your user name)": "Независимо дали сте в профила си или не (не записваме Вашето потребителско име)", + "Your language of choice": "Вашият език по избор", + "Which officially provided instance you are using, if any": "Коя официално предоставена инстанция използвате, ако има такава", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Независимо дали използвате Richtext режим на Rich Text Editor", + "Your homeserver's URL": "Адрес на Вашия Home сървър", + "Your identity server's URL": "Адрес на Вашия сървър за самоличност", + "Analytics": "Статистика", + "The information being sent to us to help make Riot.im better includes:": "За да направи Riot по-добър, информацията изпратена до нас включва:", + "Call Failed": "Неуспешно повикване", + "Call": "Обаждане" } From 07b691a45d14fa817fe9d08d8ed1ecc2886b313c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 15 Feb 2018 20:20:19 +0000 Subject: [PATCH 090/242] typo --- src/components/views/messages/MFileBody.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index c324c291e7..90efe24df3 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -82,7 +82,7 @@ Tinter.registerTintable(updateTintedDownloadImage); // downloaded. This limit does not seem to apply when the url is used as // the source attribute of an image tag. // -// Blob URLs are generated using window.URL.createObjectURL and unforuntately +// Blob URLs are generated using window.URL.createObjectURL and unfortunately // for our purposes they inherit the origin of the page that created them. // This means that any scripts that run when the URL is viewed will be able // to access local storage. From b111a824e88fc4ceb29ec03ef7c2765480ada2d1 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Thu, 15 Feb 2018 19:36:52 +0000 Subject: [PATCH 091/242] Translated using Weblate (Bulgarian) Currently translated at 12.0% (119 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 53 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 7574c0278f..948181fa9d 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -49,7 +49,7 @@ "Notifications": "Известия", "Rooms": "Стаи", "Add rooms to this community": "Добави стаи в това общество", - "Unnamed room": "Ненаименувана стая", + "Unnamed room": "Стая без име", "World readable": "Четимо за всички", "Guests can join": "Гости могат да се присъединят", "No rooms to show": "Няма стаи, които да бъдат показани", @@ -68,5 +68,54 @@ "Analytics": "Статистика", "The information being sent to us to help make Riot.im better includes:": "За да направи Riot по-добър, информацията изпратена до нас включва:", "Call Failed": "Неуспешно повикване", - "Call": "Обаждане" + "Call": "Обаждане", + "Answer": "Отговори, приеми", + "You are already in a call.": "Вече сте в разговор.", + "VoIP is unsupported": "Не се поддържа VoIP", + "You cannot place VoIP calls in this browser.": "Не може да осъществите VoIP разговори в този браузър.", + "You cannot place a call with yourself.": "Не може да осъществите разговор със себе си.", + "Existing Call": "Съществуващ разговор", + "Conference calls are not supported in this client": "Групови разговори не се поддържат в тази програма", + "Conference calls are not supported in encrypted rooms": "Групови разговори не се поддържат в шифровани стаи", + "Warning!": "Внимание!", + "Conference calling is in development and may not be reliable.": "Груповите разговори са в процес на разработка и не са надеждни.", + "Review Devices": "Преглед на устройства", + "Failed to set up conference call": "Неуспешно осъществяване на групов чат", + "Conference call failed.": "Неуспешен групов разговор.", + "The file '%(fileName)s' failed to upload": "Неуспешно качване на файл '%(fileName)s'", + "The file '%(fileName)s' exceeds this home server's size limit for uploads": "Файлът '%(fileName)s' надхвърля ограничението на размера за качвания на този Home сървър", + "Upload Failed": "Качването е неуспешно", + "PM": "PM", + "AM": "AM", + "Who would you like to add to this community?": "Кой бихте желали да добавите в това общество?", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Предупреждение: Всеки човек, който добавяте в дадено общество, ще бъде публично видим за знаещите идентификатора на обществото", + "Invite new community members": "Покани нови членове на обществото", + "Name or matrix ID": "Име или matrix ID", + "Invite to Community": "Покани в обществото", + "Which rooms would you like to add to this community?": "Кои стаи бихте желали да добавите в това общество?", + "Show these rooms to non-members on the community page and room list?": "Показване на тези стаи на не-членове на страницата на обществата и списъка със стаи?", + "Add rooms to the community": "Добави стаи в обществото", + "Room name or alias": "Име или псевдоним на стая", + "Add to community": "Добави в обществото", + "Failed to invite the following users to %(groupId)s:": "Следните потребители не могат да бъдат поканени в %(groupId)s:", + "Failed to invite users to community": "Потребителите не могат да бъдат поканени в обществото", + "Failed to invite users to %(groupId)s": "Потребителите не могат да бъдат поканени в %(groupId)s", + "Failed to add the following rooms to %(groupId)s:": "Следните стаи не могат да бъдат добавени в %(groupId)s:", + "Riot does not have permission to send you notifications - please check your browser settings": "Riot няма разрешение да Ви изпраща известия - моля проверете вашите настройки на браузъра", + "Riot was not given permission to send notifications - please try again": "Riot не е получил разрешение да изпраща известия - моля опитайте отново", + "Unable to enable Notifications": "Неупешно включване на известия", + "This email address was not found": "Този имейл адрес не беше открит", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Изглежда вашият имейл адрес не може да се асоциира с Matrix ID на този Home сървър.", + "Default": "По подразбиране", + "Restricted": "Ограничен", + "Moderator": "Модератор", + "Admin": "Администратор", + "Start a chat": "Започване на чат", + "Who would you like to communicate with?": "С кой бихте желали да си комуникирате?", + "Email, name or matrix ID": "Имейл, име или matrix ID", + "Start Chat": "Започни чат", + "Invite new room members": "Покани нови членове на стаята", + "Who would you like to add to this room?": "Кой бихте желали да добавите в тази стая?", + "Send Invites": "Изпрати покани", + "Failed to invite user": "Неуспешна покана на потребителя" } From 94a0a904574ba3e63bf80dffc381db2f20842747 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 16 Feb 2018 14:16:50 +0000 Subject: [PATCH 092/242] Make RoomListStore aware of Room.timeline events so that we can do reorderings of lists ordered by most recent event. No optimisations here; we only update for timeline events on live timelines that could update the "unread count". --- src/actions/MatrixActionCreators.js | 10 ++++++ src/components/views/rooms/RoomList.js | 9 ------ src/stores/RoomListStore.js | 43 +++++++++++++++++--------- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index dbfe910533..27fbb6dda5 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -66,6 +66,15 @@ function createRoomTagsAction(matrixClient, roomTagsEvent, room) { return { action: 'MatrixActions.Room.tags', room }; } +function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTimeline, removed, data) { + return { + action: 'MatrixActions.Room.timeline', + event: timelineEvent, + isLiveEvent: data.liveEvent, + room, + }; +} + function createRoomMembershipAction(matrixClient, membershipEvent, member, oldMembership) { return { action: 'MatrixActions.RoomMember.membership', member }; } @@ -87,6 +96,7 @@ export default { this._addMatrixClientListener(matrixClient, 'sync', createSyncAction); this._addMatrixClientListener(matrixClient, 'accountData', createAccountDataAction); this._addMatrixClientListener(matrixClient, 'Room.tags', createRoomTagsAction); + this._addMatrixClientListener(matrixClient, 'Room.timeline', createRoomTimelineAction); this._addMatrixClientListener(matrixClient, 'RoomMember.membership', createRoomMembershipAction); }, diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 41a200420d..bab8054c60 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -76,7 +76,6 @@ module.exports = React.createClass({ cli.on("Room", this.onRoom); cli.on("deleteRoom", this.onDeleteRoom); - cli.on("Room.timeline", this.onRoomTimeline); cli.on("Room.name", this.onRoomName); cli.on("Room.receipt", this.onRoomReceipt); cli.on("RoomState.events", this.onRoomStateEvents); @@ -177,7 +176,6 @@ module.exports = React.createClass({ if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Room", this.onRoom); MatrixClientPeg.get().removeListener("deleteRoom", this.onDeleteRoom); - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); @@ -236,13 +234,6 @@ module.exports = React.createClass({ this._updateStickyHeaders(true, scrollToPosition); }, - onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) { - if (toStartOfTimeline) return; - if (!room) return; - if (data.timeline.getTimelineSet() !== room.getUnfilteredTimelineSet()) return; - this._delayedRefreshRoomList(); - }, - onRoomReceipt: function(receiptEvent, room) { // because if we read a notification, it will affect notification count // only bother updating if there's a receipt from us diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index fdd9ca6692..707a9da17e 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -23,6 +23,16 @@ import Unread from '../Unread'; * the RoomList. */ class RoomListStore extends Store { + + static _listOrders = { + "m.favourite": "manual", + "im.vector.fake.invite": "recent", + "im.vector.fake.recent": "recent", + "im.vector.fake.direct": "recent", + "m.lowpriority": "recent", + "im.vector.fake.archived": "recent", + }; + constructor() { super(dis); @@ -68,6 +78,14 @@ class RoomListStore extends Store { this._generateRoomLists(); } break; + case 'MatrixActions.Room.timeline': { + if (!this._state.ready || + !payload.isLiveEvent || + !this._eventTriggersRecentReorder(payload.event) + ) break; + this._generateRoomLists(); + } + break; case 'MatrixActions.accountData': { if (payload.event_type !== 'm.direct') break; this._generateRoomLists(); @@ -159,18 +177,9 @@ class RoomListStore extends Store { } }); - const listOrders = { - "m.favourite": "manual", - "im.vector.fake.invite": "recent", - "im.vector.fake.recent": "recent", - "im.vector.fake.direct": "recent", - "m.lowpriority": "recent", - "im.vector.fake.archived": "recent", - }; - Object.keys(lists).forEach((listKey) => { let comparator; - switch (listOrders[listKey]) { + switch (RoomListStore._listOrders[listKey]) { case "recent": comparator = this._recentsComparator; break; @@ -188,13 +197,17 @@ class RoomListStore extends Store { }); } + _eventTriggersRecentReorder(ev) { + return ev.getTs() && ( + Unread.eventTriggersUnreadCount(ev) || + ev.getSender() === this._matrixClient.credentials.userId + ); + } + _tsOfNewestEvent(room) { for (let i = room.timeline.length - 1; i >= 0; --i) { const ev = room.timeline[i]; - if (ev.getTs() && - (Unread.eventTriggersUnreadCount(ev) || - (ev.getSender() === this._matrixClient.credentials.userId)) - ) { + if (this._eventTriggersRecentReorder(ev)) { return ev.getTs(); } } @@ -210,6 +223,8 @@ class RoomListStore extends Store { } _recentsComparator(roomA, roomB) { + // XXX: We could use a cache here and update it when we see new + // events that trigger a reorder return this._tsOfNewestEvent(roomB) - this._tsOfNewestEvent(roomA); } From 84ab1ae3e2996157c358f0ca152669585be93863 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 16 Feb 2018 15:52:15 +0000 Subject: [PATCH 093/242] Do not assume that tags have been removed when moving tags --- src/actions/TagOrderActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/TagOrderActions.js b/src/actions/TagOrderActions.js index 38bada2228..a257ff16d8 100644 --- a/src/actions/TagOrderActions.js +++ b/src/actions/TagOrderActions.js @@ -35,7 +35,7 @@ const TagOrderActions = {}; TagOrderActions.moveTag = function(matrixClient, tag, destinationIx) { // Only commit tags if the state is ready, i.e. not null let tags = TagOrderStore.getOrderedTags(); - let removedTags = TagOrderStore.getRemovedTagsAccountData(); + let removedTags = TagOrderStore.getRemovedTagsAccountData() || []; if (!tags) { return; } From cca820c3538ae6e806fd6929b34f728eaf35d109 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Fri, 16 Feb 2018 11:48:04 +0000 Subject: [PATCH 094/242] Translated using Weblate (Bulgarian) Currently translated at 15.2% (150 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 948181fa9d..5df65775fe 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -117,5 +117,36 @@ "Invite new room members": "Покани нови членове на стаята", "Who would you like to add to this room?": "Кой бихте желали да добавите в тази стая?", "Send Invites": "Изпрати покани", - "Failed to invite user": "Неуспешна покана на потребителя" + "Failed to invite user": "Неуспешна покана на потребителя", + "Failed to invite": "Неуспешна покана", + "Failed to invite the following users to the %(roomName)s room:": "Следните потребителите не успяха да бъдат добавени в %(roomName)s:", + "You need to be logged in.": "Трябва да влезете в профила си.", + "You need to be able to invite users to do that.": "Трябва да имате право да добавите потребители, за да извършите това.", + "Unable to create widget.": "Неуспешно създаване на приспособление.", + "Failed to send request.": "Неуспешно изпращане на запитване.", + "This room is not recognised.": "Стаята не е разпозната.", + "Power level must be positive integer.": "Нивото на достъп трябва да бъде позитивно число.", + "Call Anyway": "Обади се въпреки това", + "Answer Anyway": "Отговори въпреки това", + "Call Timeout": "Изтекло време за повикване", + "The remote side failed to pick up": "Отсрещната страна не успя да отговори", + "Unable to capture screen": "Неуспешно заснемане на екрана", + "You are not in this room.": "Не сте в тази стая.", + "You do not have permission to do that in this room.": "Нямате достъп да направите това в тази стая.", + "Missing room_id in request": "Липсва room_id в заявката", + "Room %(roomId)s not visible": "Стая %(roomId)s не е видима", + "Missing user_id in request": "Липсва user_id в заявката", + "Failed to lookup current room": "Неуспешно намиране на текущата стая", + "/ddg is not a command": "/ddg не е команда", + "To use it, just wait for autocomplete results to load and tab through them.": "За използване, изчакайте зареждането на списъка с предложения и изберете от него.", + "Unrecognised room alias:": "Непознат псевдоним на стая:", + "Ignored user": "Игнориран потребител", + "You are now ignoring %(userId)s": "Вече игнорирате %(userId)s", + "Unignored user": "Неигнориран потребител", + "You are no longer ignoring %(userId)s": "Вече не игнорирате %(userId)s", + "Device already verified!": "Устройството е вече верифицирано!", + "WARNING: Device already verified, but keys do NOT MATCH!": "ВНИМАНИЕ: Устройстовото е верифицирано, но ключовете не съвпадат!", + "Verified key": "Верифициран ключ", + "Unrecognised command:": "Неразпозната команда:", + "Reason": "Причина" } From f2903d1439eb62cdc97dca0b2eb71ed586c39472 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 16 Feb 2018 08:45:19 +0000 Subject: [PATCH 095/242] Translated using Weblate (Finnish) Currently translated at 95.2% (939 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://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 fc7eac51a7..48a8ea755f 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -561,7 +561,7 @@ "Sep": "syyskuu", "Oct": "lokakuu", "Nov": "marraskuu", - "Dec": "jolukuu", + "Dec": "joulukuu", "User names may only contain letters, numbers, dots, hyphens and underscores.": "Käyttäjänimet voivat sisältää vain kirjaimia, numeroita, pisteitä, viivoja ja alaviivoja.", "To continue, please enter your password.": "Ole hyvä ja syötä salasanasi jatkaaksesi.", "Verifies a user, device, and pubkey tuple": "Varmentaa käyttäjän, laitteen ja julkisen avaimen kolmikon", From 3f6c15506c4116cb7bbe016c167d8d759842ab1f Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 16 Feb 2018 16:17:47 +0000 Subject: [PATCH 096/242] Remove unused `room` parameter of MatrixActions.Room.timeline --- src/actions/MatrixActionCreators.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index 27fbb6dda5..a9ea671fbe 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -71,7 +71,6 @@ function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTi action: 'MatrixActions.Room.timeline', event: timelineEvent, isLiveEvent: data.liveEvent, - room, }; } From cbeee72062c6e9f4fb7fb3e24b91beb92454d1f6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 16 Feb 2018 10:11:04 -0700 Subject: [PATCH 097/242] Don't show empty custom tags when filtering tags Signed-off-by: Travis Ralston --- src/components/views/rooms/RoomList.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 41a200420d..68b171b0ee 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -34,6 +34,7 @@ import RoomListStore from '../../../stores/RoomListStore'; import GroupStoreCache from '../../../stores/GroupStoreCache'; const HIDE_CONFERENCE_CHANS = true; +const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/; function phraseForSection(section) { switch (section) { @@ -365,7 +366,7 @@ module.exports = React.createClass({ }); Object.keys(lists).forEach((tagName) => { - filteredLists[tagName] = lists[tagName].filter((taggedRoom) => { + const filteredRooms = lists[tagName].filter((taggedRoom) => { // Somewhat impossible, but guard against it anyway if (!taggedRoom) { return; @@ -377,6 +378,10 @@ module.exports = React.createClass({ return Boolean(isRoomVisible[taggedRoom.roomId]); }); + + if (filteredRooms.length > 0 || tagName.match(STANDARD_TAGS_REGEX)) { + filteredLists[tagName] = filteredRooms; + } }); return filteredLists; @@ -682,7 +687,7 @@ module.exports = React.createClass({ onShowMoreRooms={self.onShowMoreRooms} /> { Object.keys(self.state.lists).map((tagName) => { - if (!tagName.match(/^(m\.(favourite|lowpriority)|im\.vector\.fake\.(invite|recent|direct|archived))$/)) { + if (!tagName.match(STANDARD_TAGS_REGEX)) { return Date: Fri, 16 Feb 2018 17:43:24 +0000 Subject: [PATCH 098/242] Implement global filter to deselect all tags and make TagPanel scrollable whilst we're at it. --- src/components/structures/TagPanel.js | 51 +++++++++++++++++---------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 6e3bcf521b..74b6656b79 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import { MatrixClient } from 'matrix-js-sdk'; +import GeminiScrollbar from 'react-gemini-scrollbar'; import TagOrderStore from '../../stores/TagOrderStore'; import GroupActions from '../../actions/GroupActions'; @@ -93,9 +94,14 @@ const TagPanel = React.createClass({ dis.dispatch({action: 'view_create_group'}); }, + onLogoClick(ev) { + dis.dispatch({action: 'deselect_tags'}); + }, + render() { const GroupsButton = sdk.getComponent('elements.GroupsButton'); const DNDTagTile = sdk.getComponent('elements.DNDTagTile'); + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const tags = this.state.orderedTags.map((tag, index) => { return ; }); return
- - { (provided, snapshot) => ( -
- { tags } - { provided.placeholder } -
- ) } -
+ + + +
+ + + { (provided, snapshot) => ( +
+ { tags } + { provided.placeholder } +
+ ) } +
+
+
From 7a0c82a327b7df5e28160c10cfd89fb55ee9b798 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Fri, 16 Feb 2018 18:08:29 +0000 Subject: [PATCH 099/242] Fix click background to deselect --- src/components/structures/TagPanel.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 74b6656b79..d614588ccc 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -84,8 +84,6 @@ const TagPanel = React.createClass({ }, onClick(e) { - // Ignore clicks on children - if (e.target !== e.currentTarget) return; dis.dispatch({action: 'deselect_tags'}); }, @@ -116,7 +114,11 @@ const TagPanel = React.createClass({
- + { tags } { provided.placeholder } From 2d5a2a9d48b3c7446cb00a2b3c8014b4edac3b11 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 16 Feb 2018 23:59:48 +0000 Subject: [PATCH 100/242] improve origin check of ScalarMessaging postmessage API. ensures that https://scalar.ve can't access the API. many thanks to @rugk for pointing out the potential vuln. cc @rxl881 in case this bug has been transplanted elsewhere. --- src/ScalarMessaging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index 3c164c6551..fc8ee9edf6 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -563,7 +563,7 @@ const onMessage = function(event) { const url = SdkConfig.get().integrations_ui_url; if ( event.origin.length === 0 || - !url.startsWith(event.origin) || + !url.startsWith(event.origin + '/') || !event.data.action || event.data.api // Ignore messages with specific API set ) { From 32130fbc28bc315adae9cd88bc19226f9ff121a6 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Mon, 19 Feb 2018 09:56:03 +0000 Subject: [PATCH 101/242] Don't regenerate RoomListStore state for notifs/scrollback/etc. Only do so for the live timeline of rooms. --- src/actions/MatrixActionCreators.js | 2 ++ src/stores/RoomListStore.js | 1 + 2 files changed, 3 insertions(+) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index a9ea671fbe..a307af6f57 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -71,6 +71,8 @@ function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTi action: 'MatrixActions.Room.timeline', event: timelineEvent, isLiveEvent: data.liveEvent, + isLiveUnfilteredRoomTimelineEvent: + room && data.timeline.getTimelineSet() === room.getUnfilteredTimelineSet(), }; } diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 707a9da17e..8a3af309fc 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -81,6 +81,7 @@ class RoomListStore extends Store { case 'MatrixActions.Room.timeline': { if (!this._state.ready || !payload.isLiveEvent || + !payload.isLiveUnfilteredRoomTimelineEvent || !this._eventTriggersRecentReorder(payload.event) ) break; this._generateRoomLists(); From da35871cb1952255335ab502aebf2ad5939825f6 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Sun, 18 Feb 2018 20:21:27 +0000 Subject: [PATCH 102/242] Translated using Weblate (Bulgarian) Currently translated at 24.4% (241 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 93 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 5df65775fe..ae049dff52 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -148,5 +148,96 @@ "WARNING: Device already verified, but keys do NOT MATCH!": "ВНИМАНИЕ: Устройстовото е верифицирано, но ключовете не съвпадат!", "Verified key": "Верифициран ключ", "Unrecognised command:": "Неразпозната команда:", - "Reason": "Причина" + "Reason": "Причина", + "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s прие поканата за %(displayName)s.", + "%(targetName)s accepted an invitation.": "%(targetName)s прие поканата.", + "%(senderName)s requested a VoIP conference.": "%(senderName)s заяви VoIP конферентен разговор.", + "%(senderName)s invited %(targetName)s.": "%(senderName)s покани %(targetName)s.", + "%(senderName)s banned %(targetName)s.": "%(senderName)s блокира %(targetName)s.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s смени своето име/псевдоним на %(displayName)s.", + "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s промени своето име на %(displayName)s.", + "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s премахна своето име (%(oldDisplayName)s).", + "%(senderName)s removed their profile picture.": "%(senderName)s премахна своята профилна снимка.", + "%(senderName)s changed their profile picture.": "%(senderName)s промени своята профилна снимка.", + "%(senderName)s set a profile picture.": "%(senderName)s зададе снимка на профила си.", + "VoIP conference started.": "VoIP конференцията започна.", + "%(targetName)s joined the room.": "%(targetName)s се присъедини към стаята.", + "VoIP conference finished.": "VoIP конференцията приключи.", + "%(targetName)s rejected the invitation.": "%(targetName)s отказа поканата.", + "%(targetName)s left the room.": "%(targetName)s напусна стаята.", + "%(senderName)s unbanned %(targetName)s.": "%(senderName)s отблокира %(targetName)s.", + "%(senderName)s kicked %(targetName)s.": "%(senderName)s изгони %(targetName)s.", + "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s оттегли поканата си към %(targetName)s.", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s смени темата на \"%(topic)s\".", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s премахна името на стаята.", + "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s промени името на стаята на %(roomName)s.", + "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s изпрати снимка.", + "Someone": "Някой", + "(not supported by this browser)": "(не се поддържа от този браузър)", + "%(senderName)s answered the call.": "%(senderName)s отговори на повикването.", + "(no answer)": "(няма отговор)", + "(unknown failure: %(reason)s)": "(непозната грешка: %(reason)s)", + "%(senderName)s ended the call.": "%(senderName)s прекрати разговора.", + "%(senderName)s placed a %(callType)s call.": "%(senderName)s започна %(callType)s разговор.", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s изпрати покана на %(targetDisplayName)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 направи бъдещата история на стаята видима за всички членове в нея.", + "%(senderName)s made future room history visible to anyone.": "%(senderName)s направи бъдещата история на стаята видима за всеки.", + "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s направи бъдещата история на стаята видима за непознат (%(visibility)s).", + "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s включи шифроване от край до край (алгоритъм %(algorithm)s).", + "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s с %(fromPowerLevel)s на %(toPowerLevel)s", + "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s смени нивото на достъп на %(powerLevelDiffText)s.", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s смени закачените съобщения на стаята.", + "%(widgetName)s widget modified by %(senderName)s": "Приспособлението %(widgetName)s е променено от %(senderName)s", + "%(widgetName)s widget added by %(senderName)s": "Приспособлението %(widgetName)s е добавено от %(senderName)s", + "%(widgetName)s widget removed by %(senderName)s": "Приспособлението %(widgetName)s е премахнато от %(senderName)s", + "%(displayName)s is typing": "%(displayName)s пише", + "%(names)s and %(count)s others are typing|other": "%(names)s и %(count)s други пишат", + "%(names)s and %(count)s others are typing|one": "%(names)s и още един човек пишат", + "%(names)s and %(lastPerson)s are typing": "%(names)s и %(lastPerson)s пишат", + "Failure to create room": "Неуспешно създаване на стая", + "Server may be unavailable, overloaded, or you hit a bug.": "Сървърът може би е претоварен, недостъпен или се натъкнахте на проблем.", + "Send anyway": "Изпрати така или иначе", + "Unnamed Room": "Стая без име", + "Your browser does not support the required cryptography extensions": "Вашият браузър не поддържа необходимите разширения за шифроване", + "Not a valid Riot keyfile": "Невалиден Riot ключов файл", + "Authentication check failed: incorrect password?": "Неуспешна автентикация: неправилна парола?", + "Failed to join room": "Неуспешно присъединяване към стаята", + "Message Replies": "Отговори на съобщението", + "Message Pinning": "Закачания на съобщението", + "Presence Management": "Управление на присъствието", + "Tag Panel": "Панел с етикети", + "Disable Emoji suggestions while typing": "Деактивиране на предложенията за емотиконите при писане", + "Use compact timeline layout": "Използване на компактно оформление за списъка със съобщения", + "Hide removed messages": "Скриване на премахнати съобщения", + "Hide join/leave messages (invites/kicks/bans unaffected)": "Скриване на съобщения присъединяване/напускане (покани/изгонвания/блокиране незасегнати)", + "Hide avatar changes": "Скриване промени на аватара", + "Hide display name changes": "Скриване промени на името", + "Hide read receipts": "Скриване", + "Show timestamps in 12 hour format (e.g. 2:30pm)": "Показване на времето в 12-часов формат (напр. 2:30pm)", + "Always show message timestamps": "Винаги показвай времето", + "Autoplay GIFs and videos": "Автоматично възпроизвеждане на GIF-файлове и видеа", + "Enable automatic language detection for syntax highlighting": "Активиране на автоматичното разпознаване на език за подчертаване на синтаксиса", + "Disable big emoji in chat": "Деактивиране на големи емотикони в чата", + "Don't send typing notifications": "Не изпращай известия за писане", + "Automatically replace plain text Emoji": "Автоматично откриване и заместване на емотикони в текста", + "Mirror local video feed": "Огледален образ", + "Disable Peer-to-Peer for 1:1 calls": "Деактивиране на Peer-to-Peer в 1:1 разговор", + "Opt out of analytics": "Отказване от събиране на статистически данни", + "Never send encrypted messages to unverified devices from this device": "Никога не изпращай шифровани съобщения до непотвърдени устройства от това устройство", + "Never send encrypted messages to unverified devices in this room from this device": "Никога не изпращай шифровани съобщение до непотвърдени устройства в тази стая от това устройство", + "Enable inline URL previews by default": "Включване по подразбиране на URL прегледи", + "Enable URL previews for this room (only affects you)": "Включване на URL прегледи за тази стая (засяга само Вас)", + "Enable URL previews by default for participants in this room": "Включване по подразбиране на URL прегледи за участниците в тази стая", + "Room Colour": "Цвят на стая", + "Active call (%(roomName)s)": "Активен разговор (%(roomName)s)", + "unknown caller": "повикване от непознат", + "Incoming voice call from %(name)s": "Входящо гласово повикване от %(name)s", + "Incoming video call from %(name)s": "Входящо видео повикване от %(name)s", + "Incoming call from %(name)s": "Входящо повикване от %(name)s", + "Decline": "Откажи", + "Accept": "Приеми", + "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "Съобщение е изпратено до +%(msisdn)s. Моля въведете кода за потвърждение, което то съдържа", + "Incorrect verification code": "Неправилен код за потвърждение" } From 71a1de1e73e77367d8d51841bb312633a0b3ee4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sim=C3=B3=20Albert=20i=20Beltran?= Date: Sat, 17 Feb 2018 13:40:44 +0000 Subject: [PATCH 103/242] Translated using Weblate (Catalan) Currently translated at 89.2% (880 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ca/ --- src/i18n/strings/ca.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json index 0b1a7b10ef..120134e296 100644 --- a/src/i18n/strings/ca.json +++ b/src/i18n/strings/ca.json @@ -869,5 +869,14 @@ "Email": "Correu electrònic", "Add email address": "Afegeix correu electrònic", "I have verified my email address": "He verificat l'adreça de correu electrònic", - "Send Reset Email": "Envia email de reinici" + "Send Reset Email": "Envia email de reinici", + "Your homeserver's URL": "URL del teu homeserver", + "Your identity server's URL": "URL del teu servidor d'identitat", + "Analytics": "Analítiques", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s ha canviat el seu nom visible a %(displayName)s", + "Server may be unavailable or overloaded": "El servidor pot estar inaccessible o sobrecarregat", + "Report it": "Informa", + "Found a bug?": "Has trobat un error?", + "Display name": "Nom visible", + "Identity Server is": "El servidor d'identitat es" } From 4998890a0ef656f2d5a979f3ed57a6e551bd40fe Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Mon, 19 Feb 2018 16:12:43 +0000 Subject: [PATCH 104/242] Translated using Weblate (Bulgarian) Currently translated at 27.7% (274 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index ae049dff52..d5dd208602 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -239,5 +239,38 @@ "Decline": "Откажи", "Accept": "Приеми", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "Съобщение е изпратено до +%(msisdn)s. Моля въведете кода за потвърждение, което то съдържа", - "Incorrect verification code": "Неправилен код за потвърждение" + "Incorrect verification code": "Неправилен код за потвърждение", + "Enter Code": "Въведи код", + "Submit": "Изпрати", + "Phone": "Телефон", + "Add phone number": "Добави телефонен номер", + "Add": "Добави", + "Failed to upload profile picture!": "Неуспешно качване на профилна снимка!", + "Upload new:": "Качи нов:", + "No display name": "Няма име", + "New passwords don't match": "Новите пароли не съвпадат", + "Passwords can't be empty": "Полето с парола не може да е празно", + "Export E2E room keys": "Експортиране E2E ключове на стая", + "Do you want to set an email address?": "Искате ли да зададете имейл адрес?", + "Current password": "Текуща парола", + "Password": "Парола", + "New Password": "Нова парола", + "Confirm password": "Потвърждаване на парола", + "Change Password": "Смяна на парола", + "Your home server does not support device management.": "Вашият home сървър не поддръжа управление на устройства.", + "Unable to load device list": "Неуспешно зареждане на списък с устройства", + "Authentication": "Автентикация", + "Delete %(count)s devices|other": "Изтрий %(count)s устройства", + "Delete %(count)s devices|one": "Изтрий устройство", + "Device ID": "Идентификатор на устройство", + "Device Name": "Име на устройство", + "Last seen": "Последно видян", + "Select devices": "Избери устройства", + "Failed to set display name": "Неуспешно задаване на име", + "Disable Notifications": "Изключване на известия", + "Enable Notifications": "Включване на известия", + "Cannot add any more widgets": "Не могат да се добавят повече приспособления", + "The maximum permitted number of widgets have already been added to this room.": "Максимално разрешеният брой приспособления е вече добавен към тази стая.", + "Add a widget": "Добавяне на приспособление", + "Drop File Here": "Постави файл тук" } From 1c96c1f4d9262cabc1841f0504abc1aee10fc88f Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Tue, 20 Feb 2018 10:17:13 +0000 Subject: [PATCH 105/242] Translated using Weblate (Bulgarian) Currently translated at 38.0% (375 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 109 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index d5dd208602..1c7c2026ed 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -144,9 +144,9 @@ "You are now ignoring %(userId)s": "Вече игнорирате %(userId)s", "Unignored user": "Неигнориран потребител", "You are no longer ignoring %(userId)s": "Вече не игнорирате %(userId)s", - "Device already verified!": "Устройството е вече верифицирано!", - "WARNING: Device already verified, but keys do NOT MATCH!": "ВНИМАНИЕ: Устройстовото е верифицирано, но ключовете не съвпадат!", - "Verified key": "Верифициран ключ", + "Device already verified!": "Устройството е вече потвърдено!", + "WARNING: Device already verified, but keys do NOT MATCH!": "ВНИМАНИЕ: Устройстовото е потвърдено, но ключовете не съвпадат!", + "Verified key": "Потвърден ключ", "Unrecognised command:": "Неразпозната команда:", "Reason": "Причина", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s прие поканата за %(displayName)s.", @@ -272,5 +272,106 @@ "Cannot add any more widgets": "Не могат да се добавят повече приспособления", "The maximum permitted number of widgets have already been added to this room.": "Максимално разрешеният брой приспособления е вече добавен към тази стая.", "Add a widget": "Добавяне на приспособление", - "Drop File Here": "Постави файл тук" + "Drop File Here": "Пусни файла тук", + "Drop file here to upload": "Пуснете файла тук, за да се качи", + " (unsupported)": " (не се поддържа)", + "Join as voice or video.": "Присъединете се като voice или video.", + "Ongoing conference call%(supportedText)s.": "Текущ групов разговор %(supportedText)s.", + "%(senderName)s sent an image": "%(senderName)s изпрати снимка", + "%(senderName)s sent a video": "%(senderName)s изпрати видео", + "%(senderName)s uploaded a file": "%(senderName)s качи файл", + "Options": "Настройки", + "Undecryptable": "Невъзможно разшифроване", + "Encrypted by a verified device": "Шифровано от потвърдено устройство", + "Encrypted by an unverified device": "Шифровано от непотвърдено устройство", + "Unencrypted message": "Нешифровано съобщение", + "Please select the destination room for this message": "Моля изберете стаята, в която искате да изпратите това съобщение", + "Blacklisted": "В черен списък", + "Verified": "Потвърдено", + "Unverified": "Непотвърдено", + "device id: ": "идентификатор на устройството: ", + "Disinvite": "Отмени поканата", + "Kick": "Изгони", + "Disinvite this user?": "Отмени поканата към този потребител?", + "Kick this user?": "Изгони този потребител?", + "Failed to kick": "Неуспешно изгонване", + "Unban": "Отблокирай", + "Ban": "Блокирай", + "Unban this user?": "Отблокирай този потребител?", + "Ban this user?": "Блокирай този потребител?", + "Failed to ban user": "Неуспешно блокиране на потребителя", + "Failed to mute user": "Неуспешно заглушаване на потребителя", + "Failed to toggle moderator status": "Неуспешна промяна на статуса на модератора", + "Failed to change power level": "Неуспешна промяна на нивото на достъп", + "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.": "След като си намалите нивото на достъп, няма да можете да възвърнете тази промяна. Ако сте потребителя с най-малко привилегии в тази стая, ще бъде невъзможно да възвърнете своите привилегии.", + "Are you sure?": "Сигурни ли сте?", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Няма да можете да възвърнете тази промяна, тъй като повишавате този потребител да има същото ниво на достъп като Вашето.", + "No devices with registered encryption keys": "Няма устройства с регистрирани шифровани ключове", + "Devices": "Устройства", + "Unignore": "Премахни игнорирането", + "Ignore": "Игнориране", + "Mention": "Спомени", + "Direct chats": "Директни чатове", + "User Options": "Опции на потребителя", + "Invite": "Покани", + "Unmute": "Премахни заглушаването", + "Make Moderator": "Направи потребителя модератор", + "Admin Tools": "Инструменти на администратора", + "Level:": "Ниво:", + "and %(count)s others...|other": "и %(count)s други...", + "and %(count)s others...|one": "и още един...", + "Invited": "Поканен", + "Filter room members": "Филтриране на членовете в стаята", + "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (ниво на достъп %(powerLevelNumber)s)", + "Attachment": "Прикачване", + "Upload Files": "Качи файлове", + "Are you sure you want to upload the following files?": "Сигурни ли сте, че искате да качите тези файлове?", + "Encrypted room": "Шифрована стая", + "Unencrypted room": "Нешифрована стая", + "Hangup": "Затвори", + "Voice call": "Гласово повикване", + "Video call": "Видео повикване", + "Hide Apps": "Скрий приложенията", + "Show Apps": "Покани приложенията", + "Upload file": "Качи файл", + "Show Text Formatting Toolbar": "Показване на лентата с инструменти за форматиране на текст", + "Send an encrypted reply…": "Изпрати шифрован отговор…", + "Send a reply (unencrypted)…": "Отговори (нешифрованo)…", + "Send an encrypted message…": "Изпрати шифровано съобщение…", + "Send a message (unencrypted)…": "Изпрати съобщение (нешифровано)…", + "You do not have permission to post to this room": "Нямате разрешение да публикувате в тази стая", + "Turn Markdown on": "Включи Markdown", + "Turn Markdown off": "Изключи Markdown", + "Hide Text Formatting Toolbar": "Скриване на лентата с инструменти за форматиране на текст", + "Server error": "Сървърна грешка", + "Server unavailable, overloaded, or something else went wrong.": "Сървърът е недостъпен, претоварен или нещо друго се обърка.", + "Command error": "Грешка в командата", + "bold": "удебелен", + "italic": "курсивен", + "strike": "задраскан", + "underline": "подчертан", + "code": "код", + "quote": "цитат", + "bullet": "списък", + "numbullet": "номериран списък", + "Markdown is disabled": "Markdown е изключен", + "Markdown is enabled": "Markdown е включен", + "No pinned messages.": "Няма закачени съобщения.", + "Loading...": "Зареждане...", + "Pinned Messages": "Закачени съобщения", + "%(duration)ss": "%(duration)sсек", + "%(duration)sm": "%(duration)sмин", + "%(duration)sh": "%(duration)sч", + "%(duration)sd": "%(duration)sд", + "Online for %(duration)s": "Онлайн от %(duration)s", + "Idle for %(duration)s": "Неактивен от %(duration)s", + "Offline for %(duration)s": "Офлайн от %(duration)s", + "Unknown for %(duration)s": "Неизвестен от %(duration)s", + "Idle": "Неактивен", + "Offline": "Офлайн", + "Unknown": "Неизвестен", + "Replying": "Отговаря", + "Seen by %(userName)s at %(dateTime)s": "Видяно от %(userName)s в %(dateTime)s", + "Failed to set avatar.": "Неуспешно задаване на аватар.", + "Save": "Запази" } From c5ad486c57d59eef7044126be2f21fe36ae61748 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Mon, 19 Feb 2018 20:17:44 +0000 Subject: [PATCH 106/242] Translated using Weblate (Catalan) Currently translated at 89.2% (880 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/ca/ --- src/i18n/strings/ca.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json index 120134e296..40fbcc53b4 100644 --- a/src/i18n/strings/ca.json +++ b/src/i18n/strings/ca.json @@ -873,7 +873,7 @@ "Your homeserver's URL": "URL del teu homeserver", "Your identity server's URL": "URL del teu servidor d'identitat", "Analytics": "Analítiques", - "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s ha canviat el seu nom visible a %(displayName)s", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s ha canviat el seu nom visible a %(displayName)s.", "Server may be unavailable or overloaded": "El servidor pot estar inaccessible o sobrecarregat", "Report it": "Informa", "Found a bug?": "Has trobat un error?", From d21f55633dfb3d5f99cf8b58f37d969b85da736e Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 20 Feb 2018 14:03:43 +0000 Subject: [PATCH 107/242] Fix DMs being marked as with the current user ("me") Whilst testing various DM paths, @lukebarnard1 found that there were many failures to add the room as a DM against the correct user. It turned out most of the failures seen were because the user chosen was the current user. If the user accepted an invite it would often be marked as with themselves because we chose the sender of the join event as the DM user. This fix makes the DM room setting process the same for both the inviting client and the invited client. A RoomState.members event causes the DM room state to be set in the room, regardless of whether we are currently `joining` (see previous impl.) The two cases for setting a DM are: - this user accepting an invite with is_direct - this user inviting someone with is_direct This should handle all cases for setting DM state. --- src/components/structures/RoomView.js | 61 +++++++++++++++------------ 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 5304f38901..c827a63057 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -678,21 +678,40 @@ module.exports = React.createClass({ // refresh the conf call notification state this._updateConfCallNotification(); - // if we are now a member of the room, where we were not before, that - // means we have finished joining a room we were previously peeking - // into. - const me = MatrixClientPeg.get().credentials.userId; - if (this.state.joining && this.state.room.hasMembershipState(me, "join")) { - // Having just joined a room, check to see if it looks like a DM room, and if so, - // mark it as one. This is to work around the fact that some clients don't support - // is_direct. We should remove this once they do. - const me = this.state.room.getMember(MatrixClientPeg.get().credentials.userId); - if (Rooms.looksLikeDirectMessageRoom(this.state.room, me)) { - // XXX: There's not a whole lot we can really do if this fails: at best - // perhaps we could try a couple more times, but since it's a temporary - // compatability workaround, let's not bother. - Rooms.setDMRoom(this.state.room.roomId, me.events.member.getSender()).done(); - } + const me = this.state.room.getMember(MatrixClientPeg.get().credentials.userId); + if (!me || me.membership !== "join") { + return; + } + + // The user may have accepted an invite with is_direct set + if (me.events.member.getPrevContent().membership === "invite" && + me.events.member.getPrevContent().is_direct + ) { + // This is a DM with the sender of the invite event (which we assume + // preceded the join event) + Rooms.setDMRoom( + this.state.room.roomId, + me.events.member.getUnsigned().prev_sender, + ); + return; + } + + const invitedMembers = this.state.room.getMembersWithMembership("invite"); + const joinedMembers = this.state.room.getMembersWithMembership("join"); + + // There must be one invited member and one joined member + if (invitedMembers.length !== 1 || joinedMembers.length !== 1) { + return; + } + + // The user may have sent an invite with is_direct sent + const other = invitedMembers[0]; + if (other && + other.membership === "invite" && + other.events.member.getContent().is_direct + ) { + Rooms.setDMRoom(this.state.room.roomId, other.userId); + return; } }, 500), @@ -826,18 +845,6 @@ module.exports = React.createClass({ action: 'join_room', opts: { inviteSignUrl: signUrl }, }); - - // if this is an invite and has the 'direct' hint set, mark it as a DM room now. - if (this.state.room) { - const me = this.state.room.getMember(MatrixClientPeg.get().credentials.userId); - if (me && me.membership == 'invite') { - if (me.events.member.getContent().is_direct) { - // The 'direct' hint is there, so declare that this is a DM room for - // whoever invited us. - return Rooms.setDMRoom(this.state.room.roomId, me.events.member.getSender()); - } - } - } return Promise.resolve(); }); }, From bc15303358c58226c4ef47793d34276d58d9b1ee Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 20 Feb 2018 14:10:34 +0000 Subject: [PATCH 108/242] Factor out updateDmState --- src/components/structures/RoomView.js | 75 ++++++++++++++------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index c827a63057..8ceba2a850 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -677,42 +677,7 @@ module.exports = React.createClass({ // a member state changed in this room // refresh the conf call notification state this._updateConfCallNotification(); - - const me = this.state.room.getMember(MatrixClientPeg.get().credentials.userId); - if (!me || me.membership !== "join") { - return; - } - - // The user may have accepted an invite with is_direct set - if (me.events.member.getPrevContent().membership === "invite" && - me.events.member.getPrevContent().is_direct - ) { - // This is a DM with the sender of the invite event (which we assume - // preceded the join event) - Rooms.setDMRoom( - this.state.room.roomId, - me.events.member.getUnsigned().prev_sender, - ); - return; - } - - const invitedMembers = this.state.room.getMembersWithMembership("invite"); - const joinedMembers = this.state.room.getMembersWithMembership("join"); - - // There must be one invited member and one joined member - if (invitedMembers.length !== 1 || joinedMembers.length !== 1) { - return; - } - - // The user may have sent an invite with is_direct sent - const other = invitedMembers[0]; - if (other && - other.membership === "invite" && - other.events.member.getContent().is_direct - ) { - Rooms.setDMRoom(this.state.room.roomId, other.userId); - return; - } + this._updateDMState(); }, 500), _checkIfAlone: function(room) { @@ -753,6 +718,44 @@ module.exports = React.createClass({ }); }, + _updateDMState() { + const me = this.state.room.getMember(MatrixClientPeg.get().credentials.userId); + if (!me || me.membership !== "join") { + return; + } + + // The user may have accepted an invite with is_direct set + if (me.events.member.getPrevContent().membership === "invite" && + me.events.member.getPrevContent().is_direct + ) { + // This is a DM with the sender of the invite event (which we assume + // preceded the join event) + Rooms.setDMRoom( + this.state.room.roomId, + me.events.member.getUnsigned().prev_sender, + ); + return; + } + + const invitedMembers = this.state.room.getMembersWithMembership("invite"); + const joinedMembers = this.state.room.getMembersWithMembership("join"); + + // There must be one invited member and one joined member + if (invitedMembers.length !== 1 || joinedMembers.length !== 1) { + return; + } + + // The user may have sent an invite with is_direct sent + const other = invitedMembers[0]; + if (other && + other.membership === "invite" && + other.events.member.getContent().is_direct + ) { + Rooms.setDMRoom(this.state.room.roomId, other.userId); + return; + } + }, + onSearchResultsResize: function() { dis.dispatch({ action: 'timeline_resize' }, true); }, From f227d13dfe701b4b96a2cfb1e1e75b3d868195bd Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Tue, 20 Feb 2018 14:21:24 +0000 Subject: [PATCH 109/242] Translated using Weblate (Bulgarian) Currently translated at 43.8% (432 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 63 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 1c7c2026ed..f47b3b24ee 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -41,7 +41,7 @@ "Online": "Онлайн", "Failed to remove tag %(tagName)s from room": "Неуспешно премахване на %(tagName)s етикет от стаята", "unknown error code": "неизвестен код за грешка", - "Failed to forget room %(errCode)s": "Не успешно забравяне на стаята %(errCode)s", + "Failed to forget room %(errCode)s": "Неуспешно забравяне на стаята %(errCode)s", "Mute": "Заглуши", "Leave": "Напусни", "Favourite": "Любим", @@ -372,6 +372,63 @@ "Unknown": "Неизвестен", "Replying": "Отговаря", "Seen by %(userName)s at %(dateTime)s": "Видяно от %(userName)s в %(dateTime)s", - "Failed to set avatar.": "Неуспешно задаване на аватар.", - "Save": "Запази" + "Failed to set avatar.": "Неуспешно задаване на профилна снимка.", + "Save": "Запази", + "(~%(count)s results)|other": "(~%(count)s резултати)", + "(~%(count)s results)|one": "(~%(count)s резултат)", + "Join Room": "Присъедини се към стаята", + "Upload avatar": "Качи профилната снимка", + "Remove avatar": "Премахни профилната снимка", + "Settings": "Настройки", + "Forget room": "Забрави стаята", + "Show panel": "Покажи панелa", + "Drop here to favourite": "За любим пуснeте тук", + "Drop here to tag direct chat": "Пуснете тук, за да означите директен чат", + "Drop here to restore": "Пуснете тук за възстановяване", + "Drop here to demote": "Пуснете тук за", + "Drop here to tag %(section)s": "Пуснете тук, за да означите %(section)s", + "Failed to set direct chat tag": "Неуспешно означаване на директен чат", + "Press to start a chat with someone": "Натиснете , за да започнете чат с някого", + "You're not in any rooms yet! Press to make a room or to browse the directory": "Все още не сте в нито една стая! Натиснете , за да направите такава или , за да прегледате директорията", + "Community Invites": "Покани за общества", + "Invites": "Покани", + "Favourites": "Любими", + "People": "Хора", + "Low priority": "Нисък приоритет", + "Historical": "Архив", + "Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Не може да се потвърди, че адреса към който е изпратена тази покана е обвързан с акаунта Ви.", + "This invitation was sent to an email address which is not associated with this account:": "Тази покана е изпратена на имейл адрес, който не е свързан с този профил:", + "You may wish to login with a different account, or add this email to this account.": "Може да искате да влезете с друг профил или да добавите този имейл в този профил.", + "You have been invited to join this room by %(inviterName)s": "Вие сте поканен да се присъедините към тази стая от %(inviterName)s", + "Would you like to accept or decline this invitation?": "Желаете да приемете или да откажете тази покана?", + "Reason: %(reasonText)s": "Причина: %(reasonText)s", + "Rejoin": "Повторно присъединяване", + "You have been kicked from %(roomName)s by %(userName)s.": "Вие сте изгонен от %(roomName)s от %(userName)s.", + "You have been kicked from this room by %(userName)s.": "Вие сте изгонен от тази стая от %(userName)s.", + "You have been banned from %(roomName)s by %(userName)s.": "Вие сте блокиран в %(roomName)s от %(userName)s.", + "You have been banned from this room by %(userName)s.": "Вие сте блокиран в тази стая от %(userName)s.", + "This room": "В тази стая", + "%(roomName)s does not exist.": "%(roomName)s не съществува.", + "%(roomName)s is not accessible at this time.": "%(roomName)s не е достъпна към този момент.", + "You are trying to access %(roomName)s.": "Опитвате се да влезете в %(roomName)s.", + "You are trying to access a room.": "Опитвате се да влезете в стая.", + "Click here to join the discussion!": "Натиснете тук, за да се присъедините към дискусията!", + "This is a preview of this room. Room interactions have been disabled": "Това е преглед на стаята. Интеракции в нея са деактивирани", + "To change the room's avatar, you must be a": "За да смените снимката на стаята, трябва да бъдете", + "To change the room's name, you must be a": "За да смените името на стаята, трябва да бъдете", + "To change the room's main address, you must be a": "За да смените основния адрес на стаята, трябва да бъдете", + "To change the room's history visibility, you must be a": "За да смените видимостта на историята на стаята, трябва да бъдете", + "To change the permissions in the room, you must be a": "За да промените разрешенията в стаята, трябва да бъдете", + "To change the topic, you must be a": "За да смените темата, трябва да бъдете", + "To modify widgets in the room, you must be a": "За да промените приспособленията в стаята, трябва да бъдете", + "Failed to unban": "Неуспешно отблокиране", + "Banned by %(displayName)s": "Блокиран от %(displayName)s", + "Privacy warning": "Предупреждение за сигурност", + "Changes to who can read history will only apply to future messages in this room": "Промени за това кой може да чете историята ще се отнасят само за бъдещи съобщения в тази стая", + "The visibility of existing history will be unchanged": "Видимостта на съществуващата история ще остане непроменена", + "End-to-end encryption is in beta and may not be reliable": "Шифроване от край до край е в бета версия и може да не е надеждно", + "Devices will not yet be able to decrypt history from before they joined the room": "Устройства все още не могат да разшифроват история от преди присъединяването към стая", + "Once encryption is enabled for a room it cannot be turned off again (for now)": "Веднъж включено шифроване в стаята не може да бъде изключено (за сега)", + "Encrypted messages will not be visible on clients that do not yet implement encryption": "Шифровани съобщения не са видими за клиенти, които все още не поддържат шифроване", + "Enable encryption": "Включване на шифроване" } From 644ddbf9b9d7488c247129f4718afed523185d90 Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Tue, 20 Feb 2018 17:57:46 +0000 Subject: [PATCH 110/242] Regenerate room lists on Room event To make sure that we handle rooms that our client has not seen previously, we regenerate the room list when the room is stored - which is indicated by the js-sdk by the Room event. --- src/actions/MatrixActionCreators.js | 5 +++++ src/stores/RoomListStore.js | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index a307af6f57..78c653c551 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -62,6 +62,10 @@ function createAccountDataAction(matrixClient, accountDataEvent) { }; } +function createRoomAction(matrixClient, room) { + return { action: 'MatrixActions.Room', room }; +} + function createRoomTagsAction(matrixClient, roomTagsEvent, room) { return { action: 'MatrixActions.Room.tags', room }; } @@ -96,6 +100,7 @@ export default { start(matrixClient) { this._addMatrixClientListener(matrixClient, 'sync', createSyncAction); this._addMatrixClientListener(matrixClient, 'accountData', createAccountDataAction); + this._addMatrixClientListener(matrixClient, 'Room', createRoomAction); this._addMatrixClientListener(matrixClient, 'Room.tags', createRoomTagsAction); this._addMatrixClientListener(matrixClient, 'Room.timeline', createRoomTimelineAction); this._addMatrixClientListener(matrixClient, 'RoomMember.membership', createRoomMembershipAction); diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 8a3af309fc..80db6ca9a8 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -97,6 +97,14 @@ class RoomListStore extends Store { this._generateRoomLists(); } break; + // This could be a new room that we've been invited to, joined or created + // we won't get a RoomMember.membership for these cases if we're not already + // a member. + case 'MatrixActions.Room': { + if (!this._state.ready || !this._matrixClient.credentials.userId) break; + this._generateRoomLists(); + } + break; case 'RoomListActions.tagRoom.pending': { // XXX: we only show one optimistic update at any one time. // Ideally we should be making a list of in-flight requests From a78575929c47f6895cfe09ec812c5bcfdde3d6ce Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 21 Feb 2018 10:15:52 +0000 Subject: [PATCH 111/242] Document a few action creators --- src/actions/MatrixActionCreators.js | 79 +++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/actions/MatrixActionCreators.js b/src/actions/MatrixActionCreators.js index 78c653c551..1998ecfef2 100644 --- a/src/actions/MatrixActionCreators.js +++ b/src/actions/MatrixActionCreators.js @@ -62,14 +62,75 @@ function createAccountDataAction(matrixClient, accountDataEvent) { }; } +/** + * @typedef RoomAction + * @type {Object} + * @property {string} action 'MatrixActions.Room'. + * @property {Room} room the Room that was stored. + */ + +/** + * Create a MatrixActions.Room action that represents a MatrixClient `Room` + * matrix event, emitted when a Room is stored in the client. + * + * @param {MatrixClient} matrixClient the matrix client. + * @param {Room} room the Room that was stored. + * @returns {RoomAction} an action of type `MatrixActions.Room`. + */ function createRoomAction(matrixClient, room) { return { action: 'MatrixActions.Room', room }; } +/** + * @typedef RoomTagsAction + * @type {Object} + * @property {string} action 'MatrixActions.Room.tags'. + * @property {Room} room the Room whose tags changed. + */ + +/** + * Create a MatrixActions.Room.tags action that represents a MatrixClient + * `Room.tags` matrix event, emitted when the m.tag room account data + * event is updated. + * + * @param {MatrixClient} matrixClient the matrix client. + * @param {MatrixEvent} roomTagsEvent the m.tag event. + * @param {Room} room the Room whose tags were changed. + * @returns {RoomTagsAction} an action of type `MatrixActions.Room.tags`. + */ function createRoomTagsAction(matrixClient, roomTagsEvent, room) { return { action: 'MatrixActions.Room.tags', room }; } +/** + * @typedef RoomTimelineAction + * @type {Object} + * @property {string} action 'MatrixActions.Room.timeline'. + * @property {boolean} isLiveEvent whether the event was attached to a + * live timeline. + * @property {boolean} isLiveUnfilteredRoomTimelineEvent whether the + * event was attached to a timeline in the set of unfiltered timelines. + * @property {Room} room the Room whose tags changed. + */ + +/** + * Create a MatrixActions.Room.timeline action that represents a + * MatrixClient `Room.timeline` matrix event, emitted when an event + * is added to or removed from a timeline of a room. + * + * @param {MatrixClient} matrixClient the matrix client. + * @param {MatrixEvent} timelineEvent the event that was added/removed. + * @param {Room} room the Room that was stored. + * @param {boolean} toStartOfTimeline whether the event is being added + * to the start (and not the end) of the timeline. + * @param {boolean} removed whether the event was removed from the + * timeline. + * @param {Object} data + * @param {boolean} data.liveEvent whether the event is a live event, + * belonging to a live timeline. + * @param {EventTimeline} data.timeline the timeline being altered. + * @returns {RoomTimelineAction} an action of type `MatrixActions.Room.timeline`. + */ function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTimeline, removed, data) { return { action: 'MatrixActions.Room.timeline', @@ -80,6 +141,24 @@ function createRoomTimelineAction(matrixClient, timelineEvent, room, toStartOfTi }; } +/** + * @typedef RoomMembershipAction + * @type {Object} + * @property {string} action 'MatrixActions.RoomMember.membership'. + * @property {RoomMember} member the member whose membership was updated. + */ + +/** + * Create a MatrixActions.RoomMember.membership action that represents + * a MatrixClient `RoomMember.membership` matrix event, emitted when a + * member's membership is updated. + * + * @param {MatrixClient} matrixClient the matrix client. + * @param {MatrixEvent} membershipEvent the m.room.member event. + * @param {RoomMember} member the member whose membership was updated. + * @param {string} oldMembership the member's previous membership. + * @returns {RoomMembershipAction} an action of type `MatrixActions.RoomMember.membership`. + */ function createRoomMembershipAction(matrixClient, membershipEvent, member, oldMembership) { return { action: 'MatrixActions.RoomMember.membership', member }; } From b7601f86d1dbdb347c439c73e4477dc3ee799583 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Wed, 21 Feb 2018 13:37:58 +0000 Subject: [PATCH 112/242] Translated using Weblate (Bulgarian) Currently translated at 76.8% (758 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 356 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 341 insertions(+), 15 deletions(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index f47b3b24ee..35505c0038 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -48,7 +48,7 @@ "Register": "Регистрация", "Notifications": "Известия", "Rooms": "Стаи", - "Add rooms to this community": "Добави стаи в това общество", + "Add rooms to this community": "Добави стаи в тази общност", "Unnamed room": "Стая без име", "World readable": "Четимо за всички", "Guests can join": "Гости могат да се присъединят", @@ -87,18 +87,18 @@ "Upload Failed": "Качването е неуспешно", "PM": "PM", "AM": "AM", - "Who would you like to add to this community?": "Кой бихте желали да добавите в това общество?", - "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Предупреждение: Всеки човек, който добавяте в дадено общество, ще бъде публично видим за знаещите идентификатора на обществото", - "Invite new community members": "Покани нови членове на обществото", + "Who would you like to add to this community?": "Кого бихте желали да добавите в тaзи общност?", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Предупреждение: Всеки човек, който добавяте в дадена общност, ще бъде публично видим за знаещите идентификатора на общността", + "Invite new community members": "Покани нови членове в общността", "Name or matrix ID": "Име или matrix ID", - "Invite to Community": "Покани в обществото", - "Which rooms would you like to add to this community?": "Кои стаи бихте желали да добавите в това общество?", - "Show these rooms to non-members on the community page and room list?": "Показване на тези стаи на не-членове на страницата на обществата и списъка със стаи?", - "Add rooms to the community": "Добави стаи в обществото", + "Invite to Community": "Покани в общността", + "Which rooms would you like to add to this community?": "Кои стаи бихте желали да добавите в тази общност?", + "Show these rooms to non-members on the community page and room list?": "Показване на тези стаи на не-членове на страницата на общностите и списъка със стаи?", + "Add rooms to the community": "Добави стаи в общността", "Room name or alias": "Име или псевдоним на стая", - "Add to community": "Добави в обществото", + "Add to community": "Добави в общност", "Failed to invite the following users to %(groupId)s:": "Следните потребители не могат да бъдат поканени в %(groupId)s:", - "Failed to invite users to community": "Потребителите не могат да бъдат поканени в обществото", + "Failed to invite users to community": "Потребителите не могат да бъдат поканени в общността", "Failed to invite users to %(groupId)s": "Потребителите не могат да бъдат поканени в %(groupId)s", "Failed to add the following rooms to %(groupId)s:": "Следните стаи не могат да бъдат добавени в %(groupId)s:", "Riot does not have permission to send you notifications - please check your browser settings": "Riot няма разрешение да Ви изпраща известия - моля проверете вашите настройки на браузъра", @@ -123,7 +123,7 @@ "You need to be logged in.": "Трябва да влезете в профила си.", "You need to be able to invite users to do that.": "Трябва да имате право да добавите потребители, за да извършите това.", "Unable to create widget.": "Неуспешно създаване на приспособление.", - "Failed to send request.": "Неуспешно изпращане на запитване.", + "Failed to send request.": "Неуспешно изпращане на заявката.", "This room is not recognised.": "Стаята не е разпозната.", "Power level must be positive integer.": "Нивото на достъп трябва да бъде позитивно число.", "Call Anyway": "Обади се въпреки това", @@ -198,7 +198,7 @@ "%(names)s and %(lastPerson)s are typing": "%(names)s и %(lastPerson)s пишат", "Failure to create room": "Неуспешно създаване на стая", "Server may be unavailable, overloaded, or you hit a bug.": "Сървърът може би е претоварен, недостъпен или се натъкнахте на проблем.", - "Send anyway": "Изпрати така или иначе", + "Send anyway": "Изпрати въпреки това", "Unnamed Room": "Стая без име", "Your browser does not support the required cryptography extensions": "Вашият браузър не поддържа необходимите разширения за шифроване", "Not a valid Riot keyfile": "Невалиден Riot ключов файл", @@ -286,7 +286,7 @@ "Encrypted by an unverified device": "Шифровано от непотвърдено устройство", "Unencrypted message": "Нешифровано съобщение", "Please select the destination room for this message": "Моля изберете стаята, в която искате да изпратите това съобщение", - "Blacklisted": "В черен списък", + "Blacklisted": "В черния списък", "Verified": "Потвърдено", "Unverified": "Непотвърдено", "device id: ": "идентификатор на устройството: ", @@ -390,7 +390,7 @@ "Failed to set direct chat tag": "Неуспешно означаване на директен чат", "Press to start a chat with someone": "Натиснете , за да започнете чат с някого", "You're not in any rooms yet! Press to make a room or to browse the directory": "Все още не сте в нито една стая! Натиснете , за да направите такава или , за да прегледате директорията", - "Community Invites": "Покани за общества", + "Community Invites": "Покани за общност", "Invites": "Покани", "Favourites": "Любими", "People": "Хора", @@ -430,5 +430,331 @@ "Devices will not yet be able to decrypt history from before they joined the room": "Устройства все още не могат да разшифроват история от преди присъединяването към стая", "Once encryption is enabled for a room it cannot be turned off again (for now)": "Веднъж включено шифроване в стаята не може да бъде изключено (за сега)", "Encrypted messages will not be visible on clients that do not yet implement encryption": "Шифровани съобщения не са видими за клиенти, които все още не поддържат шифроване", - "Enable encryption": "Включване на шифроване" + "Enable encryption": "Включване на шифроване", + "(warning: cannot be disabled again!)": "(внимание: не може да бъде изключено отново!)", + "Encryption is enabled in this room": "Шифроването е включено в тази стая", + "Encryption is not enabled in this room": "Шифроването не е включено в тази стая", + "Privileged Users": "Потребители с привилегии", + "%(user)s is a": "%(user)s е", + "No users have specific privileges in this room": "Никой няма специфични привилегии в тази стая", + "Banned users": "Блокирани потребители", + "This room is not accessible by remote Matrix servers": "Тази стая не е достъпна за далечни Matrix сървъри", + "Leave room": "Напусни стаята", + "Tagged as: ": "Означен като: ", + "To link to a room it must have an address.": "За да дадете линк към стаята, тя трябва да има адрес.", + "Guests cannot join this room even if explicitly invited.": "Гости не могат да се присъединят към тази стая, дори изрично поканени.", + "Click here to fix": "Натиснете тук за поправяне", + "Who can access this room?": "Кой има достъп до тази стая?", + "Only people who have been invited": "Само хора, които са поканени", + "Anyone who knows the room's link, apart from guests": "Всеки, който знае адреса на стаята, освен гости", + "Anyone who knows the room's link, including guests": "Всеки, който знае адрес на стаята, включително гости", + "Publish this room to the public in %(domain)s's room directory?": "Публично публикуване на тази стая в директорията на %(domain)s?", + "Who can read history?": "Кой може да чете историята?", + "Anyone": "Всеки", + "Members only (since the point in time of selecting this option)": "Само членове (от момента на избиране на тази опция)", + "Members only (since they were invited)": "Само членове (от момента, в който те са поканени)", + "Members only (since they joined)": "Само членове (от момента, в който са се присъединили)", + "Permissions": "Разрешения", + "The default role for new room members is": "По подразбиране ролята за нови членове в стаята е", + "To send messages, you must be a": "За да изпращате съобщения, трябва да бъдете", + "To invite users into the room, you must be a": "За да поканите потребители в стаята, трябва да бъдете", + "To configure the room, you must be a": "За да конфигурирате стаята, трябва да бъдете", + "To kick users, you must be a": "За да изгоните потребител, трябва да бъдете", + "To ban users, you must be a": "За да блокирате потребител, трябва да бъдете", + "To remove other users' messages, you must be a": "За да премахнете съобщения на друг потребител, трябва да бъдете", + "To send events of type , you must be a": "За да изпратите събития от вида , трябва да бъдете", + "Advanced": "Разширени", + "This room's internal ID is": "Вътрешният идентификатор на тази стая е", + "Add a topic": "Добавете тема", + "Jump to first unread message.": "Отиди до първото непрочетено съобщение.", + "Scroll to unread messages": "Скролирай до непрочетените съобщения", + "Invalid alias format": "Невалиден формат на псевдонима", + "'%(alias)s' is not a valid format for an alias": "%(alias)s не е валиден формат на псевдоним", + "Invalid address format": "Невалиден формат на адреса", + "'%(alias)s' is not a valid format for an address": "%(alias)s не е валиден формат на адрес", + "not specified": "неопределен", + "not set": "незададен", + "Remote addresses for this room:": "Далечни адреси на тази стая:", + "Addresses": "Адреси", + "The main address for this room is": "Основният адрес на тази стая е", + "Local addresses for this room:": "Локалните адреси на тази стая са:", + "This room has no local addresses": "Тази стая няма локални адреси", + "New address (e.g. #foo:%(localDomain)s)": "Нов адрес (напр. #foo:%(localDomain)s)", + "Invalid community ID": "Невалиден идентификатор на общност", + "'%(groupId)s' is not a valid community ID": "'%(groupId)s' е невалиден идентификатор на общност", + "Flair": "Значка", + "Showing flair for these communities:": "Показване на значки за тези общности:", + "This room is not showing flair for any communities": "Тази стая не показва значки за нито една общност", + "New community ID (e.g. +foo:%(localDomain)s)": "Нов идентификатор на общност (напр. +foo:%(localDomain)s)", + "You have enabled URL previews by default.": "Вие сте включил URL прегледи по подразбиране.", + "You have disabled URL previews by default.": "Вие сте изключил URL прегледи по подразбиране.", + "URL previews are enabled by default for participants in this room.": "URL прегледи са включени по подразбиране за участниците в тази стая.", + "URL previews are disabled by default for participants in this room.": "URL прегледи са изключени по подразбиране за участниците в тази стая.", + "URL Previews": "URL прегледи", + "Error decrypting audio": "Грешка при разшифроване на аудио файл", + "Error decrypting attachment": "Грешка при разшифроване на прикачване", + "Decrypt %(text)s": "Разшифровай %(text)s", + "Download %(text)s": "Изтегли %(text)s", + "(could not connect media)": "(неуспешно свързване на медийните устройства)", + "Must be viewing a room": "Трябва да видите стаята", + "Usage": "Употреба", + "Remove from community": "Премахни от общността", + "Disinvite this user from community?": "Оттегляне на поканата към този потребител от общността?", + "Remove this user from community?": "Премахване на този потребител от общността?", + "Failed to remove user from community": "Неуспешно премахване на потребителя от тази общност", + "Filter community members": "Филтриране на членовете на общността", + "Removing a room from the community will also remove it from the community page.": "Премахване на стая от общността ще бъде също премахната от страницата с общността.", + "Failed to remove room from community": "Неуспешно премахване на стаята от общността", + "Only visible to community members": "Видимо само за членове на общността", + "Filter community rooms": "Филтрирай стаи на общността", + "Community IDs cannot not be empty.": "Идентификаторите на общността не могат да бъдат празни.", + "Create Community": "Създай общност", + "Community Name": "Име на общност", + "Community ID": "Идентификатор на общност", + "

HTML for your community's page

\n

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

\n

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

\n": "

HTML за страница на Вашата общност

\n

\n Използвайте дългото описание, за да въведете нови членове в общността, \n или да разпространите важни връзки\n

\n

\n Можете дори да използвате 'img' тагове\n

\n", + "Add rooms to the community summary": "Добавете стаи към обобщението на общността", + "Add users to the community summary": "Добавете потребители към обобщението на общността", + "Failed to update community": "Неуспешно обновяване на общността", + "Leave Community": "Напусни общността", + "Community Settings": "Настройки на общността", + "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Тези стаи са показани на членове на общността на страницата на общността. Членовете на общността могат да се присъединят към стаите като натиснат върху тях.", + "%(inviter)s has invited you to join this community": "%(inviter)s Ви покани да се присъедините към тази общност", + "You are an administrator of this community": "Вие сте администратор на тази общност", + "You are a member of this community": "Вие сте член на тази общност", + "Your community hasn't got a Long Description, a HTML page to show to community members.
Click here to open settings and give it one!": "Вашата общност няма дълго описание - HTML страница, която да се показва на членовете на общността.
Натиснете тук, за да отворите настройките и да създадете такова!", + "Community %(groupId)s not found": "Общност %(groupId)s не е намерена", + "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.": "Създайте общност, за да обедините заедно потребители и стаи! Изградете персонализирана начална страница, за да маркирате своето пространство във Вселената на матрицата.", + "Join an existing community": "Присъединяване към вече съществуваща общност", + "To join an existing community you'll have to know its community identifier; this will look something like +example:matrix.org.": "За да се присъедините към вече съществуваща общност, трябва да знаете неиния идентификатор; това изглежда нещо подобно на +example:matrix.org.", + "Unknown (user, device) pair:": "Непозната двойка (потребител, устройство):", + "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "Подписващият ключ, който сте предоставили, съвпада с подписващия ключ, който сте получили от устройството %(deviceId)s на %(userId)s. Устройството е маркирано като потвърдено.", + "Hide avatars in user and room mentions": "Скриване на профилната снимка при споменаване на потребители и стаи", + "Jump to message": "Отиди до съобщението", + "Jump to read receipt": "Отиди до потвърдението за прочетено", + "Revoke Moderator": "Премахване на правата на модератора", + "You should not yet trust it to secure data": "Все още не трябва да се доверявате на това, че ще запази Вашите данни", + "Invalid file%(extra)s": "Невалиден файл%(extra)s", + "Error decrypting image": "Грешка при разшифроване на снимка", + "This image cannot be displayed.": "Тази снимка не може да бъде показана.", + "Image '%(Body)s' cannot be displayed.": "Снимката '%(Body)s' не може да бъде показана.", + "Error decrypting video": "Грешка при разшифроване на видео", + "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s промени аватара на %(roomName)s", + "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s премахна аватара на стаята.", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s промени аватара на стаята на ", + "Copied!": "Копирано!", + "Failed to copy": "Неуспешно копиране", + "Add an Integration": "Добавяне на интеграция", + "Removed or unknown message type": "Премахнато или неизвестен тип съобщение", + "Message removed by %(userId)s": "Съобщението е премахнато от %(userId)s", + "Message removed": "Съобщението е премахнато", + "This Home Server would like to make sure you are not a robot": "Този Home сървър би искал да се увери, че не сте робот", + "Sign in with CAS": "Влез с CAS", + "To continue, please enter your password.": "За да продължите, моля, въведете своята парола.", + "Password:": "Парола:", + "An email has been sent to %(emailAddress)s": "Имейл беше изпратен на %(emailAddress)s", + "Please check your email to continue registration.": "Моля, проверете имейла си, за да продължите регистрацията.", + "Token incorrect": "Неправителен token", + "A text message has been sent to %(msisdn)s": "Текстово съобщение беше изпратено на %(msisdn)s", + "Please enter the code it contains:": "Моля, въведете кода, който то съдържа:", + "Start authentication": "Започнете автентикация", + "Username on %(hs)s": "Потребителско име на %(hs)s", + "User name": "Потребителско име", + "Mobile phone number": "Мобилен номер", + "Forgot your password?": "Забравена парола?", + "%(serverName)s Matrix ID": "%(serverName)s Matrix ID", + "Sign in with": "Влезте с", + "Email address": "Имейл адрес", + "Sign in": "Вход", + "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Ако не посочите имейл адрес, няма да бъде възможно да възстановите Вашата парола. Сигурни ли сте?", + "Email address (optional)": "Имейл адрес (по избор)", + "You are registering with %(SelectedTeamName)s": "Регистрирате се с %(SelectedTeamName)s", + "Mobile phone number (optional)": "Мобилен номер (по избор)", + "Default server": "Сървър по подразбиране", + "Custom server": "Потребителски сървър", + "Home server URL": "Адрес на home сървър", + "Identity server URL": "Адрес на сървър за самоличност", + "What does this mean?": "Какво означава това?", + "Failed to withdraw invitation": "Неуспешно оттегляне на поканата", + "Flair will appear if enabled in room settings": "Значката ще се покаже, ако е включена в настройките на стаята", + "Flair will not appear": "Значката няма да се покаже", + "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Сигурни ли сте, че искате да премахнете '%(roomName)s' от %(groupId)s?", + "Failed to remove '%(roomName)s' from %(groupId)s": "Неуспешно премахване на '%(roomName)s' от %(groupId)s", + "Something went wrong!": "Нещо се обърка!", + "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "Видимостта на '%(roomName)s' в %(groupId)s не може да бъде обновена.", + "Visibility in Room List": "Видимост в списъка със стаи", + "Visible to everyone": "Видимо за всеки", + "Something went wrong when trying to get your communities.": "Нещо се обърка при зареждането на Вашите общности.", + "Display your community flair in rooms configured to show it.": "Показване на значката на общността в стаи, кофигурирани да я показват.", + "You're not currently a member of any communities.": "Към момента не сте член на нито една общност.", + "Unknown Address": "Неизвестен адрес", + "NOTE: Apps are not end-to-end encrypted": "ЗАБЕЛЕЖКА: Приложенията не са шифровани от край до край", + "Do you want to load widget from URL:": "Искате ли да заредите приспособление от URL адреса:", + "Allow": "Позволение", + "Delete Widget": "Изтриване на приспособление", + "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Изтриването на приспособление го премахва за всички потребители в тази стая. Сигурни ли сте, че искате да изтриете това приспособление?", + "Delete widget": "Изтрий приспособлението", + "Revoke widget access": "Премахване на достъпа до приспособления", + "Minimize apps": "Минимизирай приложенията", + "Create new room": "Създай нова стая", + "Unblacklist": "Премахване от черния списък", + "Blacklist": "Черен списък", + "Unverify": "Махни потвърждението", + "Verify...": "Потвърди...", + "Your unverified device '%(displayName)s' is requesting encryption keys.": "Вашето непотвърдено устройство '%(displayName)s' изисква ключове за шифроване.", + "I have verified my email address": "Потвърдих имейл адреса си", + "NOT verified": "НЕ е потвърдено", + "verified": "потвърдено", + "No results": "Няма резултати", + "Delete": "Изтрий", + "Communities": "Общности", + "Home": "Начална страница", + "Integrations Error": "Грешка при интеграциите", + "Could not connect to the integration server": "Неуспешно свързване със сървъра с интеграции", + "Manage Integrations": "Управление на интеграциите", + "%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s", + "%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)sсе присъединиха %(count)s пъти", + "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sсе присъединиха", + "%(oneUser)sjoined %(count)s times|other": "%(oneUser)sсе присъедини %(count)s пъти", + "%(oneUser)sjoined %(count)s times|one": "%(oneUser)sсе присъедини", + "%(severalUsers)sleft %(count)s times|other": "%(severalUsers)sнапуснаха %(count)s пъти", + "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)sнапуснаха", + "%(oneUser)sleft %(count)s times|other": "%(oneUser)sнапусна %(count)s пъти", + "%(oneUser)sleft %(count)s times|one": "%(oneUser)sнапусна", + "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)sсе присъединиха и напуснаха %(count)s пъти", + "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)sсе присъединиха и напуснаха", + "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)sсе присъедини и напусна %(count)s пъти", + "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)sсе присъедини и напусна", + "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)sнапуснаха и се присъединиха отново %(count)s пъти", + "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)sнапуснаха и се присъединиха отново", + "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)sнапусна и се присъедини отново %(count)s пъти", + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)sнапусна и се присъедини отново", + "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)sотказаха своите покани %(count)s пъти", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)sотказаха своите покани", + "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)sотказа своята покана %(count)s пъти", + "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)sотказа своята покана", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)sоттеглиха своите покани %(count)s пъти", + "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "%(severalUsers)sоттеглиха своите покани", + "%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)sоттегли своята покана %(count)s пъти", + "%(oneUser)shad their invitation withdrawn %(count)s times|one": "%(oneUser)sоттегли своята покана", + "were invited %(count)s times|other": "бяха поканени %(count)s пъти", + "were invited %(count)s times|one": "бяха поканени", + "was invited %(count)s times|other": "беше поканен %(count)s пъти", + "was invited %(count)s times|one": "беше поканен", + "were banned %(count)s times|other": "бяха блокирани %(count)s пъти", + "were banned %(count)s times|one": "бяха блокирани", + "was banned %(count)s times|other": "беше блокиран %(count)s пъти", + "was banned %(count)s times|one": "беше блокиран", + "were unbanned %(count)s times|other": "бяха отблокирани %(count)s пъти", + "were unbanned %(count)s times|one": "бяха отблокирани", + "was unbanned %(count)s times|other": "беше отблокиран %(count)s пъти", + "was unbanned %(count)s times|one": "беше отблокиран", + "were kicked %(count)s times|other": "бяха изгонени %(count)s пъти", + "were kicked %(count)s times|one": "бяха изгонени", + "was kicked %(count)s times|other": "беше изгонен %(count)s пъти", + "was kicked %(count)s times|one": "беше изгонен", + "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)sсмениха своето име %(count)s пъти", + "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)sсмениха своето име", + "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)sсмени своето име %(count)s пъти", + "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)sсмени своето име", + "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)sсмениха своята профилна снимка %(count)s пъти", + "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)sсмениха своята профилна снимка", + "%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)sсмени своята профилна снимка %(count)s пъти", + "%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)sсмени своята профилна снимка", + "%(items)s and %(count)s others|other": "%(items)s и %(count)s други", + "%(items)s and %(count)s others|one": "%(items)s и още един", + "%(items)s and %(lastItem)s": "%(items)s и %(lastItem)s", + "collapse": "свий", + "expand": "разшири", + "Custom of %(powerLevel)s": "Персонализирано със стойност %(powerLevel)s", + "Custom level": "Персонализирано ниво", + "Custom": "Персонализирано", + "In reply to ": "В отговор на ", + "Room directory": "Директория на стаята", + "Start chat": "Започни чат", + "And %(count)s more...|other": "И %(count)s други...", + "ex. @bob:example.com": "напр. @bob:example.com", + "Add User": "Добави потребител", + "Matrix ID": "Matrix ID", + "Matrix Room ID": "Идентификатор на стаята", + "email address": "имейл адрес", + "Try using one of the following valid address types: %(validTypesList)s.": "Опитайте се да използвате един от следните видове валидни адреси: %(validTypesList)s.", + "You have entered an invalid address.": "Въвели сте невалиден адрес.", + "Create a new chat or reuse an existing one": "Създаване на нов чат или повторно използване на съществуващ", + "Start new chat": "Започни нов чат", + "You already have existing direct chats with this user:": "Вече имате налични директни чатове с този потребител:", + "Start chatting": "Започнете чата", + "Click on the button below to start chatting!": "Натиснете бутона по-долу, за да започнете чата!", + "Start Chatting": "Започнете чата", + "Confirm Removal": "Потвърдете премахването", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Идентификаторите на общността могат да съдържат само a-z, 0-9, или '=_-./'", + "Something went wrong whilst creating your community": "Нещо се обърка по време на създаването на Вашата общност", + "Example": "Пример", + "example": "пример", + "Create": "Създай", + "Create Room": "Създай стая", + "Room name (optional)": "Име на стая (по избор)", + "Advanced options": "Разширени настройки", + "Block users on other matrix homeservers from joining this room": "Не позволявай на потребители от други matrix home сървъри да се присъединяват към тази стая", + "This setting cannot be changed later!": "Тази настройка не може да бъде променена по-късно!", + "Unknown error": "Непозната грешка", + "Incorrect password": "Неправилна парола", + "Deactivate Account": "Деактивация на профила", + "Deactivate my account": "Деактивирай моя профил", + "This will make your account permanently unusable. You will not be able to re-register the same user ID.": "Това ще направи профил Ви перманентно неизползваем. Няма да можете да се регистрирате отново със същия потребителски идентификатор.", + "This action is irreversible.": "Това действие е необратимо.", + "Device name": "Име на устройството", + "Device key": "Ключ на устройството", + "In future this verification process will be more sophisticated.": "В бъдеще този процес на потвърждение ще бъде по-лесен.", + "Verify device": "Потвърди устройството", + "Start verification": "Започни потвърждението", + "Verification Pending": "Очакване на потвърждението", + "Verification": "Потвърждение", + "I verify that the keys match": "Потвърждавам, че ключовете съвпадат", + "An error has occurred.": "Възникна грешка.", + "You added a new device '%(displayName)s', which is requesting encryption keys.": "Добавихте ново устройство '%(displayName)s', което изисква ключове за шифроване.", + "Share without verifying": "Сподели без потвърждение", + "Ignore request": "Игнорирай поканата", + "Loading device info...": "Зареждане на информация за устройството...", + "Encryption key request": "Шифроване на ключове за заявка", + "Otherwise, click here to send a bug report.": "В противен случай, натиснете тук, за да изпратите съобщение за грешка.", + "Report it": "Съобщете го", + "Bug Report": "Съобщение за грешка", + "Unable to restore session": "Неуспешно възстановяване на сесията", + "Continue anyway": "Продължете въпреки това", + "Invalid Email Address": "Невалиден имейл адрес", + "This doesn't appear to be a valid email address": "Това не изглежда да е валиден имейл адрес", + "Please check your email and click on the link it contains. Once this is done, click continue.": "Моля, проверете своя имейл адрес и натиснете връзката, която той съдържа. След като направите това, натиснете продължи.", + "Unable to add email address": "Неуспешно добавяне на имейл адрес", + "Unable to verify email address.": "Неуспешно потвърждение на имейл адрес.", + "Unable to accept invite": "Неуспешно приемане на поканата", + "Unable to reject invite": "Неуспешно отхвърляне на поканата", + "Unable to leave room": "Неуспешно напускане на стаята", + "Tried to load a specific point in this room's timeline, but was unable to find it.": "Опита се да зареди конкретна точка в хронологията на тази стая, но не успя да я намери.", + "Unable to remove contact information": "Неуспешно премахване на информацията на контакта", + "This will allow you to reset your password and receive notifications.": "Това ще Ви позволи да възстановите Вашата парола и да получавате известия.", + "Skip": "Пропусни", + "User names may only contain letters, numbers, dots, hyphens and underscores.": "Потребителските имена могат да съдържат само букви, цифри, точки, тирета и долни черти.", + "Username not available": "Потребителското име е заето", + "Username invalid: %(errMessage)s": "Невалидно потребителско име: %(errMessage)s", + "An error occurred: %(error_string)s": "Възникна грешка: %(error_string)s", + "Username available": "Потребителското име не е заето", + "To get started, please pick a username!": "За да започнете, моля изберете потребителско име!", + "If you already have a Matrix account you can log in instead.": "Ако вече имате Matrix профил, можете да влезете с него.", + "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "В момента Вие блокирате непотвърдени устройства; за да изпращате съобщения до тези устройства, трябва да ги потвърдите.", + "Room contains unknown devices": "Стаята съдържа непознати устройства", + "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" съдържа устройства, който не сте виждали до сега.", + "Unknown devices": "Непознати устройства", + "Private Chat": "Личен чат", + "Public Chat": "Публичен чат", + "Alias (optional)": "Псевдоним (по избор)", + "Name": "Име", + "Topic": "Тема", + "Make this room private": "Направи тази стая лична", + "Share message history with new users": "Сподели историята на съобщението с новите потребители", + "Encrypt room": "Шифровай стаята", + "You must register to use this functionality": "Трябва да се регистрирате, за да използвате тази функционалност", + "You must join the room to see its files": "Трябва да се присъедините към стаята, за да видите файловете, които съдържа", + "There are no visible files in this room": "Няма видими файлове в тази стая", + "Which rooms would you like to add to this summary?": "Кои стаи бихте искали да добавите в това обобщение?" } From 5e90da73f0489d5e6c25c8f31bf017889116c951 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Wed, 21 Feb 2018 11:56:55 +0000 Subject: [PATCH 113/242] Translated using Weblate (Galician) Currently translated at 98.7% (974 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/gl/ --- src/i18n/strings/gl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json index 7a1fd567ee..d972376d41 100644 --- a/src/i18n/strings/gl.json +++ b/src/i18n/strings/gl.json @@ -768,7 +768,7 @@ "Create a new community": "Crear unha nova comunidade", "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Crear unha comunidade para agrupar usuarias e salas! Poña unha páxina de inicio personalizada para destacar o seu lugar no universo Matrix.", "Join an existing community": "Unirse a unha comunidade existente", - "To join an existing community you'll have to know its community identifier; this will look something like +example:matrix.org.": "Para unirse a unha comunidade existente deberá coñecer o identificador de esa comunidade; terá un aspecto como +exemplo:matrix.org", + "To join an existing community you'll have to know its community identifier; this will look something like +example:matrix.org.": "Para unirse a unha comunidade existente deberá coñecer o identificador de esa comunidade; terá un aspecto como +exemplo:matrix.org.", "You have no visible notifications": "Non ten notificacións visibles", "Scroll to bottom of page": "Desplácese ate o final da páxina", "Message not sent due to unknown devices being present": "Non se enviou a mensaxe porque hai dispositivos non coñecidos", From fc73442cdc4fba8cf7c610bee8a45c76aee8b67b Mon Sep 17 00:00:00 2001 From: Luke Barnard Date: Wed, 21 Feb 2018 15:06:10 +0000 Subject: [PATCH 114/242] Change icon from "R" to "X" --- src/components/structures/TagPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index d614588ccc..59365d8139 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -111,7 +111,7 @@ const TagPanel = React.createClass({ }); return
- +
Date: Wed, 21 Feb 2018 17:15:43 +0000 Subject: [PATCH 115/242] Only show "X" when filtering, add alt/title --- src/components/structures/TagPanel.js | 17 ++++++++++++++--- src/i18n/strings/en_EN.json | 9 +++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/components/structures/TagPanel.js b/src/components/structures/TagPanel.js index 59365d8139..46e539fa04 100644 --- a/src/components/structures/TagPanel.js +++ b/src/components/structures/TagPanel.js @@ -24,6 +24,7 @@ import GroupActions from '../../actions/GroupActions'; import sdk from '../../index'; import dis from '../../dispatcher'; +import { _t } from '../../languageHandler'; import { Droppable } from 'react-beautiful-dnd'; @@ -92,7 +93,7 @@ const TagPanel = React.createClass({ dis.dispatch({action: 'view_create_group'}); }, - onLogoClick(ev) { + onClearFilterClick(ev) { dis.dispatch({action: 'deselect_tags'}); }, @@ -109,9 +110,19 @@ const TagPanel = React.createClass({ selected={this.state.selectedTags.includes(tag)} />; }); + + const clearButton = this.state.selectedTags.length > 0 ? + {_t("Clear : +
; + return
- - + + { clearButton }
to start a chat with someone": "Press to start a chat with someone", "You're not in any rooms yet! Press to make a room or to browse the directory": "You're not in any rooms yet! Press to make a room or to browse the directory", "Community Invites": "Community Invites", @@ -826,6 +823,7 @@ "Click to mute video": "Click to mute video", "Click to unmute audio": "Click to unmute audio", "Click to mute audio": "Click to mute audio", + "Clear filter": "Clear filter", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.", "Failed to load timeline position": "Failed to load timeline position", @@ -984,5 +982,8 @@ "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.", "File to import": "File to import", - "Import": "Import" + "Import": "Import", + "Failed to set direct chat tag": "Failed to set direct chat tag", + "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", + "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" } From bb386c05d906eda9e519a7c70812ee5b98948e65 Mon Sep 17 00:00:00 2001 From: Ralitsa Bozhkova Date: Wed, 21 Feb 2018 14:27:58 +0000 Subject: [PATCH 116/242] Translated using Weblate (Bulgarian) Currently translated at 79.5% (784 of 986 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://translate.riot.im/projects/riot-web/matrix-react-sdk/bg/ --- src/i18n/strings/bg.json | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 35505c0038..4b0993e4ba 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -756,5 +756,31 @@ "You must register to use this functionality": "Трябва да се регистрирате, за да използвате тази функционалност", "You must join the room to see its files": "Трябва да се присъедините към стаята, за да видите файловете, които съдържа", "There are no visible files in this room": "Няма видими файлове в тази стая", - "Which rooms would you like to add to this summary?": "Кои стаи бихте искали да добавите в това обобщение?" + "Which rooms would you like to add to this summary?": "Кои стаи бихте искали да добавите в това обобщение?", + "Add to summary": "Добави в обобщението", + "Failed to add the following rooms to the summary of %(groupId)s:": "Неуспешно добавяне на следните стаи в обобщението на %(groupId)s:", + "Add a Room": "Добавяне на стая", + "Failed to remove the room from the summary of %(groupId)s": "Неуспешно премахване на стаята от обобщението на %(groupId)s", + "The room '%(roomName)s' could not be removed from the summary.": "Стаята '%(roomName)s' не може да бъде премахната от обобщението.", + "Who would you like to add to this summary?": "Кого бихте желали да добавите в това обобщение?", + "Failed to add the following users to the summary of %(groupId)s:": "Неуспешно добавяне на следните потребители в обобщението на %(groupId)s:", + "Add a User": "Добавяне на потребител", + "Failed to remove a user from the summary of %(groupId)s": "Неуспешно премахване на потребител от обобщението на %(groupId)s", + "The user '%(displayName)s' could not be removed from the summary.": "Потребителят '%(displayName)s' не може да бъде премахнат от обобщението.", + "Failed to upload image": "Неуспешно качване на снимка", + "Leave %(groupName)s?": "Напускане на %(groupName)s?", + "Featured Rooms:": "Препоръчани стаи:", + "Featured Users:": "Препоръчани потребители:", + "Long Description (HTML)": "Дълго описание (HTML)", + "Description": "Описание", + "This Home server does not support communities": "Този Home сървър не поддържа общности", + "Failed to load %(groupId)s": "Неуспешно зареждане на %(groupId)s", + "Reject invitation": "Отхвърли поканата", + "Are you sure you want to reject the invitation?": "Сигурни ли сте, че искате да отхвърлите поканата?", + "Failed to reject invitation": "Неуспешно отхвърляне на поканата", + "This room is not public. You will not be able to rejoin without an invite.": "Тази стая не е публична. Няма да можете да се присъедините отново без покана.", + "Are you sure you want to leave the room '%(roomName)s'?": "Сигурни ли сте, че искате да напуснете стаята '%(roomName)s'?", + "Failed to leave room": "Неуспешно напускане на стаята", + "Old cryptography data detected": "Старите криптирани данни са изтрити", + "Your Communities": "Вашите общности" } From d9032d706f5ea80b51edaaad86dbbdbe8d748144 Mon Sep 17 00:00:00 2001 From: Walter Date: Tue, 13 Feb 2018 18:55:45 +0000 Subject: [PATCH 117/242] Translated using Weblate (Russian) Currently translated at 100.0% (987 of 987 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://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 d24ee71de1..c07ea1e1fb 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -984,5 +984,6 @@ "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s изменил отображаемое имя на %(displayName)s.", "Failed to set direct chat tag": "Не удалось установить тег прямого чата", "Failed to remove tag %(tagName)s from room": "Не удалось удалить тег %(tagName)s из комнаты", - "Failed to add tag %(tagName)s to room": "Не удалось добавить тег %(tagName)s в комнату" + "Failed to add tag %(tagName)s to room": "Не удалось добавить тег %(tagName)s в комнату", + "Clear filter": "Очистить фильтр" } From 296e2bd928e703d1afbb48a778bde338e0d81c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Tue, 6 Feb 2018 19:11:45 +0000 Subject: [PATCH 118/242] Translated using Weblate (French) Currently translated at 100.0% (987 of 987 strings) Translation: Riot Web/matrix-react-sdk Translate-URL: https://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 f0f9b2dae9..7efbf5f548 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -984,5 +984,6 @@ "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s a changé son nom affiché en %(displayName)s.", "Failed to set direct chat tag": "Échec de l'ajout de l'étiquette discussion directe", "Failed to remove tag %(tagName)s from room": "Échec de la suppression de l'étiquette %(tagName)s du salon", - "Failed to add tag %(tagName)s to room": "Échec de l'ajout de l'étiquette %(tagName)s au salon" + "Failed to add tag %(tagName)s to room": "Échec de l'ajout de l'étiquette %(tagName)s au salon", + "Clear filter": "Supprimer les filtres" } From 5cd7a7fc061784bff84795c961782d73866c97f2 Mon Sep 17 00:00:00 2001 From: lukebarnard Date: Wed, 21 Feb 2018 19:26:14 +0000 Subject: [PATCH 119/242] Fix group member spinner being out of flex order --- src/components/views/groups/GroupMemberInfo.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/groups/GroupMemberInfo.js b/src/components/views/groups/GroupMemberInfo.js index 305aec8cdd..097fb1f7db 100644 --- a/src/components/views/groups/GroupMemberInfo.js +++ b/src/components/views/groups/GroupMemberInfo.js @@ -132,7 +132,9 @@ module.exports = React.createClass({ render: function() { if (this.state.removingUser) { const Spinner = sdk.getComponent("elements.Spinner"); - return ; + return
+ +
; } let adminTools; From ffb524b6a5a614734d9ae30401b95b44eb62ca48 Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 21 Feb 2018 23:10:08 +0000 Subject: [PATCH 120/242] Allow widget iframes to request camera and microphone permissions. --- src/components/views/elements/AppTile.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index a63823555f..b325dace84 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -393,6 +393,10 @@ export default React.createClass({ const sandboxFlags = "allow-forms allow-popups allow-popups-to-escape-sandbox "+ "allow-same-origin allow-scripts allow-presentation"; + // Additional iframe feature pemissions + // (see - https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-permissions-in-cross-origin-iframes and https://wicg.github.io/feature-policy/) + const iframeFeatures = "microphone; camera; encrypted-media;"; + if (this.props.show) { const loadingElement = (
@@ -413,6 +417,8 @@ export default React.createClass({
{ this.state.loading && loadingElement }