Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/home-page-analytics

 Conflicts:
	src/components/structures/HomePage.tsx
This commit is contained in:
Michael Telatynski 2020-11-19 11:11:10 +00:00
commit 532b2e5ced
105 changed files with 5816 additions and 1619 deletions

View file

@ -1,3 +1,79 @@
Changes in [3.8.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.8.0) (2020-11-09)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.8.0-rc.1...v3.8.0)
* Upgrade JS SDK to 9.1.0
Changes in [3.8.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.8.0-rc.1) (2020-11-04)
=============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.1...v3.8.0-rc.1)
* Upgrade JS SDK to 9.1.0-rc.1
* Log when saving profile
[\#5394](https://github.com/matrix-org/matrix-react-sdk/pull/5394)
* Translations update from Weblate
[\#5395](https://github.com/matrix-org/matrix-react-sdk/pull/5395)
* Hide prompt to add email for notifications if 3pid ui feature is off
[\#5392](https://github.com/matrix-org/matrix-react-sdk/pull/5392)
* Fix room list message preview copy for hangup events
[\#5388](https://github.com/matrix-org/matrix-react-sdk/pull/5388)
* Track UISIs as Countly Events
[\#5382](https://github.com/matrix-org/matrix-react-sdk/pull/5382)
* Don't let users accidentally redact ACL events
[\#5384](https://github.com/matrix-org/matrix-react-sdk/pull/5384)
* Two more easy files to remove from eslintignore
[\#5378](https://github.com/matrix-org/matrix-react-sdk/pull/5378)
* Fix Widget OpenID Permissions for realsies
[\#5381](https://github.com/matrix-org/matrix-react-sdk/pull/5381)
* Fix regression with OpenID permissions on widgets
[\#5380](https://github.com/matrix-org/matrix-react-sdk/pull/5380)
* Fix room directory events happening in the wrong order for Funnels
[\#5379](https://github.com/matrix-org/matrix-react-sdk/pull/5379)
* Remove a couple more files from eslintignore
[\#5377](https://github.com/matrix-org/matrix-react-sdk/pull/5377)
* Fix countly method bindings and errors
[\#5376](https://github.com/matrix-org/matrix-react-sdk/pull/5376)
* Fix a bunch of silly lint errors
[\#5375](https://github.com/matrix-org/matrix-react-sdk/pull/5375)
* Typescript: ImageUtils
[\#5374](https://github.com/matrix-org/matrix-react-sdk/pull/5374)
* Convert AuxPanel to TypeScript
[\#5373](https://github.com/matrix-org/matrix-react-sdk/pull/5373)
* Only pass metrics if they exist otherwise Countly will be unhappy!
[\#5372](https://github.com/matrix-org/matrix-react-sdk/pull/5372)
* Fix CountlyAnalytics NPE on MatrixClientPeg
[\#5370](https://github.com/matrix-org/matrix-react-sdk/pull/5370)
* fix CountlyAnalytics canEnable on wrong target
[\#5369](https://github.com/matrix-org/matrix-react-sdk/pull/5369)
* Initial Countly work
[\#5365](https://github.com/matrix-org/matrix-react-sdk/pull/5365)
* Fix videos not playing in non-encrypted rooms
[\#5368](https://github.com/matrix-org/matrix-react-sdk/pull/5368)
* Fix custom tag layout which regressed in #5309
[\#5367](https://github.com/matrix-org/matrix-react-sdk/pull/5367)
* Watch replyToEvent at RoomView to prevent races
[\#5360](https://github.com/matrix-org/matrix-react-sdk/pull/5360)
* Add a UI Feature flag for room history settings
[\#5362](https://github.com/matrix-org/matrix-react-sdk/pull/5362)
* Hide inline images when preference disabled
[\#5361](https://github.com/matrix-org/matrix-react-sdk/pull/5361)
* Fix React warning by moving handler to each button
[\#5359](https://github.com/matrix-org/matrix-react-sdk/pull/5359)
* Do not preload encrypted videos|images unless autoplay or thumbnailing is on
[\#5352](https://github.com/matrix-org/matrix-react-sdk/pull/5352)
* Fix theme variable passed to Jitsi
[\#5357](https://github.com/matrix-org/matrix-react-sdk/pull/5357)
* docs: added comment explanation
[\#5349](https://github.com/matrix-org/matrix-react-sdk/pull/5349)
* Modal Widgets - MSC2790
[\#5252](https://github.com/matrix-org/matrix-react-sdk/pull/5252)
* Widgets fixes
[\#5350](https://github.com/matrix-org/matrix-react-sdk/pull/5350)
* Fix User Menu avatar colouring being based on wrong string
[\#5348](https://github.com/matrix-org/matrix-react-sdk/pull/5348)
* Support 'answered elsewhere'
[\#5345](https://github.com/matrix-org/matrix-react-sdk/pull/5345)
Changes in [3.7.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.7.1) (2020-10-28) Changes in [3.7.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.7.1) (2020-10-28)
=================================================================================================== ===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.0...v3.7.1) [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.7.0...v3.7.1)

View file

@ -1,6 +1,6 @@
{ {
"name": "matrix-react-sdk", "name": "matrix-react-sdk",
"version": "3.7.1", "version": "3.8.0",
"description": "SDK for matrix.org using React", "description": "SDK for matrix.org using React",
"author": "matrix.org", "author": "matrix.org",
"repository": { "repository": {
@ -79,7 +79,7 @@
"linkifyjs": "^2.1.9", "linkifyjs": "^2.1.9",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-widget-api": "^0.1.0-beta.5", "matrix-widget-api": "^0.1.0-beta.8",
"minimist": "^1.2.5", "minimist": "^1.2.5",
"pako": "^1.0.11", "pako": "^1.0.11",
"parse5": "^5.1.1", "parse5": "^5.1.1",

View file

@ -110,11 +110,11 @@
@import "./views/elements/_EventListSummary.scss"; @import "./views/elements/_EventListSummary.scss";
@import "./views/elements/_Field.scss"; @import "./views/elements/_Field.scss";
@import "./views/elements/_FormButton.scss"; @import "./views/elements/_FormButton.scss";
@import "./views/elements/_IconButton.scss";
@import "./views/elements/_ImageView.scss"; @import "./views/elements/_ImageView.scss";
@import "./views/elements/_InfoTooltip.scss"; @import "./views/elements/_InfoTooltip.scss";
@import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_InlineSpinner.scss";
@import "./views/elements/_ManageIntegsButton.scss"; @import "./views/elements/_ManageIntegsButton.scss";
@import "./views/elements/_MiniAvatarUploader.scss";
@import "./views/elements/_PowerSelector.scss"; @import "./views/elements/_PowerSelector.scss";
@import "./views/elements/_ProgressBar.scss"; @import "./views/elements/_ProgressBar.scss";
@import "./views/elements/_QRCode.scss"; @import "./views/elements/_QRCode.scss";
@ -139,6 +139,7 @@
@import "./views/groups/_GroupUserSettings.scss"; @import "./views/groups/_GroupUserSettings.scss";
@import "./views/messages/_CreateEvent.scss"; @import "./views/messages/_CreateEvent.scss";
@import "./views/messages/_DateSeparator.scss"; @import "./views/messages/_DateSeparator.scss";
@import "./views/messages/_EventTileBubble.scss";
@import "./views/messages/_MEmoteBody.scss"; @import "./views/messages/_MEmoteBody.scss";
@import "./views/messages/_MFileBody.scss"; @import "./views/messages/_MFileBody.scss";
@import "./views/messages/_MImageBody.scss"; @import "./views/messages/_MImageBody.scss";
@ -182,6 +183,7 @@
@import "./views/rooms/_MemberList.scss"; @import "./views/rooms/_MemberList.scss";
@import "./views/rooms/_MessageComposer.scss"; @import "./views/rooms/_MessageComposer.scss";
@import "./views/rooms/_MessageComposerFormatBar.scss"; @import "./views/rooms/_MessageComposerFormatBar.scss";
@import "./views/rooms/_NewRoomIntro.scss";
@import "./views/rooms/_NotificationBadge.scss"; @import "./views/rooms/_NotificationBadge.scss";
@import "./views/rooms/_PinnedEventTile.scss"; @import "./views/rooms/_PinnedEventTile.scss";
@import "./views/rooms/_PinnedEventsPanel.scss"; @import "./views/rooms/_PinnedEventsPanel.scss";
@ -225,8 +227,9 @@
@import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss"; @import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss";
@import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss"; @import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss";
@import "./views/terms/_InlineTermsAgreement.scss"; @import "./views/terms/_InlineTermsAgreement.scss";
@import "./views/toasts/_AnalyticsToast.scss";
@import "./views/toasts/_NonUrgentEchoFailureToast.scss"; @import "./views/toasts/_NonUrgentEchoFailureToast.scss";
@import "./views/verification/_VerificationShowSas.scss"; @import "./views/verification/_VerificationShowSas.scss";
@import "./views/voip/_CallContainer.scss"; @import "./views/voip/_CallContainer.scss";
@import "./views/voip/_CallView.scss"; @import "./views/voip/_CallView.scss";
@import "./views/voip/_VideoView.scss"; @import "./views/voip/_VideoFeed.scss";

View file

@ -26,9 +26,10 @@ limitations under the License.
.mx_HomePage_default { .mx_HomePage_default {
text-align: center; text-align: center;
display: flex;
.mx_HomePage_default_wrapper { .mx_HomePage_default_wrapper {
padding: 25vh 0 12px; margin: auto;
} }
img { img {
@ -50,46 +51,12 @@ limitations under the License.
color: $muted-fg-color; color: $muted-fg-color;
} }
.mx_HomePage_userAvatar { .mx_MiniAvatarUploader {
position: relative;
width: min-content;
margin: 0 auto; margin: 0 auto;
&::before, &::after {
content: '';
position: absolute;
height: 26px;
width: 26px;
right: -6px;
bottom: -6px;
}
&::before {
background-color: $primary-bg-color;
border-radius: 50%;
z-index: 1;
}
&::after {
background-color: $secondary-fg-color;
mask-position: center;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/camera.svg');
mask-size: 16px;
z-index: 2;
}
&.mx_HomePage_userAvatar_busy::after {
background: url("$(res)/img/spinner.gif") no-repeat center;
background-size: 80%;
mask: unset;
}
} }
.mx_HomePage_default_buttons { .mx_HomePage_default_buttons {
margin: 80px auto 0; margin: 60px auto 0;
width: fit-content; width: fit-content;
.mx_AccessibleButton { .mx_AccessibleButton {
@ -97,7 +64,7 @@ limitations under the License.
width: 160px; width: 160px;
height: 132px; height: 132px;
margin: 0 20px; margin: 20px;
position: relative; position: relative;
display: inline-block; display: inline-block;
border-radius: 8px; border-radius: 8px;

View file

@ -153,16 +153,6 @@ limitations under the License.
display: block; display: block;
} }
.mx_RoomStatusBar_isAlone {
height: 50px;
line-height: $font-50px;
color: $primary-fg-color;
opacity: 0.5;
overflow-y: hidden;
display: block;
}
.mx_MatrixChat_useCompactLayout { .mx_MatrixChat_useCompactLayout {
.mx_RoomStatusBar { .mx_RoomStatusBar {
min-height: 40px; min-height: 40px;

View file

@ -14,6 +14,35 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_InteractiveAuthEntryComponents_emailWrapper {
padding-right: 60px;
position: relative;
margin-top: 32px;
margin-bottom: 32px;
&::before, &::after {
position: absolute;
width: 116px;
height: 116px;
content: "";
right: -10px;
}
&::before {
background-color: rgba(244, 246, 250, 0.91);
border-radius: 50%;
top: -20px;
}
&::after {
background-image: url('$(res)/img/element-icons/email-prompt.svg');
background-repeat: no-repeat;
background-position: center;
background-size: contain;
top: -25px;
}
}
.mx_InteractiveAuthEntryComponents_msisdnWrapper { .mx_InteractiveAuthEntryComponents_msisdnWrapper {
text-align: center; text-align: center;
} }

View file

@ -1,55 +0,0 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_IconButton {
width: 32px;
height: 32px;
border-radius: 100%;
background-color: $accent-bg-color;
// don't shrink or grow if in a flex container
flex: 0 0 auto;
&.mx_AccessibleButton_disabled {
background-color: none;
&::before {
background-color: lightgrey;
}
}
&:hover {
opacity: 90%;
}
&::before {
content: "";
display: block;
width: 100%;
height: 100%;
mask-repeat: no-repeat;
mask-position: center;
mask-size: 55%;
background-color: $accent-color;
}
&.mx_IconButton_icon_check::before {
mask-image: url('$(res)/img/feather-customised/check.svg');
}
&.mx_IconButton_icon_edit::before {
mask-image: url('$(res)/img/feather-customised/edit.svg');
}
}

View file

@ -0,0 +1,56 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_MiniAvatarUploader {
position: relative;
width: min-content;
&::before, &::after {
content: '';
position: absolute;
height: 26px;
width: 26px;
right: -6px;
bottom: -6px;
}
&::before {
background-color: $primary-bg-color;
border-radius: 50%;
z-index: 1;
}
&::after {
background-color: $secondary-fg-color;
mask-position: center;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/camera.svg');
mask-size: 16px;
z-index: 2;
}
&.mx_MiniAvatarUploader_busy::after {
background: url("$(res)/img/spinner.gif") no-repeat center;
background-size: 80%;
mask: unset;
}
}
.mx_MiniAvatarUploader_input {
display: none;
}

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2018 New Vector Ltd Copyright 2018, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -15,25 +15,8 @@ limitations under the License.
*/ */
.mx_CreateEvent { .mx_CreateEvent {
background-color: $info-plinth-bg-color; &::before {
padding-left: 20px; background-color: $composer-e2e-icon-color;
padding-right: 20px; mask-image: url('$(res)/img/element-icons/chat-bubbles.svg');
padding-top: 10px; }
padding-bottom: 10px;
}
.mx_CreateEvent_image {
float: left;
margin-right: 20px;
width: 72px;
height: 34px;
background-color: $primary-fg-color;
mask: url('$(res)/img/room-continuation.svg');
mask-repeat: no-repeat;
mask-position: center;
}
.mx_CreateEvent_header {
font-weight: bold;
} }

View file

@ -0,0 +1,60 @@
/*
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_EventTileBubble {
background-color: $dark-panel-bg-color;
padding: 10px;
border-radius: 8px;
margin: 10px auto;
max-width: 75%;
box-sizing: border-box;
display: grid;
grid-template-columns: 24px minmax(0, 1fr) min-content;
&::before, &::after {
position: relative;
grid-column: 1;
grid-row: 1 / 3;
width: 16px;
height: 16px;
content: "";
top: 0;
bottom: 0;
left: 0;
right: 0;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
margin-top: 4px;
}
.mx_EventTileBubble_title, .mx_EventTileBubble_subtitle {
overflow-wrap: break-word;
}
.mx_EventTileBubble_title {
font-weight: 600;
font-size: $font-15px;
grid-column: 2;
grid-row: 1;
}
.mx_EventTileBubble_subtitle {
font-size: $font-12px;
grid-column: 2;
grid-row: 2;
}
}

View file

@ -15,41 +15,8 @@ limitations under the License.
*/ */
.mx_MJitsiWidgetEvent { .mx_MJitsiWidgetEvent {
display: grid;
grid-template-columns: 24px minmax(0, 1fr) min-content;
&::before { &::before {
grid-column: 1;
grid-row: 1 / 3;
width: 16px;
height: 16px;
content: "";
top: 0;
bottom: 0;
left: 0;
right: 0;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
background-color: $composer-e2e-icon-color; // XXX: Variable abuse background-color: $composer-e2e-icon-color; // XXX: Variable abuse
margin-top: 4px;
mask-image: url('$(res)/img/element-icons/call/video-call.svg'); mask-image: url('$(res)/img/element-icons/call/video-call.svg');
} }
.mx_MJitsiWidgetEvent_title {
font-weight: 600;
font-size: $font-15px;
grid-column: 2;
grid-row: 1;
}
.mx_MJitsiWidgetEvent_subtitle {
grid-column: 2;
grid-row: 2;
}
.mx_MJitsiWidgetEvent_title,
.mx_MJitsiWidgetEvent_subtitle {
overflow-wrap: break-word;
}
} }

View file

@ -18,5 +18,6 @@ span.mx_MVideoBody {
video.mx_MVideoBody { video.mx_MVideoBody {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
border-radius: 4px;
} }
} }

View file

@ -15,28 +15,6 @@ limitations under the License.
*/ */
.mx_cryptoEvent { .mx_cryptoEvent {
display: grid;
grid-template-columns: 24px minmax(0, 1fr) min-content;
&.mx_cryptoEvent_icon::before,
&.mx_cryptoEvent_icon::after {
grid-column: 1;
grid-row: 1 / 3;
width: 16px;
height: 16px;
content: "";
top: 0;
bottom: 0;
left: 0;
right: 0;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
mask-image: url('$(res)/img/e2e/normal.svg');
background-color: $composer-e2e-icon-color;
margin-top: 4px;
}
// white infill for the transparency // white infill for the transparency
&.mx_cryptoEvent_icon::before { &.mx_cryptoEvent_icon::before {
background-color: #ffffff; background-color: #ffffff;
@ -46,6 +24,11 @@ limitations under the License.
mask-size: 90%; mask-size: 90%;
} }
&.mx_cryptoEvent_icon::after {
mask-image: url('$(res)/img/e2e/normal.svg');
background-color: $composer-e2e-icon-color;
}
&.mx_cryptoEvent_icon_verified::after { &.mx_cryptoEvent_icon_verified::after {
mask-image: url("$(res)/img/e2e/verified.svg"); mask-image: url("$(res)/img/e2e/verified.svg");
background-color: $accent-color; background-color: $accent-color;
@ -56,25 +39,6 @@ limitations under the License.
background-color: $notice-primary-color; background-color: $notice-primary-color;
} }
.mx_cryptoEvent_title, .mx_cryptoEvent_subtitle, .mx_cryptoEvent_state {
overflow-wrap: break-word;
}
.mx_cryptoEvent_title {
font-weight: 600;
font-size: $font-15px;
grid-column: 2;
grid-row: 1;
}
.mx_cryptoEvent_subtitle {
grid-column: 2;
grid-row: 2;
}
.mx_cryptoEvent_state, .mx_cryptoEvent_subtitle {
font-size: $font-12px;
}
.mx_cryptoEvent_state, .mx_cryptoEvent_buttons { .mx_cryptoEvent_state, .mx_cryptoEvent_buttons {
grid-column: 3; grid-column: 3;
@ -92,5 +56,7 @@ limitations under the License.
margin: auto 0; margin: auto 0;
text-align: center; text-align: center;
color: $notice-secondary-color; color: $notice-secondary-color;
overflow-wrap: break-word;
font-size: $font-12px;
} }
} }

View file

@ -173,26 +173,12 @@ limitations under the License.
margin: 6px 0; margin: 6px 0;
.mx_IconButton, .mx_Spinner {
margin-left: 20px;
width: 16px;
height: 16px;
&::before {
mask-size: 80%;
}
}
.mx_UserInfo_roleDescription { .mx_UserInfo_roleDescription {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
// try to make it the same height as the dropdown // try to make it the same height as the dropdown
margin: 11px 0 12px 0; margin: 11px 0 12px 0;
.mx_IconButton {
margin-left: 6px;
}
} }
.mx_Field { .mx_Field {

View file

@ -25,15 +25,6 @@ $left-gutter: 64px;
position: relative; position: relative;
} }
.mx_EventTile_bubble {
background-color: $dark-panel-bg-color;
padding: 10px;
border-radius: 5px;
margin: 10px auto;
max-width: 75%;
box-sizing: border-box;
}
.mx_EventTile.mx_EventTile_info { .mx_EventTile.mx_EventTile_info {
padding-top: 0px; padding-top: 0px;
} }
@ -131,9 +122,10 @@ $left-gutter: 64px;
grid-template-columns: 1fr 100px; grid-template-columns: 1fr 100px;
.mx_EventTile_line { .mx_EventTile_line {
margin-right: 0px; margin-right: 0;
grid-column: 1 / 3; grid-column: 1 / 3;
padding: 0; // override default padding of mx_EventTile_line so that we can be centered
padding: 0 !important;
} }
.mx_EventTile_msgOption { .mx_EventTile_msgOption {

View file

@ -186,6 +186,7 @@ $irc-line-height: $font-18px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
min-width: var(--name-width); min-width: var(--name-width);
text-align: end;
} }
} }
} }

View file

@ -0,0 +1,67 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_NewRoomIntro {
margin: 40px 0 48px 64px;
.mx_MiniAvatarUploader_hasAvatar:not(.mx_MiniAvatarUploader_busy):not(:hover) {
&::before, &::after {
content: unset;
}
}
.mx_AccessibleButton_kind_link {
padding: 0;
font-size: inherit;
}
.mx_NewRoomIntro_buttons {
margin-top: 28px;
.mx_AccessibleButton {
line-height: $font-24px;
&::before {
content: '';
display: inline-block;
background-color: $button-fg-color;
mask-position: center;
mask-repeat: no-repeat;
mask-size: 20px;
width: 20px;
height: 20px;
margin-right: 5px;
vertical-align: text-bottom;
}
}
.mx_NewRoomIntro_inviteButton::before {
mask-image: url('$(res)/img/element-icons/room/invite.svg');
}
}
> h2 {
margin-top: 24px;
font-size: $font-24px;
font-weight: 600;
}
> p {
margin: 0;
font-size: $font-15px;
color: $secondary-fg-color;
}
}

View file

@ -33,7 +33,6 @@ limitations under the License.
div:first-child { div:first-child {
font-weight: $font-semi-bold; font-weight: $font-semi-bold;
margin-bottom: 8px;
} }
.mx_AccessibleButton { .mx_AccessibleButton {
@ -41,6 +40,7 @@ limitations under the License.
position: relative; position: relative;
padding: 0 0 0 24px; padding: 0 0 0 24px;
font-size: inherit; font-size: inherit;
margin-top: 8px;
&::before { &::before {
content: ''; content: '';
@ -53,6 +53,13 @@ limitations under the License.
mask-position: center; mask-position: center;
mask-size: contain; mask-size: contain;
mask-repeat: no-repeat; mask-repeat: no-repeat;
}
&.mx_RoomList_explorePrompt_startChat::before {
mask-image: url('$(res)/img/element-icons/feedback.svg');
}
&.mx_RoomList_explorePrompt_explore::before {
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg'); mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
} }
} }

View file

@ -0,0 +1,27 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_AnalyticsToast {
.mx_AccessibleButton_kind_danger {
background: none;
color: $accent-color;
}
.mx_AccessibleButton_kind_primary {
background: $accent-color;
color: #ffffff;
}
}

View file

@ -33,11 +33,11 @@ limitations under the License.
pointer-events: initial; // restore pointer events so the user can leave/interact pointer-events: initial; // restore pointer events so the user can leave/interact
cursor: pointer; cursor: pointer;
.mx_VideoView { .mx_CallView_video {
width: 350px; width: 350px;
} }
.mx_VideoView_localVideoFeed { .mx_VideoFeed_local {
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
} }

View file

@ -92,3 +92,10 @@ limitations under the License.
background-color: $primary-fg-color; background-color: $primary-fg-color;
} }
} }
.mx_CallView_video {
width: 100%;
position: relative;
z-index: 30;
}

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -14,23 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
.mx_VideoView { .mx_VideoFeed video {
width: 100%;
position: relative;
z-index: 30;
}
.mx_VideoView video {
width: 100%; width: 100%;
} }
.mx_VideoView_remoteVideoFeed { .mx_VideoFeed_remote {
width: 100%; width: 100%;
background-color: #000; background-color: #000;
z-index: 50; z-index: 50;
} }
.mx_VideoView_localVideoFeed { .mx_VideoFeed_local {
width: 25%; width: 25%;
height: 25%; height: 25%;
position: absolute; position: absolute;
@ -39,11 +33,11 @@ limitations under the License.
z-index: 100; z-index: 100;
} }
.mx_VideoView_localVideoFeed video { .mx_VideoFeed_local video {
width: auto; width: auto;
height: 100%; height: 100%;
} }
.mx_VideoView_localVideoFeed.mx_VideoView_localVideoFeed_flipped video { .mx_VideoFeed_mirror video {
transform: scale(-1, 1); transform: scale(-1, 1);
} }

View file

@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.90964 11.5297C9.09231 11.5297 11.6724 8.94865 11.6724 5.76483C11.6724 2.581 9.09231 0 5.90964 0C2.72697 0 0.146904 2.581 0.146904 5.76483C0.146904 6.65678 0.3494 7.50142 0.710912 8.25525L0.0648767 10.3556C-0.171716 11.1248 0.550948 11.8442 1.31906 11.6041L3.39724 10.9544C4.15657 11.323 5.00898 11.5297 5.90964 11.5297Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.03851 12.8449C5.70399 13.1151 6.4314 13.2638 7.19345 13.2638C10.3676 13.2638 13.5 10.6832 13.5 7.49979C13.5 6.63255 13.2676 5.81005 12.8651 5.07227C14.6487 6.05071 15.8583 7.94999 15.8583 10.1326C15.8583 11.0243 15.6564 11.8688 15.2959 12.6224L15.9404 14.7232C16.1765 15.4926 15.4533 16.2114 14.6854 15.9708L12.6155 15.322C11.8585 15.6902 11.0088 15.8966 10.111 15.8966C7.91459 15.8966 6.00594 14.661 5.03851 12.8449Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,13 @@
<svg width="57" height="77" viewBox="0 0 57 77" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.55298 38.9352H4C1.79086 38.9352 0 40.726 0 42.9352V72.0304C0 74.2396 1.79086 76.0304 4 76.0304H53C55.2091 76.0304 57 74.2396 57 72.0304V42.9352C57 40.726 55.2091 38.9352 53 38.9352H51.365V41.6473H5.55298V38.9352ZM26.9753 61.3068L3.10141 43.4482C2.33137 42.8721 2.73876 41.6474 3.70041 41.6474H28.459H53.3841C54.3282 41.6474 54.7464 42.8352 54.0107 43.4268L31.8776 61.2212C30.4545 62.3653 28.4374 62.4005 26.9753 61.3068Z" fill="#8A8C8E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.5885 33.0898C48.9384 33.2156 48.2703 33.2911 47.5885 33.3119V34.706V44.4238V54.1415H49.5885V44.4238V34.706V33.0898ZM36.5604 14.2706H13.7177C10.9562 14.2706 8.71765 16.5092 8.71765 19.2706V34.706V44.4238V54.1415H10.7177V44.4238V34.706V19.2706C10.7177 17.6138 12.0608 16.2706 13.7177 16.2706H35.5616C35.8354 15.571 36.1706 14.9022 36.5604 14.2706Z" fill="#8A8C8E"/>
<path d="M16.6589 30.5414H37.4826" stroke="#8A8C8E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="16.2706" y1="37.8708" x2="40.6473" y2="37.8708" stroke="#8A8C8E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="16.2706" y1="44.812" x2="40.6473" y2="44.812" stroke="#8A8C8E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="47.2003" cy="20.8237" r="9.71771" fill="#FE2928"/>
<rect x="45.812" y="14.5765" width="2.77649" height="8.32946" rx="1" fill="white"/>
<rect x="45.812" y="24.2943" width="2.77649" height="2.77649" rx="1" fill="white"/>
<line x1="27.3766" y1="1" x2="27.3766" y2="10.106" stroke="#8A8C8E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="34.3179" y1="6.55298" x2="34.3179" y2="10.106" stroke="#8A8C8E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="20.4354" y1="6.55298" x2="20.4354" y2="10.106" stroke="#8A8C8E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,6 +0,0 @@
<svg width="72" height="34" viewBox="0 0 72 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 7.26087V1H28.7889V7.26087M1 7.26087V33H28.7889V7.26087M1 7.26087H28.7889M4.16583 4.13043H16.8291" stroke="#454545" stroke-width="2" stroke-linejoin="round"/>
<path d="M43.2109 7.26087V1H70.9999V7.26087M43.2109 7.26087V33H70.9999V7.26087M43.2109 7.26087H70.9999M46.3768 4.13043H59.0401" stroke="#454545" stroke-width="2" stroke-linejoin="round"/>
<path d="M27.03 28.8262C34.2226 28.8262 36.0207 26.343 36.0207 25.1014V16.0996C36.0207 12.1264 43.6283 11.3401 47.432 11.4436" stroke="black" stroke-width="2"/>
</svg>

Before

Width:  |  Height:  |  Size: 623 B

View file

@ -274,6 +274,10 @@ $composer-shadow-color: rgba(0, 0, 0, 0.28);
background-color: #080808; background-color: #080808;
} }
} }
blockquote {
color: #919191;
}
} }
// diff highlight colors // diff highlight colors

View file

@ -69,6 +69,13 @@ declare global {
interface Document { interface Document {
// https://developer.mozilla.org/en-US/docs/Web/API/Document/hasStorageAccess // https://developer.mozilla.org/en-US/docs/Web/API/Document/hasStorageAccess
hasStorageAccess?: () => Promise<boolean>; hasStorageAccess?: () => Promise<boolean>;
// Safari & IE11 only have this prefixed: we used prefixed versions
// previously so let's continue to support them for now
webkitExitFullscreen(): Promise<void>;
msExitFullscreen(): Promise<void>;
readonly webkitFullscreenElement: Element | null;
readonly msFullscreenElement: Element | null;
} }
interface Navigator { interface Navigator {
@ -99,6 +106,13 @@ declare global {
type?: string; type?: string;
} }
interface Element {
// Safari & IE11 only have this prefixed: we used prefixed versions
// previously so let's continue to support them for now
webkitRequestFullScreen(options?: FullscreenOptions): Promise<void>;
msRequestFullscreen(options?: FullscreenOptions): Promise<void>;
}
interface Error { interface Error {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/fileName // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/fileName
fileName?: string; fileName?: string;

View file

@ -59,8 +59,7 @@ import {MatrixClientPeg} from './MatrixClientPeg';
import PlatformPeg from './PlatformPeg'; import PlatformPeg from './PlatformPeg';
import Modal from './Modal'; import Modal from './Modal';
import { _t } from './languageHandler'; import { _t } from './languageHandler';
// @ts-ignore - XXX: tsc doesn't like this: our js-sdk imports are complex so this isn't surprising import { createNewMatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import Matrix from 'matrix-js-sdk';
import dis from './dispatcher/dispatcher'; import dis from './dispatcher/dispatcher';
import WidgetUtils from './utils/WidgetUtils'; import WidgetUtils from './utils/WidgetUtils';
import WidgetEchoStore from './stores/WidgetEchoStore'; import WidgetEchoStore from './stores/WidgetEchoStore';
@ -77,7 +76,7 @@ import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import WidgetStore from "./stores/WidgetStore"; import WidgetStore from "./stores/WidgetStore";
import { WidgetMessagingStore } from "./stores/widgets/WidgetMessagingStore"; import { WidgetMessagingStore } from "./stores/widgets/WidgetMessagingStore";
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions"; import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
import { MatrixCall, CallErrorCode, CallState, CallEvent, CallParty, CallType } from "matrix-js-sdk/lib/webrtc/call"; import { MatrixCall, CallErrorCode, CallState, CallEvent, CallParty, CallType } from "matrix-js-sdk/src/webrtc/call";
import Analytics from './Analytics'; import Analytics from './Analytics';
import CountlyAnalytics from "./CountlyAnalytics"; import CountlyAnalytics from "./CountlyAnalytics";
@ -98,6 +97,21 @@ export enum PlaceCallType {
ScreenSharing = 'screensharing', ScreenSharing = 'screensharing',
} }
function getRemoteAudioElement(): HTMLAudioElement {
// this needs to be somewhere at the top of the DOM which
// always exists to avoid audio interruptions.
// Might as well just use DOM.
const remoteAudioElement = document.getElementById("remoteAudio") as HTMLAudioElement;
if (!remoteAudioElement) {
console.error(
"Failed to find remoteAudio element - cannot play audio!" +
"You need to add an <audio/> to the DOM.",
);
return null;
}
return remoteAudioElement;
}
export default class CallHandler { export default class CallHandler {
private calls = new Map<string, MatrixCall>(); private calls = new Map<string, MatrixCall>();
private audioPromises = new Map<AudioID, Promise<void>>(); private audioPromises = new Map<AudioID, Promise<void>>();
@ -291,6 +305,11 @@ export default class CallHandler {
}); });
} }
private setCallAudioElement(call: MatrixCall) {
const audioElement = getRemoteAudioElement();
if (audioElement) call.setRemoteAudioElement(audioElement);
}
private setCallState(call: MatrixCall, status: CallState) { private setCallState(call: MatrixCall, status: CallState) {
console.log( console.log(
`Call state in ${call.roomId} changed to ${status}`, `Call state in ${call.roomId} changed to ${status}`,
@ -343,9 +362,11 @@ export default class CallHandler {
) { ) {
Analytics.trackEvent('voip', 'placeCall', 'type', type); Analytics.trackEvent('voip', 'placeCall', 'type', type);
CountlyAnalytics.instance.trackStartCall(roomId, type === PlaceCallType.Video, false); CountlyAnalytics.instance.trackStartCall(roomId, type === PlaceCallType.Video, false);
const call = Matrix.createNewMatrixCall(MatrixClientPeg.get(), roomId); const call = createNewMatrixCall(MatrixClientPeg.get(), roomId);
this.calls.set(roomId, call); this.calls.set(roomId, call);
this.setCallListeners(call); this.setCallListeners(call);
this.setCallAudioElement(call);
if (type === PlaceCallType.Voice) { if (type === PlaceCallType.Voice) {
call.placeVoiceCall(); call.placeVoiceCall();
} else if (type === 'video') { } else if (type === 'video') {
@ -451,6 +472,7 @@ export default class CallHandler {
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type); Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
this.calls.set(call.roomId, call) this.calls.set(call.roomId, call)
this.setCallListeners(call); this.setCallListeners(call);
this.setCallAudioElement(call);
} }
break; break;
case 'hangup': case 'hangup':

View file

@ -147,6 +147,15 @@ export class ModalManager {
return this.appendDialogAsync<T>(...rest); return this.appendDialogAsync<T>(...rest);
} }
public closeCurrentModal(reason: string) {
const modal = this.getCurrentModal();
if (!modal) {
return;
}
modal.closeReason = reason;
modal.close();
}
private buildModal<T extends any[]>( private buildModal<T extends any[]>(
prom: Promise<React.ComponentType>, prom: Promise<React.ComponentType>,
props?: IProps<T>, props?: IProps<T>,

View file

@ -34,6 +34,8 @@ import SettingsStore from "./settings/SettingsStore";
import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast"; import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast";
import {SettingLevel} from "./settings/SettingLevel"; import {SettingLevel} from "./settings/SettingLevel";
import {isPushNotifyDisabled} from "./settings/controllers/NotificationControllers"; import {isPushNotifyDisabled} from "./settings/controllers/NotificationControllers";
import RoomViewStore from "./stores/RoomViewStore";
import UserActivity from "./UserActivity";
/* /*
* Dispatches: * Dispatches:
@ -376,6 +378,11 @@ export const Notifier = {
const room = MatrixClientPeg.get().getRoom(ev.getRoomId()); const room = MatrixClientPeg.get().getRoom(ev.getRoomId());
const actions = MatrixClientPeg.get().getPushActionsForEvent(ev); const actions = MatrixClientPeg.get().getPushActionsForEvent(ev);
if (actions && actions.notify) { if (actions && actions.notify) {
if (RoomViewStore.getRoomId() === room.roomId && UserActivity.sharedInstance().userActiveRecently()) {
// don't bother notifying as user was recently active in this room
return;
}
if (this.isEnabled()) { if (this.isEnabled()) {
this._displayPopupNotification(ev, room); this._displayPopupNotification(ev, room);
} }

View file

@ -40,11 +40,11 @@ export function inviteMultipleToRoom(roomId, addrs) {
return inviter.invite(addrs).then(states => Promise.resolve({states, inviter})); return inviter.invite(addrs).then(states => Promise.resolve({states, inviter}));
} }
export function showStartChatInviteDialog() { export function showStartChatInviteDialog(initialText) {
// This dialog handles the room creation internally - we don't need to worry about it. // This dialog handles the room creation internally - we don't need to worry about it.
const InviteDialog = sdk.getComponent("dialogs.InviteDialog"); const InviteDialog = sdk.getComponent("dialogs.InviteDialog");
Modal.createTrackedDialog( Modal.createTrackedDialog(
'Start DM', '', InviteDialog, {kind: KIND_DM}, 'Start DM', '', InviteDialog, {kind: KIND_DM, initialText},
/*className=*/null, /*isPriority=*/false, /*isStatic=*/true, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
); );
} }

View file

@ -50,8 +50,8 @@ class Skinner {
return null; return null;
} }
// components have to be functions. // components have to be functions or forwardRef objects with a render function.
const validType = typeof comp === 'function'; const validType = typeof comp === 'function' || comp.render;
if (!validType) { if (!validType) {
throw new Error(`Not a valid component: ${name} (type = ${typeof(comp)}).`); throw new Error(`Not a valid component: ${name} (type = ${typeof(comp)}).`);
} }

View file

@ -46,6 +46,7 @@ import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from
import SdkConfig from "./SdkConfig"; import SdkConfig from "./SdkConfig";
import SettingsStore from "./settings/SettingsStore"; import SettingsStore from "./settings/SettingsStore";
import {UIFeature} from "./settings/UIFeature"; import {UIFeature} from "./settings/UIFeature";
import CallHandler from "./CallHandler";
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
interface HTMLInputEvent extends Event { interface HTMLInputEvent extends Event {
@ -1057,6 +1058,32 @@ export const Commands = [
}, },
category: CommandCategories.actions, category: CommandCategories.actions,
}), }),
new Command({
command: "holdcall",
description: _td("Places the call in the current room on hold"),
category: CommandCategories.other,
runFn: function(roomId, args) {
const call = CallHandler.sharedInstance().getCallForRoom(roomId);
if (!call) {
return reject("No active call in this room");
}
call.setRemoteOnHold(true);
return success();
},
}),
new Command({
command: "unholdcall",
description: _td("Takes the call in the current room off hold"),
category: CommandCategories.other,
runFn: function(roomId, args) {
const call = CallHandler.sharedInstance().getCallForRoom(roomId);
if (!call) {
return reject("No active call in this room");
}
call.setRemoteOnHold(false);
return success();
},
}),
// Command definitions for autocompletion ONLY: // Command definitions for autocompletion ONLY:
// /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes // /me is special because its not handled by SlashCommands.js and is instead done inside the Composer classes

View file

@ -257,6 +257,12 @@ const shortcuts: Record<Categories, IShortcut[]> = {
key: Key.SLASH, key: Key.SLASH,
}], }],
description: _td("Toggle this dialog"), description: _td("Toggle this dialog"),
}, {
keybinds: [{
modifiers: [CMD_OR_CTRL, Modifiers.ALT],
key: Key.H,
}],
description: _td("Go to Home View"),
}, },
], ],

View file

@ -47,7 +47,7 @@ const LONG_DESC_PLACEHOLDER = _td(
some important <a href="foo">links</a> some important <a href="foo">links</a>
</p> </p>
<p> <p>
You can even use 'img' tags You can even add images with Matrix URLs <img src="mxc://url" />
</p> </p>
`); `);

View file

@ -15,7 +15,7 @@ limitations under the License.
*/ */
import * as React from "react"; import * as React from "react";
import {useContext, useRef, useState} from "react"; import {useContext, useState} from "react";
import AutoHideScrollbar from './AutoHideScrollbar'; import AutoHideScrollbar from './AutoHideScrollbar';
import {getHomePageUrl} from "../../utils/pages"; import {getHomePageUrl} from "../../utils/pages";
@ -24,16 +24,13 @@ import SdkConfig from "../../SdkConfig";
import * as sdk from "../../index"; import * as sdk from "../../index";
import dis from "../../dispatcher/dispatcher"; import dis from "../../dispatcher/dispatcher";
import {Action} from "../../dispatcher/actions"; import {Action} from "../../dispatcher/actions";
import {Transition} from "react-transition-group";
import BaseAvatar from "../views/avatars/BaseAvatar"; import BaseAvatar from "../views/avatars/BaseAvatar";
import {OwnProfileStore} from "../../stores/OwnProfileStore"; import {OwnProfileStore} from "../../stores/OwnProfileStore";
import AccessibleButton from "../views/elements/AccessibleButton"; import AccessibleButton from "../views/elements/AccessibleButton";
import Tooltip from "../views/elements/Tooltip";
import {UPDATE_EVENT} from "../../stores/AsyncStore"; import {UPDATE_EVENT} from "../../stores/AsyncStore";
import {useEventEmitter} from "../../hooks/useEventEmitter"; import {useEventEmitter} from "../../hooks/useEventEmitter";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
import classNames from "classnames"; import MiniAvatarUploader, {AVATAR_SIZE} from "../views/elements/MiniAvatarUploader";
import {ENTERING} from "react-transition-group/Transition";
import Analytics from "../../Analytics"; import Analytics from "../../Analytics";
import CountlyAnalytics from "../../CountlyAnalytics"; import CountlyAnalytics from "../../CountlyAnalytics";
@ -59,11 +56,9 @@ interface IProps {
justRegistered?: boolean; justRegistered?: boolean;
} }
const avatarSize = 52;
const getOwnProfile = (userId: string) => ({ const getOwnProfile = (userId: string) => ({
displayName: OwnProfileStore.instance.displayName || userId, displayName: OwnProfileStore.instance.displayName || userId,
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(avatarSize), avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE),
}); });
const UserWelcomeTop = () => { const UserWelcomeTop = () => {
@ -73,58 +68,23 @@ const UserWelcomeTop = () => {
useEventEmitter(OwnProfileStore.instance, UPDATE_EVENT, () => { useEventEmitter(OwnProfileStore.instance, UPDATE_EVENT, () => {
setOwnProfile(getOwnProfile(userId)); setOwnProfile(getOwnProfile(userId));
}); });
const [busy, setBusy] = useState(false);
const uploadRef = useRef<HTMLInputElement>();
return <div> return <div>
<input <MiniAvatarUploader
type="file" hasAvatar={!!ownProfile.avatarUrl}
ref={uploadRef} hasAvatarLabel={_t("Great, that'll help people know it's you")}
className="mx_ProfileSettings_avatarUpload" noAvatarLabel={_t("Add a photo so people know it's you.")}
onChange={async (ev) => { setAvatarUrl={url => cli.setAvatarUrl(url)}
if (!ev.target.files?.length) return;
setBusy(true);
Analytics.trackEvent("home_page", "upload_avatar");
CountlyAnalytics.instance.track("home_page_upload_avatar");
const file = ev.target.files[0];
const uri = await cli.uploadContent(file);
await cli.setAvatarUrl(uri);
setBusy(false);
}}
accept="image/*"
/>
<AccessibleButton
className={classNames("mx_HomePage_userAvatar", {
mx_HomePage_userAvatar_busy: busy,
})}
disabled={busy}
onClick={() => {
uploadRef.current.click();
}}
> >
<BaseAvatar <BaseAvatar
idName={userId} idName={userId}
name={ownProfile.displayName} name={ownProfile.displayName}
url={ownProfile.avatarUrl} url={ownProfile.avatarUrl}
width={avatarSize} width={AVATAR_SIZE}
height={avatarSize} height={AVATAR_SIZE}
resizeMethod="crop" resizeMethod="crop"
/> />
</MiniAvatarUploader>
<Transition appear in timeout={3000}>
{state => (
<Tooltip
label={ownProfile.avatarUrl || busy
? _t("Great, that'll help people know it's you")
: _t("Add a photo so people know it's you.")}
visible={state !== ENTERING}
forceOnRight
/>
)}
</Transition>
</AccessibleButton>
<h1>{ _t("Welcome %(name)s", { name: ownProfile.displayName }) }</h1> <h1>{ _t("Welcome %(name)s", { name: ownProfile.displayName }) }</h1>
<h4>{ _t("Now, let's help you get started") }</h4> <h4>{ _t("Now, let's help you get started") }</h4>

View file

@ -21,7 +21,7 @@ import * as PropTypes from 'prop-types';
import { MatrixClient } from 'matrix-js-sdk/src/client'; import { MatrixClient } from 'matrix-js-sdk/src/client';
import { DragDropContext } from 'react-beautiful-dnd'; import { DragDropContext } from 'react-beautiful-dnd';
import {Key, isOnlyCtrlOrCmdKeyEvent, isOnlyCtrlOrCmdIgnoreShiftKeyEvent} from '../../Keyboard'; import {Key, isOnlyCtrlOrCmdKeyEvent, isOnlyCtrlOrCmdIgnoreShiftKeyEvent, isMac} from '../../Keyboard';
import PageTypes from '../../PageTypes'; import PageTypes from '../../PageTypes';
import CallMediaHandler from '../../CallMediaHandler'; import CallMediaHandler from '../../CallMediaHandler';
import { fixupColorFonts } from '../../utils/FontManager'; import { fixupColorFonts } from '../../utils/FontManager';
@ -52,6 +52,7 @@ import RoomListStore from "../../stores/room-list/RoomListStore";
import NonUrgentToastContainer from "./NonUrgentToastContainer"; import NonUrgentToastContainer from "./NonUrgentToastContainer";
import { ToggleRightPanelPayload } from "../../dispatcher/payloads/ToggleRightPanelPayload"; import { ToggleRightPanelPayload } from "../../dispatcher/payloads/ToggleRightPanelPayload";
import { IThreepidInvite } from "../../stores/ThreepidInviteStore"; import { IThreepidInvite } from "../../stores/ThreepidInviteStore";
import Modal from "../../Modal";
import { ICollapseConfig } from "../../resizer/distributors/collapse"; import { ICollapseConfig } from "../../resizer/distributors/collapse";
// We need to fetch each pinned message individually (if we don't already have it) // We need to fetch each pinned message individually (if we don't already have it)
@ -392,6 +393,7 @@ class LoggedInView extends React.Component<IProps, IState> {
const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev); const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
const hasModifier = ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey; const hasModifier = ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey;
const isModifier = ev.key === Key.ALT || ev.key === Key.CONTROL || ev.key === Key.META || ev.key === Key.SHIFT; const isModifier = ev.key === Key.ALT || ev.key === Key.CONTROL || ev.key === Key.META || ev.key === Key.SHIFT;
const modKey = isMac ? ev.metaKey : ev.ctrlKey;
switch (ev.key) { switch (ev.key) {
case Key.PAGE_UP: case Key.PAGE_UP:
@ -436,6 +438,16 @@ class LoggedInView extends React.Component<IProps, IState> {
} }
break; break;
case Key.H:
if (ev.altKey && modKey) {
dis.dispatch({
action: 'view_home_page',
});
Modal.closeCurrentModal("homeKeyboardShortcut");
handled = true;
}
break;
case Key.ARROW_UP: case Key.ARROW_UP:
case Key.ARROW_DOWN: case Key.ARROW_DOWN:
if (ev.altKey && !ev.ctrlKey && !ev.metaKey) { if (ev.altKey && !ev.ctrlKey && !ev.metaKey) {

View file

@ -87,38 +87,37 @@ import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
export enum Views { export enum Views {
// a special initial state which is only used at startup, while we are // a special initial state which is only used at startup, while we are
// trying to re-animate a matrix client or register as a guest. // trying to re-animate a matrix client or register as a guest.
LOADING = 0, LOADING,
// we are showing the welcome view // we are showing the welcome view
WELCOME = 1, WELCOME,
// we are showing the login view // we are showing the login view
LOGIN = 2, LOGIN,
// we are showing the registration view // we are showing the registration view
REGISTER = 3, REGISTER,
// completing the registration flow
POST_REGISTRATION = 4,
// showing the 'forgot password' view // showing the 'forgot password' view
FORGOT_PASSWORD = 5, FORGOT_PASSWORD,
// showing flow to trust this new device with cross-signing // showing flow to trust this new device with cross-signing
COMPLETE_SECURITY = 6, COMPLETE_SECURITY,
// flow to setup SSSS / cross-signing on this account // flow to setup SSSS / cross-signing on this account
E2E_SETUP = 7, E2E_SETUP,
// we are logged in with an active matrix client. The logged_in state also // we are logged in with an active matrix client. The logged_in state also
// includes guests users as they too are logged in at the client level. // includes guests users as they too are logged in at the client level.
LOGGED_IN = 8, LOGGED_IN,
// We are logged out (invalid token) but have our local state again. The user // We are logged out (invalid token) but have our local state again. The user
// should log back in to rehydrate the client. // should log back in to rehydrate the client.
SOFT_LOGOUT = 9, SOFT_LOGOUT,
} }
const AUTH_SCREENS = ["register", "login", "forgot_password", "start_sso", "start_cas"];
// Actions that are redirected through the onboarding process prior to being // Actions that are redirected through the onboarding process prior to being
// re-dispatched. NOTE: some actions are non-trivial and would require // re-dispatched. NOTE: some actions are non-trivial and would require
// re-factoring to be included in this list in future. // re-factoring to be included in this list in future.
@ -562,11 +561,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
ThemeController.isLogin = true; ThemeController.isLogin = true;
this.themeWatcher.recheck(); this.themeWatcher.recheck();
break; break;
case 'start_post_registration':
this.setState({
view: Views.POST_REGISTRATION,
});
break;
case 'start_password_recovery': case 'start_password_recovery':
this.setStateForNewView({ this.setStateForNewView({
view: Views.FORGOT_PASSWORD, view: Views.FORGOT_PASSWORD,
@ -653,8 +647,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
case Action.ViewRoomDirectory: { case Action.ViewRoomDirectory: {
const RoomDirectory = sdk.getComponent("structures.RoomDirectory"); const RoomDirectory = sdk.getComponent("structures.RoomDirectory");
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {}, Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
'mx_RoomDirectory_dialogWrapper', false, true); initialText: payload.initialText,
}, 'mx_RoomDirectory_dialogWrapper', false, true);
// View the welcome or home page if we need something to look at // View the welcome or home page if we need something to look at
this.viewSomethingBehindModal(); this.viewSomethingBehindModal();
@ -677,7 +672,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.chatCreateOrReuse(payload.user_id); this.chatCreateOrReuse(payload.user_id);
break; break;
case 'view_create_chat': case 'view_create_chat':
showStartChatInviteDialog(); showStartChatInviteDialog(payload.initialText || "");
break; break;
case 'view_invite': case 'view_invite':
showRoomInviteDialog(payload.roomId); showRoomInviteDialog(payload.roomId);
@ -1554,6 +1549,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
showScreen(screen: string, params?: {[key: string]: any}) { showScreen(screen: string, params?: {[key: string]: any}) {
const cli = MatrixClientPeg.get();
const isLoggedOutOrGuest = !cli || cli.isGuest();
if (!isLoggedOutOrGuest && AUTH_SCREENS.includes(screen)) {
// user is logged in and landing on an auth page which will uproot their session, redirect them home instead
dis.dispatch({ action: "view_home_page" });
return;
}
if (screen === 'register') { if (screen === 'register') {
dis.dispatch({ dis.dispatch({
action: 'start_registration', action: 'start_registration',
@ -1570,7 +1573,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
params: params, params: params,
}); });
} else if (screen === 'soft_logout') { } else if (screen === 'soft_logout') {
if (MatrixClientPeg.get() && MatrixClientPeg.get().getUserId() && !Lifecycle.isSoftLogout()) { if (cli.getUserId() && !Lifecycle.isSoftLogout()) {
// Logged in - visit a room // Logged in - visit a room
this.viewLastRoom(); this.viewLastRoom();
} else { } else {
@ -1621,14 +1624,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
dis.dispatch({ dis.dispatch({
action: 'view_my_groups', action: 'view_my_groups',
}); });
} else if (screen === 'complete_security') {
dis.dispatch({
action: 'start_complete_security',
});
} else if (screen === 'post_registration') {
dis.dispatch({
action: 'start_post_registration',
});
} else if (screen.indexOf('room/') === 0) { } else if (screen.indexOf('room/') === 0) {
// Rooms can have the following formats: // Rooms can have the following formats:
// #room_alias:domain or !opaque_id:domain // #room_alias:domain or !opaque_id:domain
@ -1799,14 +1794,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
return Lifecycle.setLoggedIn(credentials); return Lifecycle.setLoggedIn(credentials);
} }
onFinishPostRegistration = () => {
// Don't confuse this with "PageType" which is the middle window to show
this.setState({
view: Views.LOGGED_IN,
});
this.showScreen("settings");
};
onSendEvent(roomId: string, event: MatrixEvent) { onSendEvent(roomId: string, event: MatrixEvent) {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
if (!cli) { if (!cli) {
@ -1971,13 +1958,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
accountPassword={this.accountPassword} accountPassword={this.accountPassword}
/> />
); );
} else if (this.state.view === Views.POST_REGISTRATION) {
// needs to be before normal PageTypes as you are logged in technically
const PostRegistration = sdk.getComponent('structures.auth.PostRegistration');
view = (
<PostRegistration
onComplete={this.onFinishPostRegistration} />
);
} else if (this.state.view === Views.LOGGED_IN) { } else if (this.state.view === Views.LOGGED_IN) {
// store errors stop the client syncing and require user intervention, so we'll // store errors stop the client syncing and require user intervention, so we'll
// be showing a dialog. Don't show anything else. // be showing a dialog. Don't show anything else.

View file

@ -30,6 +30,8 @@ import {_t} from "../../languageHandler";
import {haveTileForEvent} from "../views/rooms/EventTile"; import {haveTileForEvent} from "../views/rooms/EventTile";
import {textForEvent} from "../../TextForEvent"; import {textForEvent} from "../../TextForEvent";
import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer"; import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer";
import DMRoomMap from "../../utils/DMRoomMap";
import NewRoomIntro from "../views/rooms/NewRoomIntro";
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const continuedTypes = ['m.sticker', 'm.room.message']; const continuedTypes = ['m.sticker', 'm.room.message'];
@ -952,15 +954,25 @@ class CreationGrouper {
}).reduce((a, b) => a.concat(b), []); }).reduce((a, b) => a.concat(b), []);
// Get sender profile from the latest event in the summary as the m.room.create doesn't contain one // Get sender profile from the latest event in the summary as the m.room.create doesn't contain one
const ev = this.events[this.events.length - 1]; const ev = this.events[this.events.length - 1];
let summaryText;
const roomId = ev.getRoomId();
const creator = ev.sender ? ev.sender.name : ev.getSender();
if (DMRoomMap.shared().getUserIdForRoomId(roomId)) {
summaryText = _t("%(creator)s created this DM.", { creator });
} else {
summaryText = _t("%(creator)s created and configured the room.", { creator });
}
ret.push(<NewRoomIntro key="newroomintro" />);
ret.push( ret.push(
<EventListSummary <EventListSummary
key="roomcreationsummary" key="roomcreationsummary"
events={this.events} events={this.events}
onToggle={panel._onHeightChanged} // Update scroll state onToggle={panel._onHeightChanged} // Update scroll state
summaryMembers={[ev.sender]} summaryMembers={[ev.sender]}
summaryText={_t("%(creator)s created and configured the room.", { summaryText={summaryText}
creator: ev.sender ? ev.sender.name : ev.getSender(),
})}
> >
{ eventTiles } { eventTiles }
</EventListSummary>, </EventListSummary>,

View file

@ -44,6 +44,7 @@ function track(action) {
export default class RoomDirectory extends React.Component { export default class RoomDirectory extends React.Component {
static propTypes = { static propTypes = {
initialText: PropTypes.string,
onFinished: PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,
}; };
@ -61,7 +62,7 @@ export default class RoomDirectory extends React.Component {
error: null, error: null,
instanceId: undefined, instanceId: undefined,
roomServer: MatrixClientPeg.getHomeserverName(), roomServer: MatrixClientPeg.getHomeserverName(),
filterString: null, filterString: this.props.initialText || "",
selectedCommunityId: SettingsStore.getValue("feature_communities_v2_prototypes") selectedCommunityId: SettingsStore.getValue("feature_communities_v2_prototypes")
? selectedCommunityId ? selectedCommunityId
: null, : null,
@ -686,6 +687,7 @@ export default class RoomDirectory extends React.Component {
onJoinClick={this.onJoinFromSearchClick} onJoinClick={this.onJoinFromSearchClick}
placeholder={placeholder} placeholder={placeholder}
showJoinButton={showJoinButton} showJoinButton={showJoinButton}
initialText={this.props.initialText}
/> />
{dropdown} {dropdown}
</div>; </div>;

View file

@ -148,7 +148,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
onBlur={this.onBlur} onBlur={this.onBlur}
onChange={this.onChange} onChange={this.onChange}
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
placeholder={_t("Search")} placeholder={_t("Filter")}
autoComplete="off" autoComplete="off"
/> />
); );
@ -164,7 +164,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
if (this.props.isMinimized) { if (this.props.isMinimized) {
icon = ( icon = (
<AccessibleButton <AccessibleButton
title={_t("Search rooms")} title={_t("Filter rooms and people")}
className="mx_RoomSearch_icon mx_RoomSearch_minimizedHandle" className="mx_RoomSearch_icon mx_RoomSearch_minimizedHandle"
onClick={this.openSearch} onClick={this.openSearch}
/> />

View file

@ -41,9 +41,6 @@ export default class RoomStatusBar extends React.Component {
static propTypes = { static propTypes = {
// the room this statusbar is representing. // the room this statusbar is representing.
room: PropTypes.object.isRequired, room: PropTypes.object.isRequired,
// This is true when the user is alone in the room, but has also sent a message.
// Used to suggest to the user to invite someone
sentMessageAndIsAlone: PropTypes.bool,
// The active call in the room, if any (means we show the call bar // The active call in the room, if any (means we show the call bar
// along with the status of the call) // along with the status of the call)
@ -68,10 +65,6 @@ export default class RoomStatusBar extends React.Component {
// 'you are alone' bar // 'you are alone' bar
onInviteClick: PropTypes.func, onInviteClick: PropTypes.func,
// callback for when the user clicks on the 'stop warning me' button in the
// 'you are alone' bar
onStopWarningClick: PropTypes.func,
// callback for when we do something that changes the size of the // callback for when we do something that changes the size of the
// status bar. This is used to trigger a re-layout in the parent // status bar. This is used to trigger a re-layout in the parent
// component. // component.
@ -159,10 +152,7 @@ export default class RoomStatusBar extends React.Component {
// changed - so we use '0' to indicate normal size, and other values to // changed - so we use '0' to indicate normal size, and other values to
// indicate other sizes. // indicate other sizes.
_getSize() { _getSize() {
if (this._shouldShowConnectionError() || if (this._shouldShowConnectionError() || this._showCallBar()) {
this._showCallBar() ||
this.props.sentMessageAndIsAlone
) {
return STATUS_BAR_EXPANDED; return STATUS_BAR_EXPANDED;
} else if (this.state.unsentMessages.length > 0) { } else if (this.state.unsentMessages.length > 0) {
return STATUS_BAR_EXPANDED_LARGE; return STATUS_BAR_EXPANDED_LARGE;
@ -325,24 +315,6 @@ export default class RoomStatusBar extends React.Component {
); );
} }
// If you're alone in the room, and have sent a message, suggest to invite someone
if (this.props.sentMessageAndIsAlone && !this.props.isPeeking) {
return (
<div className="mx_RoomStatusBar_isAlone">
{ _t("There's no one else here! Would you like to <inviteText>invite others</inviteText> " +
"or <nowarnText>stop warning about the empty room</nowarnText>?",
{},
{
'inviteText': (sub) =>
<a className="mx_RoomStatusBar_resend_link" key="invite" onClick={this.props.onInviteClick}>{ sub }</a>,
'nowarnText': (sub) =>
<a className="mx_RoomStatusBar_resend_link" key="nowarn" onClick={this.props.onStopWarningClick}>{ sub }</a>,
},
) }
</div>
);
}
return null; return null;
} }

View file

@ -71,7 +71,7 @@ import RoomHeader from "../views/rooms/RoomHeader";
import TintableSvg from "../views/elements/TintableSvg"; import TintableSvg from "../views/elements/TintableSvg";
import {XOR} from "../../@types/common"; import {XOR} from "../../@types/common";
import { IThreepidInvite } from "../../stores/ThreepidInviteStore"; import { IThreepidInvite } from "../../stores/ThreepidInviteStore";
import { CallState, CallType, MatrixCall } from "matrix-js-sdk/lib/webrtc/call"; import { CallState, CallType, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import WidgetStore from "../../stores/WidgetStore"; import WidgetStore from "../../stores/WidgetStore";
import {UPDATE_EVENT} from "../../stores/AsyncStore"; import {UPDATE_EVENT} from "../../stores/AsyncStore";
import Notifier from "../../Notifier"; import Notifier from "../../Notifier";
@ -150,7 +150,6 @@ export interface IState {
guestsCanJoin: boolean; guestsCanJoin: boolean;
canPeek: boolean; canPeek: boolean;
showApps: boolean; showApps: boolean;
isAlone: boolean;
isPeeking: boolean; isPeeking: boolean;
showingPinned: boolean; showingPinned: boolean;
showReadReceipts: boolean; showReadReceipts: boolean;
@ -223,7 +222,6 @@ export default class RoomView extends React.Component<IProps, IState> {
guestsCanJoin: false, guestsCanJoin: false,
canPeek: false, canPeek: false,
showApps: false, showApps: false,
isAlone: false,
isPeeking: false, isPeeking: false,
showingPinned: false, showingPinned: false,
showReadReceipts: true, showReadReceipts: true,
@ -705,9 +703,8 @@ export default class RoomView extends React.Component<IProps, IState> {
private onAction = payload => { private onAction = payload => {
switch (payload.action) { switch (payload.action) {
case 'message_send_failed':
case 'message_sent': case 'message_sent':
this.checkIfAlone(this.state.room); this.checkDesktopNotifications();
break; break;
case 'post_sticker_message': case 'post_sticker_message':
this.injectSticker( this.injectSticker(
@ -1025,36 +1022,15 @@ export default class RoomView extends React.Component<IProps, IState> {
} }
// rate limited because a power level change will emit an event for every member in the room. // rate limited because a power level change will emit an event for every member in the room.
private updateRoomMembers = rateLimitedFunc((dueToMember) => { private updateRoomMembers = rateLimitedFunc(() => {
this.updateDMState(); this.updateDMState();
let memberCountInfluence = 0;
if (dueToMember && dueToMember.membership === "invite" && this.state.room.getInvitedMemberCount() === 0) {
// A member got invited, but the room hasn't detected that change yet. Influence the member
// count by 1 to counteract this.
memberCountInfluence = 1;
}
this.checkIfAlone(this.state.room, memberCountInfluence);
this.updateE2EStatus(this.state.room); this.updateE2EStatus(this.state.room);
}, 500); }, 500);
private checkIfAlone(room: Room, countInfluence?: number) { private checkDesktopNotifications() {
let warnedAboutLonelyRoom = false; const memberCount = this.state.room.getJoinedMemberCount() + this.state.room.getInvitedMemberCount();
if (localStorage) { // if they are not alone prompt the user about notifications so they don't miss replies
warnedAboutLonelyRoom = Boolean(localStorage.getItem('mx_user_alone_warned_' + this.state.room.roomId)); if (memberCount > 1 && Notifier.shouldShowPrompt()) {
}
if (warnedAboutLonelyRoom) {
if (this.state.isAlone) this.setState({isAlone: false});
return;
}
let joinedOrInvitedMemberCount = room.getJoinedMemberCount() + room.getInvitedMemberCount();
if (countInfluence) joinedOrInvitedMemberCount += countInfluence;
this.setState({isAlone: joinedOrInvitedMemberCount === 1});
// if they are not alone additionally prompt the user about notifications so they don't miss replies
if (joinedOrInvitedMemberCount > 1 && Notifier.shouldShowPrompt()) {
showNotificationsToast(true); showNotificationsToast(true);
} }
} }
@ -1091,14 +1067,6 @@ export default class RoomView extends React.Component<IProps, IState> {
action: 'view_invite', action: 'view_invite',
roomId: this.state.room.roomId, roomId: this.state.room.roomId,
}); });
this.setState({isAlone: false}); // there's a good chance they'll invite someone
};
private onStopAloneWarningClick = () => {
if (localStorage) {
localStorage.setItem('mx_user_alone_warned_' + this.state.room.roomId, String(true));
}
this.setState({isAlone: false});
}; };
private onJoinButtonClicked = () => { private onJoinButtonClicked = () => {
@ -1147,16 +1115,9 @@ export default class RoomView extends React.Component<IProps, IState> {
ev.dataTransfer.dropEffect = 'none'; ev.dataTransfer.dropEffect = 'none';
const items = [...ev.dataTransfer.items]; if (ev.dataTransfer.types.includes("Files") || ev.dataTransfer.types.includes("application/x-moz-file")) {
if (items.length >= 1) { this.setState({ draggingFile: true });
const isDraggingFiles = items.every(function(item) { ev.dataTransfer.dropEffect = 'copy';
return item.kind == 'file';
});
if (isDraggingFiles) {
this.setState({ draggingFile: true });
ev.dataTransfer.dropEffect = 'copy';
}
} }
}; };
@ -1797,12 +1758,10 @@ export default class RoomView extends React.Component<IProps, IState> {
isStatusAreaExpanded = this.state.statusBarVisible; isStatusAreaExpanded = this.state.statusBarVisible;
statusBar = <RoomStatusBar statusBar = <RoomStatusBar
room={this.state.room} room={this.state.room}
sentMessageAndIsAlone={this.state.isAlone}
callState={this.state.callState} callState={this.state.callState}
callType={activeCall ? activeCall.type : null} callType={activeCall ? activeCall.type : null}
isPeeking={myMembership !== "join"} isPeeking={myMembership !== "join"}
onInviteClick={this.onInviteButtonClick} onInviteClick={this.onInviteButtonClick}
onStopWarningClick={this.onStopAloneWarningClick}
onVisible={this.onStatusBarVisible} onVisible={this.onStatusBarVisible}
onHidden={this.onStatusBarHidden} onHidden={this.onStatusBarHidden}
/>; />;

View file

@ -55,11 +55,11 @@ export default class ToastContainer extends React.Component<{}, IState> {
let toast; let toast;
if (totalCount !== 0) { if (totalCount !== 0) {
const topToast = this.state.toasts[0]; const topToast = this.state.toasts[0];
const {title, icon, key, component, props} = topToast; const {title, icon, key, component, className, props} = topToast;
const toastClasses = classNames("mx_Toast_toast", { const toastClasses = classNames("mx_Toast_toast", {
"mx_Toast_hasIcon": icon, "mx_Toast_hasIcon": icon,
[`mx_Toast_icon_${icon}`]: icon, [`mx_Toast_icon_${icon}`]: icon,
}); }, className);
let countIndicator; let countIndicator;
if (isStacked || this.state.countSeen > 0) { if (isStacked || this.state.countSeen > 0) {

View file

@ -190,11 +190,18 @@ export default class UserMenu extends React.Component<IProps, IState> {
this.setState({contextMenuPosition: null}); // also close the menu this.setState({contextMenuPosition: null}); // also close the menu
}; };
private onSignOutClick = (ev: ButtonEvent) => { private onSignOutClick = async (ev: ButtonEvent) => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
Modal.createTrackedDialog('Logout from LeftPanel', '', LogoutDialog); const cli = MatrixClientPeg.get();
if (!cli || !cli.isCryptoEnabled() || !(await cli.exportRoomKeys())?.length) {
// log out without user prompt if they have no local megolm sessions
dis.dispatch({action: 'logout'});
} else {
Modal.createTrackedDialog('Logout from LeftPanel', '', LogoutDialog);
}
this.setState({contextMenuPosition: null}); // also close the menu this.setState({contextMenuPosition: null}); // also close the menu
}; };
@ -203,6 +210,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
ev.stopPropagation(); ev.stopPropagation();
defaultDispatcher.dispatch({action: 'view_home_page'}); defaultDispatcher.dispatch({action: 'view_home_page'});
this.setState({contextMenuPosition: null}); // also close the menu
}; };
private onCommunitySettingsClick = (ev: ButtonEvent) => { private onCommunitySettingsClick = (ev: ButtonEvent) => {

View file

@ -1,77 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import AuthPage from "../../views/auth/AuthPage";
export default class PostRegistration extends React.Component {
static propTypes = {
onComplete: PropTypes.func.isRequired,
};
state = {
avatarUrl: null,
errorString: null,
busy: false,
};
componentDidMount() {
// There is some assymetry between ChangeDisplayName and ChangeAvatar,
// as ChangeDisplayName will auto-get the name but ChangeAvatar expects
// the URL to be passed to you (because it's also used for room avatars).
const cli = MatrixClientPeg.get();
this.setState({busy: true});
const self = this;
cli.getProfileInfo(cli.credentials.userId).then(function(result) {
self.setState({
avatarUrl: MatrixClientPeg.get().mxcUrlToHttp(result.avatar_url),
busy: false,
});
}, function(error) {
self.setState({
errorString: _t("Failed to fetch avatar URL"),
busy: false,
});
});
}
render() {
const ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
const AuthHeader = sdk.getComponent('auth.AuthHeader');
const AuthBody = sdk.getComponent("auth.AuthBody");
return (
<AuthPage>
<AuthHeader />
<AuthBody>
<div className="mx_Login_profile">
{ _t('Set a display name:') }
<ChangeDisplayName />
{ _t('Upload an avatar:') }
<ChangeAvatar
initialAvatarUrl={this.state.avatarUrl} />
<button onClick={this.props.onComplete}>{ _t('Continue') }</button>
{ this.state.errorString }
</div>
</AuthBody>
</AuthPage>
);
}
}

View file

@ -502,6 +502,11 @@ export default class Registration extends React.Component {
return null; return null;
} }
// Hide the server picker once the user is doing UI Auth unless encountered a fatal server error
if (this.state.phase !== PHASE_SERVER_DETAILS && this.state.doingUIAuth && !this.state.serverErrorIsFatal) {
return null;
}
// If we're on a different phase, we only show the server type selector, // If we're on a different phase, we only show the server type selector,
// which is always shown if we allow custom URLs at all. // which is always shown if we allow custom URLs at all.
// (if there's a fatal server error, we need to show the full server // (if there's a fatal server error, we need to show the full server
@ -582,17 +587,6 @@ export default class Registration extends React.Component {
<Spinner /> <Spinner />
</div>; </div>;
} else if (this.state.flows.length) { } else if (this.state.flows.length) {
let onEditServerDetailsClick = null;
// If custom URLs are allowed and we haven't selected the Free server type, wire
// up the server details edit link.
if (
PHASES_ENABLED &&
!SdkConfig.get()['disable_custom_urls'] &&
this.state.serverType !== ServerType.FREE
) {
onEditServerDetailsClick = this.onEditServerDetailsClick;
}
return <RegistrationForm return <RegistrationForm
defaultUsername={this.state.formVals.username} defaultUsername={this.state.formVals.username}
defaultEmail={this.state.formVals.email} defaultEmail={this.state.formVals.email}
@ -600,7 +594,6 @@ export default class Registration extends React.Component {
defaultPhoneNumber={this.state.formVals.phoneNumber} defaultPhoneNumber={this.state.formVals.phoneNumber}
defaultPassword={this.state.formVals.password} defaultPassword={this.state.formVals.password}
onRegisterClick={this.onFormSubmit} onRegisterClick={this.onFormSubmit}
onEditServerDetailsClick={onEditServerDetailsClick}
flows={this.state.flows} flows={this.state.flows}
serverConfig={this.props.serverConfig} serverConfig={this.props.serverConfig}
canSubmit={!this.state.serverErrorIsFatal} canSubmit={!this.state.serverErrorIsFatal}
@ -686,11 +679,48 @@ export default class Registration extends React.Component {
{ regDoneText } { regDoneText }
</div>; </div>;
} else { } else {
let yourMatrixAccountText = _t('Create your Matrix account on %(serverName)s', {
serverName: this.props.serverConfig.hsName,
});
if (this.props.serverConfig.hsNameIsDifferent) {
const TextWithTooltip = sdk.getComponent("elements.TextWithTooltip");
yourMatrixAccountText = _t('Create your Matrix account on <underlinedServerName />', {}, {
'underlinedServerName': () => {
return <TextWithTooltip
class="mx_Login_underlinedServerName"
tooltip={this.props.serverConfig.hsUrl}
>
{this.props.serverConfig.hsName}
</TextWithTooltip>;
},
});
}
// If custom URLs are allowed, user is not doing UIA flows and they haven't selected the Free server type,
// wire up the server details edit link.
let editLink = null;
if (PHASES_ENABLED &&
!SdkConfig.get()['disable_custom_urls'] &&
this.state.serverType !== ServerType.FREE &&
!this.state.doingUIAuth
) {
editLink = (
<a className="mx_AuthBody_editServerDetails" href="#" onClick={this.onEditServerDetailsClick}>
{_t('Change')}
</a>
);
}
body = <div> body = <div>
<h2>{ _t('Create your account') }</h2> <h2>{ _t('Create your account') }</h2>
{ errorText } { errorText }
{ serverDeadSection } { serverDeadSection }
{ this.renderServerComponent() } { this.renderServerComponent() }
{ this.state.phase !== PHASE_SERVER_DETAILS && <h3>
{yourMatrixAccountText}
{editLink}
</h3> }
{ this.renderRegisterComponent() } { this.renderRegisterComponent() }
{ goBack } { goBack }
{ signIn } { signIn }

View file

@ -102,6 +102,10 @@ export default class CaptchaForm extends React.Component {
console.log("Loaded recaptcha script."); console.log("Loaded recaptcha script.");
try { try {
this._renderRecaptcha(DIV_ID); this._renderRecaptcha(DIV_ID);
// clear error if re-rendered
this.setState({
errorText: null,
});
CountlyAnalytics.instance.track("onboarding_grecaptcha_loaded"); CountlyAnalytics.instance.track("onboarding_grecaptcha_loaded");
} catch (e) { } catch (e) {
this.setState({ this.setState({

View file

@ -421,12 +421,12 @@ export class EmailIdentityAuthEntry extends React.Component {
return <Spinner />; return <Spinner />;
} else { } else {
return ( return (
<div> <div className="mx_InteractiveAuthEntryComponents_emailWrapper">
<p>{ _t("An email has been sent to %(emailAddress)s", <p>{ _t("A confirmation email has been sent to %(emailAddress)s",
{ emailAddress: (sub) => <i>{ this.props.inputs.emailAddress }</i> }, { emailAddress: (sub) => <b>{ this.props.inputs.emailAddress }</b> },
) } ) }
</p> </p>
<p>{ _t("Please check your email to continue registration.") }</p> <p>{ _t("Open the link in the email to continue registration.") }</p>
</div> </div>
); );
} }

View file

@ -51,7 +51,6 @@ export default class RegistrationForm extends React.Component {
defaultUsername: PropTypes.string, defaultUsername: PropTypes.string,
defaultPassword: PropTypes.string, defaultPassword: PropTypes.string,
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
onEditServerDetailsClick: PropTypes.func,
flows: PropTypes.arrayOf(PropTypes.object).isRequired, flows: PropTypes.arrayOf(PropTypes.object).isRequired,
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired, serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
canSubmit: PropTypes.bool, canSubmit: PropTypes.bool,
@ -250,6 +249,7 @@ export default class RegistrationForm extends React.Component {
validateEmailRules = withValidation({ validateEmailRules = withValidation({
description: () => _t("Use an email address to recover your account"), description: () => _t("Use an email address to recover your account"),
hideDescriptionIfValid: true,
rules: [ rules: [
{ {
key: "required", key: "required",
@ -326,6 +326,7 @@ export default class RegistrationForm extends React.Component {
validatePhoneNumberRules = withValidation({ validatePhoneNumberRules = withValidation({
description: () => _t("Other users can invite you to rooms using your contact details"), description: () => _t("Other users can invite you to rooms using your contact details"),
hideDescriptionIfValid: true,
rules: [ rules: [
{ {
key: "required", key: "required",
@ -356,6 +357,7 @@ export default class RegistrationForm extends React.Component {
validateUsernameRules = withValidation({ validateUsernameRules = withValidation({
description: () => _t("Use lowercase letters, numbers, dashes and underscores only"), description: () => _t("Use lowercase letters, numbers, dashes and underscores only"),
hideDescriptionIfValid: true,
rules: [ rules: [
{ {
key: "required", key: "required",
@ -458,7 +460,7 @@ export default class RegistrationForm extends React.Component {
ref={field => this[FIELD_PASSWORD_CONFIRM] = field} ref={field => this[FIELD_PASSWORD_CONFIRM] = field}
type="password" type="password"
autoComplete="new-password" autoComplete="new-password"
label={_t("Confirm")} label={_t("Confirm password")}
value={this.state.passwordConfirm} value={this.state.passwordConfirm}
onChange={this.onPasswordConfirmChange} onChange={this.onPasswordConfirmChange}
onValidate={this.onPasswordConfirmValidate} onValidate={this.onPasswordConfirmValidate}
@ -510,33 +512,6 @@ export default class RegistrationForm extends React.Component {
} }
render() { render() {
let yourMatrixAccountText = _t('Create your Matrix account on %(serverName)s', {
serverName: this.props.serverConfig.hsName,
});
if (this.props.serverConfig.hsNameIsDifferent) {
const TextWithTooltip = sdk.getComponent("elements.TextWithTooltip");
yourMatrixAccountText = _t('Create your Matrix account on <underlinedServerName />', {}, {
'underlinedServerName': () => {
return <TextWithTooltip
class="mx_Login_underlinedServerName"
tooltip={this.props.serverConfig.hsUrl}
>
{this.props.serverConfig.hsName}
</TextWithTooltip>;
},
});
}
let editLink = null;
if (this.props.onEditServerDetailsClick) {
editLink = <a className="mx_AuthBody_editServerDetails"
href="#" onClick={this.props.onEditServerDetailsClick}
>
{_t('Change')}
</a>;
}
const registerButton = ( const registerButton = (
<input className="mx_Login_submit" type="submit" value={_t("Register")} disabled={!this.props.canSubmit} /> <input className="mx_Login_submit" type="submit" value={_t("Register")} disabled={!this.props.canSubmit} />
); );
@ -572,10 +547,6 @@ export default class RegistrationForm extends React.Component {
return ( return (
<div> <div>
<h3>
{yourMatrixAccountText}
{editLink}
</h3>
<form onSubmit={this.onSubmit}> <form onSubmit={this.onSubmit}>
<div className="mx_AuthBody_fieldRow"> <div className="mx_AuthBody_fieldRow">
{this.renderUsername()} {this.renderUsername()}

View file

@ -51,7 +51,8 @@ const calculateUrls = (url, urls) => {
_urls = urls || []; _urls = urls || [];
if (url) { if (url) {
_urls.unshift(url); // put in urls[0] // copy urls and put url first
_urls = [url, ..._urls];
} }
} }

View file

@ -35,6 +35,7 @@ interface IProps {
height?: number; height?: number;
resizeMethod?: ResizeMethod; resizeMethod?: ResizeMethod;
viewAvatarOnClick?: boolean; viewAvatarOnClick?: boolean;
onClick?(): void;
} }
interface IState { interface IState {
@ -130,7 +131,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
}; };
public render() { public render() {
const {room, oobData, viewAvatarOnClick, ...otherProps} = this.props; const {room, oobData, viewAvatarOnClick, onClick, ...otherProps} = this.props;
const roomName = room ? room.name : oobData.name; const roomName = room ? room.name : oobData.name;
@ -139,7 +140,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
name={roomName} name={roomName}
idName={room ? room.roomId : null} idName={room ? room.roomId : null}
urls={this.state.urls} urls={this.state.urls}
onClick={viewAvatarOnClick && this.state.urls[0] ? this.onRoomAvatarClick : null} onClick={viewAvatarOnClick && this.state.urls[0] ? this.onRoomAvatarClick : onClick}
/> />
); );
} }

View file

@ -48,8 +48,8 @@ export default (props) => {
title: _t('Feedback sent'), title: _t('Feedback sent'),
description: _t('Thank you!'), description: _t('Thank you!'),
}); });
props.onFinished();
} }
props.onFinished();
}; };
const brand = SdkConfig.get().brand; const brand = SdkConfig.get().brand;

View file

@ -31,7 +31,7 @@ import dis from "../../../dispatcher/dispatcher";
import IdentityAuthClient from "../../../IdentityAuthClient"; import IdentityAuthClient from "../../../IdentityAuthClient";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import {humanizeTime} from "../../../utils/humanize"; import {humanizeTime} from "../../../utils/humanize";
import createRoom, {canEncryptToAllUsers, privateShouldBeEncrypted} from "../../../createRoom"; import createRoom, {canEncryptToAllUsers, findDMForUser, privateShouldBeEncrypted} from "../../../createRoom";
import {inviteMultipleToRoom, showCommunityInviteDialog} from "../../../RoomInvite"; import {inviteMultipleToRoom, showCommunityInviteDialog} from "../../../RoomInvite";
import {Key} from "../../../Keyboard"; import {Key} from "../../../Keyboard";
import {Action} from "../../../dispatcher/actions"; import {Action} from "../../../dispatcher/actions";
@ -41,6 +41,7 @@ import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import {UIFeature} from "../../../settings/UIFeature"; import {UIFeature} from "../../../settings/UIFeature";
import CountlyAnalytics from "../../../CountlyAnalytics"; import CountlyAnalytics from "../../../CountlyAnalytics";
import {Room} from "matrix-js-sdk/src/models/room";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here. // we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */ /* eslint-disable camelcase */
@ -308,10 +309,14 @@ export default class InviteDialog extends React.PureComponent {
// The room ID this dialog is for. Only required for KIND_INVITE. // The room ID this dialog is for. Only required for KIND_INVITE.
roomId: PropTypes.string, roomId: PropTypes.string,
// Initial value to populate the filter with
initialText: PropTypes.string,
}; };
static defaultProps = { static defaultProps = {
kind: KIND_DM, kind: KIND_DM,
initialText: "",
}; };
_debounceTimer: number = null; _debounceTimer: number = null;
@ -338,7 +343,7 @@ export default class InviteDialog extends React.PureComponent {
this.state = { this.state = {
targets: [], // array of Member objects (see interface above) targets: [], // array of Member objects (see interface above)
filterText: "", filterText: this.props.initialText,
recents: InviteDialog.buildRecents(alreadyInvited), recents: InviteDialog.buildRecents(alreadyInvited),
numRecentsShown: INITIAL_ROOMS_SHOWN, numRecentsShown: INITIAL_ROOMS_SHOWN,
suggestions: this._buildSuggestions(alreadyInvited), suggestions: this._buildSuggestions(alreadyInvited),
@ -356,6 +361,12 @@ export default class InviteDialog extends React.PureComponent {
this._editorRef = createRef(); this._editorRef = createRef();
} }
componentDidMount() {
if (this.props.initialText) {
this._updateSuggestions(this.props.initialText);
}
}
static buildRecents(excludedTargetIds: Set<string>): {userId: string, user: RoomMember, lastActive: number} { static buildRecents(excludedTargetIds: Set<string>): {userId: string, user: RoomMember, lastActive: number} {
const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals(); // map of userId => js-sdk Room const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals(); // map of userId => js-sdk Room
@ -575,7 +586,12 @@ export default class InviteDialog extends React.PureComponent {
const targetIds = targets.map(t => t.userId); const targetIds = targets.map(t => t.userId);
// Check if there is already a DM with these people and reuse it if possible. // Check if there is already a DM with these people and reuse it if possible.
const existingRoom = DMRoomMap.shared().getDMRoomForIdentifiers(targetIds); let existingRoom: Room;
if (targetIds.length === 1) {
existingRoom = findDMForUser(MatrixClientPeg.get(), targetIds[0]);
} else {
existingRoom = DMRoomMap.shared().getDMRoomForIdentifiers(targetIds);
}
if (existingRoom) { if (existingRoom) {
dis.dispatch({ dis.dispatch({
action: 'view_room', action: 'view_room',
@ -687,6 +703,115 @@ export default class InviteDialog extends React.PureComponent {
} }
}; };
_updateSuggestions = async (term) => {
MatrixClientPeg.get().searchUserDirectory({term}).then(async r => {
if (term !== this.state.filterText) {
// Discard the results - we were probably too slow on the server-side to make
// these results useful. This is a race we want to avoid because we could overwrite
// more accurate results.
return;
}
if (!r.results) r.results = [];
// While we're here, try and autocomplete a search result for the mxid itself
// if there's no matches (and the input looks like a mxid).
if (term[0] === '@' && term.indexOf(':') > 1) {
try {
const profile = await MatrixClientPeg.get().getProfileInfo(term);
if (profile) {
// If we have a profile, we have enough information to assume that
// the mxid can be invited - add it to the list. We stick it at the
// top so it is most obviously presented to the user.
r.results.splice(0, 0, {
user_id: term,
display_name: profile['displayname'],
avatar_url: profile['avatar_url'],
});
}
} catch (e) {
console.warn("Non-fatal error trying to make an invite for a user ID");
console.warn(e);
// Add a result anyways, just without a profile. We stick it at the
// top so it is most obviously presented to the user.
r.results.splice(0, 0, {
user_id: term,
display_name: term,
avatar_url: null,
});
}
}
this.setState({
serverResultsMixin: r.results.map(u => ({
userId: u.user_id,
user: new DirectoryMember(u),
})),
});
}).catch(e => {
console.error("Error searching user directory:");
console.error(e);
this.setState({serverResultsMixin: []}); // clear results because it's moderately fatal
});
// Whenever we search the directory, also try to search the identity server. It's
// all debounced the same anyways.
if (!this.state.canUseIdentityServer) {
// The user doesn't have an identity server set - warn them of that.
this.setState({tryingIdentityServer: true});
return;
}
if (term.indexOf('@') > 0 && Email.looksValid(term) && SettingsStore.getValue(UIFeature.IdentityServer)) {
// Start off by suggesting the plain email while we try and resolve it
// to a real account.
this.setState({
// per above: the userId is a lie here - it's just a regular identifier
threepidResultsMixin: [{user: new ThreepidMember(term), userId: term}],
});
try {
const authClient = new IdentityAuthClient();
const token = await authClient.getAccessToken();
if (term !== this.state.filterText) return; // abandon hope
const lookup = await MatrixClientPeg.get().lookupThreePid(
'email',
term,
undefined, // callback
token,
);
if (term !== this.state.filterText) return; // abandon hope
if (!lookup || !lookup.mxid) {
// We weren't able to find anyone - we're already suggesting the plain email
// as an alternative, so do nothing.
return;
}
// We append the user suggestion to give the user an option to click
// the email anyways, and so we don't cause things to jump around. In
// theory, the user would see the user pop up and think "ah yes, that
// person!"
const profile = await MatrixClientPeg.get().getProfileInfo(lookup.mxid);
if (term !== this.state.filterText || !profile) return; // abandon hope
this.setState({
threepidResultsMixin: [...this.state.threepidResultsMixin, {
user: new DirectoryMember({
user_id: lookup.mxid,
display_name: profile.displayname,
avatar_url: profile.avatar_url,
}),
userId: lookup.mxid,
}],
});
} catch (e) {
console.error("Error searching identity server:");
console.error(e);
this.setState({threepidResultsMixin: []}); // clear results because it's moderately fatal
}
}
};
_updateFilter = (e) => { _updateFilter = (e) => {
const term = e.target.value; const term = e.target.value;
this.setState({filterText: term}); this.setState({filterText: term});
@ -697,113 +822,8 @@ export default class InviteDialog extends React.PureComponent {
if (this._debounceTimer) { if (this._debounceTimer) {
clearTimeout(this._debounceTimer); clearTimeout(this._debounceTimer);
} }
this._debounceTimer = setTimeout(async () => { this._debounceTimer = setTimeout(() => {
MatrixClientPeg.get().searchUserDirectory({term}).then(async r => { this._updateSuggestions(term);
if (term !== this.state.filterText) {
// Discard the results - we were probably too slow on the server-side to make
// these results useful. This is a race we want to avoid because we could overwrite
// more accurate results.
return;
}
if (!r.results) r.results = [];
// While we're here, try and autocomplete a search result for the mxid itself
// if there's no matches (and the input looks like a mxid).
if (term[0] === '@' && term.indexOf(':') > 1) {
try {
const profile = await MatrixClientPeg.get().getProfileInfo(term);
if (profile) {
// If we have a profile, we have enough information to assume that
// the mxid can be invited - add it to the list. We stick it at the
// top so it is most obviously presented to the user.
r.results.splice(0, 0, {
user_id: term,
display_name: profile['displayname'],
avatar_url: profile['avatar_url'],
});
}
} catch (e) {
console.warn("Non-fatal error trying to make an invite for a user ID");
console.warn(e);
// Add a result anyways, just without a profile. We stick it at the
// top so it is most obviously presented to the user.
r.results.splice(0, 0, {
user_id: term,
display_name: term,
avatar_url: null,
});
}
}
this.setState({
serverResultsMixin: r.results.map(u => ({
userId: u.user_id,
user: new DirectoryMember(u),
})),
});
}).catch(e => {
console.error("Error searching user directory:");
console.error(e);
this.setState({serverResultsMixin: []}); // clear results because it's moderately fatal
});
// Whenever we search the directory, also try to search the identity server. It's
// all debounced the same anyways.
if (!this.state.canUseIdentityServer) {
// The user doesn't have an identity server set - warn them of that.
this.setState({tryingIdentityServer: true});
return;
}
if (term.indexOf('@') > 0 && Email.looksValid(term) && SettingsStore.getValue(UIFeature.IdentityServer)) {
// Start off by suggesting the plain email while we try and resolve it
// to a real account.
this.setState({
// per above: the userId is a lie here - it's just a regular identifier
threepidResultsMixin: [{user: new ThreepidMember(term), userId: term}],
});
try {
const authClient = new IdentityAuthClient();
const token = await authClient.getAccessToken();
if (term !== this.state.filterText) return; // abandon hope
const lookup = await MatrixClientPeg.get().lookupThreePid(
'email',
term,
undefined, // callback
token,
);
if (term !== this.state.filterText) return; // abandon hope
if (!lookup || !lookup.mxid) {
// We weren't able to find anyone - we're already suggesting the plain email
// as an alternative, so do nothing.
return;
}
// We append the user suggestion to give the user an option to click
// the email anyways, and so we don't cause things to jump around. In
// theory, the user would see the user pop up and think "ah yes, that
// person!"
const profile = await MatrixClientPeg.get().getProfileInfo(lookup.mxid);
if (term !== this.state.filterText || !profile) return; // abandon hope
this.setState({
threepidResultsMixin: [...this.state.threepidResultsMixin, {
user: new DirectoryMember({
user_id: lookup.mxid,
display_name: profile.displayname,
avatar_url: profile.avatar_url,
}),
userId: lookup.mxid,
}],
});
} catch (e) {
console.error("Error searching identity server:");
console.error(e);
this.setState({threepidResultsMixin: []}); // clear results because it's moderately fatal
}
}
}, 150); // 150ms debounce (human reaction time + some) }, 150); // 150ms debounce (human reaction time + some)
}; };

View file

@ -23,6 +23,11 @@ import {
IModalWidgetCloseRequest, IModalWidgetCloseRequest,
IModalWidgetOpenRequestData, IModalWidgetOpenRequestData,
IModalWidgetReturnData, IModalWidgetReturnData,
ISetModalButtonEnabledActionRequest,
IWidgetApiAcknowledgeResponseData,
IWidgetApiErrorResponseData,
BuiltInModalButtonID,
ModalButtonID,
ModalButtonKind, ModalButtonKind,
Widget, Widget,
WidgetApiFromWidgetAction, WidgetApiFromWidgetAction,
@ -31,6 +36,7 @@ import {StopGapWidgetDriver} from "../../../stores/widgets/StopGapWidgetDriver";
import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {MatrixClientPeg} from "../../../MatrixClientPeg";
import RoomViewStore from "../../../stores/RoomViewStore"; import RoomViewStore from "../../../stores/RoomViewStore";
import {OwnProfileStore} from "../../../stores/OwnProfileStore"; import {OwnProfileStore} from "../../../stores/OwnProfileStore";
import { arrayFastClone } from "../../../utils/arrays";
interface IProps { interface IProps {
widgetDefinition: IModalWidgetOpenRequestData; widgetDefinition: IModalWidgetOpenRequestData;
@ -40,15 +46,19 @@ interface IProps {
interface IState { interface IState {
messaging?: ClientWidgetApi; messaging?: ClientWidgetApi;
disabledButtonIds: ModalButtonID[];
} }
const MAX_BUTTONS = 3; const MAX_BUTTONS = 3;
export default class ModalWidgetDialog extends React.PureComponent<IProps, IState> { export default class ModalWidgetDialog extends React.PureComponent<IProps, IState> {
private readonly widget: Widget; private readonly widget: Widget;
private readonly possibleButtons: ModalButtonID[];
private appFrame: React.RefObject<HTMLIFrameElement> = React.createRef(); private appFrame: React.RefObject<HTMLIFrameElement> = React.createRef();
state: IState = {}; state: IState = {
disabledButtonIds: [],
};
constructor(props) { constructor(props) {
super(props); super(props);
@ -58,6 +68,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
creatorUserId: MatrixClientPeg.get().getUserId(), creatorUserId: MatrixClientPeg.get().getUserId(),
id: `modal_${this.props.sourceWidgetId}`, id: `modal_${this.props.sourceWidgetId}`,
}); });
this.possibleButtons = (this.props.widgetDefinition.buttons || []).map(b => b.id);
} }
public componentDidMount() { public componentDidMount() {
@ -79,12 +90,35 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
private onLoad = () => { private onLoad = () => {
this.state.messaging.once("ready", this.onReady); this.state.messaging.once("ready", this.onReady);
this.state.messaging.on(`action:${WidgetApiFromWidgetAction.CloseModalWidget}`, this.onWidgetClose); this.state.messaging.on(`action:${WidgetApiFromWidgetAction.CloseModalWidget}`, this.onWidgetClose);
this.state.messaging.on(`action:${WidgetApiFromWidgetAction.SetModalButtonEnabled}`, this.onButtonEnableToggle);
}; };
private onWidgetClose = (ev: CustomEvent<IModalWidgetCloseRequest>) => { private onWidgetClose = (ev: CustomEvent<IModalWidgetCloseRequest>) => {
this.props.onFinished(true, ev.detail.data); this.props.onFinished(true, ev.detail.data);
} }
private onButtonEnableToggle = (ev: CustomEvent<ISetModalButtonEnabledActionRequest>) => {
ev.preventDefault();
const isClose = ev.detail.data.button === BuiltInModalButtonID.Close;
if (isClose || !this.possibleButtons.includes(ev.detail.data.button)) {
return this.state.messaging.transport.reply(ev.detail, {
error: {message: "Invalid button"},
} as IWidgetApiErrorResponseData);
}
let buttonIds: ModalButtonID[];
if (ev.detail.data.enabled) {
buttonIds = arrayFastClone(this.state.disabledButtonIds).filter(i => i !== ev.detail.data.button);
} else {
// use a set to swap the operation to avoid memory leaky arrays.
const tempSet = new Set(this.state.disabledButtonIds);
tempSet.add(ev.detail.data.button);
buttonIds = Array.from(tempSet);
}
this.setState({disabledButtonIds: buttonIds});
this.state.messaging.transport.reply(ev.detail, {} as IWidgetApiAcknowledgeResponseData);
};
public render() { public render() {
const templated = this.widget.getCompleteUrl({ const templated = this.widget.getCompleteUrl({
currentRoomId: RoomViewStore.getRoomId(), currentRoomId: RoomViewStore.getRoomId(),

View file

@ -39,7 +39,7 @@ interface IProps extends React.InputHTMLAttributes<Element> {
tabIndex?: number; tabIndex?: number;
disabled?: boolean; disabled?: boolean;
className?: string; className?: string;
onClick?(e?: ButtonEvent): void; onClick(e?: ButtonEvent): void;
} }
interface IAccessibleButtonProps extends React.InputHTMLAttributes<Element> { interface IAccessibleButtonProps extends React.InputHTMLAttributes<Element> {

View file

@ -20,8 +20,8 @@ import * as sdk from '../../../index';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
export default class DirectorySearchBox extends React.Component { export default class DirectorySearchBox extends React.Component {
constructor() { constructor(props) {
super(); super(props);
this._collectInput = this._collectInput.bind(this); this._collectInput = this._collectInput.bind(this);
this._onClearClick = this._onClearClick.bind(this); this._onClearClick = this._onClearClick.bind(this);
this._onChange = this._onChange.bind(this); this._onChange = this._onChange.bind(this);
@ -31,7 +31,7 @@ export default class DirectorySearchBox extends React.Component {
this.input = null; this.input = null;
this.state = { this.state = {
value: '', value: this.props.initialText || '',
}; };
} }
@ -90,15 +90,20 @@ export default class DirectorySearchBox extends React.Component {
} }
return <div className={`mx_DirectorySearchBox ${this.props.className} mx_textinput`}> return <div className={`mx_DirectorySearchBox ${this.props.className} mx_textinput`}>
<input type="text" name="dirsearch" value={this.state.value} <input
className="mx_textinput_icon mx_textinput_search" type="text"
ref={this._collectInput} name="dirsearch"
onChange={this._onChange} onKeyUp={this._onKeyUp} value={this.state.value}
placeholder={this.props.placeholder} autoFocus className="mx_textinput_icon mx_textinput_search"
/> ref={this._collectInput}
{ joinButton } onChange={this._onChange}
<AccessibleButton className="mx_DirectorySearchBox_clear" onClick={this._onClearClick}></AccessibleButton> onKeyUp={this._onKeyUp}
</div>; placeholder={this.props.placeholder}
autoFocus
/>
{ joinButton }
<AccessibleButton className="mx_DirectorySearchBox_clear" onClick={this._onClearClick} />
</div>;
} }
} }
@ -109,4 +114,5 @@ DirectorySearchBox.propTypes = {
onJoinClick: PropTypes.func, onJoinClick: PropTypes.func,
placeholder: PropTypes.string, placeholder: PropTypes.string,
showJoinButton: PropTypes.bool, showJoinButton: PropTypes.bool,
initialText: PropTypes.string,
}; };

View file

@ -1,34 +0,0 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import AccessibleButton from "./AccessibleButton";
export default function IconButton(props) {
const {icon, className, ...restProps} = props;
let newClassName = (className || "") + " mx_IconButton";
newClassName = newClassName + " mx_IconButton_icon_" + icon;
const allProps = Object.assign({}, restProps, {className: newClassName});
return React.createElement(AccessibleButton, allProps);
}
IconButton.propTypes = Object.assign({
icon: PropTypes.string,
}, AccessibleButton.propTypes);

View file

@ -0,0 +1,90 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {useContext, useRef, useState} from 'react';
import classNames from 'classnames';
import AccessibleButton from "./AccessibleButton";
import Tooltip from './Tooltip';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {useTimeout} from "../../../hooks/useTimeout";
export const AVATAR_SIZE = 52;
interface IProps {
hasAvatar: boolean;
noAvatarLabel?: string;
hasAvatarLabel?: string;
setAvatarUrl(url: string): Promise<void>;
}
const MiniAvatarUploader: React.FC<IProps> = ({ hasAvatar, hasAvatarLabel, noAvatarLabel, setAvatarUrl, children }) => {
const cli = useContext(MatrixClientContext);
const [busy, setBusy] = useState(false);
const [hover, setHover] = useState(false);
const [show, setShow] = useState(false);
useTimeout(() => {
setShow(true);
}, 3000); // show after 3 seconds
useTimeout(() => {
setShow(false);
}, 13000); // hide after being shown for 10 seconds
const uploadRef = useRef<HTMLInputElement>();
const label = (hasAvatar || busy) ? hasAvatarLabel : noAvatarLabel;
return <React.Fragment>
<input
type="file"
ref={uploadRef}
className="mx_MiniAvatarUploader_input"
onChange={async (ev) => {
if (!ev.target.files?.length) return;
setBusy(true);
const file = ev.target.files[0];
const uri = await cli.uploadContent(file);
await setAvatarUrl(uri);
setBusy(false);
}}
accept="image/*"
/>
<AccessibleButton
className={classNames("mx_MiniAvatarUploader", {
mx_MiniAvatarUploader_busy: busy,
mx_MiniAvatarUploader_hasAvatar: hasAvatar,
})}
disabled={busy}
onClick={() => {
uploadRef.current.click();
}}
onMouseOver={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{ children }
<Tooltip
label={label}
visible={!!label && (hover || show)}
forceOnRight
/>
</AccessibleButton>
</React.Fragment>;
};
export default MiniAvatarUploader;

View file

@ -33,6 +33,7 @@ interface IRule<T, D = void> {
interface IArgs<T, D = void> { interface IArgs<T, D = void> {
rules: IRule<T, D>[]; rules: IRule<T, D>[];
description(this: T, derivedData: D): React.ReactChild; description(this: T, derivedData: D): React.ReactChild;
hideDescriptionIfValid?: boolean;
deriveData?(data: Data): Promise<D>; deriveData?(data: Data): Promise<D>;
} }
@ -54,6 +55,8 @@ export interface IValidationResult {
* @param {Function} description * @param {Function} description
* Function that returns a string summary of the kind of value that will * Function that returns a string summary of the kind of value that will
* meet the validation rules. Shown at the top of the validation feedback. * meet the validation rules. Shown at the top of the validation feedback.
* @param {Boolean} hideDescriptionIfValid
* If true, don't show the description if the validation passes validation.
* @param {Function} deriveData * @param {Function} deriveData
* Optional function that returns a Promise to an object of generic type D. * Optional function that returns a Promise to an object of generic type D.
* The result of this Promise is passed to rule methods `skip`, `test`, `valid`, and `invalid`. * The result of this Promise is passed to rule methods `skip`, `test`, `valid`, and `invalid`.
@ -71,7 +74,9 @@ export interface IValidationResult {
* A validation function that takes in the current input value and returns * A validation function that takes in the current input value and returns
* the overall validity and a feedback UI that can be rendered for more detail. * the overall validity and a feedback UI that can be rendered for more detail.
*/ */
export default function withValidation<T = undefined, D = void>({ description, deriveData, rules }: IArgs<T, D>) { export default function withValidation<T = undefined, D = void>({
description, hideDescriptionIfValid, deriveData, rules,
}: IArgs<T, D>) {
return async function onValidate({ value, focused, allowEmpty = true }: IFieldState): Promise<IValidationResult> { return async function onValidate({ value, focused, allowEmpty = true }: IFieldState): Promise<IValidationResult> {
if (!value && allowEmpty) { if (!value && allowEmpty) {
return { return {
@ -156,7 +161,7 @@ export default function withValidation<T = undefined, D = void>({ description, d
} }
let summary; let summary;
if (description) { if (description && (details || !hideDescriptionIfValid)) {
// We're setting `this` to whichever component holds the validation // We're setting `this` to whichever component holds the validation
// function. That allows rules to access the state of the component. // function. That allows rules to access the state of the component.
const content = description.call(this, derivedData); const content = description.call(this, derivedData);

View file

@ -1,63 +0,0 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
export default class EncryptionEvent extends React.Component {
render() {
const {mxEvent} = this.props;
let body;
let classes = "mx_EventTile_bubble mx_cryptoEvent mx_cryptoEvent_icon";
const isRoomEncrypted = MatrixClientPeg.get().isRoomEncrypted(mxEvent.getRoomId());
if (mxEvent.getContent().algorithm === 'm.megolm.v1.aes-sha2' && isRoomEncrypted) {
body = <div>
<div className="mx_cryptoEvent_title">{_t("Encryption enabled")}</div>
<div className="mx_cryptoEvent_subtitle">
{_t(
"Messages in this room are end-to-end encrypted. " +
"Learn more & verify this user in their user profile.",
)}
</div>
</div>;
} else if (isRoomEncrypted) {
body = <div>
<div className="mx_cryptoEvent_title">{_t("Encryption enabled")}</div>
<div className="mx_cryptoEvent_subtitle">
{_t("Ignored attempt to disable encryption")}
</div>
</div>;
} else {
body = <div>
<div className="mx_cryptoEvent_title">{_t("Encryption not enabled")}</div>
<div className="mx_cryptoEvent_subtitle">{_t("The encryption used by this room isn't supported.")}</div>
</div>;
classes += " mx_cryptoEvent_icon_warning";
}
return (<div className={classes}>
{body}
</div>);
}
}
EncryptionEvent.propTypes = {
/* the MatrixEvent to show */
mxEvent: PropTypes.object.isRequired,
};

View file

@ -0,0 +1,68 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {forwardRef, useContext} from 'react';
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import EventTileBubble from "./EventTileBubble";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import DMRoomMap from "../../../utils/DMRoomMap";
interface IProps {
mxEvent: MatrixEvent;
}
const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({mxEvent}, ref) => {
const cli = useContext(MatrixClientContext);
const roomId = mxEvent.getRoomId();
const isRoomEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
if (mxEvent.getContent().algorithm === 'm.megolm.v1.aes-sha2' && isRoomEncrypted) {
let subtitle: string;
const dmPartner = DMRoomMap.shared().getUserIdForRoomId(roomId);
if (dmPartner) {
const displayName = cli?.getRoom(roomId)?.getMember(dmPartner)?.rawDisplayName || dmPartner;
subtitle = _t("Messages here are end-to-end encrypted. " +
"Verify %(displayName)s in their profile - tap on their avatar.", { displayName });
} else {
subtitle = _t("Messages in this room are end-to-end encrypted. " +
"When people join, you can verify them in their profile, just tap on their avatar.");
}
return <EventTileBubble
className="mx_cryptoEvent mx_cryptoEvent_icon"
title={_t("Encryption enabled")}
subtitle={subtitle}
/>;
} else if (isRoomEncrypted) {
return <EventTileBubble
className="mx_cryptoEvent mx_cryptoEvent_icon"
title={_t("Encryption enabled")}
subtitle={_t("Ignored attempt to disable encryption")}
/>;
}
return <EventTileBubble
className="mx_cryptoEvent mx_cryptoEvent_icon mx_cryptoEvent_icon_warning"
title={_t("Encryption not enabled")}
subtitle={_t("The encryption used by this room isn't supported.")}
ref={ref}
/>;
});
export default EncryptionEvent;

View file

@ -0,0 +1,34 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {forwardRef, ReactNode} from "react";
import classNames from "classnames";
interface IProps {
className: string;
title: string;
subtitle?: ReactNode;
}
const EventTileBubble = forwardRef<HTMLDivElement, IProps>(({ className, title, subtitle, children }, ref) => {
return <div className={classNames("mx_EventTileBubble", className)} ref={ref}>
<div className="mx_EventTileBubble_title">{ title }</div>
{ subtitle && <div className="mx_EventTileBubble_subtitle">{ subtitle }</div> }
{ children }
</div>;
});
export default EventTileBubble;

View file

@ -18,6 +18,7 @@ import React from 'react';
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import WidgetStore from "../../../stores/WidgetStore"; import WidgetStore from "../../../stores/WidgetStore";
import EventTileBubble from "./EventTileBubble";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
@ -40,37 +41,24 @@ export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
if (!url) { if (!url) {
// removed // removed
return ( return <EventTileBubble
<div className='mx_EventTile_bubble mx_MJitsiWidgetEvent'> className="mx_MJitsiWidgetEvent"
<div className='mx_MJitsiWidgetEvent_title'> title={_t('Video conference ended by %(senderName)s', {senderName})}
{_t('Video conference ended by %(senderName)s', {senderName})} />;
</div>
</div>
);
} else if (prevUrl) { } else if (prevUrl) {
// modified // modified
return ( return <EventTileBubble
<div className='mx_EventTile_bubble mx_MJitsiWidgetEvent'> className="mx_MJitsiWidgetEvent"
<div className='mx_MJitsiWidgetEvent_title'> title={_t('Video conference updated by %(senderName)s', {senderName})}
{_t('Video conference updated by %(senderName)s', {senderName})} subtitle={joinCopy}
</div> />;
<div className='mx_MJitsiWidgetEvent_subtitle'>
{joinCopy}
</div>
</div>
);
} else { } else {
// assume added // assume added
return ( return <EventTileBubble
<div className='mx_EventTile_bubble mx_MJitsiWidgetEvent'> className="mx_MJitsiWidgetEvent"
<div className='mx_MJitsiWidgetEvent_title'> title={_t("Video conference started by %(senderName)s", {senderName})}
{_t("Video conference started by %(senderName)s", {senderName})} subtitle={joinCopy}
</div> />;
<div className='mx_MJitsiWidgetEvent_subtitle'>
{joinCopy}
</div>
</div>
);
} }
} }
} }

View file

@ -21,6 +21,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import {getNameForEventRoom, userLabelForEventRoom} import {getNameForEventRoom, userLabelForEventRoom}
from '../../../utils/KeyVerificationStateObserver'; from '../../../utils/KeyVerificationStateObserver';
import EventTileBubble from "./EventTileBubble";
export default class MKeyVerificationConclusion extends React.Component { export default class MKeyVerificationConclusion extends React.Component {
constructor(props) { constructor(props) {
@ -115,14 +116,14 @@ export default class MKeyVerificationConclusion extends React.Component {
} }
if (title) { if (title) {
const subtitle = userLabelForEventRoom(request.otherUserId, mxEvent.getRoomId()); const classes = classNames("mx_cryptoEvent mx_cryptoEvent_icon", {
const classes = classNames("mx_EventTile_bubble", "mx_cryptoEvent", "mx_cryptoEvent_icon", {
mx_cryptoEvent_icon_verified: request.done, mx_cryptoEvent_icon_verified: request.done,
}); });
return (<div className={classes}> return <EventTileBubble
<div className="mx_cryptoEvent_title">{title}</div> className={classes}
<div className="mx_cryptoEvent_subtitle">{subtitle}</div> title={title}
</div>); subtitle={userLabelForEventRoom(request.otherUserId, mxEvent.getRoomId())}
/>;
} }
return null; return null;

View file

@ -24,6 +24,7 @@ import {getNameForEventRoom, userLabelForEventRoom}
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {RightPanelPhases} from "../../../stores/RightPanelStorePhases";
import {Action} from "../../../dispatcher/actions"; import {Action} from "../../../dispatcher/actions";
import EventTileBubble from "./EventTileBubble";
export default class MKeyVerificationRequest extends React.Component { export default class MKeyVerificationRequest extends React.Component {
constructor(props) { constructor(props) {
@ -146,10 +147,8 @@ export default class MKeyVerificationRequest extends React.Component {
if (!request.initiatedByMe) { if (!request.initiatedByMe) {
const name = getNameForEventRoom(request.requestingUserId, mxEvent.getRoomId()); const name = getNameForEventRoom(request.requestingUserId, mxEvent.getRoomId());
title = (<div className="mx_cryptoEvent_title">{ title = _t("%(name)s wants to verify", {name});
_t("%(name)s wants to verify", {name})}</div>); subtitle = userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId());
subtitle = (<div className="mx_cryptoEvent_subtitle">{
userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId())}</div>);
if (request.canAccept) { if (request.canAccept) {
stateNode = (<div className="mx_cryptoEvent_buttons"> stateNode = (<div className="mx_cryptoEvent_buttons">
<FormButton kind="danger" onClick={this._onRejectClicked} label={_t("Decline")} /> <FormButton kind="danger" onClick={this._onRejectClicked} label={_t("Decline")} />
@ -157,18 +156,18 @@ export default class MKeyVerificationRequest extends React.Component {
</div>); </div>);
} }
} else { // request sent by us } else { // request sent by us
title = (<div className="mx_cryptoEvent_title">{ title = _t("You sent a verification request");
_t("You sent a verification request")}</div>); subtitle = userLabelForEventRoom(request.receivingUserId, mxEvent.getRoomId());
subtitle = (<div className="mx_cryptoEvent_subtitle">{
userLabelForEventRoom(request.receivingUserId, mxEvent.getRoomId())}</div>);
} }
if (title) { if (title) {
return (<div className="mx_EventTile_bubble mx_cryptoEvent mx_cryptoEvent_icon"> return <EventTileBubble
{title} className="mx_cryptoEvent mx_cryptoEvent_icon"
{subtitle} title={title}
{stateNode} subtitle={subtitle}
</div>); >
{ stateNode }
</EventTileBubble>;
} }
return null; return null;
} }

View file

@ -22,6 +22,7 @@ import dis from '../../../dispatcher/dispatcher';
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {MatrixClientPeg} from '../../../MatrixClientPeg';
import EventTileBubble from "./EventTileBubble";
export default class RoomCreate extends React.Component { export default class RoomCreate extends React.Component {
static propTypes = { static propTypes = {
@ -51,17 +52,16 @@ export default class RoomCreate extends React.Component {
const permalinkCreator = new RoomPermalinkCreator(prevRoom, predecessor['room_id']); const permalinkCreator = new RoomPermalinkCreator(prevRoom, predecessor['room_id']);
permalinkCreator.load(); permalinkCreator.load();
const predecessorPermalink = permalinkCreator.forEvent(predecessor['event_id']); const predecessorPermalink = permalinkCreator.forEvent(predecessor['event_id']);
return <div className="mx_CreateEvent"> const link = (
<div className="mx_CreateEvent_image" /> <a href={predecessorPermalink} onClick={this._onLinkClicked}>
<div className="mx_CreateEvent_header">
{_t("This room is a continuation of another conversation.")}
</div>
<a className="mx_CreateEvent_link"
href={predecessorPermalink}
onClick={this._onLinkClicked}
>
{_t("Click here to see older messages.")} {_t("Click here to see older messages.")}
</a> </a>
</div>; );
return <EventTileBubble
className="mx_CreateEvent"
title={_t("This room is a continuation of another conversation.")}
subtitle={link}
/>;
} }
} }

View file

@ -28,7 +28,7 @@ import {EventTimeline} from 'matrix-js-sdk/src/models/event-timeline';
import dis from '../../../dispatcher/dispatcher'; import dis from '../../../dispatcher/dispatcher';
import Modal from '../../../Modal'; import Modal from '../../../Modal';
import {_t} from '../../../languageHandler'; import {_t} from '../../../languageHandler';
import createRoom, {privateShouldBeEncrypted} from '../../../createRoom'; import createRoom, { findDMForUser, privateShouldBeEncrypted } from '../../../createRoom';
import DMRoomMap from '../../../utils/DMRoomMap'; import DMRoomMap from '../../../utils/DMRoomMap';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import SdkConfig from '../../../SdkConfig'; import SdkConfig from '../../../SdkConfig';
@ -51,7 +51,6 @@ import BaseCard from "./BaseCard";
import {E2EStatus} from "../../../utils/ShieldUtils"; import {E2EStatus} from "../../../utils/ShieldUtils";
import ImageView from "../elements/ImageView"; import ImageView from "../elements/ImageView";
import Spinner from "../elements/Spinner"; import Spinner from "../elements/Spinner";
import IconButton from "../elements/IconButton";
import PowerSelector from "../elements/PowerSelector"; import PowerSelector from "../elements/PowerSelector";
import MemberAvatar from "../avatars/MemberAvatar"; import MemberAvatar from "../avatars/MemberAvatar";
import PresenceLabel from "../rooms/PresenceLabel"; import PresenceLabel from "../rooms/PresenceLabel";
@ -106,17 +105,7 @@ export const getE2EStatus = (cli: MatrixClient, userId: string, devices: IDevice
}; };
async function openDMForUser(matrixClient: MatrixClient, userId: string) { async function openDMForUser(matrixClient: MatrixClient, userId: string) {
const dmRooms = DMRoomMap.shared().getDMRoomsForUserId(userId); const lastActiveRoom = findDMForUser(matrixClient, userId);
const lastActiveRoom = dmRooms.reduce((lastActiveRoom, roomId) => {
const room = matrixClient.getRoom(roomId);
if (!room || room.getMyMembership() === "leave") {
return lastActiveRoom;
}
if (!lastActiveRoom || lastActiveRoom.getLastActiveTimestamp() < room.getLastActiveTimestamp()) {
return room;
}
return lastActiveRoom;
}, null);
if (lastActiveRoom) { if (lastActiveRoom) {
dis.dispatch({ dis.dispatch({
@ -1028,24 +1017,15 @@ const PowerLevelSection: React.FC<{
roomPermissions: IRoomPermissions; roomPermissions: IRoomPermissions;
powerLevels: IPowerLevelsContent; powerLevels: IPowerLevelsContent;
}> = ({user, room, roomPermissions, powerLevels}) => { }> = ({user, room, roomPermissions, powerLevels}) => {
const [isEditing, setEditing] = useState(false); if (roomPermissions.canEdit) {
if (isEditing) { return (<PowerLevelEditor user={user} room={room} roomPermissions={roomPermissions} />);
return (<PowerLevelEditor
user={user} room={room} roomPermissions={roomPermissions}
onFinished={() => setEditing(false)} />);
} else { } else {
const powerLevelUsersDefault = powerLevels.users_default || 0; const powerLevelUsersDefault = powerLevels.users_default || 0;
const powerLevel = parseInt(user.powerLevel, 10); const powerLevel = parseInt(user.powerLevel, 10);
const modifyButton = roomPermissions.canEdit ?
(<IconButton icon="edit" onClick={() => setEditing(true)} />) : null;
const role = textualPowerLevel(powerLevel, powerLevelUsersDefault); const role = textualPowerLevel(powerLevel, powerLevelUsersDefault);
const label = _t("<strong>%(role)s</strong> in %(roomName)s",
{role, roomName: room.name},
{strong: label => <strong>{label}</strong>},
);
return ( return (
<div className="mx_UserInfo_profileField"> <div className="mx_UserInfo_profileField">
<div className="mx_UserInfo_roleDescription">{label}{modifyButton}</div> <div className="mx_UserInfo_roleDescription">{role}</div>
</div> </div>
); );
} }
@ -1055,20 +1035,15 @@ const PowerLevelEditor: React.FC<{
user: User; user: User;
room: Room; room: Room;
roomPermissions: IRoomPermissions; roomPermissions: IRoomPermissions;
onFinished(): void; }> = ({user, room, roomPermissions}) => {
}> = ({user, room, roomPermissions, onFinished}) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const [isUpdating, setIsUpdating] = useState(false);
const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10)); const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10));
const [isDirty, setIsDirty] = useState(false); const onPowerChange = useCallback(async (powerLevelStr: string) => {
const onPowerChange = useCallback((powerLevel) => { const powerLevel = parseInt(powerLevelStr, 10);
setIsDirty(true); setSelectedPowerLevel(powerLevel);
setSelectedPowerLevel(parseInt(powerLevel, 10));
}, [setSelectedPowerLevel, setIsDirty]);
const changePowerLevel = useCallback(async () => { const applyPowerChange = (roomId, target, powerLevel, powerLevelEvent) => {
const _applyPowerChange = (roomId, target, powerLevel, powerLevelEvent) => {
return cli.setPowerLevel(roomId, target, parseInt(powerLevel), powerLevelEvent).then( return cli.setPowerLevel(roomId, target, parseInt(powerLevel), powerLevelEvent).then(
function() { function() {
// NO-OP; rely on the m.room.member event coming down else we could // NO-OP; rely on the m.room.member event coming down else we could
@ -1084,64 +1059,42 @@ const PowerLevelEditor: React.FC<{
); );
}; };
try { const roomId = user.roomId;
if (!isDirty) { const target = user.userId;
return;
}
setIsUpdating(true); const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
if (!powerLevelEvent) return;
const powerLevel = selectedPowerLevel; const myUserId = cli.getUserId();
const myPower = powerLevelEvent.getContent().users[myUserId];
if (myPower && parseInt(myPower) === powerLevel) {
const {finished} = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, {
title: _t("Warning!"),
description:
<div>
{ _t("You will not be able to undo this change as you are promoting the user " +
"to have the same power level as yourself.") }<br />
{ _t("Are you sure?") }
</div>,
button: _t("Continue"),
});
const roomId = user.roomId; const [confirmed] = await finished;
const target = user.userId; if (!confirmed) return;
} else if (myUserId === target) {
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
if (!powerLevelEvent) return;
if (!powerLevelEvent.getContent().users) {
_applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
return;
}
const myUserId = cli.getUserId();
// If we are changing our own PL it can only ever be decreasing, which we cannot reverse. // If we are changing our own PL it can only ever be decreasing, which we cannot reverse.
if (myUserId === target) { try {
try { if (!(await warnSelfDemote())) return;
if (!(await warnSelfDemote())) return; } catch (e) {
} catch (e) { console.error("Failed to warn about self demotion: ", e);
console.error("Failed to warn about self demotion: ", e);
}
await _applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
return;
} }
const myPower = powerLevelEvent.getContent().users[myUserId];
if (parseInt(myPower) === powerLevel) {
const {finished} = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, {
title: _t("Warning!"),
description:
<div>
{ _t("You will not be able to undo this change as you are promoting the user " +
"to have the same power level as yourself.") }<br />
{ _t("Are you sure?") }
</div>,
button: _t("Continue"),
});
const [confirmed] = await finished;
if (!confirmed) return;
}
await _applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
} finally {
onFinished();
} }
}, [user.roomId, user.userId, cli, selectedPowerLevel, isDirty, setIsUpdating, onFinished, room]);
await applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
}, [user.roomId, user.userId, cli, room]);
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", ""); const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
const powerLevelUsersDefault = powerLevelEvent ? powerLevelEvent.getContent().users_default : 0; const powerLevelUsersDefault = powerLevelEvent ? powerLevelEvent.getContent().users_default : 0;
const buttonOrSpinner = isUpdating ? <Spinner w={16} h={16} /> :
<IconButton icon="check" onClick={changePowerLevel} />;
return ( return (
<div className="mx_UserInfo_profileField"> <div className="mx_UserInfo_profileField">
@ -1151,9 +1104,7 @@ const PowerLevelEditor: React.FC<{
maxValue={roomPermissions.modifyLevelMax} maxValue={roomPermissions.modifyLevelMax}
usersDefault={powerLevelUsersDefault} usersDefault={powerLevelUsersDefault}
onChange={onPowerChange} onChange={onPowerChange}
disabled={isUpdating}
/> />
{buttonOrSpinner}
</div> </div>
); );
}; };
@ -1343,13 +1294,17 @@ const BasicUserInfo: React.FC<{
} }
let memberDetails; let memberDetails;
if (room && member.roomId) { // hide the Roles section for DMs as it doesn't make sense there
memberDetails = <PowerLevelSection if (room && member.roomId && !DMRoomMap.shared().getUserIdForRoomId(member.roomId)) {
powerLevels={powerLevels} memberDetails = <div className="mx_UserInfo_container">
user={member} <h3>{ _t("Role") }</h3>
room={room} <PowerLevelSection
roomPermissions={roomPermissions} powerLevels={powerLevels}
/>; user={member}
room={room}
roomPermissions={roomPermissions}
/>
</div>;
} }
// only display the devices list if our client supports E2E // only display the devices list if our client supports E2E
@ -1419,12 +1374,7 @@ const BasicUserInfo: React.FC<{
); );
return <React.Fragment> return <React.Fragment>
{ memberDetails && { memberDetails }
<div className="mx_UserInfo_container mx_UserInfo_separator mx_UserInfo_memberDetailsContainer">
<div className="mx_UserInfo_memberDetails">
{ memberDetails }
</div>
</div> }
{ securitySection } { securitySection }
<UserOptionsSection <UserOptionsSection

View file

@ -21,6 +21,7 @@ import ReplyThread from "../elements/ReplyThread";
import React, {createRef} from 'react'; import React, {createRef} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from "classnames"; import classNames from "classnames";
import {EventType} from "matrix-js-sdk/src/@types/event";
import { _t, _td } from '../../../languageHandler'; import { _t, _td } from '../../../languageHandler';
import * as TextForEvent from "../../../TextForEvent"; import * as TextForEvent from "../../../TextForEvent";
import * as sdk from "../../../index"; import * as sdk from "../../../index";
@ -646,12 +647,13 @@ export default class EventTile extends React.Component {
// Info messages are basically information about commands processed on a room // Info messages are basically information about commands processed on a room
const isBubbleMessage = eventType.startsWith("m.key.verification") || const isBubbleMessage = eventType.startsWith("m.key.verification") ||
(eventType === "m.room.message" && msgtype && msgtype.startsWith("m.key.verification")) || (eventType === EventType.RoomMessage && msgtype && msgtype.startsWith("m.key.verification")) ||
(eventType === "m.room.encryption") || (eventType === EventType.RoomCreate) ||
(eventType === EventType.RoomEncryption) ||
(tileHandler === "messages.MJitsiWidgetEvent"); (tileHandler === "messages.MJitsiWidgetEvent");
let isInfoMessage = ( let isInfoMessage = (
!isBubbleMessage && eventType !== 'm.room.message' && !isBubbleMessage && eventType !== EventType.RoomMessage &&
eventType !== 'm.sticker' && eventType !== 'm.room.create' eventType !== EventType.Sticker && eventType !== EventType.RoomCreate
); );
// If we're showing hidden events in the timeline, we should use the // If we're showing hidden events in the timeline, we should use the

View file

@ -0,0 +1,135 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {useContext} from "react";
import {EventType} from "matrix-js-sdk/src/@types/event";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomContext from "../../../contexts/RoomContext";
import DMRoomMap from "../../../utils/DMRoomMap";
import {_t} from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import MiniAvatarUploader, {AVATAR_SIZE} from "../elements/MiniAvatarUploader";
import RoomAvatar from "../avatars/RoomAvatar";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import {ViewUserPayload} from "../../../dispatcher/payloads/ViewUserPayload";
import {Action} from "../../../dispatcher/actions";
import dis from "../../../dispatcher/dispatcher";
const NewRoomIntro = () => {
const cli = useContext(MatrixClientContext);
const {room, roomId} = useContext(RoomContext);
const dmPartner = DMRoomMap.shared().getUserIdForRoomId(roomId);
let body;
if (dmPartner) {
let caption;
if ((room.getJoinedMemberCount() + room.getInvitedMemberCount()) === 2) {
caption = _t("Only the two of you are in this conversation, unless either of you invites anyone to join.");
}
const member = room?.getMember(dmPartner);
const displayName = member?.rawDisplayName || dmPartner;
body = <React.Fragment>
<RoomAvatar room={room} width={AVATAR_SIZE} height={AVATAR_SIZE} onClick={() => {
defaultDispatcher.dispatch<ViewUserPayload>({
action: Action.ViewUser,
// XXX: We should be using a real member object and not assuming what the receiver wants.
member: member || {userId: dmPartner},
});
}} />
<h2>{ room.name }</h2>
<p>{_t("This is the beginning of your direct message history with <displayName/>.", {}, {
displayName: () => <b>{ displayName }</b>,
})}</p>
{ caption && <p>{ caption }</p> }
</React.Fragment>;
} else {
const topic = room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic;
const canAddTopic = room.currentState.maySendStateEvent(EventType.RoomTopic, cli.getUserId());
const onTopicClick = () => {
dis.dispatch({
action: "open_room_settings",
room_id: roomId,
}, true);
// focus the topic field to help the user find it as it'll gain an outline
setImmediate(() => {
window.document.getElementById("profileTopic").focus();
});
};
let topicText;
if (canAddTopic && topic) {
topicText = _t("Topic: %(topic)s (<a>edit</a>)", { topic }, {
a: sub => <AccessibleButton kind="link" onClick={onTopicClick}>{ sub }</AccessibleButton>,
});
} else if (topic) {
topicText = _t("Topic: %(topic)s ", { topic });
} else if (canAddTopic) {
topicText = _t("<a>Add a topic</a> to help people know what it is about.", {}, {
a: sub => <AccessibleButton kind="link" onClick={onTopicClick}>{ sub }</AccessibleButton>,
});
}
const creator = room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
const creatorName = room?.getMember(creator)?.rawDisplayName || creator;
let createdText;
if (creator === cli.getUserId()) {
createdText = _t("You created this room.");
} else {
createdText = _t("%(displayName)s created this room.", {
displayName: creatorName,
});
}
const onInviteClick = () => {
dis.dispatch({ action: "view_invite", roomId });
};
const avatarUrl = room.currentState.getStateEvents(EventType.RoomAvatar, "")?.getContent()?.url;
body = <React.Fragment>
<MiniAvatarUploader
hasAvatar={!!avatarUrl}
noAvatarLabel={_t("Add a photo, so people can easily spot your room.")}
setAvatarUrl={url => cli.sendStateEvent(roomId, EventType.RoomAvatar, { url }, '')}
>
<RoomAvatar room={room} width={AVATAR_SIZE} height={AVATAR_SIZE} />
</MiniAvatarUploader>
<h2>{ room.name }</h2>
<p>{createdText} {_t("This is the start of <roomName/>.", {}, {
roomName: () => <b>{ room.name }</b>,
})}</p>
<p>{topicText}</p>
<div className="mx_NewRoomIntro_buttons">
<AccessibleButton className="mx_NewRoomIntro_inviteButton" kind="primary" onClick={onInviteClick}>
{_t("Invite to this room")}
</AccessibleButton>
</div>
</React.Fragment>;
}
return <div className="mx_NewRoomIntro">
{ body }
</div>;
};
export default NewRoomIntro;

View file

@ -58,6 +58,7 @@ interface IProps {
interface IState { interface IState {
sublists: ITagMap; sublists: ITagMap;
isNameFiltering: boolean;
} }
const TAG_ORDER: TagID[] = [ const TAG_ORDER: TagID[] = [
@ -183,6 +184,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
this.state = { this.state = {
sublists: {}, sublists: {},
isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(),
}; };
this.dispatcherRef = defaultDispatcher.register(this.onAction); this.dispatcherRef = defaultDispatcher.register(this.onAction);
@ -253,7 +255,8 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
return CustomRoomTagStore.getTags()[t]; return CustomRoomTagStore.getTags()[t];
}); });
let doUpdate = arrayHasDiff(previousListIds, newListIds); const isNameFiltering = !!RoomListStore.instance.getFirstNameFilterCondition();
let doUpdate = this.state.isNameFiltering !== isNameFiltering || arrayHasDiff(previousListIds, newListIds);
if (!doUpdate) { if (!doUpdate) {
// so we didn't have the visible sublists change, but did the contents of those // so we didn't have the visible sublists change, but did the contents of those
// sublists change significantly enough to break the sticky headers? Probably, so // sublists change significantly enough to break the sticky headers? Probably, so
@ -275,14 +278,20 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const newSublists = objectWithOnly(newLists, newListIds); const newSublists = objectWithOnly(newLists, newListIds);
const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v));
this.setState({sublists}, () => { this.setState({sublists, isNameFiltering}, () => {
this.props.onResize(); this.props.onResize();
}); });
} }
}; };
private onStartChat = () => {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
dis.dispatch({ action: "view_create_chat", initialText });
};
private onExplore = () => { private onExplore = () => {
dis.fire(Action.ViewRoomDirectory); const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
dis.dispatch({ action: Action.ViewRoomDirectory, initialText });
}; };
private renderCommunityInvites(): TemporaryTile[] { private renderCommunityInvites(): TemporaryTile[] {
@ -332,7 +341,9 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
return p; return p;
}, [] as TagID[]); }, [] as TagID[]);
const showSkeleton = tagOrder.every(tag => !this.state.sublists[tag]?.length); // show a skeleton UI if the user is in no rooms and they are not filtering
const showSkeleton = !this.state.isNameFiltering &&
Object.values(RoomListStore.instance.unfilteredLists).every(list => !list?.length);
for (const orderedTagId of tagOrder) { for (const orderedTagId of tagOrder) {
const orderedRooms = this.state.sublists[orderedTagId] || []; const orderedRooms = this.state.sublists[orderedTagId] || [];
@ -369,10 +380,21 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
public render() { public render() {
let explorePrompt: JSX.Element; let explorePrompt: JSX.Element;
if (!this.props.isMinimized) { if (!this.props.isMinimized) {
if (RoomListStore.instance.getFirstNameFilterCondition()) { if (this.state.isNameFiltering) {
explorePrompt = <div className="mx_RoomList_explorePrompt"> explorePrompt = <div className="mx_RoomList_explorePrompt">
<div>{_t("Can't see what youre looking for?")}</div> <div>{_t("Can't see what youre looking for?")}</div>
<AccessibleButton kind="link" onClick={this.onExplore}> <AccessibleButton
className="mx_RoomList_explorePrompt_startChat"
kind="link"
onClick={this.onStartChat}
>
{_t("Start a new chat")}
</AccessibleButton>
<AccessibleButton
className="mx_RoomList_explorePrompt_explore"
kind="link"
onClick={this.onExplore}
>
{_t("Explore all public rooms")} {_t("Explore all public rooms")}
</AccessibleButton> </AccessibleButton>
</div>; </div>;
@ -384,7 +406,18 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
if (unfilteredRooms.length < 1 && unfilteredHistorical < 1) { if (unfilteredRooms.length < 1 && unfilteredHistorical < 1) {
explorePrompt = <div className="mx_RoomList_explorePrompt"> explorePrompt = <div className="mx_RoomList_explorePrompt">
<div>{_t("Use the + to make a new room or explore existing ones below")}</div> <div>{_t("Use the + to make a new room or explore existing ones below")}</div>
<AccessibleButton kind="link" onClick={this.onExplore}> <AccessibleButton
className="mx_RoomList_explorePrompt_startChat"
kind="link"
onClick={this.onStartChat}
>
{_t("Start a new chat")}
</AccessibleButton>
<AccessibleButton
className="mx_RoomList_explorePrompt_explore"
kind="link"
onClick={this.onExplore}
>
{_t("Explore all public rooms")} {_t("Explore all public rooms")}
</AccessibleButton> </AccessibleButton>
</div>; </div>;

View file

@ -422,7 +422,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
room = this.state.rooms && this.state.rooms[0]; room = this.state.rooms && this.state.rooms[0];
} else { } else {
// find the first room with a count of the same colour as the badge count // find the first room with a count of the same colour as the badge count
room = this.state.rooms.find((r: Room) => { room = RoomListStore.instance.unfilteredLists[this.props.tagId].find((r: Room) => {
const notifState = this.notificationState.getForRoom(r); const notifState = this.notificationState.getForRoom(r);
return notifState.count > 0 && notifState.color === this.notificationState.color; return notifState.count > 0 && notifState.color === this.notificationState.color;
}); });

View file

@ -308,6 +308,9 @@ export default class SendMessageComposer extends React.Component {
const startTime = CountlyAnalytics.getTimestamp(); const startTime = CountlyAnalytics.getTimestamp();
const {roomId} = this.props.room; const {roomId} = this.props.room;
const content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent); const content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent);
// don't bother sending an empty message
if (!content.body.trim()) return;
const prom = this.context.sendMessage(roomId, content); const prom = this.context.sendMessage(roomId, content);
if (replyToEvent) { if (replyToEvent) {
// Clear reply_to_event as we put the message into the queue // Clear reply_to_event as we put the message into the queue

View file

@ -129,11 +129,16 @@ export default class EventIndexPanel extends React.Component {
eventIndexingSettings = ( eventIndexingSettings = (
<div> <div>
<div className='mx_SettingsTab_subsectionText'> <div className='mx_SettingsTab_subsectionText'>
{_t( "Securely cache encrypted messages locally for them " + {_t("Securely cache encrypted messages locally for them " +
"to appear in search results, using ") "to appear in search results, using %(size)s to store messages from %(rooms)s rooms.",
} {formatBytes(this.state.eventIndexSize, 0)} {
{_t( " to store messages from ")} size: formatBytes(this.state.eventIndexSize, 0),
{formatCountLong(this.state.roomCount)} {_t("rooms.")} // This drives the singular / plural string
// selection for "room" / "rooms" only.
count: this.state.roomCount,
rooms: formatCountLong(this.state.roomCount),
},
)}
</div> </div>
<div> <div>
<AccessibleButton kind="primary" onClick={this._onManage}> <AccessibleButton kind="primary" onClick={this._onManage}>

View file

@ -24,7 +24,7 @@ import dis from '../../../dispatcher/dispatcher';
import { ActionPayload } from '../../../dispatcher/payloads'; import { ActionPayload } from '../../../dispatcher/payloads';
import PersistentApp from "../elements/PersistentApp"; import PersistentApp from "../elements/PersistentApp";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import { CallState, MatrixCall } from 'matrix-js-sdk/lib/webrtc/call'; import { CallState, MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
interface IProps { interface IProps {
} }

View file

@ -15,17 +15,18 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, {createRef} from 'react'; import React, { createRef } from 'react';
import Room from 'matrix-js-sdk/src/models/room'; import Room from 'matrix-js-sdk/src/models/room';
import dis from '../../../dispatcher/dispatcher'; import dis from '../../../dispatcher/dispatcher';
import CallHandler from '../../../CallHandler'; import CallHandler from '../../../CallHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import VideoView from "./VideoView"; import VideoFeed, { VideoFeedType } from "./VideoFeed";
import RoomAvatar from "../avatars/RoomAvatar"; import RoomAvatar from "../avatars/RoomAvatar";
import PulsedAvatar from '../avatars/PulsedAvatar'; import PulsedAvatar from '../avatars/PulsedAvatar';
import { CallState, MatrixCall } from 'matrix-js-sdk/lib/webrtc/call'; import { CallState, CallType, MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import { CallEvent } from 'matrix-js-sdk/src/webrtc/call';
interface IProps { interface IProps {
// js-sdk room object. If set, we will only show calls for the given // js-sdk room object. If set, we will only show calls for the given
@ -50,53 +51,104 @@ interface IProps {
} }
interface IState { interface IState {
call: any; call: MatrixCall;
isLocalOnHold: boolean,
}
function getFullScreenElement() {
return (
document.fullscreenElement ||
// moz omitted because firefox supports this unprefixed now (webkit here for safari)
document.webkitFullscreenElement ||
document.msFullscreenElement
);
}
function requestFullscreen(element: Element) {
const method = (
element.requestFullscreen ||
// moz omitted since firefox supports unprefixed now
element.webkitRequestFullScreen ||
element.msRequestFullscreen
);
if (method) method.call(element);
}
function exitFullscreen() {
const exitMethod = (
document.exitFullscreen ||
document.webkitExitFullscreen ||
document.msExitFullscreen
);
if (exitMethod) exitMethod.call(document);
} }
export default class CallView extends React.Component<IProps, IState> { export default class CallView extends React.Component<IProps, IState> {
private videoref: React.RefObject<any>;
private dispatcherRef: string; private dispatcherRef: string;
public call: any; private container = createRef<HTMLDivElement>();
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
const call = this.getCall();
this.state = { this.state = {
// the call this view is displaying (if any) call,
call: null, isLocalOnHold: call ? call.isLocalOnHold() : null,
}; }
this.videoref = createRef(); this.updateCallListeners(null, call);
} }
public componentDidMount() { public componentDidMount() {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
this.showCall();
} }
public componentWillUnmount() { public componentWillUnmount() {
this.updateCallListeners(this.state.call, null);
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
} }
private onAction = (payload) => { private onAction = (payload) => {
// don't filter out payloads for room IDs other than props.room because switch (payload.action) {
// we may be interested in the conf 1:1 room case 'video_fullscreen': {
if (payload.action !== 'call_state') { if (!this.container.current) {
return; return;
}
if (payload.fullscreen) {
requestFullscreen(this.container.current);
} else if (getFullScreenElement()) {
exitFullscreen();
}
break;
}
case 'call_state': {
const newCall = this.getCall();
if (newCall !== this.state.call) {
this.updateCallListeners(this.state.call, newCall);
this.setState({
call: newCall,
isLocalOnHold: newCall ? newCall.isLocalOnHold() : null,
});
}
if (!newCall && getFullScreenElement()) {
exitFullscreen();
}
break;
}
} }
this.showCall();
}; };
private showCall() { private getCall(): MatrixCall {
let call: MatrixCall; let call: MatrixCall;
if (this.props.room) { if (this.props.room) {
const roomId = this.props.room.roomId; const roomId = this.props.room.roomId;
call = CallHandler.sharedInstance().getCallForRoom(roomId); call = CallHandler.sharedInstance().getCallForRoom(roomId);
if (this.call) { // We don't currently show voice calls in this view when in the room:
this.setState({ call: call }); // they're represented in the room status bar at the bottom instead
} // (but this will all change with the new designs)
if (call && call.type == CallType.Voice) call = null;
} else { } else {
call = CallHandler.sharedInstance().getAnyActiveCall(); call = CallHandler.sharedInstance().getAnyActiveCall();
// Ignore calls if we can't get the room associated with them. // Ignore calls if we can't get the room associated with them.
@ -106,65 +158,68 @@ export default class CallView extends React.Component<IProps, IState> {
if (MatrixClientPeg.get().getRoom(call.roomId) === null) { if (MatrixClientPeg.get().getRoom(call.roomId) === null) {
call = null; call = null;
} }
this.setState({ call: call });
} }
if (call) { if (call && call.state == CallState.Ended) return null;
if (this.getVideoView()) { return call;
call.setLocalVideoElement(this.getVideoView().getLocalVideoElement());
call.setRemoteVideoElement(this.getVideoView().getRemoteVideoElement());
// always use a separate element for audio stream playback.
// this is to let us move CallView around the DOM without interrupting remote audio
// during playback, by having the audio rendered by a top-level <audio/> element.
// rather than being rendered by the main remoteVideo <video/> element.
call.setRemoteAudioElement(this.getVideoView().getRemoteAudioElement());
}
}
if (call && call.type === "video" && call.state !== CallState.Ended && call.state !== CallState.Ringing) {
this.getVideoView().getLocalVideoElement().style.display = "block";
this.getVideoView().getRemoteVideoElement().style.display = "block";
} else {
this.getVideoView().getLocalVideoElement().style.display = "none";
this.getVideoView().getRemoteVideoElement().style.display = "none";
dis.dispatch({action: 'video_fullscreen', fullscreen: false});
}
if (this.props.onResize) {
this.props.onResize();
}
} }
private getVideoView() { private updateCallListeners(oldCall: MatrixCall, newCall: MatrixCall) {
return this.videoref.current; if (oldCall === newCall) return;
if (oldCall) oldCall.removeListener(CallEvent.HoldUnhold, this.onCallHoldUnhold);
if (newCall) newCall.on(CallEvent.HoldUnhold, this.onCallHoldUnhold);
} }
private onCallHoldUnhold = () => {
this.setState({
isLocalOnHold: this.state.call ? this.state.call.isLocalOnHold() : null,
});
};
public render() { public render() {
let view: React.ReactNode; let view: React.ReactNode;
if (this.state.call && this.state.call.type === "voice") {
const client = MatrixClientPeg.get();
const callRoom = client.getRoom(this.state.call.roomId);
view = <AccessibleButton className="mx_CallView_voice" onClick={this.props.onClick}> if (this.state.call) {
<PulsedAvatar> if (this.state.call.type === "voice") {
<RoomAvatar const client = MatrixClientPeg.get();
room={callRoom} const callRoom = client.getRoom(this.state.call.roomId);
height={35}
width={35} let caption = _t("Active call");
if (this.state.isLocalOnHold) {
// we currently have no UI for holding / unholding a call (apart from slash
// commands) so we don't disintguish between when we've put the call on hold
// (ie. we'd show an unhold button) and when the other side has put us on hold
// (where obviously we would not show such a button).
caption = _t("Call Paused");
}
view = <AccessibleButton className="mx_CallView_voice" onClick={this.props.onClick}>
<PulsedAvatar>
<RoomAvatar
room={callRoom}
height={35}
width={35}
/>
</PulsedAvatar>
<div>
<h1>{callRoom.name}</h1>
<p>{ caption }</p>
</div>
</AccessibleButton>;
} else {
// For video calls, we currently ignore the call hold state altogether
// (the video will just go black)
// if we're fullscreen, we don't want to set a maxHeight on the video element.
const maxVideoHeight = getFullScreenElement() ? null : this.props.maxVideoHeight;
view = <div className="mx_CallView_video" onClick={this.props.onClick}>
<VideoFeed type={VideoFeedType.Remote} call={this.state.call} onResize={this.props.onResize}
maxHeight={maxVideoHeight}
/> />
</PulsedAvatar> <VideoFeed type={VideoFeedType.Local} call={this.state.call} />
<div> </div>;
<h1>{callRoom.name}</h1> }
<p>{ _t("Active call") }</p>
</div>
</AccessibleButton>;
} else {
view = <VideoView
ref={this.videoref}
onClick={this.props.onClick}
onResize={this.props.onResize}
maxHeight={this.props.maxVideoHeight}
/>;
} }
let hangup: React.ReactNode; let hangup: React.ReactNode;
@ -180,10 +235,9 @@ export default class CallView extends React.Component<IProps, IState> {
/>; />;
} }
return <div className={this.props.className}> return <div className={this.props.className} ref={this.container}>
{view} {view}
{hangup} {hangup}
</div>; </div>;
} }
} }

View file

@ -1,58 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
export default class VideoFeed extends React.Component {
static propTypes = {
// maxHeight style attribute for the video element
maxHeight: PropTypes.number,
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize: PropTypes.func,
};
constructor(props) {
super(props);
this._vid = createRef();
}
componentDidMount() {
this._vid.current.addEventListener('resize', this.onResize);
}
componentWillUnmount() {
this._vid.current.removeEventListener('resize', this.onResize);
}
onResize = (e) => {
if (this.props.onResize) {
this.props.onResize(e);
}
};
render() {
return (
<video ref={this._vid} style={{maxHeight: this.props.maxHeight}}>
</video>
);
}
}

View file

@ -0,0 +1,80 @@
/*
Copyright 2015, 2016, 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import classnames from 'classnames';
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import React, {createRef} from 'react';
import SettingsStore from "../../../settings/SettingsStore";
export enum VideoFeedType {
Local,
Remote,
}
interface IProps {
call: MatrixCall,
type: VideoFeedType,
// maxHeight style attribute for the video element
maxHeight?: number,
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize?: (e: Event) => void,
}
export default class VideoFeed extends React.Component<IProps> {
private vid = createRef<HTMLVideoElement>();
componentDidMount() {
this.vid.current.addEventListener('resize', this.onResize);
if (this.props.type === VideoFeedType.Local) {
this.props.call.setLocalVideoElement(this.vid.current);
} else {
this.props.call.setRemoteVideoElement(this.vid.current);
}
}
componentWillUnmount() {
this.vid.current.removeEventListener('resize', this.onResize);
}
onResize = (e) => {
if (this.props.onResize) {
this.props.onResize(e);
}
};
render() {
const videoClasses = {
mx_VideoFeed: true,
mx_VideoFeed_local: this.props.type === VideoFeedType.Local,
mx_VideoFeed_remote: this.props.type === VideoFeedType.Remote,
mx_VideoFeed_mirror: (
this.props.type === VideoFeedType.Local &&
SettingsStore.getValue('VideoView.flipVideoHorizontally')
),
};
let videoStyle = {};
if (this.props.maxHeight) videoStyle = { maxHeight: this.props.maxHeight };
return <div className={classnames(videoClasses)}>
<video ref={this.vid} style={videoStyle}></video>
</div>;
}
}

View file

@ -1,142 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {createRef} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import * as sdk from '../../../index';
import dis from '../../../dispatcher/dispatcher';
import SettingsStore from "../../../settings/SettingsStore";
function getFullScreenElement() {
return (
document.fullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
);
}
export default class VideoView extends React.Component {
static propTypes = {
// maxHeight style attribute for the video element
maxHeight: PropTypes.number,
// a callback which is called when the user clicks on the video div
onClick: PropTypes.func,
// a callback which is called when the video element is resized due to
// a change in video metadata
onResize: PropTypes.func,
};
constructor(props) {
super(props);
this._local = createRef();
this._remote = createRef();
}
componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
}
componentWillUnmount() {
dis.unregister(this.dispatcherRef);
}
getRemoteVideoElement = () => {
return ReactDOM.findDOMNode(this._remote.current);
};
getRemoteAudioElement = () => {
// this needs to be somewhere at the top of the DOM which
// always exists to avoid audio interruptions.
// Might as well just use DOM.
const remoteAudioElement = document.getElementById("remoteAudio");
if (!remoteAudioElement) {
console.error("Failed to find remoteAudio element - cannot play audio!"
+ "You need to add an <audio/> to the DOM.");
}
return remoteAudioElement;
};
getLocalVideoElement = () => {
return ReactDOM.findDOMNode(this._local.current);
};
setContainer = (c) => {
this.container = c;
};
onAction = (payload) => {
switch (payload.action) {
case 'video_fullscreen': {
if (!this.container) {
return;
}
const element = this.container;
if (payload.fullscreen) {
const requestMethod = (
element.requestFullScreen ||
element.webkitRequestFullScreen ||
element.mozRequestFullScreen ||
element.msRequestFullscreen
);
requestMethod.call(element);
} else if (getFullScreenElement()) {
const exitMethod = (
document.exitFullscreen ||
document.mozCancelFullScreen ||
document.webkitExitFullscreen ||
document.msExitFullscreen
);
if (exitMethod) {
exitMethod.call(document);
}
}
break;
}
}
};
render() {
const VideoFeed = sdk.getComponent('voip.VideoFeed');
// if we're fullscreen, we don't want to set a maxHeight on the video element.
const maxVideoHeight = getFullScreenElement() ? null : this.props.maxHeight;
const localVideoFeedClasses = classNames("mx_VideoView_localVideoFeed",
{ "mx_VideoView_localVideoFeed_flipped":
SettingsStore.getValue('VideoView.flipVideoHorizontally'),
},
);
return (
<div className="mx_VideoView" ref={this.setContainer} onClick={this.props.onClick}>
<div className="mx_VideoView_remoteVideoFeed">
<VideoFeed ref={this._remote} onResize={this.props.onResize}
maxHeight={maxVideoHeight} />
</div>
<div className={localVideoFeedClasses}>
<VideoFeed ref={this._local} />
</div>
</div>
);
}
}

View file

@ -29,7 +29,6 @@ const RoomContext = createContext<IState>({
guestsCanJoin: false, guestsCanJoin: false,
canPeek: false, canPeek: false,
showApps: false, showApps: false,
isAlone: false,
isPeeking: false, isPeeking: false,
showingPinned: false, showingPinned: false,
showReadReceipts: true, showReadReceipts: true,

View file

@ -15,20 +15,21 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {MatrixClient} from "matrix-js-sdk/src/client"; import { MatrixClient } from "matrix-js-sdk/src/client";
import {Room} from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import {MatrixClientPeg} from './MatrixClientPeg'; import { MatrixClientPeg } from './MatrixClientPeg';
import Modal from './Modal'; import Modal from './Modal';
import * as sdk from './index'; import * as sdk from './index';
import { _t } from './languageHandler'; import { _t } from './languageHandler';
import dis from "./dispatcher/dispatcher"; import dis from "./dispatcher/dispatcher";
import * as Rooms from "./Rooms"; import * as Rooms from "./Rooms";
import DMRoomMap from "./utils/DMRoomMap"; import DMRoomMap from "./utils/DMRoomMap";
import {getAddressType} from "./UserAddress"; import { getAddressType } from "./UserAddress";
import { getE2EEWellKnown } from "./utils/WellKnownUtils"; import { getE2EEWellKnown } from "./utils/WellKnownUtils";
import GroupStore from "./stores/GroupStore"; import GroupStore from "./stores/GroupStore";
import CountlyAnalytics from "./CountlyAnalytics"; import CountlyAnalytics from "./CountlyAnalytics";
import { isJoinedOrNearlyJoined } from "./utils/membership";
// we define a number of interfaces which take their names from the js-sdk // we define a number of interfaces which take their names from the js-sdk
/* eslint-disable camelcase */ /* eslint-disable camelcase */
@ -236,9 +237,16 @@ export function findDMForUser(client: MatrixClient, userId: string): Room {
const roomIds = DMRoomMap.shared().getDMRoomsForUserId(userId); const roomIds = DMRoomMap.shared().getDMRoomsForUserId(userId);
const rooms = roomIds.map(id => client.getRoom(id)); const rooms = roomIds.map(id => client.getRoom(id));
const suitableDMRooms = rooms.filter(r => { const suitableDMRooms = rooms.filter(r => {
// Validate that we are joined and the other person is also joined. We'll also make sure
// that the room also looks like a DM (until we have canonical DMs to tell us). For now,
// a DM is a room of two people that contains those two people exactly. This does mean
// that bots, assistants, etc will ruin a room's DM-ness, though this is a problem for
// canonical DMs to solve.
if (r && r.getMyMembership() === "join") { if (r && r.getMyMembership() === "join") {
const member = r.getMember(userId); const members = r.currentState.getMembers();
return member && (member.membership === "invite" || member.membership === "join"); const joinedMembers = members.filter(m => isJoinedOrNearlyJoined(m.membership));
const otherMember = joinedMembers.find(m => m.userId === userId);
return otherMember && joinedMembers.length === 2;
} }
return false; return false;
}).sort((r1, r2) => { }).sort((r1, r2) => {

File diff suppressed because it is too large Load diff

View file

@ -2347,5 +2347,188 @@
"🎉 All servers are banned from participating! This room can no longer be used.": "🎉 Всички сървъри за възбранени от участие! Тази стая вече не може да бъде използвана.", "🎉 All servers are banned from participating! This room can no longer be used.": "🎉 Всички сървъри за възбранени от участие! Тази стая вече не може да бъде използвана.",
"%(senderDisplayName)s changed the server ACLs for this room.": "%(senderDisplayName)s промени сървърните разрешения за контрол на достъпа до тази стая.", "%(senderDisplayName)s changed the server ACLs for this room.": "%(senderDisplayName)s промени сървърните разрешения за контрол на достъпа до тази стая.",
"Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Добавя ( ͡° ͜ʖ ͡°) в началото на текстовото съобщение", "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Добавя ( ͡° ͜ʖ ͡°) в началото на текстовото съобщение",
"The call was answered on another device.": "На обаждането беше отговорено от друго устройство." "The call was answered on another device.": "На обаждането беше отговорено от друго устройство.",
"This room is public": "Тази стая е публична",
"Move right": "Премести надясно",
"Move left": "Премести наляво",
"Revoke permissions": "Оттеглете привилегии",
"Take a picture": "Направете снимка",
"Unable to set up keys": "Неуспешна настройка на ключовете",
"Use your Security Key to continue.": "Използвайте ключа си за сигурност за да продължите.",
"Security Key": "Ключ за сигурност",
"Enter your Security Phrase or <button>Use your Security Key</button> to continue.": "Въведете защитната фраза или <button>използвайте ключа за сигурност</button> за да продължите.",
"Security Phrase": "Защитна фраза",
"Invalid Recovery Key": "Невалиден ключ за възстановяване",
"Wrong Recovery Key": "Грешен ключ за възстановяване",
"Looks good!": "Изглежда добре!",
"Wrong file type": "Грешен тип файл",
"Recent changes that have not yet been received": "Скорошни промени, които още не са били получени",
"The server is not configured to indicate what the problem is (CORS).": "Сървърът не е конфигуриран да укаже какъв е проблемът (CORS).",
"A connection error occurred while trying to contact the server.": "Възникнал е проблем с връзката при свързване към сървъра.",
"Your area is experiencing difficulties connecting to the internet.": "В районът ви има проблеми с връзката с интернет.",
"The server has denied your request.": "Сървърът е забранил заявката ви.",
"The server is offline.": "Сървърът е офлайн.",
"A browser extension is preventing the request.": "Разширение на браузъра блокира заявката.",
"Your firewall or anti-virus is blocking the request.": "Защитната ви стена (firewall) или антивирусен софтуер блокират заявката.",
"The server (%(serverName)s) took too long to respond.": "Сървърът %(serverName)s отне твърде дълго да отговори.",
"Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "Сървърът ви не отговаря на някой от заявките ви. По-долу са някои от най-вероятните причини.",
"Server isn't responding": "Сървърът не отговаря",
"You're all caught up.": "Наваксали сте с всичко.",
"Data on this screen is shared with %(widgetDomain)s": "Данните на този екран са споделени с %(widgetDomain)s",
"Modal Widget": "Модално приспособление",
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.": "Поканете някой по име, потребителско име (като <userId/>) или <a>споделете тази стая</a>.",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Поканете някой по име, имейл адрес, потребителско име (като <userId/>) или <a>споделете тази стая</a>.",
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>": "Това няма да ги покани в %(communityName)s. За да поканите някой в %(communityName)s, кликнете <a>тук</a>",
"Start a conversation with someone using their name or username (like <userId/>).": "Започнете разговор с някой използвайки тяхното име или потребителско име (като <userId/>).",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Започнете разговор с някой използвайки тяхното име, имейл адрес или потребителско име (като <userId/>).",
"May include members not in %(communityName)s": "Може да съдържа членове, които не са в %(communityName)s",
"Invite by email": "Покани по имейл",
"Send feedback": "Изпрати обратна връзка",
"PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> to help us track down the problem.": "ПРОФЕСИОНАЛЕН СЪВЕТ: Ако ще съобщавате за проблем, изпратете и <debugLogsLink>логове за разработчици</debugLogsLink> за да ни помогнете да открием проблема.",
"Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. No match? <newIssueLink>Start a new one</newIssueLink>.": "Първо прегледайте <existingIssuesLink>съществуващите проблеми в Github</existingIssuesLink>. Няма подобни? <newIssueLink>Създайте нов</newIssueLink>.",
"Report a bug": "Съобщете за проблем",
"There are two ways you can provide feedback and help us improve %(brand)s.": "Има два начина да дадете обратна връзка и да ни помогнете да подобрим %(brand)s.",
"Comment": "Коментар",
"Add comment": "Добави коментар",
"Please go into as much detail as you like, so we can track down the problem.": "Моля, разкажете колкото подробно желаете, за да можем да открием проблема.",
"Tell us below how you feel about %(brand)s so far.": "Кажете ни какво мислите за %(brand)s към този момент.",
"Rate %(brand)s": "Оценете %(brand)s",
"Feedback sent": "Обратната връзка беше изпратена",
"Update community": "Обнови общността",
"There was an error updating your community. The server is unable to process your request.": "Възникна грешка при обновяването на общността. Сървърът не може да обработки заявката ви.",
"Block anyone not part of %(serverName)s from ever joining this room.": "Блокирай всеки, който не е част от %(serverName)s от присъединяване в тази стая.",
"Create a room in %(communityName)s": "Създай стая в %(communityName)s",
"You might disable this if the room will be used for collaborating with external teams who have their own homeserver. This cannot be changed later.": "Може да изключите това, ако стаята ще се използва за съвместна работа с външни екипи, имащи собствен сървър. Това не може да бъде променено по-късно.",
"You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "Може да включите това, ако стаята ще се използва само за съвместна работа на вътрешни екипи на сървъра ви. Това не може да бъде променено по-късно.",
"Your server requires encryption to be enabled in private rooms.": "Сървърът ви изисква в частните стаи да е включено шифроване.",
"Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone in this community.": "Към частните стаи присъединяването е само с покана. Публичните могат да бъдат открити и присъединени от всеки в тази общност.",
"Private rooms can be found and joined by invitation only. Public rooms can be found and joined by anyone.": "Към частните стаи присъединяването е само с покана. Публичните могат да бъдат открити и присъединени от всеки.",
"An image will help people identify your community.": "Снимката би помогнала на хората да идентифицират общността ви.",
"Add image (optional)": "Добавете снимка (незадължително)",
"Enter name": "Въведете име",
"What's the name of your community or team?": "Какво е името на общността или екипа ви?",
"You can change this later if needed.": "Може да промените това и по-късно, ако е нужно.",
"Use this when referencing your community to others. The community ID cannot be changed.": "Използвайте това когато се обръщате към общността сред други хора. Идентификатора не може да бъде променен.",
"Community ID: +<localpart />:%(domain)s": "Идентификатор на общност: +<localpart />:%(domain)s",
"There was an error creating your community. The name may be taken or the server is unable to process your request.": "Възникна грешка при създаването на общността. Името може да е заето или пък сървърът не може да обработи заявката.",
"Invite people to join %(communityName)s": "Поканете хора в %(communityName)s",
"Send %(count)s invites|one": "Изпрати %(count)s покана",
"Send %(count)s invites|other": "Изпрати %(count)s покани",
"People you know on %(brand)s": "Хора, които познаване в %(brand)s",
"Add another email": "Добави друг имейл",
"Download logs": "Изтегли на логове",
"Preparing to download logs": "Подготвяне за изтегляне на логове",
"Information": "Информация",
"This version of %(brand)s does not support searching encrypted messages": "Тази версия на %(brand)s не поддържа търсенето в шифровани съобщения",
"This version of %(brand)s does not support viewing some encrypted files": "Тази версия на %(brand)s не поддържа преглеждането на някои шифровани файлове",
"Use the <a>Desktop app</a> to search encrypted messages": "Използвайте <a>Desktop приложението</a> за да търсите в шифровани съобщения",
"Use the <a>Desktop app</a> to see all encrypted files": "Използвайте <a>Desktop приложението</a> за да видите всички шифровани файлове",
"Click to view edits": "Кликнете за да видите редакциите",
"Edited at %(date)s": "Редактирано на %(date)s",
"Message deleted on %(date)s": "Съобщението изтрито на %(date)s",
"Video conference started by %(senderName)s": "Видео конференцията беше стартирана от %(senderName)s",
"Video conference updated by %(senderName)s": "Видео конференцията беше обновена от %(senderName)s",
"Video conference ended by %(senderName)s": "Видео конференцията беше прекратена от %(senderName)s",
"Join the conference from the room information card on the right": "Присъединете се към конференцията от информацията за стаята в дясно",
"Join the conference at the top of this room": "Присъединете се към конференцията в горната част на стаята",
"Ignored attempt to disable encryption": "Опитът за изключване на шифроването беше игнориран",
"Room settings": "Настройки на стаята",
"Show files": "Покажи файловете",
"%(count)s people|other": "%(count)s човека",
"%(count)s people|one": "%(count)s човек",
"About": "Относно",
"Not encrypted": "Не е шифровано",
"Add widgets, bridges & bots": "Добави приспособления, мостове и ботове",
"Edit widgets, bridges & bots": "Промени приспособления, мостове и ботове",
"Widgets": "Приспособления",
"Unpin a widget to view it in this panel": "Разкачете приспособление за да го видите в този панел",
"Unpin": "Разкачи",
"You can only pin up to %(count)s widgets|other": "Може да закачите максимум %(count)s приспособления",
"Room Info": "Информация за стаята",
"Favourited": "В любими",
"Forget Room": "Забрави стаята",
"Notification options": "Настройки за уведомление",
"Mentions & Keywords": "Споменавания и ключови думи",
"Use default": "Използвай по подразбиране",
"Show previews of messages": "Показвай преглед на съобщенията",
"Show rooms with unread messages first": "Показвай стаи с непрочетени съобщения първи",
"%(count)s results|one": "%(count)s резултат",
"%(count)s results|other": "%(count)s резултата",
"Use the + to make a new room or explore existing ones below": "Използвайте + за да направите нова стая или да прегледате съществуващите",
"Explore all public rooms": "Прегледай всички публични стаи",
"Can't see what youre looking for?": "Не намирате това, което търсите?",
"Custom Tag": "Собствен етикет",
"Explore public rooms": "Прегледай публични стаи",
"Explore community rooms": "Прегледай стаи от общността",
"Show Widgets": "Покажи приспособленията",
"Hide Widgets": "Скрий приспособленията",
"Remove messages sent by others": "Премахвай съобщения изпратени от други",
"Privacy": "Поверителност",
"Secure Backup": "Защитено резервно копие",
"Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Настройте името на шрифт инсталиран в системата и %(brand)s ще се опита да го използва.",
"not ready": "не е готово",
"ready": "готово",
"Secret storage:": "Секретно складиране:",
"Backup key cached:": "Резервният ключ е кеширан:",
"Backup key stored:": "Резервният ключ е съхранен:",
"Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Recovery Key.": "Правете резервно копие на ключовете за шифроване и данните в профила, в случай че загубите достъп до сесиите си. Ключовете ви ще бъдат защитени с уникален ключ за възстановяване.",
"Algorithm:": "Алгоритъм:",
"Backup version:": "Версия на резервното копие:",
"The operation could not be completed": "Операцията не можа да бъде завършена",
"Failed to save your profile": "Неуспешно запазване на профила ви",
"You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Вероятно сте ги конфигурирали в клиент различен от %(brand)s. Не можете да ги управлявате в %(brand)s, но те все пак важат.",
"There are advanced notifications which are not shown here.": "Съществуват по-сложни уведомления, които не са показани тук.",
"%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.": "%(brand)s не може да кешира шифровани съобщения локално по сигурен начин когато работи в уеб браузър. Използвайте <desktopLink>%(brand)s Desktop </desktopLink> за да можете да търсите шифровани съобщения.",
"Master private key:": "Главен частен ключ:",
"not found in storage": "не е намерено в складирането",
"Cross-signing is not set up.": "Кръстосаното-подписване не е настроено.",
"Cross-signing is ready for use.": "Кръстосаното-подписване е готово за използване.",
"Your server isn't responding to some <a>requests</a>.": "Сървърът ви не отговаря на някои <a>заявки</a>.",
"%(senderName)s ended the call": "%(senderName)s приключи разговора",
"You ended the call": "Приключихте разговора",
"New version of %(brand)s is available": "Налична е нова версия на %(brand)s",
"Update %(brand)s": "Обнови %(brand)s",
"Enable desktop notifications": "Включете уведомления на работния плот",
"Don't miss a reply": "Не пропускайте отговор",
"User menu": "Потребителско меню",
"Search rooms": "Търси стаи",
"Save your Security Key": "Запази ключа за сигурност",
"Confirm Security Phrase": "Потвърди фразата за сигурност",
"Set a Security Phrase": "Настрой фраза за сигурност",
"You can also set up Secure Backup & manage your keys in Settings.": "Също така, може да конфигурирате защитено резервно копиране и да управлявате ключовете си от Настройки.",
"If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "Ако се откажете сега, може да загубите достъп до шифрованите съобщения и данни, в случай че загубите достъп до тази сесия.",
"Store your Security Key somewhere safe, like a password manager or a safe, as its used to safeguard your encrypted data.": "Запазете ключа за сигурност на сигурно място, като password manager или сейф, понеже се използва за предпазване на шифрованите данни.",
"Enter a security phrase only you know, as its used to safeguard your data. To be secure, you shouldnt re-use your account password.": "Въведете фраза за сигурност, която знаете само вие. Тя ще се използва за предпазване на данните ви. За да е по-сигурно, не използвайте паролата за профила си.",
"Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "Използвайте секретна фраза, която знаете само вие. При необходимост запазете и ключа за сигурност за резервното копие.",
"Enter a Security Phrase": "Въведете фраза за сигурност",
"Well generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "Ще генерираме ключ за сигурност, който да съхраните на сигурно място, като password manager или сейф.",
"Generate a Security Key": "Генерирай ключ за сигурност",
"Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Предпазете се от загуба на достъп до шифрованите съобщения и данни като направите резервно копие на ключовете за шифроване върху сървъра.",
"Now, let's help you get started": "Нека ви помогнем да започнете",
"Welcome %(name)s": "Добре дошли, %(name)s",
"Add a photo so people know it's you.": "Добавете снимка, за да може другите хора да знаят, че сте вие.",
"Great, that'll help people know it's you": "Чудесно, това ще позволи на хората да знаят, че сте вие",
"Starting microphone...": "Стартиране на микрофона...",
"Starting camera...": "Стартиране на камерата...",
"Call connecting...": "Свързване на разговор...",
"Calling...": "Звънене...",
"You do not have permission to create rooms in this community.": "Нямате привилегии да създавате стаи в тази общност.",
"Cannot create rooms in this community": "Не можете да създавате стаи в тази общност",
"Community and user menu": "Меню за общността и потребителя",
"User settings": "Потребителски настройки",
"Community settings": "Настройки на общност",
"Failed to find the general chat for this community": "Неуспешно откриване на основния чат за тази общност",
"Create community": "Създай общност",
"Explore rooms in %(communityName)s": "Преглед на стаи в %(communityName)s",
"%(brand)s Android": "%(brand)s за Android",
"You have no visible notifications in this room.": "Нямате видими уведомления за тази стая.",
"Youre all caught up": "Наваксали сте с всичко",
"Attach files from chat or just drag and drop them anywhere in a room.": "Прикачете файлове от чата или ги издърпайте и пуснете в стаята.",
"No files visible in this room": "Няма видими файлове в тази стая",
"Away": "Отсъства",
"%(brand)s iOS": "%(brand)s за iOS",
"%(brand)s Desktop": "%(brand)s Desktop",
"%(brand)s Web": "Уеб версия на %(brand)s",
"Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of <a>element.io</a>.": "Въведете адреса на вашия Element Matrix Services сървър. Той или използва ваш собствен домейн или е поддомейн на <a>element.io</a>.",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Може да използвате опцията за собствен сървър, за да влезете в друг Matrix сървър, чрез указване на адреса му. Това позволява да използвате %(brand)s с Matrix профил съществуващ на друг сървър."
} }

View file

@ -15,9 +15,9 @@
"Favourite": "Favorit", "Favourite": "Favorit",
"Mute": "Silencia", "Mute": "Silencia",
"Room directory": "Directori de sales", "Room directory": "Directori de sales",
"Settings": "Paràmetres", "Settings": "Configuració",
"Start chat": "Inicia un xat", "Start chat": "Inicia un xat",
"Failed to change password. Is your password correct?": "Hi ha hagut un error al canviar la vostra contrasenya. És correcte la vostra contrasenya?", "Failed to change password. Is your password correct?": "S'ha produït un error en canviar la contrasenya. És correcta la teva contrasenya?",
"Continue": "Continua", "Continue": "Continua",
"Custom Server Options": "Opcions de servidor personalitzat", "Custom Server Options": "Opcions de servidor personalitzat",
"Dismiss": "Omet", "Dismiss": "Omet",
@ -29,7 +29,7 @@
"Search": "Cerca", "Search": "Cerca",
"powered by Matrix": "amb tecnologia de Matrix", "powered by Matrix": "amb tecnologia de Matrix",
"Edit": "Edita", "Edit": "Edita",
"Unpin Message": "Desenganxa el missatge", "Unpin Message": "Anul·la la fixació de missatge",
"Register": "Registre", "Register": "Registre",
"Rooms": "Sales", "Rooms": "Sales",
"Add rooms to this community": "Afegeix sales a aquesta comunitat", "Add rooms to this community": "Afegeix sales a aquesta comunitat",
@ -37,17 +37,17 @@
"Guests can join": "Els usuaris d'altres xarxes s'hi poden unir", "Guests can join": "Els usuaris d'altres xarxes s'hi poden unir",
"This email address is already in use": "Aquesta adreça de correu electrònic ja està en ús", "This email address is already in use": "Aquesta adreça de correu electrònic ja està en ús",
"This phone number is already in use": "Aquest número de telèfon ja està en ús", "This phone number is already in use": "Aquest número de telèfon ja està en ús",
"Failed to verify email address: make sure you clicked the link in the email": "No s'ha pogut verificar l'adreça de correu electrònic. Assegureu-vos de fer clic a l'enllaç del correu electrònic de verificació", "Failed to verify email address: make sure you clicked the link in the email": "No s'ha pogut verificar l'adreça de correu electrònic: assegura't de fer clic a l'enllaç del correu electrònic",
"Call Failed": "No s'ha pogut realitzar la trucada", "Call Failed": "No s'ha pogut realitzar la trucada",
"The remote side failed to pick up": "El costat remot no ha contestat", "The remote side failed to pick up": "El part remota no ha contestat",
"Unable to capture screen": "No s'ha pogut capturar la pantalla", "Unable to capture screen": "No s'ha pogut capturar la pantalla",
"Existing Call": "Trucada existent", "Existing Call": "Trucada existent",
"You are already in a call.": "Ja sou a una trucada.", "You are already in a call.": "Ja ets en una trucada.",
"VoIP is unsupported": "El VoIP no és compatible", "VoIP is unsupported": "VoIP no és compatible",
"You cannot place VoIP calls in this browser.": "No es poden fer trucades VoIP amb aquest navegador.", "You cannot place VoIP calls in this browser.": "No pots fer trucades VoIP en aquest navegador.",
"You cannot place a call with yourself.": "No és possible trucar-se a un mateix.", "You cannot place a call with yourself.": "No pots trucar-te a tu mateix.",
"Warning!": "Avís!", "Warning!": "Avís!",
"Upload Failed": "No s'ha pogut realitzar la pujada", "Upload Failed": "No s'ha pogut pujar",
"Sun": "dg.", "Sun": "dg.",
"Mon": "dl.", "Mon": "dl.",
"Tue": "dt.", "Tue": "dt.",
@ -69,51 +69,51 @@
"Dec": "des.", "Dec": "des.",
"PM": "PM", "PM": "PM",
"AM": "AM", "AM": "AM",
"%(weekDayName)s %(time)s": "%(weekDayName)s%(time)s", "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s",
"%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(day)s de %(monthName)s %(time)s", "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(day)s de/d' %(monthName)s %(time)s",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s de %(monthName)s de %(fullYear)s", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s de/d' %(monthName)s de %(fullYear)s",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(day)s de %(monthName)s de %(fullYear)s %(time)s", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(day)s de/d' %(monthName)s de %(fullYear)s %(time)s",
"Who would you like to add to this community?": "A qui voleu afegir a aquesta comunitat?", "Who would you like to add to this community?": "A qui vols afegir a aquesta comunitat?",
"Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Avís: les persones que afegiu a aquesta comunitat seran visibles públicament per a qualsevol que conegui l'ID de la comunitat", "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Avís: qualsevol persona que afegeixis a una comunitat serà visible públicament per a qualsevol que conegui l'ID de la comunitat",
"Invite new community members": "Convida nous membres a unir-se a la comunitat", "Invite new community members": "Convida nous membres a la comunitat",
"Invite to Community": "Convida a la comunitat", "Invite to Community": "Convida a la comunitat",
"Which rooms would you like to add to this community?": "Quines sales voleu afegir a aquesta comunitat?", "Which rooms would you like to add to this community?": "Quines sales vols afegir a aquesta comunitat?",
"Show these rooms to non-members on the community page and room list?": "Voleu mostrar aquestes sales als que no son membres a la pàgina de la comunitat i a la llista de sales?", "Show these rooms to non-members on the community page and room list?": "Vols mostrar aquestes sales a la pàgina de la comunitat i a la llista de sales per als que no hi son membres?",
"Add rooms to the community": "Afegeix sales a la comunitat", "Add rooms to the community": "Afegeix sales a la comunitat",
"Add to community": "Afegeix a la comunitat", "Add to community": "Afegeix a la comunitat",
"Failed to invite the following users to %(groupId)s:": "No s'ha pogut convidar a %(groupId)s els següents usuaris:", "Failed to invite the following users to %(groupId)s:": "No s'han pogut convidar a %(groupId)s els següents usuaris:",
"Failed to invite users to community": "No s'ha pogut convidar als usuaris a la comunitat", "Failed to invite users to community": "No s'han pogut convidar els usuaris a la comunitat",
"Failed to invite users to %(groupId)s": "No s'ha pogut convidar els usuaris a %(groupId)s", "Failed to invite users to %(groupId)s": "No s'han pogut convidar els usuaris a %(groupId)s",
"Failed to add the following rooms to %(groupId)s:": "No s'ha pogut afegir les següents sales al %(groupId)s:", "Failed to add the following rooms to %(groupId)s:": "No s'han pogut afegir a %(groupId)s les següents sales:",
"%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s no té permís per enviar-vos notificacions. Comproveu la configuració del vostre navegador", "%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s no té permís per enviar-te notificacions, comprova la configuració del teu navegador",
"%(brand)s was not given permission to send notifications - please try again": "%(brand)s no ha rebut cap permís per enviar notificacions. Torneu-ho a provar", "%(brand)s was not given permission to send notifications - please try again": "%(brand)s no ha rebut cap permís per enviar notificacions, torna-ho a provar",
"Unable to enable Notifications": "No s'ha pogut activar les notificacions", "Unable to enable Notifications": "No s'han pogut activar les notificacions",
"This email address was not found": "Aquesta adreça de correu electrònic no s'ha trobat", "This email address was not found": "Aquesta adreça de correu electrònic no s'ha trobat",
"Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "La vostra adreça de correu electrònic no sembla que estigui associada amb un identificador de Matrix d'aquest servidor.", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "La teva adreça de correu electrònic no sembla estar associada amb un ID de Matrix en aquest servidor.",
"Default": "Per defecte", "Default": "Predeterminat",
"Restricted": "Restringit", "Restricted": "Restringit",
"Moderator": "Moderador", "Moderator": "Moderador",
"Admin": "Administrador", "Admin": "Administrador",
"Failed to invite": "No s'ha pogut tramitar la invitació", "Failed to invite": "No s'ha pogut convidar",
"Failed to invite the following users to the %(roomName)s room:": "No s'ha pogut convidar a la sala %(roomName)s els següents usuaris:", "Failed to invite the following users to the %(roomName)s room:": "No s'ha pogut convidar a la sala %(roomName)s els següents usuaris:",
"You need to be logged in.": "És necessari estar autenticat.", "You need to be logged in.": "Has d'haver iniciat sessió.",
"You need to be able to invite users to do that.": "Per poder fer això, heu de poder convidar a altres usuaris.", "You need to be able to invite users to do that.": "Per fer això, necessites poder convidar a usuaris.",
"Unable to create widget.": "No s'ha pogut crear el giny.", "Unable to create widget.": "No s'ha pogut crear el giny.",
"Failed to send request.": "No s'ha pogut enviar la sol·licitud.", "Failed to send request.": "No s'ha pogut enviar la sol·licitud.",
"This room is not recognised.": "No es reconeix aquesta sala.", "This room is not recognised.": "No es reconeix aquesta sala.",
"Power level must be positive integer.": "El nivell de poders ha de ser un enter positiu.", "Power level must be positive integer.": "El nivell d'autoritat ha de ser un enter positiu.",
"You are not in this room.": "No heu entrat a aquesta sala.", "You are not in this room.": "No ets en aquesta sala.",
"You do not have permission to do that in this room.": "No teniu el permís per realitzar aquesta acció en aquesta sala.", "You do not have permission to do that in this room.": "No tens permís per fer això en aquesta sala.",
"Missing room_id in request": "Falta el room_id en la vostra sol·licitud", "Missing room_id in request": "Falta el room_id a la sol·licitud",
"Room %(roomId)s not visible": "La sala %(roomId)s no és visible", "Room %(roomId)s not visible": "Sala %(roomId)s no visible",
"Missing user_id in request": "Falta l'user_id a la vostra sol·licitud", "Missing user_id in request": "Falta l'user_id a la sol·licitud",
"Usage": "Ús", "Usage": "Ús",
"/ddg is not a command": "/ddg no és un comandament", "/ddg is not a command": "/ddg no és una ordre",
"To use it, just wait for autocomplete results to load and tab through them.": "Per utilitzar-lo, simplement espereu que es completin els resultats automàticament i seleccioneu-ne el desitjat.", "To use it, just wait for autocomplete results to load and tab through them.": "Per utilitzar-ho, simplement espera que es completin els resultats automàticament i clica'n el desitjat.",
"Ignored user": "Usuari ignorat", "Ignored user": "Usuari ignorat",
"You are now ignoring %(userId)s": "Esteu ignorant l'usuari %(userId)s", "You are now ignoring %(userId)s": "Estàs ignorant l'usuari %(userId)s",
"Unignored user": "Usuari no ignorat", "Unignored user": "Usuari no ignorat",
"You are no longer ignoring %(userId)s": "Ja no esteu ignorant l'usuari %(userId)s", "You are no longer ignoring %(userId)s": "Ja no estàs ignorant l'usuari %(userId)s",
"Verified key": "Claus verificades", "Verified key": "Claus verificades",
"Call Timeout": "Temps d'espera de les trucades", "Call Timeout": "Temps d'espera de les trucades",
"Reason": "Raó", "Reason": "Raó",
@ -122,7 +122,7 @@
"%(senderName)s requested a VoIP conference.": "%(senderName)s ha sol·licitat una conferència VoIP.", "%(senderName)s requested a VoIP conference.": "%(senderName)s ha sol·licitat una conferència VoIP.",
"%(senderName)s invited %(targetName)s.": "%(senderName)s ha convidat a %(targetName)s.", "%(senderName)s invited %(targetName)s.": "%(senderName)s ha convidat a %(targetName)s.",
"%(senderName)s banned %(targetName)s.": "%(senderName)s ha expulsat a %(targetName)s.", "%(senderName)s banned %(targetName)s.": "%(senderName)s ha expulsat a %(targetName)s.",
"%(senderName)s set their display name to %(displayName)s.": "%(senderName)s ha establert %(displayName)s com el seu nom visible.", "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s han establert el seu nom visible a %(displayName)s.",
"%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s ha retirat el seu nom visible %(oldDisplayName)s.", "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s ha retirat el seu nom visible %(oldDisplayName)s.",
"%(senderName)s removed their profile picture.": "%(senderName)s ha retirat la seva foto de perfil.", "%(senderName)s removed their profile picture.": "%(senderName)s ha retirat la seva foto de perfil.",
"%(senderName)s changed their profile picture.": "%(senderName)s ha canviat la seva foto de perfil.", "%(senderName)s changed their profile picture.": "%(senderName)s ha canviat la seva foto de perfil.",
@ -147,19 +147,19 @@
"(unknown failure: %(reason)s)": "(error desconegut: %(reason)s)", "(unknown failure: %(reason)s)": "(error desconegut: %(reason)s)",
"%(senderName)s ended the call.": "%(senderName)s ha penjat.", "%(senderName)s ended the call.": "%(senderName)s ha penjat.",
"%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s ha convidat a %(targetDisplayName)s a entrar a la sala.", "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s ha convidat a %(targetDisplayName)s a entrar a la sala.",
"%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s ha fet visible l'històric futur de la sala per a tots els membres, a partir de que hi són convidats.", "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s ha establert la visibilitat de l'historial futur de la sala a tots els seus membres, a partir de que hi són convidats.",
"%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s ha fet visible l'històric futur de la sala a tots els membres, des de que entren a la sala.", "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s ha establert la visibilitat de l'historial futur de la sala a tots els seus membres des de que s'hi uneixen.",
"%(senderName)s made future room history visible to all room members.": "%(senderName)s ha fet visible l'històric futur de la sala a tots els membres de la sala.", "%(senderName)s made future room history visible to all room members.": "%(senderName)s ha establert la visibilitat de l'historial futur de la sala a tots els seus membres.",
"%(senderName)s made future room history visible to anyone.": "%(senderName)s ha fet visible el futur historial de la sala per a tothom.", "%(senderName)s made future room history visible to anyone.": "%(senderName)s ha establert la visibilitat de l'historial futur de la sala a tothom.",
"%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s ha fet visible el futur historial de la sala per a desconeguts (%(visibility)s).", "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s ha establert la visibilitat de l'historial futur de la sala a desconegut (%(visibility)s).",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s de %(fromPowerLevel)s a %(toPowerLevel)s", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s de %(fromPowerLevel)s a %(toPowerLevel)s",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ha canviat el nivell de poders de %(powerLevelDiffText)s.", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ha canviat el nivell d'autoritat de %(powerLevelDiffText)s.",
"%(senderName)s changed the pinned messages for the room.": "%(senderName)s ha canviat els missatges fixats de la sala.", "%(senderName)s changed the pinned messages for the room.": "%(senderName)s ha canviat els missatges fixats de la sala.",
"%(widgetName)s widget modified by %(senderName)s": "%(senderName)s ha modificat el giny %(widgetName)s", "%(widgetName)s widget modified by %(senderName)s": "%(senderName)s ha modificat el giny %(widgetName)s",
"%(widgetName)s widget added by %(senderName)s": "%(senderName)s ha afegit el giny %(widgetName)s", "%(widgetName)s widget added by %(senderName)s": "%(senderName)s ha afegit el giny %(widgetName)s",
"%(widgetName)s widget removed by %(senderName)s": "%(senderName)s ha eliminat el giny %(widgetName)s", "%(widgetName)s widget removed by %(senderName)s": "%(senderName)s ha eliminat el giny %(widgetName)s",
"Failure to create room": "No s'ha pogut crear la sala", "Failure to create room": "No s'ha pogut crear la sala",
"Server may be unavailable, overloaded, or you hit a bug.": "És possible que el servidor no estigui disponible, amb sobrecàrrega o que s'hagi trobat un error.", "Server may be unavailable, overloaded, or you hit a bug.": "És possible que el servidor no estigui disponible, sobrecarregat o que hagi topat amb un error.",
"Send": "Envia", "Send": "Envia",
"Unnamed Room": "Sala sense nom", "Unnamed Room": "Sala sense nom",
"Your browser does not support the required cryptography extensions": "El vostre navegador no és compatible amb els complements criptogràfics necessaris", "Your browser does not support the required cryptography extensions": "El vostre navegador no és compatible amb els complements criptogràfics necessaris",
@ -167,7 +167,7 @@
"Authentication check failed: incorrect password?": "Ha fallat l'autenticació: heu introduït correctament la contrasenya?", "Authentication check failed: incorrect password?": "Ha fallat l'autenticació: heu introduït correctament la contrasenya?",
"Failed to join room": "No s'ha pogut entrar a la sala", "Failed to join room": "No s'ha pogut entrar a la sala",
"Message Pinning": "Fixació de missatges", "Message Pinning": "Fixació de missatges",
"Show timestamps in 12 hour format (e.g. 2:30pm)": "Mostra les marques de temps en format de 12 hores (per exemple, 2:30pm)", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Mostra les marques de temps en format de 12 hores (p.e. 2:30pm)",
"Autoplay GIFs and videos": "Reprodueix de forma automàtica els GIF i vídeos", "Autoplay GIFs and videos": "Reprodueix de forma automàtica els GIF i vídeos",
"Enable automatic language detection for syntax highlighting": "Activa la detecció automàtica d'idiomes per al ressaltat de sintaxi", "Enable automatic language detection for syntax highlighting": "Activa la detecció automàtica d'idiomes per al ressaltat de sintaxi",
"Automatically replace plain text Emoji": "Substitueix automàticament Emoji de text pla", "Automatically replace plain text Emoji": "Substitueix automàticament Emoji de text pla",
@ -204,7 +204,7 @@
"Cannot add any more widgets": "No s'ha pogut afegir cap més giny", "Cannot add any more widgets": "No s'ha pogut afegir cap més giny",
"The maximum permitted number of widgets have already been added to this room.": "Ja s'han afegit el màxim de ginys permesos en aquesta sala.", "The maximum permitted number of widgets have already been added to this room.": "Ja s'han afegit el màxim de ginys permesos en aquesta sala.",
"Drop File Here": "Deixeu anar un fitxer aquí", "Drop File Here": "Deixeu anar un fitxer aquí",
"Drop file here to upload": "Deixeu anar un arxiu aquí per pujar-lo", "Drop file here to upload": "Deixa anar el fitxer aquí per pujar-lo",
" (unsupported)": " (incompatible)", " (unsupported)": " (incompatible)",
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.": "Uneix-te com <voiceText>voice</voiceText> o <videoText>video</videoText>.", "Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.": "Uneix-te com <voiceText>voice</voiceText> o <videoText>video</videoText>.",
"Ongoing conference call%(supportedText)s.": "Trucada de conferència en curs %(supportedText)s.", "Ongoing conference call%(supportedText)s.": "Trucada de conferència en curs %(supportedText)s.",
@ -225,10 +225,10 @@
"Ban this user?": "Voleu expulsar a aquest usuari?", "Ban this user?": "Voleu expulsar a aquest usuari?",
"Failed to ban user": "No s'ha pogut expulsar l'usuari", "Failed to ban user": "No s'ha pogut expulsar l'usuari",
"Failed to mute user": "No s'ha pogut silenciar l'usuari", "Failed to mute user": "No s'ha pogut silenciar l'usuari",
"Failed to change power level": "No s'ha pogut canviar el nivell de poders", "Failed to change power level": "No s'ha pogut canviar el nivell d'autoritat",
"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.": "No podreu desfer aquest canvi ja que estareu baixant de grau de privilegis. Només un altre usuari amb més privilegis podrà fer que els recupereu.", "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.": "No podràs desfer aquest canvi ja que t'estàs baixant de rang, si ets l'últim usuari de la sala amb privilegis, et serà impossible recuperar-los.",
"Are you sure?": "Esteu segur?", "Are you sure?": "Estàs segur?",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "No podreu desfer aquesta acció ja que esteu donant al usuari el mateix nivell de privilegi que el vostre.", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "No podràs desfer aquest canvi ja que estàs donant a l'usuari el mateix nivell d'autoritat que el teu.",
"Unignore": "Deixa de ignorar", "Unignore": "Deixa de ignorar",
"Ignore": "Ignora", "Ignore": "Ignora",
"Jump to read receipt": "Vés a l'últim missatge llegit", "Jump to read receipt": "Vés a l'últim missatge llegit",
@ -240,7 +240,7 @@
"and %(count)s others...|one": "i un altre...", "and %(count)s others...|one": "i un altre...",
"Invited": "Convidat", "Invited": "Convidat",
"Filter room members": "Filtra els membres de la sala", "Filter room members": "Filtra els membres de la sala",
"%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (poder %(powerLevelNumber)s)", "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (autoritat %(powerLevelNumber)s)",
"Attachment": "Adjunt", "Attachment": "Adjunt",
"Hangup": "Penja", "Hangup": "Penja",
"Voice call": "Trucada de veu", "Voice call": "Trucada de veu",
@ -248,11 +248,11 @@
"Upload file": "Puja un fitxer", "Upload file": "Puja un fitxer",
"Send an encrypted reply…": "Envia una resposta xifrada…", "Send an encrypted reply…": "Envia una resposta xifrada…",
"Send an encrypted message…": "Envia un missatge xifrat…", "Send an encrypted message…": "Envia un missatge xifrat…",
"You do not have permission to post to this room": "No teniu el permís per escriure en aquesta sala", "You do not have permission to post to this room": "No tens permís per enviar res en aquesta sala",
"Server error": "S'ha produït un error al servidor", "Server error": "Error de servidor",
"Mirror local video feed": "Mostra el vídeo local com un mirall", "Mirror local video feed": "Remet el flux de vídeo local",
"Server unavailable, overloaded, or something else went wrong.": "El servidor no està disponible, està sobrecarregat o alguna altra cosa no ha funcionat correctament.", "Server unavailable, overloaded, or something else went wrong.": "El servidor no està disponible, està sobrecarregat o alguna altra cosa no ha funcionat correctament.",
"Command error": "S'ha produït un error en l'ordre", "Command error": "Error en l'ordre",
"Jump to message": "Salta al missatge", "Jump to message": "Salta al missatge",
"No pinned messages.": "No hi ha cap missatge fixat.", "No pinned messages.": "No hi ha cap missatge fixat.",
"Loading...": "S'està carregant...", "Loading...": "S'està carregant...",
@ -263,15 +263,15 @@
"%(duration)sd": "%(duration)sd", "%(duration)sd": "%(duration)sd",
"Online for %(duration)s": "En línia durant %(duration)s", "Online for %(duration)s": "En línia durant %(duration)s",
"Idle for %(duration)s": "Inactiu durant %(duration)s", "Idle for %(duration)s": "Inactiu durant %(duration)s",
"Offline for %(duration)s": "Desconnectat durant %(duration)s", "Offline for %(duration)s": "Fora de línia durant %(duration)s",
"Unknown for %(duration)s": "Desconegut durant %(duration)s", "Unknown for %(duration)s": "Desconegut durant %(duration)s",
"Online": "Conectat", "Online": "En línia",
"Idle": "Inactiu", "Idle": "Inactiu",
"Offline": "Desconnectat", "Offline": "Fora de línia",
"Unknown": "Desconegut", "Unknown": "Desconegut",
"Replying": "S'està contestant", "Replying": "S'està contestant",
"Seen by %(userName)s at %(dateTime)s": "Vist per %(userName)s a les %(dateTime)s", "Seen by %(userName)s at %(dateTime)s": "Vist per %(userName)s a les %(dateTime)s",
"No rooms to show": "No hi ha cap sala per a mostrar", "No rooms to show": "No hi ha sales per mostrar",
"Unnamed room": "Sala sense nom", "Unnamed room": "Sala sense nom",
"Save": "Desa", "Save": "Desa",
"(~%(count)s results)|other": "(~%(count)s resultats)", "(~%(count)s results)|other": "(~%(count)s resultats)",
@ -299,7 +299,7 @@
"Who can access this room?": "Qui pot entrar a aquesta sala?", "Who can access this room?": "Qui pot entrar a aquesta sala?",
"Only people who have been invited": "Només les persones que hi hagin sigut convidades", "Only people who have been invited": "Només les persones que hi hagin sigut convidades",
"Anyone who knows the room's link, apart from guests": "Qualsevol que conegui l'enllaç de la sala, excepte usuaris d'altres xarxes", "Anyone who knows the room's link, apart from guests": "Qualsevol que conegui l'enllaç de la sala, excepte usuaris d'altres xarxes",
"Publish this room to the public in %(domain)s's room directory?": "Voleu que es publiqui aquesta sala al directori de sales públiques de %(domain)s?", "Publish this room to the public in %(domain)s's room directory?": "Vols publicar aquesta sala al directori de sales públiques de %(domain)s?",
"Who can read history?": "Qui pot llegir l'historial?", "Who can read history?": "Qui pot llegir l'historial?",
"Anyone": "Qualsevol", "Anyone": "Qualsevol",
"Members only (since the point in time of selecting this option)": "Només els membres (a partir del punt en què seleccioneu aquesta opció)", "Members only (since the point in time of selecting this option)": "Només els membres (a partir del punt en què seleccioneu aquesta opció)",
@ -313,30 +313,30 @@
"This room has no local addresses": "Aquesta sala no té adreces locals", "This room has no local addresses": "Aquesta sala no té adreces locals",
"Invalid community ID": "L'ID de la comunitat no és vàlid", "Invalid community ID": "L'ID de la comunitat no és vàlid",
"'%(groupId)s' is not a valid community ID": "'%(groupId)s' no és un ID de comunitat vàlid", "'%(groupId)s' is not a valid community ID": "'%(groupId)s' no és un ID de comunitat vàlid",
"New community ID (e.g. +foo:%(localDomain)s)": "Nou ID de comunitat (per exemple +foo:%(localDomain)s)", "New community ID (e.g. +foo:%(localDomain)s)": "Nou ID de comunitat (p.e. +foo:%(localDomain)s)",
"You have <a>enabled</a> URL previews by default.": "Heu <a>habilitat</a> les previsualitzacions per defecte dels URL.", "You have <a>enabled</a> URL previews by default.": "Heu <a>habilitat</a> les previsualitzacions per defecte dels URL.",
"You have <a>disabled</a> URL previews by default.": "Heu <a>inhabilitat</a> les previsualitzacions per defecte dels URL.", "You have <a>disabled</a> URL previews by default.": "Heu <a>inhabilitat</a> les previsualitzacions per defecte dels URL.",
"URL previews are enabled by default for participants in this room.": "Les previsualitzacions dels URL estan habilitades per defecte per als membres d'aquesta sala.", "URL previews are enabled by default for participants in this room.": "Les previsualitzacions dels URL estan habilitades per defecte per als membres d'aquesta sala.",
"URL previews are disabled by default for participants in this room.": "Les previsualitzacions dels URL estan inhabilitades per defecte per als membres d'aquesta sala.", "URL previews are disabled by default for participants in this room.": "Les previsualitzacions dels URL estan inhabilitades per defecte per als membres d'aquesta sala.",
"URL Previews": "Previsualitzacions dels URL", "URL Previews": "Previsualitzacions dels URL",
"Error decrypting audio": "S'ha produït un error mentre es desxifrava l'àudio", "Error decrypting audio": "Error desxifrant àudio",
"Error decrypting attachment": "S'ha produït un error en desxifrar el fitxer adjunt", "Error decrypting attachment": "Error desxifrant fitxer adjunt",
"Decrypt %(text)s": "Desxifra %(text)s", "Decrypt %(text)s": "Desxifra %(text)s",
"Download %(text)s": "Baixa %(text)s", "Download %(text)s": "Baixa %(text)s",
"Invalid file%(extra)s": "Fitxer invàlid%(extra)s", "Invalid file%(extra)s": "Fitxer invàlid%(extra)s",
"Error decrypting image": "S'ha produït un error en desxifrar la imatge", "Error decrypting image": "Error desxifrant imatge",
"Error decrypting video": "S'ha produït un error en desxifrar el vídeo", "Error decrypting video": "Error desxifrant video",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s ha canviat el seu avatar per a la sala %(roomName)s", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s ha canviat l'avatar de %(roomName)s",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s ha eliminat l'avatar de la sala.", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s ha eliminat l'avatar de la sala.",
"%(senderDisplayName)s changed the room avatar to <img/>": "%(senderDisplayName)s ha canviat l'avatar de la sala per aquest <img/>", "%(senderDisplayName)s changed the room avatar to <img/>": "%(senderDisplayName)s ha canviat l'avatar de la sala a <img/>",
"Copied!": "Copiat!", "Copied!": "Copiat!",
"Failed to copy": "No s'ha pogut copiar", "Failed to copy": "No s'ha pogut copiar",
"Add an Integration": "Afegeix una integració", "Add an Integration": "Afegeix una integració",
"An email has been sent to %(emailAddress)s": "S'ha enviat un correu electrònic a %(emailAddress)s", "An email has been sent to %(emailAddress)s": "S'ha enviat un correu electrònic a %(emailAddress)s",
"Please check your email to continue registration.": "Reviseu el vostre correu electrònic per a poder continuar amb el registre.", "Please check your email to continue registration.": "Reviseu el vostre correu electrònic per a poder continuar amb el registre.",
"Token incorrect": "El testimoni és incorrecte", "Token incorrect": "Token incorrecte",
"A text message has been sent to %(msisdn)s": "S'ha enviat un missatge de text a %(msisdn)s", "A text message has been sent to %(msisdn)s": "S'ha enviat un missatge de text a %(msisdn)s",
"Please enter the code it contains:": "Introduïu el codi que conté:", "Please enter the code it contains:": "Introdueix el codi que conté:",
"Start authentication": "Inicia l'autenticació", "Start authentication": "Inicia l'autenticació",
"Sign in with": "Inicieu sessió amb", "Sign in with": "Inicieu sessió amb",
"Email address": "Correu electrònic", "Email address": "Correu electrònic",
@ -349,17 +349,17 @@
"Failed to remove user from community": "No s'ha pogut treure l'usuari de la comunitat", "Failed to remove user from community": "No s'ha pogut treure l'usuari de la comunitat",
"Filter community members": "Filtra els membres de la comunitat", "Filter community members": "Filtra els membres de la comunitat",
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Esteu segur que voleu treure l'usuari '%(roomName)s' del grup %(groupId)s?", "Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Esteu segur que voleu treure l'usuari '%(roomName)s' del grup %(groupId)s?",
"<a>In reply to</a> <pill>": "<a>In reply to</a> <pill>", "<a>In reply to</a> <pill>": "<a>En resposta a</a> <pill>",
"Removing a room from the community will also remove it from the community page.": "L'eliminació d'una sala de la comunitat també l'eliminarà de la pàgina de la comunitat.", "Removing a room from the community will also remove it from the community page.": "L'eliminació d'una sala de la comunitat també l'eliminarà de la pàgina de la comunitat.",
"Failed to remove room from community": "No s'ha pogut eliminar la sala de la comunitat", "Failed to remove room from community": "No s'ha pogut eliminar la sala de la comunitat",
"Failed to remove '%(roomName)s' from %(groupId)s": "No s'ha pogut treure la sala '%(roomName)s' de la comunitat %(groupId)s", "Failed to remove '%(roomName)s' from %(groupId)s": "No s'ha pogut eliminar '%(roomName)s' de %(groupId)s",
"Something went wrong!": "Alguna cosa ha anat malament!", "Something went wrong!": "Alguna cosa ha anat malament!",
"The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "No s'ha pogut actualitzar la visibilitat de la sala '%(roomName)s' de la comunitat %(groupId)s.", "The visibility of '%(roomName)s' in %(groupId)s could not be updated.": "No s'ha pogut actualitzar la visibilitat de la sala '%(roomName)s' de la comunitat %(groupId)s.",
"Visibility in Room List": "Visibilitat a la llista de les sales", "Visibility in Room List": "Visibilitat a la llista de les sales",
"Visible to everyone": "Visible per a tothom", "Visible to everyone": "Visible per a tothom",
"Only visible to community members": "Només visible per als membres de la comunitat", "Only visible to community members": "Només visible per als membres de la comunitat",
"Filter community rooms": "Filtra sales de comunitats", "Filter community rooms": "Filtra sales de comunitats",
"Something went wrong when trying to get your communities.": "S'ha produït un error en intentar obtenir les vostres comunitats.", "Something went wrong when trying to get your communities.": "Alguna cosa ha anat malament mentre s'intentaven obtenir les comunitats.",
"You're not currently a member of any communities.": "Actualment no sou membre de cap comunitat.", "You're not currently a member of any communities.": "Actualment no sou membre de cap comunitat.",
"Unknown Address": "Adreça desconeguda", "Unknown Address": "Adreça desconeguda",
"Allow": "Permetre", "Allow": "Permetre",
@ -372,12 +372,12 @@
"Home": "Inici", "Home": "Inici",
"Manage Integrations": "Gestiona les integracions", "Manage Integrations": "Gestiona les integracions",
"%(nameList)s %(transitionList)s": "%(transitionList)s%(nameList)s", "%(nameList)s %(transitionList)s": "%(transitionList)s%(nameList)s",
"%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)s han entrat", "%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)s s'hi han unit",
"%(oneUser)sjoined %(count)s times|one": "%(oneUser)s s'ha unit", "%(oneUser)sjoined %(count)s times|one": "%(oneUser)s s'ha unit",
"%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s han sortit", "%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s han sortit",
"%(oneUser)sleft %(count)s times|one": "%(oneUser)s ha sortit", "%(oneUser)sleft %(count)s times|one": "%(oneUser)s ha sortit",
"%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s s'han unit i han sortit %(count)s vegades", "%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s s'hi han unit i han sortit %(count)s vegades",
"%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s s'han unit i han sortit", "%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s s'hi han unit i han sortit",
"%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s ha entrat i ha sortit %(count)s vegades", "%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s ha entrat i ha sortit %(count)s vegades",
"%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s ha entrat i ha sortit", "%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s ha entrat i ha sortit",
"%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s han sortit i han tornat a entrar %(count)s vegades", "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s han sortit i han tornat a entrar %(count)s vegades",
@ -388,10 +388,10 @@
"%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s han rebutjat les seves invitacions", "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s han rebutjat les seves invitacions",
"%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s ha rebutjat la seva invitació %(count)s vegades", "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s ha rebutjat la seva invitació %(count)s vegades",
"%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s ha rebutjat la seva invitació", "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s ha rebutjat la seva invitació",
"%(severalUsers)shad their invitations withdrawn %(count)s times|other": "a %(severalUsers)s els hi han retirat les seves invitacions %(count)s vegades", "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "S'han retirat les invitacions de %(severalUsers)s %(count)s vegades",
"%(severalUsers)shad their invitations withdrawn %(count)s times|one": "a %(severalUsers)s els hi han retirat les seves invitacions", "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "S'han retirat les invitacions de %(severalUsers)s",
"%(oneUser)shad their invitation withdrawn %(count)s times|other": "a %(oneUser)s li han retirat la seva invitació %(count)s vegades", "%(oneUser)shad their invitation withdrawn %(count)s times|other": "S'ha retirat la invitació de %(oneUser)s %(count)s vegades",
"%(oneUser)shad their invitation withdrawn %(count)s times|one": "a %(oneUser)s li han retirat la seva invitació", "%(oneUser)shad their invitation withdrawn %(count)s times|one": "S'ha retirat la invitació de %(oneUser)s",
"were invited %(count)s times|other": "a sigut invitat %(count)s vegades", "were invited %(count)s times|other": "a sigut invitat %(count)s vegades",
"were invited %(count)s times|one": "han sigut convidats", "were invited %(count)s times|one": "han sigut convidats",
"was invited %(count)s times|other": "ha sigut convidat %(count)s vegades", "was invited %(count)s times|other": "ha sigut convidat %(count)s vegades",
@ -410,7 +410,7 @@
"was kicked %(count)s times|one": "l'han fet fora", "was kicked %(count)s times|one": "l'han fet fora",
"%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s han canviat el seu nom %(count)s vegades", "%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)s han canviat el seu nom %(count)s vegades",
"%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s han canviat el seu nom", "%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)s han canviat el seu nom",
"%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s han canviat el seu nom %(count)s vegades", "%(oneUser)schanged their name %(count)s times|other": "%(oneUser)s ha canviat el seu nom %(count)s vegades",
"%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s ha canviat el seu nom", "%(oneUser)schanged their name %(count)s times|one": "%(oneUser)s ha canviat el seu nom",
"%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s han canviat el seu avatar %(count)s vegades", "%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)s han canviat el seu avatar %(count)s vegades",
"%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s han canviat el seu avatar", "%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)s han canviat el seu avatar",
@ -426,12 +426,12 @@
"ex. @bob:example.com": "per exemple @carles:exemple.cat", "ex. @bob:example.com": "per exemple @carles:exemple.cat",
"Add User": "Afegeix un usuari", "Add User": "Afegeix un usuari",
"Matrix ID": "ID de Matrix", "Matrix ID": "ID de Matrix",
"Matrix Room ID": "ID de sala de Matrix", "Matrix Room ID": "ID de la sala de Matrix",
"email address": "correu electrònic", "email address": "correu electrònic",
"Try using one of the following valid address types: %(validTypesList)s.": "Proveu d'utilitzar un dels següents tipus d'adreça vàlids: %(validTypesList)s.", "Try using one of the following valid address types: %(validTypesList)s.": "Proveu d'utilitzar un dels següents tipus d'adreça vàlids: %(validTypesList)s.",
"You have entered an invalid address.": "No heu introduït una adreça vàlida.", "You have entered an invalid address.": "No heu introduït una adreça vàlida.",
"Confirm Removal": "Confirmeu l'eliminació", "Confirm Removal": "Confirmeu l'eliminació",
"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.": "Esteu segur que voleu eliminar (suprimir) aquest esdeveniment? Tingueu en compte que si suprimiu un nom sala o si feu un canvi de tema, desfaria el canvi.", "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.": "Estàs segur que vols eliminar (suprimir) aquest esdeveniment? Tingues en compte que, si suprimeixes un nom de sala o es canvia el tema, podria ser que es revertís.",
"This room is not showing flair for any communities": "Aquesta sala no mostra talent per a cap comunitat", "This room is not showing flair for any communities": "Aquesta sala no mostra talent per a cap comunitat",
"Flair": "Talents", "Flair": "Talents",
"Showing flair for these communities:": "Mostra els talents d'aquestes comunitats:", "Showing flair for these communities:": "Mostra els talents d'aquestes comunitats:",
@ -442,7 +442,7 @@
"%(oneUser)sleft %(count)s times|other": "%(oneUser)s ha sortit %(count)s vegades", "%(oneUser)sleft %(count)s times|other": "%(oneUser)s ha sortit %(count)s vegades",
"Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Les ID de les comunitats només poden contendre caràcters a-z, 0-9, o '=_-./'", "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Les ID de les comunitats només poden contendre caràcters a-z, 0-9, o '=_-./'",
"Community IDs cannot be empty.": "Les ID de les comunitats no poden estar buides.", "Community IDs cannot be empty.": "Les ID de les comunitats no poden estar buides.",
"Something went wrong whilst creating your community": "S'ha produït un error al crear la vostra comunitat", "Something went wrong whilst creating your community": "S'ha produït un error mentre es creava la comunitat",
"Create Community": "Crea una comunitat", "Create Community": "Crea una comunitat",
"Community Name": "Nom de la comunitat", "Community Name": "Nom de la comunitat",
"Example": "Exemple", "Example": "Exemple",
@ -450,13 +450,13 @@
"example": "exemple", "example": "exemple",
"Create": "Crea", "Create": "Crea",
"Create Room": "Crea una sala", "Create Room": "Crea una sala",
"Unknown error": "S'ha produït un error desconegut", "Unknown error": "Error desconegut",
"Incorrect password": "Contrasenya incorrecta", "Incorrect password": "Contrasenya incorrecta",
"Deactivate Account": "Desactivar el compte", "Deactivate Account": "Desactivar el compte",
"An error has occurred.": "S'ha produït un error.", "An error has occurred.": "S'ha produït un error.",
"Unable to restore session": "No s'ha pogut restaurar la sessió", "Unable to restore session": "No s'ha pogut restaurar la sessió",
"Invalid Email Address": "El correu electrònic no és vàlid", "Invalid Email Address": "El correu electrònic no és vàlid",
"This doesn't appear to be a valid email address": "Aquest no sembla ser un correu electrònic vàlid", "This doesn't appear to be a valid email address": "Sembla que aquest correu electrònic no és vàlid",
"Verification Pending": "Verificació pendent", "Verification Pending": "Verificació pendent",
"Please check your email and click on the link it contains. Once this is done, click continue.": "Reviseu el vostre correu electrònic i feu clic a l'enllaç que conté. Un cop fet això, feu clic a Continua.", "Please check your email and click on the link it contains. Once this is done, click continue.": "Reviseu el vostre correu electrònic i feu clic a l'enllaç que conté. Un cop fet això, feu clic a Continua.",
"Unable to add email address": "No s'ha pogut afegir el correu electrònic", "Unable to add email address": "No s'ha pogut afegir el correu electrònic",
@ -475,8 +475,8 @@
"Public Chat": "Xat públic", "Public Chat": "Xat públic",
"Custom": "Personalitzat", "Custom": "Personalitzat",
"Name": "Nom", "Name": "Nom",
"You must <a>register</a> to use this functionality": "Heu de <a>register</a> per utilitzar aquesta funcionalitat", "You must <a>register</a> to use this functionality": "Per poder utilitzar aquesta funcionalitat has de <a>registrar-te</a>",
"You must join the room to see its files": "Heu d'entrar a la sala per poder-ne veure els fitxers", "You must join the room to see its files": "Per poder veure els fitxers de la sala t'hi has d'unir",
"There are no visible files in this room": "No hi ha fitxers visibles en aquesta sala", "There are no visible files in this room": "No hi ha fitxers visibles en aquesta sala",
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>Aquest és l'HTML per a la pàgina de la vostra comunitat</h1>\n<p>\n Utilitzeu la descripció llarga per a presentar la comunitat a nous membres,\n o per afegir-hi <a href=\"foo\">enlaços</a> d'interès. \n</p>\n<p>\n També podeu utilitzar etiquetes 'img'.\n</p>\n", "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>Aquest és l'HTML per a la pàgina de la vostra comunitat</h1>\n<p>\n Utilitzeu la descripció llarga per a presentar la comunitat a nous membres,\n o per afegir-hi <a href=\"foo\">enlaços</a> d'interès. \n</p>\n<p>\n També podeu utilitzar etiquetes 'img'.\n</p>\n",
"Add rooms to the community summary": "Afegiu sales al resum de la comunitat", "Add rooms to the community summary": "Afegiu sales al resum de la comunitat",
@ -499,15 +499,15 @@
"Leave Community": "Abandona la comunitat", "Leave Community": "Abandona la comunitat",
"Leave %(groupName)s?": "Voleu sortir de la comunitat %(groupName)s?", "Leave %(groupName)s?": "Voleu sortir de la comunitat %(groupName)s?",
"Leave": "Surt", "Leave": "Surt",
"Community Settings": "Paràmetres de la comunitat", "Community Settings": "Configuració de comunitat",
"These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Aquestes sales es mostren a la pàgina de la comunitat als seus membres i poden entrar-hi fent clic sobre elles.", "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Aquestes sales es mostren a la pàgina de la comunitat als seus membres i poden entrar-hi fent clic sobre elles.",
"Featured Rooms:": "Sales destacades:", "Featured Rooms:": "Sales destacades:",
"Featured Users:": "Usuaris destacats:", "Featured Users:": "Usuaris destacats:",
"%(inviter)s has invited you to join this community": "%(inviter)s vos convida a unir-vos a aquesta comunitat", "%(inviter)s has invited you to join this community": "%(inviter)s vos convida a unir-vos a aquesta comunitat",
"You are an administrator of this community": "Sou un administrador d'aquesta comunitat", "You are an administrator of this community": "Sou un administrador d'aquesta comunitat",
"You are a member of this community": "Sou un membre d'aquesta comunitat", "You are a member of this community": "Sou un membre d'aquesta comunitat",
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Esteu a punt de ser portat a un lloc de tercers perquè pugui autenticar-se amb el vostre compte per utilitzar-lo amb %(integrationsUrl)s. Voleu continuar?", "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Estàs a punt de ser redirigit a una web de tercers per autenticar el teu compte i poder ser utilitzat amb %(integrationsUrl)s. Vols continuar?",
"Your community hasn't got a Long Description, a HTML page to show to community members.<br />Click here to open settings and give it one!": "La vostra comunitat no té una descripció llarga, una pàgina HTML per mostrar als membres de la comunitat. <br />Feu clic aquí per obrir la configuració i donar-ne una!", "Your community hasn't got a Long Description, a HTML page to show to community members.<br />Click here to open settings and give it one!": "La teva comunitat no té cap descripció llarga (una pàgina HTML per mostrar als membres de la comunitat).<br />Clica aquí per obrir la configuració i crear-ne una!",
"Long Description (HTML)": "Descripció llarga (HTML)", "Long Description (HTML)": "Descripció llarga (HTML)",
"Description": "Descripció", "Description": "Descripció",
"Community %(groupId)s not found": "No s'ha pogut trobar la comunitat %(groupId)s", "Community %(groupId)s not found": "No s'ha pogut trobar la comunitat %(groupId)s",
@ -522,7 +522,7 @@
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "S'han detectat dades d'una versió antiga del %(brand)s. Això haurà provocat que el xifratge d'extrem a extrem no funcioni correctament a la versió anterior. Els missatges xifrats d'extrem a extrem que s'han intercanviat recentment mentre s'utilitzava la versió anterior no es poden desxifrar en aquesta versió. També pot provocar que els missatges intercanviats amb aquesta versió fallin. Si teniu problemes, sortiu de la sessió i torneu a entrar-hi. Per poder llegir l'historial dels missatges xifrats, exporteu i torneu a importar les vostres claus.", "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "S'han detectat dades d'una versió antiga del %(brand)s. Això haurà provocat que el xifratge d'extrem a extrem no funcioni correctament a la versió anterior. Els missatges xifrats d'extrem a extrem que s'han intercanviat recentment mentre s'utilitzava la versió anterior no es poden desxifrar en aquesta versió. També pot provocar que els missatges intercanviats amb aquesta versió fallin. Si teniu problemes, sortiu de la sessió i torneu a entrar-hi. Per poder llegir l'historial dels missatges xifrats, exporteu i torneu a importar les vostres claus.",
"Logout": "Surt", "Logout": "Surt",
"Your Communities": "Les teves comunitats", "Your Communities": "Les teves comunitats",
"Error whilst fetching joined communities": "S'ha produït un error en buscar comunitats unides", "Error whilst fetching joined communities": "Error en l'obtenció de comunitats unides",
"Create a new community": "Crea una comunitat nova", "Create a new community": "Crea una comunitat nova",
"Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Crea una comunitat per agrupar usuaris i sales! Creeu una pàgina d'inici personalitzada per definir el vostre espai a l'univers Matrix.", "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Crea una comunitat per agrupar usuaris i sales! Creeu una pàgina d'inici personalitzada per definir el vostre espai a l'univers Matrix.",
"You have no visible notifications": "No teniu cap notificació visible", "You have no visible notifications": "No teniu cap notificació visible",
@ -556,7 +556,7 @@
"Sign out": "Tanca la sessió", "Sign out": "Tanca la sessió",
"Import E2E room keys": "Importar claus E2E de sala", "Import E2E room keys": "Importar claus E2E de sala",
"Cryptography": "Criptografia", "Cryptography": "Criptografia",
"Labs": "Laboraroris", "Labs": "Laboratoris",
"%(brand)s version:": "Versió de %(brand)s:", "%(brand)s version:": "Versió de %(brand)s:",
"olm version:": "Versió d'olm:", "olm version:": "Versió d'olm:",
"Incorrect username and/or password.": "Usuari i/o contrasenya incorrectes.", "Incorrect username and/or password.": "Usuari i/o contrasenya incorrectes.",
@ -568,23 +568,23 @@
"Export": "Exporta", "Export": "Exporta",
"Import room keys": "Importa les claus de la sala", "Import room keys": "Importa les claus de la sala",
"Import": "Importa", "Import": "Importa",
"The version of %(brand)s": "La versió del %(brand)s", "The version of %(brand)s": "La versió de %(brand)s",
"Email": "Correu electrònic", "Email": "Correu electrònic",
"I have verified my email address": "He verificat l'adreça de 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": "L'URL del vostre servidor personal", "Your homeserver's URL": "L'URL del teu servidor propi",
"Analytics": "Analítiques", "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.",
"Identity Server is": "El servidor d'identitat és", "Identity Server is": "El servidor d'identitat és",
"Submit debug logs": "Enviar logs de depuració", "Submit debug logs": "Enviar logs de depuració",
"The platform you're on": "La plataforma a la que estàs", "The platform you're on": "La plataforma a la que et trobes",
"Your language of choice": "El teu idioma preferit", "Your language of choice": "El teu idioma desitjat",
"Which officially provided instance you are using, if any": "Quina instància oficial estàs utilitzant, si escau", "Which officially provided instance you are using, if any": "Quina instància oficial estàs utilitzant, si escau",
"Whether or not you're using the Richtext mode of the Rich Text Editor": "Si esteu utilitzant el mode Richtext del Rich Text Editor o no", "Whether or not you're using the Richtext mode of the Rich Text Editor": "Si estàs utilitzant, o no, el mode Richtext de Rich Text Editor",
"The information being sent to us to help make %(brand)s better includes:": "La informació enviada a %(brand)s per ajudar-nos a millorar inclou:", "The information being sent to us to help make %(brand)s better includes:": "La informació que s'envia a %(brand)s per ajudar-nos a millorar inclou:",
"Fetching third party location failed": "S'ha produït un error en obtenir la ubicació de tercers", "Fetching third party location failed": "Ha fallat l'obtenció de la ubicació de tercers",
"Send Account Data": "Envia les dades del compte", "Send Account Data": "Envia les dades del compte",
"Advanced notification settings": "Paràmetres avançats de notificacions", "Advanced notification settings": "Configuració avançada de notificacions",
"Uploading report": "S'està enviant l'informe", "Uploading report": "S'està enviant l'informe",
"Sunday": "Diumenge", "Sunday": "Diumenge",
"Failed to add tag %(tagName)s to room": "No s'ha pogut afegir l'etiqueta %(tagName)s a la sala", "Failed to add tag %(tagName)s to room": "No s'ha pogut afegir l'etiqueta %(tagName)s a la sala",
@ -612,14 +612,14 @@
"Messages containing my display name": "Missatges que contenen el meu nom visible", "Messages containing my display name": "Missatges que contenen el meu nom visible",
"Messages in one-to-one chats": "Missatges en xats un a un", "Messages in one-to-one chats": "Missatges en xats un a un",
"Unavailable": "No disponible", "Unavailable": "No disponible",
"Error saving email notification preferences": "No s'han pogut desar les preferències de les notificacions a causa d'un error", "Error saving email notification preferences": "Error desant preferències de notificacions de correu electrònic",
"View Decrypted Source": "Mostra el codi desxifrat", "View Decrypted Source": "Mostra el codi desxifrat",
"Failed to update keywords": "No s'han pogut actualitzar les paraules clau", "Failed to update keywords": "No s'han pogut actualitzar les paraules clau",
"remove %(name)s from the directory.": "elimina %(name)s del directori.", "remove %(name)s from the directory.": "elimina %(name)s del directori.",
"Notifications on the following keywords follow rules which cant be displayed here:": "Les notificacions sobre les següents paraules clau segueixen regles que no es poden mostrar aquí:", "Notifications on the following keywords follow rules which cant be displayed here:": "Les notificacions sobre les següents paraules clau segueixen regles que no es poden mostrar aquí:",
"Please set a password!": "Si us plau, establiu una contrasenya", "Please set a password!": "Si us plau, establiu una contrasenya",
"You have successfully set a password!": "Heu establert correctament la contrasenya", "You have successfully set a password!": "Heu establert correctament la contrasenya",
"An error occurred whilst saving your email notification preferences.": "S'ha produït un error en desar les vostres preferències de notificació per correu electrònic.", "An error occurred whilst saving your email notification preferences.": "S'ha produït un error mentre es desaven les teves preferències de notificació de correu electrònic.",
"Explore Room State": "Esbrina els estats de les sales", "Explore Room State": "Esbrina els estats de les sales",
"Source URL": "URL origen", "Source URL": "URL origen",
"Messages sent by bot": "Missatges enviats pel bot", "Messages sent by bot": "Missatges enviats pel bot",
@ -653,7 +653,7 @@
"Enable them now": "Habilita-ho ara", "Enable them now": "Habilita-ho ara",
"Toolbox": "Caixa d'eines", "Toolbox": "Caixa d'eines",
"Collecting logs": "S'estan recopilant els registres", "Collecting logs": "S'estan recopilant els registres",
"You must specify an event type!": "Heu d'especificar un tipus d'esdeveniment", "You must specify an event type!": "Has d'especificar un tipus d'esdeveniment!",
"(HTTP status %(httpStatus)s)": "(Estat de l´HTTP %(httpStatus)s)", "(HTTP status %(httpStatus)s)": "(Estat de l´HTTP %(httpStatus)s)",
"All Rooms": "Totes les sales", "All Rooms": "Totes les sales",
"State Key": "Clau d'estat", "State Key": "Clau d'estat",
@ -668,7 +668,7 @@
"Notify me for anything else": "Notifica'm per a qualsevol altra cosa", "Notify me for anything else": "Notifica'm per a qualsevol altra cosa",
"View Source": "Mostra el codi", "View Source": "Mostra el codi",
"Keywords": "Paraules clau", "Keywords": "Paraules clau",
"Can't update user notification settings": "No es poden actualitzar els paràmetres de les notificacions de l'usuari", "Can't update user notification settings": "No es pot actualitzar la configuració de notificacions d'usuari",
"Notify for all other messages/rooms": "Notifica per a tots els altres missatges o sales", "Notify for all other messages/rooms": "Notifica per a tots els altres missatges o sales",
"Unable to look up room ID from server": "No s'ha pogut cercar l'ID de la sala en el servidor", "Unable to look up room ID from server": "No s'ha pogut cercar l'ID de la sala en el servidor",
"Couldn't find a matching Matrix room": "No s'ha pogut trobar una sala de Matrix que coincideixi", "Couldn't find a matching Matrix room": "No s'ha pogut trobar una sala de Matrix que coincideixi",
@ -700,44 +700,44 @@
"Event Type": "Tipus d'esdeveniment", "Event Type": "Tipus d'esdeveniment",
"Download this file": "Descarrega aquest fitxer", "Download this file": "Descarrega aquest fitxer",
"Pin Message": "Enganxa el missatge", "Pin Message": "Enganxa el missatge",
"Failed to change settings": "No s'han pogut modificar els paràmetres", "Failed to change settings": "No s'ha pogut canviar la configuració",
"View Community": "Mira la communitat", "View Community": "Mira la communitat",
"Event sent!": "S'ha enviat l'esdeveniment", "Event sent!": "Esdeveniment enviat!",
"Event Content": "Contingut de l'esdeveniment", "Event Content": "Contingut de l'esdeveniment",
"Thank you!": "Gràcies!", "Thank you!": "Gràcies!",
"With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Amb el vostre navegador actual, l'aparença de l'aplicació pot ser completament incorrecta i algunes o totes les funcions poden no funcionar correctament. Si voleu provar-ho de totes maneres, podeu continuar, però esteu sols pel que fa als problemes que pugueu trobar!", "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Amb el vostre navegador actual, l'aparença de l'aplicació pot ser completament incorrecta i algunes o totes les funcions poden no funcionar correctament. Si voleu provar-ho de totes maneres, podeu continuar, però esteu sols pel que fa als problemes que pugueu trobar!",
"Checking for an update...": "Comprovant si hi ha actualitzacions...", "Checking for an update...": "Comprovant si hi ha actualitzacions...",
"e.g. %(exampleValue)s": "p. ex. %(exampleValue)s", "e.g. %(exampleValue)s": "p.e. %(exampleValue)s",
"Every page you use in the app": "Cada pàgina que utilitzeu a l'aplicació", "Every page you use in the app": "Cada pàgina que utilitzes a l'aplicació",
"e.g. <CurrentPageURL>": "p. ex. <CurrentPageURL>", "e.g. <CurrentPageURL>": "p.e. <CurrentPageURL>",
"Your device resolution": "La resolució del vostre dispositiu", "Your device resolution": "La resolució del teu dispositiu",
"Show Stickers": "Mostra els adhesius", "Show Stickers": "Mostra els adhesius",
"Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Quan aquesta pàgina contingui informació identificable, com per exemple una sala, usuari o ID de grup, aquestes dades se suprimeixen abans d'enviar-se al servidor.", "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Quan aquesta pàgina contingui informació d'identificació, com per exemple una sala, usuari o ID de grup, aquestes dades s'eliminen abans d'enviar-se al servidor.",
"Call in Progress": "Trucada en curs", "Call in Progress": "Trucada en curs",
"A call is currently being placed!": "S'està fent una trucada en aquest moment!", "A call is currently being placed!": "En aquest moment s'està realitzant una trucada!",
"A call is already in progress!": "Ja hi ha una trucada en curs!", "A call is already in progress!": "Ja hi ha una trucada en curs!",
"Permission Required": "Permís requerit", "Permission Required": "Es necessita permís",
"You do not have permission to start a conference call in this room": "No teniu permís per iniciar una trucada de conferència en aquesta sala", "You do not have permission to start a conference call in this room": "No tens permís per iniciar una conferència telefònica en aquesta sala",
"Unable to load! Check your network connectivity and try again.": "No s'ha pogut carregar! Comproveu la vostra connectivitat i torneu-ho a provar.", "Unable to load! Check your network connectivity and try again.": "No s'ha pogut carregar! Comprova la connectivitat de xarxa i torna-ho a intentar.",
"Failed to invite users to the room:": "No s'ha pogut convidar els usuaris a aquesta sala:", "Failed to invite users to the room:": "No s'han pogut convidar els usuaris a la sala:",
"Missing roomId.": "Manca l'ID de la sala.", "Missing roomId.": "Falta l'ID de sala.",
"Searches DuckDuckGo for results": "Cerca al DuckDuckGo els resultats", "Searches DuckDuckGo for results": "Cerca al DuckDuckGo els resultats",
"Changes your display nickname": "Canvia el vostre malnom", "Changes your display nickname": "Canvia el teu àlies de visualització",
"Invites user with given id to current room": "Convida l'usuari amb l'id donat a la sala actual", "Invites user with given id to current room": "Convida a la sala actual l'usuari amb l'ID indicat",
"Kicks user with given id": "Expulsa l'usuari amb l'id donat", "Kicks user with given id": "Expulsa l'usuari amb l'ID indicat",
"Bans user with given id": "Bandeja l'usuari amb l'id donat", "Bans user with given id": "Bandeja l'usuari amb l'ID indicat",
"Ignores a user, hiding their messages from you": "Ignora un usuari, amagant-te els seus missatges", "Ignores a user, hiding their messages from you": "Ignora un usuari, amagant-te els seus missatges",
"Stops ignoring a user, showing their messages going forward": "Deixa d'ignorar un usuari, mostrant els seus missatges ara en avant", "Stops ignoring a user, showing their messages going forward": "Deixa d'ignorar un usuari, i mostra els seus missatges a partir d'ara",
"Define the power level of a user": "Defineix el nivell d'autoritat d'un usuari", "Define the power level of a user": "Defineix el nivell d'autoritat d'un usuari",
"Deops user with given id": "Degrada l'usuari amb l'id donat", "Deops user with given id": "Degrada l'usuari amb l'id donat",
"Opens the Developer Tools dialog": "Obre el diàleg d'Eines del desenvolupador", "Opens the Developer Tools dialog": "Obre el diàleg d'Eines del desenvolupador",
"Displays action": "Mostra l'acció", "Displays action": "Mostra l'acció",
"Whether or not you're logged in (we don't record your username)": "Si heu iniciat sessió o no (no desem el vostre usuari)", "Whether or not you're logged in (we don't record your username)": "Si has iniciat sessió o no (no registrem el teu nom d'usuari)",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "El fitxer %(fileName)s supera el límit de pujades del servidor", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "El fitxer %(fileName)s supera la mida màxima permesa per a pujades d'aquest servidor",
"Upgrades a room to a new version": "Actualitza la sala a una versió nova", "Upgrades a room to a new version": "Actualitza la sala a una versió nova",
"Gets or sets the room topic": "Consulta o canvia el tema de la sala", "Gets or sets the room topic": "Obté o estableix el tema de la sala",
"This room has no topic.": "Aquesta sala no te tema.", "This room has no topic.": "Aquesta sala no té tema.",
"Sets the room name": "Canvia el nom de la sala", "Sets the room name": "Estableix el nom de la sala",
"%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s ha actualitzat aquesta sala.", "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s ha actualitzat aquesta sala.",
"%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s ha fet la sala pública a tothom qui conegui l'adreça.", "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s ha fet la sala pública a tothom qui conegui l'adreça.",
"%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s ha limitat la sala als convidats.", "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s ha limitat la sala als convidats.",
@ -778,7 +778,7 @@
"Common names and surnames are easy to guess": "Noms i cognoms comuns són fàcils d'esbrinar", "Common names and surnames are easy to guess": "Noms i cognoms comuns són fàcils d'esbrinar",
"Straight rows of keys are easy to guess": "Fileres seguides de tecles són fàcils d'esbrinar", "Straight rows of keys are easy to guess": "Fileres seguides de tecles són fàcils d'esbrinar",
"Short keyboard patterns are easy to guess": "Patrons curts de teclat són fàcils d'esbrinar", "Short keyboard patterns are easy to guess": "Patrons curts de teclat són fàcils d'esbrinar",
"There was an error joining the room": "Hi ha hagut un error en entrar a la sala", "There was an error joining the room": "Hi ha hagut un error unint-se a la sala",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "No s'ha trobat el perfil pels IDs de Matrix següents, els voleu convidar igualment?", "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "No s'ha trobat el perfil pels IDs de Matrix següents, els voleu convidar igualment?",
"Invite anyway and never warn me again": "Convidar igualment i no avisar-me de nou", "Invite anyway and never warn me again": "Convidar igualment i no avisar-me de nou",
"Invite anyway": "Convidar igualment", "Invite anyway": "Convidar igualment",
@ -811,5 +811,142 @@
"Theme": "Tema", "Theme": "Tema",
"Phone Number": "Número de telèfon", "Phone Number": "Número de telèfon",
"Help": "Ajuda", "Help": "Ajuda",
"Send typing notifications": "Envia notificacions d'escriptura" "Send typing notifications": "Envia notificacions d'escriptura",
"Delete the room address %(alias)s and remove %(name)s from the directory?": "Vols suprimir l'adreça de la sala %(alias)s i eliminar %(name)s del directori?",
"We encountered an error trying to restore your previous session.": "Hem trobat un error en intentar recuperar la teva sessió prèvia.",
"There was an error updating your community. The server is unable to process your request.": "S'ha produït un error en actualitzar la comunitat. El servidor no ha pogut processar la petició.",
"There was an error creating your community. The name may be taken or the server is unable to process your request.": "S'ha produït un error en crear la comunitat. Potser el nom ja existeix o el servidor no ha pogut processar la petició.",
"An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to a room admin.": "S'ha retornat un error (%(errcode)s) mentre s'intentava validar la invitació. Pots provar a informar d'això a un administrador de sala.",
"Error: Problem communicating with the given homeserver.": "Error: problema comunicant-se amb el servidor local proporcionat.",
"Upload Error": "Error de pujada",
"A connection error occurred while trying to contact the server.": "S'ha produït un error de connexió mentre s'intentava connectar al servidor.",
"%(brand)s encountered an error during upload of:": "%(brand)s ha trobat un error durant la pujada de:",
"There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "S'ha produït un error en actualitzar l'adreça principal de la sala. Pot ser que el servidor no ho permeti o que s'hagi produït un error temporal.",
"Error upgrading room": "Error actualitzant sala",
"Error unsubscribing from list": "Error en cancel·lar subscripció de la llista",
"Error changing power level requirement": "Error en canviar requisit del nivell d'autoritat",
"Error changing power level": "Error en canviar nivell d'autoritat",
"Error updating main address": "Error actualitzant adreça principal",
"Error creating address": "Error creant adreça",
"Error removing address": "Error eliminant adreça",
"There was an error removing that address. It may no longer exist or a temporary error occurred.": "S'ha produït un error en eliminar l'adreça. Pot ser que ja no existeixi o que s'hagi produït un error temporal.",
"There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "S'ha produït un error en crear l'adreça. Pot ser que el servidor no ho permeti o que s'hagi produït un error temporal.",
"There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "S'ha produït un error en actualitzar l'adreça alternativa de la sala. Pot ser que el servidor no ho permeti o que s'hagi produït un error temporal.",
"%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.": "S'ha retornat %(errcode)s mentre s'intentava accedir a la sala. Si creus que aquest missatge és un error, <issueLink>envia un informe d'error</issueLink>.",
"Error removing ignored user/server": "Error eliminant usuari/servidor ignorat",
"Error subscribing to list": "Error subscrivint-se a la llista",
"Error adding ignored user/server": "Error afegint usuari/servidor ignorat",
"Error downloading theme information.": "Error baixant informació de tema.",
"Unexpected server error trying to leave the room": "Error de servidor inesperat intentant sortir de la sala",
"Error leaving room": "Error sortint de la sala",
"Unexpected error resolving identity server configuration": "Error inesperat resolent la configuració del servidor d'identitat",
"Unexpected error resolving homeserver configuration": "Error inesperat resolent la configuració del servidor local",
"(an error occurred)": "(s'ha produït un error)",
"Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Els gestors d'integracions reben dades de configuració i poden modificar ginys, enviar invitacions a sales i establir nivells d'autoritat en nom teu.",
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "S'ha produït un error en canviar els requisits del nivell d'autoritat de la sala. Assegura't que tens suficients permisos i torna-ho a provar.",
"An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "S'ha produït un error en canviar el nivell d'autoritat de l'usuari. Assegura't que tens suficients permisos i torna-ho a provar.",
"Power level": "Nivell d'autoritat",
"Unbans user with given ID": "Desbandeja l'usuari amb l'ID indicat",
"Unrecognised room address:": "Adreça de sala no reconeguda:",
"Joins room with given address": "S'uneix a la sala amb l'adreça indicada",
"Use an identity server": "Utilitza un servidor d'identitat",
"Failed to set topic": "No s'ha pogut establir el tema",
"Changes your avatar in all rooms": "Canvia el teu avatar en totes les sales",
"Changes your avatar in this current room only": "Canvia el teu avatar només en aquesta sala actual",
"Changes the avatar of the current room": "Canvia l'avatar de la sala actual",
"Changes your display nickname in the current room only": "Canvia el teu àlies de visualització només en la sala actual",
"Double check that your server supports the room version chosen and try again.": "Comprova que el teu servidor és compatible amb la versió de sala que has triat i torna-ho a intentar.",
"You do not have the required permissions to use this command.": "No disposes dels permisos necessaris per utilitzar aquesta ordre.",
"Sends a message as html, without interpreting it as markdown": "Envia un missatge com a html sense interpretar-lo com a markdown",
"Sends a message as plain text, without interpreting it as markdown": "Envia un missatge com a text pla sense interpretar-lo com a markdown",
"Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Afegeix ( ͡° ͜ʖ ͡°) al principi d'un missatge de text pla",
"Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Afegeix ¯\\_(ツ)_/¯ al principi d'un missatge de text pla",
"Other": "Altres",
"Actions": "Accions",
"Messages": "Missatges",
"Setting up keys": "Configurant claus",
"Go Back": "Torna",
"Are you sure you want to cancel entering passphrase?": "Estàs segur que vols cancel·lar la introducció de la frase secreta?",
"Cancel entering passphrase?": "Vols cancel·lar la introducció de la frase secreta?",
"Custom (%(level)s)": "Personalitzat (%(level)s)",
"Sign In": "Inicia sessió",
"Create Account": "Crea un compte",
"Use your account or create a new one to continue.": "Utilitza el teu compte o crea'n un de nou per continuar.",
"Sign In or Create Account": "Inicia sessió o Crea un compte",
"%(name)s is requesting verification": "%(name)s està demanant verificació",
"Trust": "Confiança",
"Only continue if you trust the owner of the server.": "Continua, només, si confies amb el propietari del servidor.",
"Identity server has no terms of service": "El servidor d'identitat no disposa de condicions de servei",
"This action requires accessing the default identity server <server /> to validate an email address or phone number, but the server does not have any terms of service.": "Aquesta acció necessita accedir al servidor d'identitat predeterminat <server /> per validar una adreça de correu electrònic o un número de telèfon, però el servidor no disposa de condicions de servei.",
"Room name or address": "Nom o adreça de la sala",
"Name or Matrix ID": "Nom o ID de Matrix",
"The server does not support the room version specified.": "El servidor no és compatible amb la versió de sala especificada.",
"The file '%(fileName)s' failed to upload.": "No s'ha pogut pujar el fitxer '%(fileName)s'.",
"At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "En aquests moments no és possible respondre amb un fitxer. Vols pujar aquest fitxer sense respondre?",
"Replying With Files": "Responent amb fitxers",
"Answered Elsewhere": "Respost en una altra banda",
"Your user agent": "El teu agent d'usuari",
"Find a room… (e.g. %(exampleRoom)s)": "Cerca un sala... (p.e. %(exampleRoom)s)",
"e.g. my-room": "p.e. la-meva-sala",
"New published address (e.g. #alias:server)": "Nova adreça publicada (p.e. #alias:server)",
"Whether you're using %(brand)s as an installed Progressive Web App": "Si estàs utilitzant %(brand)s com a una instal·lació d'una Aplicació Web Progressiva (PWA)",
"Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Si estàs utilitzant, o no, la funció 'molles de pa' (avatars a sobre la llista de sales)",
"Whether you're using %(brand)s on a device where touch is the primary input mechanism": "Si estàs utilitzant %(brand)s en un dispositiu on el tàctil és el principal mecanisme d'entrada",
"If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Si no has eliminat el mètode de recuperació, pot ser que un atacant estigui intentant accedir al teu compte. Canvia la teva contrasenya i configura un nou mètode de recuperació a Configuració, immediatament.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Si no has configurat el teu mètode de recuperació, pot ser que un atacant estigui intentant accedir al teu compte. Canvia la teva contrasenya i configura un nou mètode de recuperació a Configuració, immediatament.",
"You can also set up Secure Backup & manage your keys in Settings.": "També pots configurar la còpia de seguretat segura i gestionar les teves claus a Configuració.",
"You've previously used %(brand)s on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, %(brand)s needs to resync your account.": "Prèviament has fet servir %(brand)s a %(host)s amb la càrrega mandrosa de membres activada. En aquesta versió la càrrega mandrosa està desactivada. Com que la memòria cau local no és compatible entre les dues versions, %(brand)s necessita tornar a sincronitzar el teu compte.",
"Show info about bridges in room settings": "Mostra informació d'enllaços a la configuració de sala",
"Use an identity server to invite by email. Manage in Settings.": "Utilitza un servidor d'identitat per convidar per correu electrònic. Gestiona'l a Configuració.",
"Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Utilitza un servidor d'identitat per poder convidar per correu electrònic. Fes clic a continua per a utilitzar el servidor d'identitat predeterminat (%(defaultIdentityServerName)s) o gestiona'l a Configuració.",
"Use an identity server to invite by email. <default>Use the default (%(defaultIdentityServerName)s)</default> or manage in <settings>Settings</settings>.": "Utilitza un servidor d'identitat per poder convidar per correu electrònic. <default>Utilitza el predeterminat (%(defaultIdentityServerName)s)</default> o gestiona'l a <settings>Configuració</settings>.",
"Use an identity server to invite by email. Manage in <settings>Settings</settings>.": "Utilitza un servidor d'identitat per poder convidar per correu electrònic. Gestiona'l a <settings>Configuració</settings>.",
"Integrations not allowed": "No es permeten integracions",
"Integrations are disabled": "Les integracions estan desactivades",
"Manage integrations": "Gestió d'integracions",
"Community settings": "Configuració de comunitat",
"Notification settings": "Configuració de notificacions",
"Room Settings - %(roomName)s": "Configuració de sala - %(roomName)s",
"Confirm this user's session by comparing the following with their User Settings:": "Confirma aquesta sessió d'usuari comparant amb la seva configuració d'usuari, el següent:",
"Confirm by comparing the following with the User Settings in your other session:": "Confirma comparant el següent amb la configuració d'usuari de la teva altra sessió:",
"Room settings": "Configuració de sala",
"Appearance Settings only affect this %(brand)s session.": "La configuració d'aspecte només afecta aquesta sessió %(brand)s.",
"Change notification settings": "Canvia la configuració de notificacions",
"⚠ These settings are meant for advanced users.": "⚠ Aquesta configuració està pensada per usuaris avançats.",
"Link this email with your account in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, enllaça aquest correu electrònic amb el teu compte a Configuració.",
"Change settings": "Canvia la configuració",
"Use an identity server in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, utilitza un servidor d'identitat a Configuració.",
"Share this email in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, comparteix aquest correu electrònic a Configuració.",
"Enable 'Manage Integrations' in Settings to do this.": "Per fer això, activa 'Gestió d'integracions' a Configuració.",
"We recommend you change your password and recovery key in Settings immediately": "Et recomanem que canviïs immediatament la teva contrasenya i clau de recuperació a Configuració",
"Go to Settings": "Ves a Configuració",
"No identity server is configured: add one in server settings to reset your password.": "No hi ha cap servidor d'identitat configurat: afegeix-ne un a la configuració del servidor per poder restablir la teva contrasenya.",
"User settings": "Configuració d'usuari",
"All settings": "Totes les configuracions",
"This will end the conference for everyone. Continue?": "Això finalitzarà la conferència per a tothom. Vols continuar?",
"End conference": "Finalitza la conferència",
"Alternatively, you can try to use the public server at <code>turn.matrix.org</code>, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Com a alternativa, pots provar d'utilitzar el servidor públic a <code>turn.matrix.org</code>, però no serà tant fiable i compartirà la teva IP amb el servidor. També pots gestionar-ho a Configuració.",
"Try using turn.matrix.org": "Prova d'utilitzar turn.matrix.org",
"Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.": "Demana a l'administrador del servidor local (<code>%(homeserverDomain)s</code>) que configuri un servidor TURN perquè les trucades funcionin de manera fiable.",
"Call failed due to misconfigured server": "La trucada ha fallat a causa d'una configuració errònia al servidor",
"The call was answered on another device.": "La trucada s'ha respost des d'un altre dispositiu.",
"The call could not be established": "No s'ha pogut establir la trucada",
"The other party declined the call.": "L'altra part ha rebutjat la trucada.",
"Call Declined": "Trucada rebutjada",
"Add Phone Number": "Afegeix número de telèfon",
"Confirm adding email": "Confirma l'addició del correu electrònic",
"To continue, use Single Sign On to prove your identity.": "Per continuar, utilitza la inscripció única SSO (per demostrar la teva identitat).",
"Confirm your account deactivation by using Single Sign On to prove your identity.": "Confirma la desactivació del teu compte mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "Confirma l'eliminació d'aquesta sessió mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "Confirma l'eliminació d'aquestes sessions mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Confirma l'addició d'aquest número de telèfon mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Confirma l'addició d'aquest correu electrònic mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Sign in with single sign-on": "Inicia sessió mitjançant la inscripció única (SSO)",
"Single Sign On": "Inscripció única (SSO)",
"Use Single Sign On to continue": "Utilitza la inscripció única (SSO) per a continuar",
"Click the button below to confirm adding this phone number.": "Fes clic al botó de sota per confirmar l'addició d'aquest número de telèfon.",
"Confirm adding phone number": "Confirma l'addició del número de telèfon",
"Add Email Address": "Afegeix una adreça de correu electrònic",
"Confirm": "Confirma",
"Click the button below to confirm adding this email address.": "Fes clic al botó de sota per confirmar l'addició d'aquesta adreça de correu electrònic."
} }

View file

@ -462,6 +462,8 @@
"Send a bug report with logs": "Send a bug report with logs", "Send a bug report with logs": "Send a bug report with logs",
"Opens chat with the given user": "Opens chat with the given user", "Opens chat with the given user": "Opens chat with the given user",
"Sends a message to the given user": "Sends a message to the given user", "Sends a message to the given user": "Sends a message to the given user",
"Places the call in the current room on hold": "Places the call in the current room on hold",
"Takes the call in the current room off hold": "Takes the call in the current room off hold",
"Displays action": "Displays action", "Displays action": "Displays action",
"Reason": "Reason", "Reason": "Reason",
"%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s accepted the invitation for %(displayName)s.", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s accepted the invitation for %(displayName)s.",
@ -646,7 +648,7 @@
"Unknown App": "Unknown App", "Unknown App": "Unknown App",
"Help us improve %(brand)s": "Help us improve %(brand)s", "Help us improve %(brand)s": "Help us improve %(brand)s",
"Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve %(brand)s. This will use a <PolicyLink>cookie</PolicyLink>.": "Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve %(brand)s. This will use a <PolicyLink>cookie</PolicyLink>.", "Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve %(brand)s. This will use a <PolicyLink>cookie</PolicyLink>.": "Send <UsageDataLink>anonymous usage data</UsageDataLink> which helps us improve %(brand)s. This will use a <PolicyLink>cookie</PolicyLink>.",
"I want to help": "I want to help", "Yes": "Yes",
"No": "No", "No": "No",
"Review where youre logged in": "Review where youre logged in", "Review where youre logged in": "Review where youre logged in",
"Verify all your sessions to ensure your account & messages are safe": "Verify all your sessions to ensure your account & messages are safe", "Verify all your sessions to ensure your account & messages are safe": "Verify all your sessions to ensure your account & messages are safe",
@ -777,6 +779,7 @@
"My Ban List": "My Ban List", "My Ban List": "My Ban List",
"This is your list of users/servers you have blocked - don't leave the room!": "This is your list of users/servers you have blocked - don't leave the room!", "This is your list of users/servers you have blocked - don't leave the room!": "This is your list of users/servers you have blocked - don't leave the room!",
"Active call": "Active call", "Active call": "Active call",
"Call Paused": "Call Paused",
"Unknown caller": "Unknown caller", "Unknown caller": "Unknown caller",
"Incoming voice call": "Incoming voice call", "Incoming voice call": "Incoming voice call",
"Incoming video call": "Incoming video call", "Incoming video call": "Incoming video call",
@ -932,9 +935,8 @@
"Failed to set display name": "Failed to set display name", "Failed to set display name": "Failed to set display name",
"Encryption": "Encryption", "Encryption": "Encryption",
"Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.", "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
"Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ", "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|other": "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.",
" to store messages from ": " to store messages from ", "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s rooms.|one": "Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(rooms)s room.",
"rooms.": "rooms.",
"Manage": "Manage", "Manage": "Manage",
"Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.", "Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.",
"%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.": "%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.", "%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.": "%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with <nativeLink>search components added</nativeLink>.",
@ -1332,6 +1334,15 @@
"Strikethrough": "Strikethrough", "Strikethrough": "Strikethrough",
"Code block": "Code block", "Code block": "Code block",
"Quote": "Quote", "Quote": "Quote",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Only the two of you are in this conversation, unless either of you invites anyone to join.",
"This is the beginning of your direct message history with <displayName/>.": "This is the beginning of your direct message history with <displayName/>.",
"Topic: %(topic)s (<a>edit</a>)": "Topic: %(topic)s (<a>edit</a>)",
"Topic: %(topic)s ": "Topic: %(topic)s ",
"<a>Add a topic</a> to help people know what it is about.": "<a>Add a topic</a> to help people know what it is about.",
"You created this room.": "You created this room.",
"%(displayName)s created this room.": "%(displayName)s created this room.",
"Add a photo, so people can easily spot your room.": "Add a photo, so people can easily spot your room.",
"This is the start of <roomName/>.": "This is the start of <roomName/>.",
"No pinned messages.": "No pinned messages.", "No pinned messages.": "No pinned messages.",
"Loading...": "Loading...", "Loading...": "Loading...",
"Pinned Messages": "Pinned Messages", "Pinned Messages": "Pinned Messages",
@ -1379,6 +1390,7 @@
"Historical": "Historical", "Historical": "Historical",
"Custom Tag": "Custom Tag", "Custom Tag": "Custom Tag",
"Can't see what youre looking for?": "Can't see what youre looking for?", "Can't see what youre looking for?": "Can't see what youre looking for?",
"Start a new chat": "Start a new chat",
"Explore all public rooms": "Explore all public rooms", "Explore all public rooms": "Explore all public rooms",
"Use the + to make a new room or explore existing ones below": "Use the + to make a new room or explore existing ones below", "Use the + to make a new room or explore existing ones below": "Use the + to make a new room or explore existing ones below",
"%(count)s results|other": "%(count)s results", "%(count)s results|other": "%(count)s results",
@ -1586,7 +1598,6 @@
"Remove this user from community?": "Remove this user from community?", "Remove this user from community?": "Remove this user from community?",
"Failed to withdraw invitation": "Failed to withdraw invitation", "Failed to withdraw invitation": "Failed to withdraw invitation",
"Failed to remove user from community": "Failed to remove user from community", "Failed to remove user from community": "Failed to remove user from community",
"<strong>%(role)s</strong> in %(roomName)s": "<strong>%(role)s</strong> in %(roomName)s",
"Failed to change power level": "Failed to change power level", "Failed to change power level": "Failed to change power level",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.",
"Are you sure?": "Are you sure?", "Are you sure?": "Are you sure?",
@ -1594,6 +1605,7 @@
"Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?", "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?",
"Deactivate user": "Deactivate user", "Deactivate user": "Deactivate user",
"Failed to deactivate user": "Failed to deactivate user", "Failed to deactivate user": "Failed to deactivate user",
"Role": "Role",
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.", "This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
"Security": "Security", "Security": "Security",
"The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.", "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.",
@ -1604,7 +1616,6 @@
"Verify by emoji": "Verify by emoji", "Verify by emoji": "Verify by emoji",
"Almost there! Is your other session showing the same shield?": "Almost there! Is your other session showing the same shield?", "Almost there! Is your other session showing the same shield?": "Almost there! Is your other session showing the same shield?",
"Almost there! Is %(displayName)s showing the same shield?": "Almost there! Is %(displayName)s showing the same shield?", "Almost there! Is %(displayName)s showing the same shield?": "Almost there! Is %(displayName)s showing the same shield?",
"Yes": "Yes",
"Verify all users in a room to ensure it's secure.": "Verify all users in a room to ensure it's secure.", "Verify all users in a room to ensure it's secure.": "Verify all users in a room to ensure it's secure.",
"In encrypted rooms, verify all users to ensure its secure.": "In encrypted rooms, verify all users to ensure its secure.", "In encrypted rooms, verify all users to ensure its secure.": "In encrypted rooms, verify all users to ensure its secure.",
"You've successfully verified your device!": "You've successfully verified your device!", "You've successfully verified your device!": "You've successfully verified your device!",
@ -1630,8 +1641,9 @@
"Today": "Today", "Today": "Today",
"Yesterday": "Yesterday", "Yesterday": "Yesterday",
"View Source": "View Source", "View Source": "View Source",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.",
"Encryption enabled": "Encryption enabled", "Encryption enabled": "Encryption enabled",
"Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.",
"Ignored attempt to disable encryption": "Ignored attempt to disable encryption", "Ignored attempt to disable encryption": "Ignored attempt to disable encryption",
"Encryption not enabled": "Encryption not enabled", "Encryption not enabled": "Encryption not enabled",
"The encryption used by this room isn't supported.": "The encryption used by this room isn't supported.", "The encryption used by this room isn't supported.": "The encryption used by this room isn't supported.",
@ -1677,8 +1689,8 @@
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s", "%(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.", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.",
"%(senderDisplayName)s changed the room avatar to <img/>": "%(senderDisplayName)s changed the room avatar to <img/>", "%(senderDisplayName)s changed the room avatar to <img/>": "%(senderDisplayName)s changed the room avatar to <img/>",
"This room is a continuation of another conversation.": "This room is a continuation of another conversation.",
"Click here to see older messages.": "Click here to see older messages.", "Click here to see older messages.": "Click here to see older messages.",
"This room is a continuation of another conversation.": "This room is a continuation of another conversation.",
"Copied!": "Copied!", "Copied!": "Copied!",
"Failed to copy": "Failed to copy", "Failed to copy": "Failed to copy",
"Add an Integration": "Add an Integration", "Add an Integration": "Add an Integration",
@ -2197,8 +2209,8 @@
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.", "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.",
"Please review and accept all of the homeserver's policies": "Please review and accept all of the homeserver's policies", "Please review and accept all of the homeserver's policies": "Please review and accept all of the homeserver's policies",
"Please review and accept the policies of this homeserver:": "Please review and accept the policies of this homeserver:", "Please review and accept the policies of this homeserver:": "Please review and accept the policies of this homeserver:",
"An email has been sent to %(emailAddress)s": "An email has been sent to %(emailAddress)s", "A confirmation email has been sent to %(emailAddress)s": "A confirmation email has been sent to %(emailAddress)s",
"Please check your email to continue registration.": "Please check your email to continue registration.", "Open the link in the email to continue registration.": "Open the link in the email to continue registration.",
"Token incorrect": "Token incorrect", "Token incorrect": "Token incorrect",
"A text message has been sent to %(msisdn)s": "A text message has been sent to %(msisdn)s", "A text message has been sent to %(msisdn)s": "A text message has been sent to %(msisdn)s",
"Please enter the code it contains:": "Please enter the code it contains:", "Please enter the code it contains:": "Please enter the code it contains:",
@ -2235,8 +2247,6 @@
"Enter username": "Enter username", "Enter username": "Enter username",
"Email (optional)": "Email (optional)", "Email (optional)": "Email (optional)",
"Phone (optional)": "Phone (optional)", "Phone (optional)": "Phone (optional)",
"Create your Matrix account on %(serverName)s": "Create your Matrix account on %(serverName)s",
"Create your Matrix account on <underlinedServerName />": "Create your Matrix account on <underlinedServerName />",
"Register": "Register", "Register": "Register",
"Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.": "Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.", "Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.": "Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.",
"Set an email for account recovery. Use email to optionally be discoverable by existing contacts.": "Set an email for account recovery. Use email to optionally be discoverable by existing contacts.", "Set an email for account recovery. Use email to optionally be discoverable by existing contacts.": "Set an email for account recovery. Use email to optionally be discoverable by existing contacts.",
@ -2260,7 +2270,7 @@
"Attach files from chat or just drag and drop them anywhere in a room.": "Attach files from chat or just drag and drop them anywhere in a room.", "Attach files from chat or just drag and drop them anywhere in a room.": "Attach files from chat or just drag and drop them anywhere in a room.",
"Communities": "Communities", "Communities": "Communities",
"Create community": "Create community", "Create community": "Create community",
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n", "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even add images with Matrix URLs <img src=\"mxc://url\" />\n</p>\n": "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even add images with Matrix URLs <img src=\"mxc://url\" />\n</p>\n",
"Add rooms to the community summary": "Add rooms to the community summary", "Add rooms to the community summary": "Add rooms to the community summary",
"Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?", "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",
"Add to summary": "Add to summary", "Add to summary": "Add to summary",
@ -2328,6 +2338,7 @@
"Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.", "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.",
"Self-verification request": "Self-verification request", "Self-verification request": "Self-verification request",
"Logout": "Logout", "Logout": "Logout",
"%(creator)s created this DM.": "%(creator)s created this DM.",
"%(creator)s created and configured the room.": "%(creator)s created and configured the room.", "%(creator)s created and configured the room.": "%(creator)s created and configured the room.",
"Your Communities": "Your Communities", "Your Communities": "Your Communities",
"Did you know: you can use communities to filter your %(brand)s experience!": "Did you know: you can use communities to filter your %(brand)s experience!", "Did you know: you can use communities to filter your %(brand)s experience!": "Did you know: you can use communities to filter your %(brand)s experience!",
@ -2358,8 +2369,9 @@
"Find a room… (e.g. %(exampleRoom)s)": "Find a room… (e.g. %(exampleRoom)s)", "Find a room… (e.g. %(exampleRoom)s)": "Find a room… (e.g. %(exampleRoom)s)",
"If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.": "If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.", "If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.": "If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.",
"Explore rooms in %(communityName)s": "Explore rooms in %(communityName)s", "Explore rooms in %(communityName)s": "Explore rooms in %(communityName)s",
"Filter": "Filter",
"Clear filter": "Clear filter", "Clear filter": "Clear filter",
"Search rooms": "Search rooms", "Filter rooms and people": "Filter rooms and people",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.", "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.",
"Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.": "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.", "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.": "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.",
"Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.": "Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.", "Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.": "Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.",
@ -2373,7 +2385,6 @@
"Starting microphone...": "Starting microphone...", "Starting microphone...": "Starting microphone...",
"Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.",
"Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.",
"There's no one else here! Would you like to <inviteText>invite others</inviteText> or <nowarnText>stop warning about the empty room</nowarnText>?": "There's no one else here! Would you like to <inviteText>invite others</inviteText> or <nowarnText>stop warning about the empty room</nowarnText>?",
"You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?",
"You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?", "You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?",
"Search failed": "Search failed", "Search failed": "Search failed",
@ -2448,9 +2459,6 @@
"Signing In...": "Signing In...", "Signing In...": "Signing In...",
"If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while", "If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while",
"Create account": "Create account", "Create account": "Create account",
"Failed to fetch avatar URL": "Failed to fetch avatar URL",
"Set a display name:": "Set a display name:",
"Upload an avatar:": "Upload an avatar:",
"Unable to query for supported registration methods.": "Unable to query for supported registration methods.", "Unable to query for supported registration methods.": "Unable to query for supported registration methods.",
"Registration has been disabled on this homeserver.": "Registration has been disabled on this homeserver.", "Registration has been disabled on this homeserver.": "Registration has been disabled on this homeserver.",
"This server does not support authentication with a phone number.": "This server does not support authentication with a phone number.", "This server does not support authentication with a phone number.": "This server does not support authentication with a phone number.",
@ -2459,6 +2467,8 @@
"<a>Log in</a> to your new account.": "<a>Log in</a> to your new account.", "<a>Log in</a> to your new account.": "<a>Log in</a> to your new account.",
"You can now close this window or <a>log in</a> to your new account.": "You can now close this window or <a>log in</a> to your new account.", "You can now close this window or <a>log in</a> to your new account.": "You can now close this window or <a>log in</a> to your new account.",
"Registration Successful": "Registration Successful", "Registration Successful": "Registration Successful",
"Create your Matrix account on %(serverName)s": "Create your Matrix account on %(serverName)s",
"Create your Matrix account on <underlinedServerName />": "Create your Matrix account on <underlinedServerName />",
"Create your account": "Create your account", "Create your account": "Create your account",
"Use Recovery Key or Passphrase": "Use Recovery Key or Passphrase", "Use Recovery Key or Passphrase": "Use Recovery Key or Passphrase",
"Use Recovery Key": "Use Recovery Key", "Use Recovery Key": "Use Recovery Key",
@ -2620,6 +2630,7 @@
"Activate selected button": "Activate selected button", "Activate selected button": "Activate selected button",
"Toggle right panel": "Toggle right panel", "Toggle right panel": "Toggle right panel",
"Toggle this dialog": "Toggle this dialog", "Toggle this dialog": "Toggle this dialog",
"Go to Home View": "Go to Home View",
"Move autocomplete selection up/down": "Move autocomplete selection up/down", "Move autocomplete selection up/down": "Move autocomplete selection up/down",
"Cancel autocomplete": "Cancel autocomplete", "Cancel autocomplete": "Cancel autocomplete",
"Page Up": "Page Up", "Page Up": "Page Up",

View file

@ -2538,5 +2538,164 @@
"Add comment": "Aldoni komenton", "Add comment": "Aldoni komenton",
"Please go into as much detail as you like, so we can track down the problem.": "Bonvolu detaligi tiel multe, kiel vi volas, por ke ni povu pli facile trovi la problemon.", "Please go into as much detail as you like, so we can track down the problem.": "Bonvolu detaligi tiel multe, kiel vi volas, por ke ni povu pli facile trovi la problemon.",
"Tell us below how you feel about %(brand)s so far.": "Diru al ni, kion vi ĝis nun pensas pri %(brand)s.", "Tell us below how you feel about %(brand)s so far.": "Diru al ni, kion vi ĝis nun pensas pri %(brand)s.",
"Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Pratipoj de la 2-a versio de komunumoj. Bezonas konforman hejmservilon. Tre eksperimenta uzu nur zorge." "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Pratipoj de la 2-a versio de komunumoj. Bezonas konforman hejmservilon. Tre eksperimenta uzu nur zorge.",
"Uzbekistan": "Uzbekujo",
"United Arab Emirates": "Unuiĝinaj Arabaj Emirlandoj",
"Ukraine": "Ukrainujo",
"Uganda": "Ugando",
"Turkey": "Turkujo",
"Tunisia": "Tunizio",
"Tajikistan": "Taĝikujo",
"Malta": "Malto",
"Mali": "Malio",
"Maldives": "Maldivoj",
"Malaysia": "Malajzio",
"Luxembourg": "Luksemburgo",
"Lithuania": "Litovujo",
"Liechtenstein": "Liĥtenŝtejno",
"Latvia": "Latvujo",
"Laos": "Laoso",
"Kyrgyzstan": "Kirgizujo",
"Kosovo": "Kosovo",
"Kenya": "Kenjo",
"Kazakhstan": "Kazaĥujo",
"Japan": "Japanujo",
"Jamaica": "Jamajko",
"Italy": "Italujo",
"Israel": "Israelo",
"Isle of Man": "Manksujo",
"Ireland": "Irlando",
"Iraq": "Irako",
"Iran": "Irano",
"Indonesia": "Indonezio",
"India": "Barato",
"Iceland": "Islando",
"Hungary": "Hungarujo",
"Hong Kong": "Honkongo",
"Honduras": "Honduro",
"Haiti": "Haitio",
"Guatemala": "Gvatemalo",
"Grenada": "Grenado",
"Greenland": "Gronlando",
"Greece": "Grekujo",
"Gibraltar": "Ĝibraltaro",
"Germany": "Germanujo",
"France": "Francujo",
"Finland": "Finlando",
"Fiji": "Fiĝio",
"Ethiopia": "Etiopujo",
"Estonia": "Estonujo",
"Eritrea": "Eritreo",
"Equatorial Guinea": "Ekvatora Gvineo",
"El Salvador": "Salvadoro",
"Egypt": "Egiptujo",
"Ecuador": "Ekvadoro",
"Dominican Republic": "Dominika Respubliko",
"Dominica": "Dominiko",
"Denmark": "Danujo",
"Côte dIvoire": "Ebur-Bordo",
"Czech Republic": "Ĉeĥujo",
"Cyprus": "Kipro",
"Cuba": "Kubo",
"Croatia": "Kroatujo",
"Costa Rica": "Kostariko",
"Cook Islands": "Insuloj de Cook",
"Comoros": "Komoroj",
"Colombia": "Kolombio",
"Christmas Island": "Kristnaskinsulo",
"China": "Ĉinujo",
"Chile": "Ĉilio",
"Chad": "Ĉado",
"Central African Republic": "Centr-Afriko",
"Cape Verde": "Kaboverdo",
"Canada": "Kanado",
"Cameroon": "Kameruno",
"Cambodia": "Kamboĝo",
"Burundi": "Burundo",
"Bulgaria": "Bulgarujo",
"Brunei": "Brunejo",
"British Virgin Islands": "Britaj Virgulininsuloj",
"Brazil": "Brazilo",
"Botswana": "Cvanujo",
"Bosnia": "Bosnujo",
"Bolivia": "Bolivio",
"Bhutan": "Butano",
"Bermuda": "Bermudo",
"Benin": "Benino",
"Belize": "Belizo",
"Belgium": "Belgujo",
"Belarus": "Belorusujo",
"Barbados": "Barbado",
"Bangladesh": "Bangladeŝo",
"Bahrain": "Barejno",
"Bahamas": "Bahamoj",
"Azerbaijan": "Azerbajĝano",
"Austria": "Aŭstrujo",
"Australia": "Aŭstralio",
"Aruba": "Arubo",
"Armenia": "Armenujo",
"Argentina": "Argentino",
"Antigua & Barbuda": "Antigvo kaj Barbudo",
"Antarctica": "Antarkto",
"Angola": "Angolo",
"Andorra": "Andoro",
"American Samoa": "Usona Samoo",
"Algeria": "Alĝerio",
"Albania": "Albanujo",
"Åland Islands": "Alando",
"Afghanistan": "Afganujo",
"United States": "Usono",
"United Kingdom": "Britujo",
"Sri Lanka": "Srilanko",
"Spain": "Hispanujo",
"South Korea": "Sud-Koreujo",
"South Africa": "Sud-Afriko",
"Somalia": "Somalujo",
"Solomon Islands": "Salomonoj",
"Slovenia": "Slovenujo",
"Slovakia": "Slovakujo",
"Singapore": "Singapuro",
"Sierra Leone": "Sieraleono",
"Seychelles": "Sejŝeloj",
"Serbia": "Serbujo",
"Senegal": "Senegalo",
"Saudi Arabia": "Sauda Arabujo",
"San Marino": "Sanmarino",
"Samoa": "Samoo",
"Rwanda": "Ruando",
"Russia": "Rusujo",
"Romania": "Rumanujo",
"Qatar": "Kataro",
"Puerto Rico": "Portoriko",
"Portugal": "Portugalujo",
"Poland": "Polujo",
"Philippines": "Filipinoj",
"Peru": "Peruo",
"Paraguay": "Paragvajo",
"Papua New Guinea": "Papuo-Nov-Gvineo",
"Panama": "Panamo",
"Palestine": "Palestino",
"Palau": "Palaŭo",
"Pakistan": "Pakistano",
"Oman": "Omano",
"Norway": "Norvegujo",
"North Korea": "Nord-Koreujo",
"Niue": "Niuo",
"Nigeria": "Niĝerio",
"Niger": "Niĝero",
"New Zealand": "Nov-Zelando",
"New Caledonia": "Nova Kaledonio",
"Netherlands": "Nederlando",
"Nepal": "Nepalo",
"Nauru": "Nauro",
"Namibia": "Namibio",
"Myanmar": "Birmo",
"Mozambique": "Mozambiko",
"Morocco": "Maroko",
"Montserrat": "Moncerato",
"Montenegro": "Montenegro",
"Caribbean Netherlands": "Kariba Nederlando",
"Burkina Faso": "Burkino",
"Bouvet Island": "Buvet-Insulo",
"Anguilla": "Angvilo"
} }

View file

@ -2562,5 +2562,289 @@
"Rate %(brand)s": "Hinda %(brand)s rakendust", "Rate %(brand)s": "Hinda %(brand)s rakendust",
"Feedback sent": "Tagasiside on saadetud", "Feedback sent": "Tagasiside on saadetud",
"%(senderName)s ended the call": "%(senderName)s lõpetas kõne", "%(senderName)s ended the call": "%(senderName)s lõpetas kõne",
"You ended the call": "Sina lõpetasid kõne" "You ended the call": "Sina lõpetasid kõne",
"Now, lets help you get started": "Nüüd näitame sulle, mida saad järgmiseks teha",
"Welcome %(name)s": "Tere tulemast, %(name)s",
"Add a photo so people know it's you.": "Enda tutvustamiseks lisa foto.",
"Great, that'll help people know it's you": "Suurepärane, nüüd teised teavad et tegemist on sinuga",
"Use the + to make a new room or explore existing ones below": "Uue jututoa tegemiseks või olemasolevatega tutvumiseks klõpsi + märki",
"New version of %(brand)s is available": "%(brand)s ralenduse uus versioon on saadaval",
"Update %(brand)s": "Uuenda %(brand)s rakendust",
"Enable desktop notifications": "Võta kasutusele töölauakeskkonna teavitused",
"Don't miss a reply": "Ära jäta vastust vahele",
"Now, let's help you get started": "Nüüd näitame sulle, mida saad järgmiseks teha",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Kutsu teist osapoolt tema nime, e-posti aadressi, kasutajanime (nagu <userId/>) alusel või <a>jaga seda jututuba</a>.",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Alusta vestlust kasutades teise osapoole nime, e-posti aadressi või kasutajanime (näiteks <userId/>).",
"Invite by email": "Saada kutse e-kirjaga",
"Zambia": "Sambia",
"Yemen": "Jeemen",
"Western Sahara": "Lääne-Sahara",
"Wallis & Futuna": "Wallis ja Futuna",
"Vietnam": "Vietnam",
"Venezuela": "Venezuela",
"Vatican City": "Vatikan",
"Vanuatu": "Vanuatu",
"Uzbekistan": "Usbekistan",
"Uruguay": "Uruguay",
"United Arab Emirates": "Araabia Ühendemiraadid",
"Ukraine": "Ukraina",
"Uganda": "Uganda",
"U.S. Virgin Islands": "USA Neitsisaared",
"Tuvalu": "Tuvalu",
"Turks & Caicos Islands": "Turks ja Caicos",
"Turkmenistan": "Türkmenistan",
"Turkey": "Türgi",
"Tunisia": "Tuneesia",
"Trinidad & Tobago": "Trinidad ja Tobago",
"Tonga": "Tonga",
"Tokelau": "Tokelau",
"Togo": "Togo",
"Timor-Leste": "Ida-Timor",
"Thailand": "Tai",
"Tanzania": "Tansaania",
"Tajikistan": "Tadžikistan",
"Taiwan": "Taiwan",
"São Tomé & Príncipe": "São Tomé ja Príncipe",
"Syria": "Süüria",
"Switzerland": "Šveits",
"Sweden": "Rootsi",
"Swaziland": "Svaasimaa",
"Svalbard & Jan Mayen": "Svalbard ja Jan Mayen",
"Suriname": "Suriname",
"Sudan": "Sudaan",
"St. Vincent & Grenadines": "Saint Vincent",
"St. Pierre & Miquelon": "Saint-Pierre ja Miquelon",
"St. Martin": "Saint-Martin",
"St. Lucia": "Saint Lucia",
"St. Kitts & Nevis": "Saint Kitts ja Nevis",
"St. Helena": "Saint Helena",
"St. Barthélemy": "Saint-Barthélemy",
"Sri Lanka": "Sri Lanka",
"Spain": "Hispaania",
"South Sudan": "Lõuna-Sudaan",
"South Korea": "Lõuna-Korea",
"South Georgia & South Sandwich Islands": "Lõuna-Georgia ja Lõuna-Sandwichi saared",
"South Africa": "Lõuna-Aafrika Vabariik",
"Somalia": "Somaalia",
"Solomon Islands": "Saalomoni Saared",
"Slovenia": "Sloveenia",
"Slovakia": "Slovakkia",
"Sint Maarten": "Sint Maarten",
"Singapore": "Singapur",
"Sierra Leone": "Sierra Leone",
"Seychelles": "Seišellid",
"Serbia": "Serbia",
"Senegal": "Senegal",
"Saudi Arabia": "Saudi Araabia",
"San Marino": "San Marino",
"Samoa": "Samoa",
"Réunion": "Réunion",
"Rwanda": "Rwanda",
"Russia": "Venemaa",
"Romania": "Rumeenia",
"Qatar": "Katar",
"Puerto Rico": "Puerto Rico",
"Portugal": "Portugal",
"Poland": "Poola",
"Pitcairn Islands": "Pitcairn",
"Philippines": "Filipiinid",
"Peru": "Peruu",
"Paraguay": "Paraguay",
"Papua New Guinea": "Paapua Uus-Guinea",
"Panama": "Panama",
"Palestine": "Palestiina",
"Palau": "Belau",
"Pakistan": "Pakistan",
"Oman": "Omaan",
"Norway": "Norra",
"Northern Mariana Islands": "Põhja-Mariaanid",
"North Korea": "Põhja-Korea",
"Norfolk Island": "Norfolk",
"Niue": "Niue",
"Nigeria": "Nigeeria",
"Niger": "Niger",
"Nicaragua": "Nicaragua",
"New Zealand": "Uus-Meremaa",
"New Caledonia": "Uus-Kaledoonia",
"Netherlands": "Holland",
"Nepal": "Nepal",
"Nauru": "Nauru",
"Namibia": "Namiibia",
"Myanmar": "Myanmar",
"Mozambique": "Mosambiik",
"Morocco": "Maroko",
"Montserrat": "Montserrat",
"Montenegro": "Montenegro",
"Mongolia": "Mongoolia",
"Monaco": "Monaco",
"Moldova": "Moldova",
"Micronesia": "Mikroneesia",
"Mexico": "Mehhiko",
"Mayotte": "Mayotte",
"Mauritius": "Mauritius",
"Mauritania": "Mauritaania",
"Martinique": "Martinique",
"Marshall Islands": "Marshalli Saared",
"Malta": "Malta",
"Mali": "Mali",
"Maldives": "Maldiivid",
"Malaysia": "Malaisia",
"Malawi": "Malawi",
"Madagascar": "Madagaskar",
"Macedonia": "Põhja-Makedoonia",
"Macau": "Macau",
"Luxembourg": "Luksemburg",
"Lithuania": "Leedu",
"Liechtenstein": "Liechtenstein",
"Libya": "Liibüa",
"Liberia": "Libeeria",
"Lesotho": "Lesotho",
"Lebanon": "Liibanon",
"Latvia": "Läti",
"Laos": "Laos",
"Kyrgyzstan": "Kõrgõzstan",
"Kuwait": "Kuveit",
"Kosovo": "Kosovo",
"Kiribati": "Kiribati",
"Kenya": "Keenia",
"Kazakhstan": "Kasahstan",
"Jordan": "Jordaania",
"Jersey": "Jersey",
"Japan": "Jaapan",
"Jamaica": "Jamaica",
"Italy": "Itaalia",
"Israel": "Iisrael",
"Isle of Man": "Mani saar",
"Ireland": "Iirimaa",
"Iraq": "Iraak",
"Iran": "Iraan",
"Indonesia": "Indoneesia",
"India": "India",
"Iceland": "Island",
"Hungary": "Ungari",
"Hong Kong": "Hongkong",
"Honduras": "Honduras",
"Heard & McDonald Islands": "Heard ja McDonald",
"Haiti": "Haiti",
"Guyana": "Guyana",
"Guinea-Bissau": "Guinea-Bissau",
"Guinea": "Guinea",
"Guernsey": "Guernsey",
"Guatemala": "Guatemala",
"Guam": "Guam",
"Guadeloupe": "Guadeloupe",
"Grenada": "Grenada",
"Greenland": "Gröönimaa",
"Greece": "Kreeka",
"Gibraltar": "Gibraltar",
"Ghana": "Ghana",
"Germany": "Saksamaa",
"Georgia": "Gruusia",
"Gambia": "Gambia",
"Gabon": "Gabon",
"French Southern Territories": "Prantsuse Lõunaalad",
"French Polynesia": "Prantsuse Polüneesia",
"French Guiana": "Prantsuse Guajaana",
"France": "Prantsusmaa",
"Zimbabwe": "Zimbabwe",
"Finland": "Soome",
"Fiji": "Fidži",
"Faroe Islands": "Fääri saared",
"Falkland Islands": "Falklandi (Malviini) saared",
"Ethiopia": "Etioopia",
"Estonia": "Eesti",
"Eritrea": "Eritrea",
"Equatorial Guinea": "Ekvatoriaal-Guinea",
"El Salvador": "El Salvador",
"Egypt": "Egiptus",
"Ecuador": "Ecuador",
"Dominican Republic": "Dominikaani Vabariik",
"Dominica": "Dominica",
"Djibouti": "Djibouti",
"Denmark": "Taani",
"Côte dIvoire": "Elevandiluurannik",
"Czech Republic": "Tšehhi",
"Cyprus": "Küpros",
"Curaçao": "Curaçao",
"Cuba": "Kuuba",
"Croatia": "Horvaatia",
"Costa Rica": "Costa Rica",
"Cook Islands": "Cooki saared",
"Congo - Kinshasa": "Kongo DV",
"Congo - Brazzaville": "Kongo Vabariik",
"Comoros": "Komoorid",
"Colombia": "Colombia",
"Cocos (Keeling) Islands": "Kookossaared",
"Christmas Island": "Jõulusaar",
"China": "Hiina",
"Chile": "Tšiili",
"Chad": "Tšaad",
"Central African Republic": "Kesk-Aafrika Vabariik",
"Cayman Islands": "Kaimanisaared",
"Caribbean Netherlands": "Bonaire, Sint Eustatius ja Saba",
"Cape Verde": "Roheneemesaared",
"Canada": "Kanada",
"Cameroon": "Kamerun",
"Cambodia": "Kambodža",
"Burundi": "Burundi",
"Burkina Faso": "Burkina Faso",
"Bulgaria": "Bulgaaria",
"Brunei": "Brunei",
"British Virgin Islands": "Briti Neitsisaared",
"British Indian Ocean Territory": "Briti India ookeani ala",
"Brazil": "Brasiilia",
"Bouvet Island": "Bouvet saar",
"Botswana": "Botswana",
"Bosnia": "Bosnia ja Hertsegoviina",
"Bolivia": "Boliivia",
"Bhutan": "Bhutan",
"Bermuda": "Bermuda",
"Benin": "Benin",
"Belize": "Belize",
"Belgium": "Belgia",
"Belarus": "Valgevene",
"Barbados": "Barbados",
"Bangladesh": "Bangladesh",
"Bahrain": "Bahrein",
"Bahamas": "Bahama",
"Azerbaijan": "Aserbaidžaan",
"Austria": "Austria",
"Australia": "Austraalia",
"Aruba": "Aruba",
"Armenia": "Armeenia",
"Argentina": "Argentina",
"Antigua & Barbuda": "Antigua ja Barbuda",
"Antarctica": "Antarktis",
"Anguilla": "Anguilla",
"Angola": "Angola",
"Andorra": "Andorra",
"American Samoa": "Ameerika Samoa",
"Algeria": "Alžeeria",
"Albania": "Albaania",
"Åland Islands": "Ahvenamaa",
"Afghanistan": "Afganistan",
"United States": "Ameerika Ühendriigid",
"United Kingdom": "Suurbritannia",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "Sõnumid siin jututoas on läbivalt krüptitud. Kui uued kasutajad liituvad, siis klõpsides nende tunnuspilti saad kontrollida nende profiili.",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Sõnumid siin jututoas on läbivalt krüptitud. Klõpsides tunnuspilti saad kontrollida kasutaja %(displayName)s profiili.",
"%(creator)s created this DM.": "%(creator)s alustas seda otsesuhtlust.",
"This is the start of <roomName/>.": "See on <roomName/> jututoa algus.",
"Add a photo, so people can easily spot your room.": "Selle, et teised märkaks sinu jututuba lihtsamini, palun lisa üks pilt.",
"%(displayName)s created this room.": "%(displayName)s lõi selle jututoa.",
"You created this room.": "Sa lõid selle jututoa.",
"<a>Add a topic</a> to help people know what it is about.": "Selleks, et teised teaks millega on tegemist, palun <a>lisa teema</a>.",
"Topic: %(topic)s ": "Teema: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "Teema: %(topic)s (<a>muudetud</a>)",
"This is the beginning of your direct message history with <displayName/>.": "See on sinu ja kasutaja <displayName/> otsesuhtluse ajaloo algus.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Seni kuni emb-kumb teist kolmandaid osapooli liituma ei kutsu, olete siin vestluses vaid teie kahekesi.",
"Call Paused": "Kõne on ajutiselt peatatud",
"Takes the call in the current room off hold": "Võtab selles jututoas ootel oleva kõne",
"Places the call in the current room on hold": "Jätab kõne selles jututoas ootele",
"Role": "Roll",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|one": "Selleks, et sisu saaks otsingus kasutada, puhverda krüptitud sõnumid kohalikus seadmes turvaliselt. %(count)s jututoa andmete salvestamiseks kulub hetkel %(size)s.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|other": "Selleks, et sisu saaks otsingus kasutada, puhverda krüptitud sõnumid kohalikus seadmes turvaliselt. %(count)s jututoa andmete salvestamiseks kulub hetkel %(size)s.",
"Filter rooms and people": "Otsi jututubasid ja inimesi",
"Open the link in the email to continue registration.": "Registreerimisega jätkamiseks vajuta e-kirjas olevat linki.",
"A confirmation email has been sent to %(emailAddress)s": "Saatsime kinnituskirja %(emailAddress)s aadressile",
"Start a new chat": "Alusta uut vestlust"
} }

View file

@ -151,5 +151,12 @@
"A new version of %(brand)s is available!": "نگارشی جدید از %(brand)s موجود است!", "A new version of %(brand)s is available!": "نگارشی جدید از %(brand)s موجود است!",
"Guest": "مهمان", "Guest": "مهمان",
"Confirm adding this email address by using Single Sign On to prove your identity.": "برای تأیید هویتتان، این نشانی رایانامه را با ورود یکپارچه تأیید کنید.", "Confirm adding this email address by using Single Sign On to prove your identity.": "برای تأیید هویتتان، این نشانی رایانامه را با ورود یکپارچه تأیید کنید.",
"Click the button below to confirm adding this email address.": "برای تأیید افزودن این نشانی رایانامه، دکمهٔ زیر را بزنید." "Click the button below to confirm adding this email address.": "برای تأیید افزودن این نشانی رایانامه، دکمهٔ زیر را بزنید.",
"Your homeserver's URL": "آدرس سرور شما",
"Whether or not you're using the Richtext mode of the Rich Text Editor": "از حالت Richtext ویرایشگر متنی استفاده می کنید یا نه",
"Which officially provided instance you are using, if any": "در صورت وجود ، از کدام سرویس رسمی استفاده می‌کنید",
"Whether or not you're logged in (we don't record your username)": "وارد حساب خود می‌شوید یا خیر (ما نام کاربری شما را ثبت نمی‌کنیم)",
"Click the button below to confirm adding this phone number.": "برای تائید اضافه‌شدن این شماره تلفن، بر روی دکمه‌ی زیر کلیک کنید.",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "برای اثبات هویت خود، اضافه‌شدن این شماره تلفن را با استفاده از Single Sign On تائید کنید.",
"Failed to verify email address: make sure you clicked the link in the email": "خطا در تائید آدرس ایمیل: مطمئن شوید که بر روی لینک موجود در ایمیل کلیک کرده اید"
} }

View file

@ -42,7 +42,7 @@
"Invite new community members": "Convidará comunidade a novos participantes", "Invite new community members": "Convidará comunidade a novos participantes",
"Invite to Community": "Convidar á comunidade", "Invite to Community": "Convidar á comunidade",
"Which rooms would you like to add to this community?": "Que salas desexaría engadir a esta comunidade?", "Which rooms would you like to add to this community?": "Que salas desexaría engadir a esta comunidade?",
"Show these rooms to non-members on the community page and room list?": "Quere que estas salas se lle mostren a outros membros de fóra da comunidade na lista de salas?", "Show these rooms to non-members on the community page and room list?": "Queres que estas salas se lle mostren a outras participantes de fóra da comunidade e na lista de salas?",
"Add rooms to the community": "Engadir salas á comunidade", "Add rooms to the community": "Engadir salas á comunidade",
"Add to community": "Engadir á comunidade", "Add to community": "Engadir á comunidade",
"Failed to invite the following users to %(groupId)s:": "Fallo ao convidar ás seguintes usuarias a %(groupId)s:", "Failed to invite the following users to %(groupId)s:": "Fallo ao convidar ás seguintes usuarias a %(groupId)s:",
@ -74,7 +74,7 @@
"Missing user_id in request": "Falta o user_id na petición", "Missing user_id in request": "Falta o user_id na petición",
"Usage": "Uso", "Usage": "Uso",
"/ddg is not a command": "/ddg non é unha orde", "/ddg is not a command": "/ddg non é unha orde",
"To use it, just wait for autocomplete results to load and tab through them.": "Para utilizala, agarde que carguen os resultados de autocompletado e escolla entre eles.", "To use it, just wait for autocomplete results to load and tab through them.": "Para utilizala, agarda a que carguen os resultados de autocompletado e escolle entre eles.",
"Ignored user": "Usuaria ignorada", "Ignored user": "Usuaria ignorada",
"You are now ignoring %(userId)s": "Agora está a ignorar %(userId)s", "You are now ignoring %(userId)s": "Agora está a ignorar %(userId)s",
"Unignored user": "Usuarias non ignoradas", "Unignored user": "Usuarias non ignoradas",
@ -131,7 +131,7 @@
"Authentication check failed: incorrect password?": "Fallou a comprobación de autenticación: contrasinal incorrecto?", "Authentication check failed: incorrect password?": "Fallou a comprobación de autenticación: contrasinal incorrecto?",
"Failed to join room": "Non puideches entrar na sala", "Failed to join room": "Non puideches entrar na sala",
"Message Pinning": "Fixando mensaxe", "Message Pinning": "Fixando mensaxe",
"Show timestamps in 12 hour format (e.g. 2:30pm)": "Mostrar marcas de tempo con formato 12 horas (ex. 2:30pm)", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Mostrar marcas de tempo con formato 12 horas (ex. 2:30pm)",
"Always show message timestamps": "Mostrar sempre marcas de tempo", "Always show message timestamps": "Mostrar sempre marcas de tempo",
"Autoplay GIFs and videos": "Reprodución automática de GIFs e vídeos", "Autoplay GIFs and videos": "Reprodución automática de GIFs e vídeos",
"Enable automatic language detection for syntax highlighting": "Activar a detección automática de idioma para o resalte da sintaxe", "Enable automatic language detection for syntax highlighting": "Activar a detección automática de idioma para o resalte da sintaxe",
@ -168,8 +168,8 @@
"Authentication": "Autenticación", "Authentication": "Autenticación",
"Last seen": "Visto por última vez", "Last seen": "Visto por última vez",
"Failed to set display name": "Fallo ao establecer o nome público", "Failed to set display name": "Fallo ao establecer o nome público",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s", "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s",
"Mirror local video feed": "Copiar fonte de vídeo local", "Mirror local video feed": "Replicar a fonte de vídeo local",
"Cannot add any more widgets": "Non pode engadir máis trebellos", "Cannot add any more widgets": "Non pode engadir máis trebellos",
"The maximum permitted number of widgets have already been added to this room.": "Xa se lle engadiron o número máximo de trebellos a esta sala.", "The maximum permitted number of widgets have already been added to this room.": "Xa se lle engadiron o número máximo de trebellos a esta sala.",
"Add a widget": "Engadir un trebello", "Add a widget": "Engadir un trebello",
@ -281,9 +281,9 @@
"Publish this room to the public in %(domain)s's room directory?": "Publicar esta sala no directorio público de salas de %(domain)s?", "Publish this room to the public in %(domain)s's room directory?": "Publicar esta sala no directorio público de salas de %(domain)s?",
"Who can read history?": "Quen pode ler o histórico?", "Who can read history?": "Quen pode ler o histórico?",
"Anyone": "Calquera", "Anyone": "Calquera",
"Members only (since the point in time of selecting this option)": "Só membros (desde o momento en que se selecciona esta opción)", "Members only (since the point in time of selecting this option)": "Só participantes (desde o momento en que se selecciona esta opción)",
"Members only (since they were invited)": "Só membros (desde que foron convidados)", "Members only (since they were invited)": "Só participantes (desde que foron convidadas)",
"Members only (since they joined)": "Só membros (desde que se uniron)", "Members only (since they joined)": "Só participantes (desde que se uniron)",
"Permissions": "Permisos", "Permissions": "Permisos",
"Advanced": "Avanzado", "Advanced": "Avanzado",
"Add a topic": "Engadir asunto", "Add a topic": "Engadir asunto",
@ -298,7 +298,7 @@
"You have <a>enabled</a> URL previews by default.": "<a>Activou</a> a vista previa de URL por defecto.", "You have <a>enabled</a> URL previews by default.": "<a>Activou</a> a vista previa de URL por defecto.",
"You have <a>disabled</a> URL previews by default.": "<a>Desactivou</a> a vista previa de URL por defecto.", "You have <a>disabled</a> URL previews by default.": "<a>Desactivou</a> a vista previa de URL por defecto.",
"URL previews are enabled by default for participants in this room.": "As vistas previas de URL están activas por defecto para os participantes desta sala.", "URL previews are enabled by default for participants in this room.": "As vistas previas de URL están activas por defecto para os participantes desta sala.",
"URL previews are disabled by default for participants in this room.": "As vistas previas de URL están desactivadas por defecto para os participantes desta sala.", "URL previews are disabled by default for participants in this room.": "As vistas previas de URL están desactivadas por defecto para as participantes desta sala.",
"URL Previews": "Vista previa de URL", "URL Previews": "Vista previa de URL",
"Error decrypting audio": "Fallo ao descifrar audio", "Error decrypting audio": "Fallo ao descifrar audio",
"Error decrypting attachment": "Fallo descifrando o anexo", "Error decrypting attachment": "Fallo descifrando o anexo",
@ -346,7 +346,7 @@
"Only visible to community members": "Só visible para os participantes da comunidade", "Only visible to community members": "Só visible para os participantes da comunidade",
"Filter community rooms": "Filtrar salas da comunidade", "Filter community rooms": "Filtrar salas da comunidade",
"Something went wrong when trying to get your communities.": "Algo fallou ao intentar obter as súas comunidades.", "Something went wrong when trying to get your communities.": "Algo fallou ao intentar obter as súas comunidades.",
"You're not currently a member of any communities.": "Ate o momento non é membro de ningunha comunidade.", "You're not currently a member of any communities.": "Ate o momento non es participante en ningunha comunidade.",
"Unknown Address": "Enderezo descoñecido", "Unknown Address": "Enderezo descoñecido",
"Allow": "Permitir", "Allow": "Permitir",
"Delete Widget": "Eliminar widget", "Delete Widget": "Eliminar widget",
@ -390,13 +390,13 @@
"was invited %(count)s times|one": "foi convidada", "was invited %(count)s times|one": "foi convidada",
"were banned %(count)s times|other": "foron prohibidas %(count)s veces", "were banned %(count)s times|other": "foron prohibidas %(count)s veces",
"were banned %(count)s times|one": "foron prohibidas", "were banned %(count)s times|one": "foron prohibidas",
"was banned %(count)s times|other": "foi prohibida %(count)s veces", "was banned %(count)s times|other": "foi vetada %(count)s veces",
"was banned %(count)s times|one": "foi prohibida", "was banned %(count)s times|one": "foi prohibida",
"were unbanned %(count)s times|other": "retiróuselle a prohibición %(count)s veces", "were unbanned %(count)s times|other": "retiróuselle a prohibición %(count)s veces",
"were unbanned %(count)s times|one": "retrouseille a prohibición", "were unbanned %(count)s times|one": "retrouseille a prohibición",
"was unbanned %(count)s times|other": "retrouseille a prohibición %(count)s veces", "was unbanned %(count)s times|other": "retirouselle o veto %(count)s veces",
"was unbanned %(count)s times|one": "retiróuselle a prohibición", "was unbanned %(count)s times|one": "retiróuselle a prohibición",
"were kicked %(count)s times|other": "foron expulsadas %(count)s veces", "were kicked %(count)s times|other": "foron expulsadas %(count)s veces",
"were kicked %(count)s times|one": "foron expulsadas", "were kicked %(count)s times|one": "foron expulsadas",
"was kicked %(count)s times|other": "foi expulsada %(count)s veces", "was kicked %(count)s times|other": "foi expulsada %(count)s veces",
"was kicked %(count)s times|one": "foi expulsada", "was kicked %(count)s times|one": "foi expulsada",
@ -465,7 +465,7 @@
"You must <a>register</a> to use this functionality": "Debe <a>rexistrarse</a> para utilizar esta función", "You must <a>register</a> to use this functionality": "Debe <a>rexistrarse</a> para utilizar esta función",
"You must join the room to see its files": "Debes unirte a sala para ver os seus ficheiros", "You must join the room to see its files": "Debes unirte a sala para ver os seus ficheiros",
"There are no visible files in this room": "Non hai ficheiros visibles nesta sala", "There are no visible files in this room": "Non hai ficheiros visibles nesta sala",
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>HTML para a páxina da súa comunidade</h1>\n<p>\n Utilice a descrición longa para presentar novos membros a comunidade, ou publicar algunha <a href=\"foo\">ligazón</a> importante\n \n</p>\n<p>\n Tamén pode utilizar etiquetas 'img'\n</p>\n", "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>HTML para a páxina da túa comunidade</h1>\n<p>\n Utiliza a descrición longa para presentalle a comunidade ás novas participantes, ou publicar algunha <a href=\"foo\">ligazón</a> importante\n \n</p>\n<p>\n Tamén podes usar etiquetas 'img'\n</p>\n",
"Add rooms to the community summary": "Engadir salas ao resumo da comunidade", "Add rooms to the community summary": "Engadir salas ao resumo da comunidade",
"Which rooms would you like to add to this summary?": "Que salas desexa engadir a este resumo?", "Which rooms would you like to add to this summary?": "Que salas desexa engadir a este resumo?",
"Add to summary": "Engadir ao resumo", "Add to summary": "Engadir ao resumo",
@ -487,13 +487,13 @@
"Leave %(groupName)s?": "Deixar %(groupName)s?", "Leave %(groupName)s?": "Deixar %(groupName)s?",
"Leave": "Saír", "Leave": "Saír",
"Community Settings": "Axustes da comunidade", "Community Settings": "Axustes da comunidade",
"These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Estas salas móstranse aos membros da comunidade na páxina da comunidade. Os participantes da comunidade poden unirse ás salas premendo nelas.", "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "Estas salas móstranse ás participantes da comunidade na páxina da comunidade. As participantes da comunidade poden unirse ás salas premendo nelas.",
"Add rooms to this community": "Engadir salas a esta comunidade", "Add rooms to this community": "Engadir salas a esta comunidade",
"Featured Rooms:": "Salas destacadas:", "Featured Rooms:": "Salas destacadas:",
"Featured Users:": "Usuarias destacadas:", "Featured Users:": "Usuarias destacadas:",
"%(inviter)s has invited you to join this community": "%(inviter)s convidoute a entrar nesta comunidade", "%(inviter)s has invited you to join this community": "%(inviter)s convidoute a entrar nesta comunidade",
"You are an administrator of this community": "Administras esta comunidade", "You are an administrator of this community": "Administras esta comunidade",
"You are a member of this community": "É membro desta comunidade", "You are a member of this community": "Participas nesta comunidade",
"Your community hasn't got a Long Description, a HTML page to show to community members.<br />Click here to open settings and give it one!": "A túa comunidade non ten unha descrición longa, ou unha páxina HTML que lle mostrar ás participantes.<br />Preme aquí para abrir os axustes e publicar unha!", "Your community hasn't got a Long Description, a HTML page to show to community members.<br />Click here to open settings and give it one!": "A túa comunidade non ten unha descrición longa, ou unha páxina HTML que lle mostrar ás participantes.<br />Preme aquí para abrir os axustes e publicar unha!",
"Long Description (HTML)": "Descrición longa (HTML)", "Long Description (HTML)": "Descrición longa (HTML)",
"Description": "Descrición", "Description": "Descrición",
@ -547,14 +547,14 @@
"<not supported>": "<non soportado>", "<not supported>": "<non soportado>",
"Import E2E room keys": "Importar chaves E2E da sala", "Import E2E room keys": "Importar chaves E2E da sala",
"Cryptography": "Criptografía", "Cryptography": "Criptografía",
"Analytics": "Analytics", "Analytics": "Análise",
"%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s recolle información analítica anónima para permitirnos mellorar a aplicación.", "%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s recolle información analítica anónima para permitirnos mellorar a aplicación.",
"Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "A intimidade impórtanos, así que non recollemos información personal ou identificable nos datos dos nosos análises.", "Privacy is important to us, so we don't collect any personal or identifiable data for our analytics.": "A intimidade impórtanos, así que non recollemos información personal ou identificable nos datos dos nosos análises.",
"Learn more about how we use analytics.": "Saber máis sobre como utilizamos analytics.", "Learn more about how we use analytics.": "Saber máis sobre como utilizamos analytics.",
"Labs": "Labs", "Labs": "Labs",
"Check for update": "Comprobar actualización", "Check for update": "Comprobar actualización",
"Reject all %(invitedRooms)s invites": "Rexeitar todos os %(invitedRooms)s convites", "Reject all %(invitedRooms)s invites": "Rexeitar todos os %(invitedRooms)s convites",
"Start automatically after system login": "Iniciar automaticamente despois de iniciar sesión", "Start automatically after system login": "Iniciar automaticamente despois de iniciar sesión",
"No media permissions": "Sen permisos de medios", "No media permissions": "Sen permisos de medios",
"You may need to manually permit %(brand)s to access your microphone/webcam": "Igual ten que permitir manualmente a %(brand)s acceder ao seus micrófono e cámara", "You may need to manually permit %(brand)s to access your microphone/webcam": "Igual ten que permitir manualmente a %(brand)s acceder ao seus micrófono e cámara",
"No Microphones detected": "Non se detectaron micrófonos", "No Microphones detected": "Non se detectaron micrófonos",
@ -639,11 +639,11 @@
"Failed to add tag %(tagName)s to room": "Fallo ao engadir a etiqueta %(tagName)s a sala", "Failed to add tag %(tagName)s to room": "Fallo ao engadir a etiqueta %(tagName)s a sala",
"Key request sent.": "Petición de chave enviada.", "Key request sent.": "Petición de chave enviada.",
"Flair": "Popularidade", "Flair": "Popularidade",
"Showing flair for these communities:": "Mostrar a popularidade destas comunidades:", "Showing flair for these communities:": "Mostrando a popularidade destas comunidades:",
"Display your community flair in rooms configured to show it.": "Mostrar a popularidade da túa comunidade nas salas configuradas para que a mostren.", "Display your community flair in rooms configured to show it.": "Mostrar a popularidade da túa comunidade nas salas configuradas para que a mostren.",
"Did you know: you can use communities to filter your %(brand)s experience!": "Sabías que podes usar as comunidades para filtrar a túa experiencia en %(brand)s!", "Did you know: you can use communities to filter your %(brand)s experience!": "Sabías que podes usar as comunidades para filtrar a túa experiencia en %(brand)s!",
"To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Para establecer un filtro, arrastra un avatar da comunidade sobre o panel de filtros na parte esquerda da pantalla. Podes premer nun avatar no panel de filtrado en calquera momento para ver só salas e xente asociada a esa comunidade.", "To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Para establecer un filtro, arrastra un avatar da comunidade sobre o panel de filtros na parte esquerda da pantalla. Podes premer nun avatar no panel de filtrado en calquera momento para ver só salas e xente asociada a esa comunidade.",
"Deops user with given id": "Degradar á usuaria con ese ID", "Deops user with given id": "Degrada usuaria co id proporcionado",
"Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Visto por %(displayName)s(%(userName)s en %(dateTime)s", "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Visto por %(displayName)s(%(userName)s en %(dateTime)s",
"Code": "Código", "Code": "Código",
"Unable to join community": "Non te puideches unir a comunidade", "Unable to join community": "Non te puideches unir a comunidade",
@ -804,8 +804,8 @@
"This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. <b>This action is irreversible.</b>": "Iso fará que a túa deixe de ter uso de xeito permanente. Non poderás acceder e ninguén vai a poder volver a rexistrar esa mesma ID de usuaria. Suporá que sairás de todalas salas de conversas nas que estabas e eliminarás os detalles da túa conta do servidores de identidade. <b>Esta acción non ten volta</b>", "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. <b>This action is irreversible.</b>": "Iso fará que a túa deixe de ter uso de xeito permanente. Non poderás acceder e ninguén vai a poder volver a rexistrar esa mesma ID de usuaria. Suporá que sairás de todalas salas de conversas nas que estabas e eliminarás os detalles da túa conta do servidores de identidade. <b>Esta acción non ten volta</b>",
"Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "Desactivando a súa conta <b>non supón que por defecto esquezamos as súas mensaxes enviadas.</b> Se quere que nos esquezamos das súas mensaxes, prema na caixa de embaixo.", "Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "Desactivando a súa conta <b>non supón que por defecto esquezamos as súas mensaxes enviadas.</b> Se quere que nos esquezamos das súas mensaxes, prema na caixa de embaixo.",
"To continue, please enter your password:": "Para continuar introduza o seu contrasinal:", "To continue, please enter your password:": "Para continuar introduza o seu contrasinal:",
"Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "A visibilidade das mensaxes en Matrix é parecida á dos correos electrónicos. Que esquezamos as túas mensaxes significa que as mensaxes non se van a compartir con ningún novo membro ou usuaria que non estea rexistrada. Mais aqueles usuarias que xa tiveron acceso a estas mensaxes si que seguirán tendo acceso as súas propias copias desas mensaxes.", "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "A visibilidade das mensaxes en Matrix é parecida á dos correos electrónicos. Que esquezamos as túas mensaxes significa que as mensaxes non se van a compartir con ningunha nova participante ou usuaria que non estea rexistrada. Mais aquelas usuarias que xa tiveron acceso a estas mensaxes si que seguirán tendo acceso as súas propias copias desas mensaxes.",
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Esquezan todas as mensaxes que eu enviara no momento en que elimine a miña conta. (<b>Aviso</b>: iso suporá que os seguintes participantes só verán unha versión incompleta das conversas.)", "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Esquece todas as mensaxes que enviei cando a miña conta está desactivada. (<b>Aviso</b>: isto fará que usuarias futuras vexan unha versión incompleta das conversas)",
"Share Room": "Compartir sala", "Share Room": "Compartir sala",
"Link to most recent message": "Ligazón ás mensaxes máis recentes", "Link to most recent message": "Ligazón ás mensaxes máis recentes",
"Share User": "Compartir usuaria", "Share User": "Compartir usuaria",
@ -833,7 +833,7 @@
"The email field must not be blank.": "Este campo de correo non pode quedar en branco.", "The email field must not be blank.": "Este campo de correo non pode quedar en branco.",
"The phone number field must not be blank.": "O número de teléfono non pode quedar en branco.", "The phone number field must not be blank.": "O número de teléfono non pode quedar en branco.",
"The password field must not be blank.": "O campo do contrasinal non pode quedar en branco.", "The password field must not be blank.": "O campo do contrasinal non pode quedar en branco.",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Non vai poder enviar mensaxes ata que revise e acepte <consentLink>os nosos termos e condicións</consentLink>.", "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Non vas poder enviar mensaxes ata que revises e aceptes <consentLink>os nosos termos e condicións</consentLink>.",
"A call is currently being placed!": "Xa se estableceu a chamada!", "A call is currently being placed!": "Xa se estableceu a chamada!",
"Sorry, your homeserver is too old to participate in this room.": "Lametámolo, o seu servidor de inicio é vello de máis para participar en esta sala.", "Sorry, your homeserver is too old to participate in this room.": "Lametámolo, o seu servidor de inicio é vello de máis para participar en esta sala.",
"Please contact your homeserver administrator.": "Por favor, contacte coa administración do seu servidor.", "Please contact your homeserver administrator.": "Por favor, contacte coa administración do seu servidor.",
@ -920,14 +920,14 @@
"Messages": "Mensaxes", "Messages": "Mensaxes",
"Actions": "Accións", "Actions": "Accións",
"Other": "Outro", "Other": "Outro",
"Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Anteponse ¯\\_(ツ)_/¯ a mensaxe en texto plano", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Anteponse ¯\\_(ツ)_/¯ a mensaxe en texto plano",
"Sends a message as plain text, without interpreting it as markdown": "Envía unha mensaxe como texto plano, sen interpretalo como markdown", "Sends a message as plain text, without interpreting it as markdown": "Envía unha mensaxe como texto plano, sen interpretalo como markdown",
"Sends a message as html, without interpreting it as markdown": "Envía unha mensaxe como html, sen interpretalo como markdown", "Sends a message as html, without interpreting it as markdown": "Envía unha mensaxe como html, sen interpretalo como markdown",
"Upgrades a room to a new version": "Subir a sala de versión", "Upgrades a room to a new version": "Subir a sala de versión",
"You do not have the required permissions to use this command.": "Non tes os permisos suficientes para usar este comando.", "You do not have the required permissions to use this command.": "Non tes os permisos suficientes para usar este comando.",
"Error upgrading room": "Fallo ao actualizar a sala", "Error upgrading room": "Fallo ao actualizar a sala",
"Double check that your server supports the room version chosen and try again.": "Comproba ben que o servidor soporta a versión da sala escollida e inténtao outra vez.", "Double check that your server supports the room version chosen and try again.": "Comproba ben que o servidor soporta a versión da sala escollida e inténtao outra vez.",
"Changes your display nickname in the current room only": "Cambia o teu nome mostrado só para esta esta sala", "Changes your display nickname in the current room only": "Cambia o teu nome mostrado só para esta sala",
"Changes the avatar of the current room": "Cambia o avatar da sala actual", "Changes the avatar of the current room": "Cambia o avatar da sala actual",
"Changes your avatar in this current room only": "Cambia o teu avatar só nesta sala", "Changes your avatar in this current room only": "Cambia o teu avatar só nesta sala",
"Changes your avatar in all rooms": "Cambia o teu avatar en todas as salas", "Changes your avatar in all rooms": "Cambia o teu avatar en todas as salas",
@ -997,7 +997,7 @@
"If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "Se hai contexto que cres que axudaría a analizar o problema, como o que estabas a facer, ID da sala, ID da usuaria, etc., por favor inclúeo aquí.", "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "Se hai contexto que cres que axudaría a analizar o problema, como o que estabas a facer, ID da sala, ID da usuaria, etc., por favor inclúeo aquí.",
"To help avoid duplicate issues, please <existingIssuesLink>view existing issues</existingIssuesLink> first (and add a +1) or <newIssueLink>create a new issue</newIssueLink> if you can't find it.": "Para evitar informes duplicados, mira <existingIssuesLink>os informes existentes</existingIssuesLink> primeiro (e engade un +1) ou <newIssueLink>crea un novo informe</newIssueLink> se non o atopas.", "To help avoid duplicate issues, please <existingIssuesLink>view existing issues</existingIssuesLink> first (and add a +1) or <newIssueLink>create a new issue</newIssueLink> if you can't find it.": "Para evitar informes duplicados, mira <existingIssuesLink>os informes existentes</existingIssuesLink> primeiro (e engade un +1) ou <newIssueLink>crea un novo informe</newIssueLink> se non o atopas.",
"Command Help": "Comando Axuda", "Command Help": "Comando Axuda",
"To help us prevent this in future, please <a>send us logs</a>.": "Para axudarnos a previr esto no futuro, envíanos <a>o rexistro</a>.", "To help us prevent this in future, please <a>send us logs</a>.": "Para axudarnos a evitar esto no futuro, envíanos <a>o rexistro</a>.",
"Help": "Axuda", "Help": "Axuda",
"Explore Public Rooms": "Explorar Salas Públicas", "Explore Public Rooms": "Explorar Salas Públicas",
"Explore": "Explorar", "Explore": "Explorar",
@ -1085,7 +1085,7 @@
"Unrecognised address": "Enderezo non recoñecible", "Unrecognised address": "Enderezo non recoñecible",
"You do not have permission to invite people to this room.": "Non tes permiso para convidar a xente a esta sala.", "You do not have permission to invite people to this room.": "Non tes permiso para convidar a xente a esta sala.",
"User %(userId)s is already in the room": "A usuaria %(userId)s xa está na sala", "User %(userId)s is already in the room": "A usuaria %(userId)s xa está na sala",
"User %(user_id)s does not exist": "A usuaria %(user_id)s non existe", "User %(user_id)s does not exist": "A usuaria %(user_id)s non existe",
"User %(user_id)s may or may not exist": "A usuaria %(user_id)s podería non existir", "User %(user_id)s may or may not exist": "A usuaria %(user_id)s podería non existir",
"The user must be unbanned before they can be invited.": "A usuria debe ser desbloqueada antes de poder convidala.", "The user must be unbanned before they can be invited.": "A usuria debe ser desbloqueada antes de poder convidala.",
"Messages in this room are end-to-end encrypted.": "As mensaxes desta sala están cifradas de extremo-a-extremo.", "Messages in this room are end-to-end encrypted.": "As mensaxes desta sala están cifradas de extremo-a-extremo.",
@ -1153,7 +1153,7 @@
"Try out new ways to ignore people (experimental)": "Novos xeitos de ignorar persoas (experimental)", "Try out new ways to ignore people (experimental)": "Novos xeitos de ignorar persoas (experimental)",
"Show join/leave messages (invites/kicks/bans unaffected)": "Mostrar mensaxes de entrada/saída (mais non convites/expulsións/bloqueos)", "Show join/leave messages (invites/kicks/bans unaffected)": "Mostrar mensaxes de entrada/saída (mais non convites/expulsións/bloqueos)",
"Subscribing to a ban list will cause you to join it!": "Subscribíndote a unha lista de bloqueo fará que te unas a ela!", "Subscribing to a ban list will cause you to join it!": "Subscribíndote a unha lista de bloqueo fará que te unas a ela!",
"<b>Warning</b>: Upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "<b>Aviso</b>: Actualizando a sala non fará que <i>os membros da sala migren automáticamente a nova versión da sala.</i> Publicaremos unha ligazón a nova sala na versión antiga da sala - os membros terán que premer na ligazón para unirse a nova sala.", "<b>Warning</b>: Upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "<b>Aviso</b>: Actualizando a sala non farás que <i>as participantes da sala migren automáticamente á nova versión da sala.</i> Publicaremos unha ligazón á nova sala na versión antiga da sala - as participantes terán que premer na ligazón para unirse a nova sala.",
"Join the conversation with an account": "Únete a conversa cunha conta", "Join the conversation with an account": "Únete a conversa cunha conta",
"Re-join": "Volta a unirte", "Re-join": "Volta a unirte",
"You can only join it with a working invite.": "Só podes unirte cun convite activo.", "You can only join it with a working invite.": "Só podes unirte cun convite activo.",
@ -1555,7 +1555,7 @@
"Revoke": "Revogar", "Revoke": "Revogar",
"Share": "Compartir", "Share": "Compartir",
"Discovery options will appear once you have added an email above.": "As opcións de descubrimento aparecerán após ti engadas un email.", "Discovery options will appear once you have added an email above.": "As opcións de descubrimento aparecerán após ti engadas un email.",
"Unable to revoke sharing for phone number": "Non se puido revogar a compartición do número de teléfono", "Unable to revoke sharing for phone number": "Non se puido revogar a compartición do número de teléfono",
"Unable to share phone number": "Non se puido compartir o número de teléfono", "Unable to share phone number": "Non se puido compartir o número de teléfono",
"Unable to verify phone number.": "Non se puido verificar o número de teléfono.", "Unable to verify phone number.": "Non se puido verificar o número de teléfono.",
"Please enter verification code sent via text.": "Escribe o código de verificación enviado no SMS.", "Please enter verification code sent via text.": "Escribe o código de verificación enviado no SMS.",
@ -1776,7 +1776,7 @@
"edited": "editada", "edited": "editada",
"Can't load this message": "Non se cargou a mensaxe", "Can't load this message": "Non se cargou a mensaxe",
"Submit logs": "Enviar rexistro", "Submit logs": "Enviar rexistro",
"Failed to load group members": "Fallou a carga dos membros do grupo", "Failed to load group members": "Fallou a carga das participantes do grupo",
"Frequently Used": "Utilizado con frecuencia", "Frequently Used": "Utilizado con frecuencia",
"Smileys & People": "Sorrisos e Persoas", "Smileys & People": "Sorrisos e Persoas",
"Animals & Nature": "Animais e Natureza", "Animals & Nature": "Animais e Natureza",
@ -1884,7 +1884,7 @@
"Message layout": "Disposición da mensaxe", "Message layout": "Disposición da mensaxe",
"Compact": "Compacta", "Compact": "Compacta",
"Modern": "Moderna", "Modern": "Moderna",
"Power level": "Nivel de permisos", "Power level": "Nivel responsabilidade",
"Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "Verifica este dispositivo para marcalo como confiable. Confiando neste dispositivo permite que ti e outras usuarias estedes máis tranquilas ao utilizar mensaxes cifradas.", "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "Verifica este dispositivo para marcalo como confiable. Confiando neste dispositivo permite que ti e outras usuarias estedes máis tranquilas ao utilizar mensaxes cifradas.",
"Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "Ao verificar este dispositivo marcaralo como confiable, e as usuarias que confiaron en ti tamén confiarán nel.", "Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "Ao verificar este dispositivo marcaralo como confiable, e as usuarias que confiaron en ti tamén confiarán nel.",
"Waiting for partner to confirm...": "Agardando a que o contacto confirme...", "Waiting for partner to confirm...": "Agardando a que o contacto confirme...",
@ -2042,7 +2042,7 @@
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Falta a chave pública do captcha na configuración do servidor. Informa desto á administración do teu servidor.", "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Falta a chave pública do captcha na configuración do servidor. Informa desto á administración do teu servidor.",
"Please review and accept all of the homeserver's policies": "Revisa e acepta todas as cláusulas do servidor", "Please review and accept all of the homeserver's policies": "Revisa e acepta todas as cláusulas do servidor",
"Please review and accept the policies of this homeserver:": "Revisa e acepta as cláusulas deste servidor:", "Please review and accept the policies of this homeserver:": "Revisa e acepta as cláusulas deste servidor:",
"Unable to validate homeserver/identity server": "Non se puido validar o servidor/servidor de identidade", "Unable to validate homeserver/identity server": "Non se puido validar o servidor de inicio/servidor de identidade",
"Your Modular server": "O teu servidor Modular", "Your Modular server": "O teu servidor Modular",
"Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of <a>modular.im</a>.": "Escribe a localización do teu servidor Modular. Podería utilizar o teu propio nome de dominio ou ser un subdominio de <a>modular.im</a>.", "Enter the location of your Modular homeserver. It may use your own domain name or be a subdomain of <a>modular.im</a>.": "Escribe a localización do teu servidor Modular. Podería utilizar o teu propio nome de dominio ou ser un subdominio de <a>modular.im</a>.",
"Server Name": "Nome do Servidor", "Server Name": "Nome do Servidor",
@ -2206,7 +2206,7 @@
"If you don't want to set this up now, you can later in Settings.": "Se non queres configurar esto agora, pódelo facer posteriormente nos Axustes.", "If you don't want to set this up now, you can later in Settings.": "Se non queres configurar esto agora, pódelo facer posteriormente nos Axustes.",
"Don't ask again": "Non preguntar outra vez", "Don't ask again": "Non preguntar outra vez",
"New Recovery Method": "Novo Método de Recuperación", "New Recovery Method": "Novo Método de Recuperación",
"A new recovery passphrase and key for Secure Messages have been detected.": "Detectouse un novo método de chave e frase de paso de recuperación para Mensaxes Seguras.", "A new recovery passphrase and key for Secure Messages have been detected.": "Detectouse unha nova frase de paso de recuperación e chave para Mensaxes Seguras.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se non configuras o novo método de recuperación, un atacante podería intentar o acceso á túa conta. Cambia inmediatamente o contrasinal da conta e configura un novo método de recuperación nos Axustes.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se non configuras o novo método de recuperación, un atacante podería intentar o acceso á túa conta. Cambia inmediatamente o contrasinal da conta e configura un novo método de recuperación nos Axustes.",
"This session is encrypting history using the new recovery method.": "Esta sesión está cifrando o historial usando o novo método de recuperación.", "This session is encrypting history using the new recovery method.": "Esta sesión está cifrando o historial usando o novo método de recuperación.",
"Go to Settings": "Ir a Axustes", "Go to Settings": "Ir a Axustes",
@ -2372,7 +2372,7 @@
"Were excited to announce Riot is now Element!": "Emociónanos comunicar que Riot agora é Element!", "Were excited to announce Riot is now Element!": "Emociónanos comunicar que Riot agora é Element!",
"Learn more at <a>element.io/previously-riot</a>": "Coñece máis en <a>element.io/previously-riot</a>", "Learn more at <a>element.io/previously-riot</a>": "Coñece máis en <a>element.io/previously-riot</a>",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Podes usar as opcións de servidor personalizado para conectar con outros servidores Matrix indicando un URL diferente para o servidor. Poderás usar %(brand)s cunha conta Matrix existente noutro servidor de inicio.", "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Podes usar as opcións de servidor personalizado para conectar con outros servidores Matrix indicando un URL diferente para o servidor. Poderás usar %(brand)s cunha conta Matrix existente noutro servidor de inicio.",
"Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of <a>element.io</a>.": "Escribe a localización do teu servidor Element Matrix Services. Podería ser o teu propio dominio ou un subdominio de <a>element.io</a>.", "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of <a>element.io</a>.": "Escribe a localización do teu servidor Element Matrix Services. Podería ser o teu propio dominio ou un subdominio de <a>element.io</a>.",
"Search rooms": "Buscar salas", "Search rooms": "Buscar salas",
"User menu": "Menú de usuaria", "User menu": "Menú de usuaria",
"%(brand)s Web": "Web %(brand)s", "%(brand)s Web": "Web %(brand)s",
@ -2453,7 +2453,7 @@
"Privacy": "Privacidade", "Privacy": "Privacidade",
"There was an error updating your community. The server is unable to process your request.": "Algo fallou ó actualizar a comunidade. O servidor non é quen de procesar a solicitude.", "There was an error updating your community. The server is unable to process your request.": "Algo fallou ó actualizar a comunidade. O servidor non é quen de procesar a solicitude.",
"Update community": "Actualizar comunidade", "Update community": "Actualizar comunidade",
"May include members not in %(communityName)s": "Podería incluir membros que non están en %(communityName)s", "May include members not in %(communityName)s": "Podería incluir participantes que non están en %(communityName)s",
"Start a conversation with someone using their name, username (like <userId/>) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>.": "Iniciar unha conversa con alguén utilizando o seu nome, nome de usuaria (como <userId/>) ou enderezo de email. Esto non as convidará a %(communityName)s. Para convidar a alguén a %(communityName)s, preme <a>aquí</a>.", "Start a conversation with someone using their name, username (like <userId/>) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>.": "Iniciar unha conversa con alguén utilizando o seu nome, nome de usuaria (como <userId/>) ou enderezo de email. Esto non as convidará a %(communityName)s. Para convidar a alguén a %(communityName)s, preme <a>aquí</a>.",
"Failed to find the general chat for this community": "Non se atopou o chat xenérico para esta comunidade", "Failed to find the general chat for this community": "Non se atopou o chat xenérico para esta comunidade",
"Community settings": "Axustes da comunidade", "Community settings": "Axustes da comunidade",
@ -2561,5 +2561,289 @@
"Add comment": "Engadir comentario", "Add comment": "Engadir comentario",
"Please go into as much detail as you like, so we can track down the problem.": "Podes entrar en detalle canto desexes, así poderemos entender mellor o problema.", "Please go into as much detail as you like, so we can track down the problem.": "Podes entrar en detalle canto desexes, así poderemos entender mellor o problema.",
"%(senderName)s ended the call": "%(senderName)s finalizou a chamada", "%(senderName)s ended the call": "%(senderName)s finalizou a chamada",
"You ended the call": "Finalizaches a chamada" "You ended the call": "Finalizaches a chamada",
"Now, let's help you get started": "Ímosche axudar neste comezo",
"Welcome %(name)s": "Benvida %(name)s",
"Add a photo so people know it's you.": "Engade unha foto así a xente recoñecerate.",
"Great, that'll help people know it's you": "Moi ben, así axudarás a que outras persoas te recoñezan",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Convida a persoas usando o seu nome, enderezo de email, nome de usuaria (como <userId/>) ou <a>comparte esta sala</a>.",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Inicia unha conversa con alguén usando o seu nome, enderezo de email ou nome de usuaria (como <userId/>).",
"Invite by email": "Convidar por email",
"Use the + to make a new room or explore existing ones below": "Usa o + para crear unha nova sala ou explora as existentes embaixo",
"Offline encrypted messaging using dehydrated devices": "Mensaxería cifrada offline usando dispositivos \"deshidratados\"",
"New version of %(brand)s is available": "Hai unha nova versión de %(brand)s dispoñible",
"Update %(brand)s": "Actualizar %(brand)s",
"Enable desktop notifications": "Activar notificacións de escritorio",
"Don't miss a reply": "Non perdas as réplicas",
"Barbados": "Barbados",
"Bangladesh": "Bangladesh",
"Bahrain": "Bahrain",
"Bahamas": "Bahamas",
"Azerbaijan": "Azerbaixán",
"Austria": "Austria",
"Australia": "Australia",
"Aruba": "Aruba",
"Armenia": "Armenia",
"Argentina": "Arxentina",
"Antigua & Barbuda": "Antigua & Barbuda",
"Antarctica": "Antártida",
"Anguilla": "Anguilla",
"Angola": "Angola",
"Andorra": "Andorra",
"American Samoa": "Samoa americana",
"Algeria": "Alxeria",
"Albania": "Albania",
"Åland Islands": "Åland Islands",
"Afghanistan": "Afghanistán",
"United States": "EEUU de América",
"United Kingdom": "Reino Unido",
"Ecuador": "Ecuador",
"Dominican Republic": "República Dominicana",
"Dominica": "Dominica",
"Djibouti": "Djibouti",
"Denmark": "Dinamarca",
"Côte dIvoire": "Costa de Marfil",
"Czech Republic": "República Checa",
"Cyprus": "Chipre",
"Curaçao": "Curaçao",
"Cuba": "Cuba",
"Croatia": "Croacia",
"Costa Rica": "Costa Rica",
"Cook Islands": "Cook Islands",
"Congo - Kinshasa": "Congo - Kinshasa",
"Congo - Brazzaville": "Congo - Brazzaville",
"Comoros": "Comoros",
"Colombia": "Colombia",
"Cocos (Keeling) Islands": "Cocos (Keeling) Islands",
"Christmas Island": "Christmas Island",
"China": "China",
"Chile": "Chile",
"Chad": "Chad",
"Central African Republic": "República Centroafricana",
"Cayman Islands": "Illas caimán",
"Caribbean Netherlands": "Paises baixos do Caribe",
"Cape Verde": "Cabo Verde",
"Canada": "Canadá",
"Cameroon": "Camerún",
"Cambodia": "Cambodia",
"Burundi": "Burundi",
"Burkina Faso": "Burkina Faso",
"Bulgaria": "Bulgaria",
"Brunei": "Brunei",
"British Virgin Islands": "British Virgin Islands",
"British Indian Ocean Territory": "British Indian Ocean Territory",
"Brazil": "Brasil",
"Bouvet Island": "Illa Bouvet",
"Botswana": "Botswana",
"Bosnia": "Bosnia",
"Bolivia": "Bolivia",
"Bhutan": "Bután",
"Bermuda": "Bermuda",
"Benin": "Benín",
"Belize": "Belice",
"Belgium": "Bélxica",
"Belarus": "Belarús",
"Places the call in the current room on hold": "Pon en pausa a chamada da sala actual",
"Takes the call in the current room off hold": "Acepta a chamada na sala actual",
"%(creator)s created this DM.": "%(creator)s creou esta MD.",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "As mensaxes desta sala están cifradas de extremo-a-extremo. Cando se unan, podes verificar as persoas no seu perfil, tocando no seu avatar.",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Aquí as mensaxes están cifradas de extremo-a-extre. Verifica a %(displayName)s no seu perfil - toca no seu avatar.",
"Role": "Rol",
"This is the start of <roomName/>.": "Este é o comezo de <roomName/>.",
"Add a photo, so people can easily spot your room.": "Engade unha foto para que se poida identificar a sala facilmente.",
"%(displayName)s created this room.": "%(displayName)s creou esta sala.",
"You created this room.": "Creaches esta sala.",
"<a>Add a topic</a> to help people know what it is about.": "<a>Engade un tema</a> para axudarlle á xente que coñeza de que trata.",
"Topic: %(topic)s ": "Asunto: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "Asunto: %(topic)s (<a>editar</a>)",
"This is the beginning of your direct message history with <displayName/>.": "Este é o comezo do teu historial de conversa con <displayName/>.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Só vós as dúas estades nesta conversa, a non ser que convidedes a alguén máis.",
"Call Paused": "Chamada en pausa",
"Zimbabwe": "Zimbabue",
"Zambia": "Zambia",
"Yemen": "Yemen",
"Western Sahara": "Sahara Occidental",
"Wallis & Futuna": "Wallis & Futuna",
"Vietnam": "Vietnam",
"Venezuela": "Venezuela",
"Vatican City": "Cidade do Vaticano",
"Vanuatu": "Vanuatu",
"Uzbekistan": "Uzbekistan",
"Uruguay": "Uruguai",
"United Arab Emirates": "Emiratos Árabes Unidos",
"Ukraine": "Ucraína",
"Uganda": "Uganda",
"U.S. Virgin Islands": "U.S. Virgin Islands",
"Tuvalu": "Tuvalu",
"Turks & Caicos Islands": "Turks & Caicos Islands",
"Turkmenistan": "Turkmenistán",
"Turkey": "Turquía",
"Tunisia": "Túnez",
"Trinidad & Tobago": "Trinidad & Tobago",
"Tonga": "Tonga",
"Tokelau": "Tokelau",
"Togo": "Togo",
"Timor-Leste": "Timor-Leste",
"Thailand": "Tailandia",
"Tanzania": "Tanzania",
"Tajikistan": "Tajikistan",
"Taiwan": "Taiwan",
"São Tomé & Príncipe": "Santo Tomé e Príncipe",
"Syria": "Siria",
"Switzerland": "Suiza",
"Sweden": "Suecia",
"Swaziland": "Suazilandia",
"Svalbard & Jan Mayen": "Svalbard & Jan Mayen",
"Suriname": "Surinam",
"Sudan": "Sudán",
"St. Vincent & Grenadines": "St. Vincent & Grenadines",
"St. Pierre & Miquelon": "St. Pierre & Miquelon",
"St. Martin": "St. Martin",
"St. Lucia": "St. Lucia",
"St. Kitts & Nevis": "St. Kitts & Nevis",
"St. Helena": "St. Helena",
"St. Barthélemy": "St. Barthélemy",
"Sri Lanka": "Sri Lanka",
"Spain": "España",
"South Sudan": "Sudán do Sur",
"South Korea": "Corea do Sur",
"South Georgia & South Sandwich Islands": "Illas South Georgia & South Sandwich",
"South Africa": "África do Sur",
"Somalia": "Somalia",
"Solomon Islands": "Illas Salomón",
"Slovenia": "Eslovenia",
"Slovakia": "Eslovaquia",
"Sint Maarten": "Sint Maarten",
"Singapore": "Singapur",
"Sierra Leone": "Serra Leona",
"Seychelles": "Seichelles",
"Serbia": "Serbia",
"Senegal": "Senegal",
"Saudi Arabia": "Arabia Saudita",
"San Marino": "San Marino",
"Samoa": "Samoa",
"Réunion": "Reunión",
"Rwanda": "Ruanda",
"Russia": "Rusia",
"Romania": "Romanía",
"Qatar": "Catar",
"Puerto Rico": "Porto Rico",
"Portugal": "Portugal",
"Poland": "Polonia",
"Pitcairn Islands": "Illas Pitcairn",
"Philippines": "Filipinas",
"Peru": "Perú",
"Paraguay": "Paraguai",
"Papua New Guinea": "Papua Nova Guinea",
"Panama": "Panamá",
"Palestine": "Palestina",
"Palau": "Palau",
"Pakistan": "Paquistán",
"Oman": "Omán",
"Norway": "Noruega",
"Northern Mariana Islands": "Illas Marianas do Norte",
"North Korea": "Corea do Norte",
"Norfolk Island": "Illa Norfolk",
"Niue": "Niue",
"Nigeria": "Nixeria",
"Niger": "Níxer",
"Nicaragua": "Nicaragua",
"New Zealand": "Nova Zelanda",
"New Caledonia": "Nova Caledonia",
"Netherlands": "Paises Baixos",
"Nepal": "Nepal",
"Nauru": "Nauru",
"Namibia": "Namibia",
"Myanmar": "Myanmar",
"Mozambique": "Mozambique",
"Morocco": "Marrocos",
"Montserrat": "Montserrat",
"Montenegro": "Montenegro",
"Mongolia": "Mongolia",
"Monaco": "Mónaco",
"Moldova": "Moldavia",
"Micronesia": "Micronesia",
"Mexico": "México",
"Mayotte": "Mayotte",
"Mauritius": "Mauricio",
"Mauritania": "Mauritania",
"Martinique": "Martinica",
"Marshall Islands": "Illas Marshall",
"Malta": "Malta",
"Mali": "Mali",
"Maldives": "Maldivas",
"Malaysia": "Malaisia",
"Malawi": "Malawi",
"Madagascar": "Madagascar",
"Macedonia": "Macedonia",
"Macau": "Macau",
"Luxembourg": "Luxemburgo",
"Lithuania": "Lituania",
"Liechtenstein": "Liechtenstein",
"Libya": "Libia",
"Liberia": "Liberia",
"Lesotho": "Lesoto",
"Lebanon": "Líbano",
"Latvia": "Letonia",
"Laos": "Laos",
"Kyrgyzstan": "Kyrgyzstan",
"Kuwait": "Kuwait",
"Kosovo": "Kosovo",
"Kiribati": "Kiribati",
"Kenya": "Kenia",
"Kazakhstan": "Kazakhstan",
"Jordan": "Xordania",
"Jersey": "Jersey",
"Japan": "Xapón",
"Jamaica": "Xamaica",
"Italy": "Italia",
"Israel": "Israel",
"Isle of Man": "Illa de Man",
"Ireland": "Irlanda",
"Iraq": "Iraq",
"Iran": "Irán",
"Indonesia": "Indonesia",
"India": "India",
"Iceland": "Islandia",
"Hungary": "Hungría",
"Hong Kong": "Hong Kong",
"Honduras": "Honduras",
"Heard & McDonald Islands": "Heard & McDonald Islands",
"Haiti": "Haiti",
"Guyana": "Guyana",
"Guinea-Bissau": "Guinea-Bissau",
"Guinea": "Guinea",
"Guernsey": "Guernsey",
"Guatemala": "Guatemala",
"Guam": "Goam",
"Guadeloupe": "Guadalupe",
"Grenada": "Granada",
"Greenland": "Groenlandia",
"Greece": "Grecia",
"Gibraltar": "Xibraltar",
"Ghana": "Ghana",
"Germany": "Alemaña",
"Georgia": "Xeorxia",
"Gambia": "Gambia",
"Gabon": "Gabón",
"French Southern Territories": "French Southern Territories",
"French Polynesia": "Polinesia francesa",
"French Guiana": "Guaiana Francesa",
"France": "Francia",
"Finland": "Finlandia",
"Fiji": "Fiji",
"Faroe Islands": "Illas Feroe",
"Falkland Islands": "Illas Falkland",
"Ethiopia": "Etiopía",
"Estonia": "Estonia",
"Eritrea": "Eritrea",
"Equatorial Guinea": "Guinea Ecuatorial",
"El Salvador": "O Salvador",
"Egypt": "Exipto",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|one": "Conservar na memoria local as mensaxes cifradas de xeito seguro para que aparezan nas buscas, usando %(size)s para gardar mensaxes de %(count)s sala.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|other": "Conservar na memoria local as mensaxes cifradas de xeito seguro para que aparezan nas buscas, usando %(size)s para gardar mensaxes de %(count)s salas.",
"Filter rooms and people": "Fitrar salas e persoas",
"Open the link in the email to continue registration.": "Abre a ligazón que hai no email para continuar co rexistro.",
"A confirmation email has been sent to %(emailAddress)s": "Enviouse un email de confirmación a %(emailAddress)s",
"Start a new chat": "Comezar nova conversa"
} }

File diff suppressed because it is too large Load diff

View file

@ -797,7 +797,7 @@
"This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. <b>This action is irreversible.</b>": "Il tuo account sarà permanentemente inutilizzabile. Non potrai accedere e nessuno potrà ri-registrare lo stesso ID utente. Il tuo account abbandonerà tutte le stanze a cui partecipa e i dettagli del tuo account saranno rimossi dal server di identità. <b>Questa azione è irreversibile.</b>", "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. <b>This action is irreversible.</b>": "Il tuo account sarà permanentemente inutilizzabile. Non potrai accedere e nessuno potrà ri-registrare lo stesso ID utente. Il tuo account abbandonerà tutte le stanze a cui partecipa e i dettagli del tuo account saranno rimossi dal server di identità. <b>Questa azione è irreversibile.</b>",
"Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "Disattivare il tuo account <b>non eliminerà in modo predefinito i messaggi che hai inviato</b>. Se vuoi che noi dimentichiamo i tuoi messaggi, seleziona la casella sotto.", "Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "Disattivare il tuo account <b>non eliminerà in modo predefinito i messaggi che hai inviato</b>. Se vuoi che noi dimentichiamo i tuoi messaggi, seleziona la casella sotto.",
"Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "La visibilità dei messaggi in Matrix è simile alle email. Se dimentichiamo i messaggi significa che quelli che hai inviato non verranno condivisi con alcun utente nuovo o non registrato, ma gli utenti registrati che avevano già accesso ai messaggi avranno ancora accesso alla loro copia.", "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "La visibilità dei messaggi in Matrix è simile alle email. Se dimentichiamo i messaggi significa che quelli che hai inviato non verranno condivisi con alcun utente nuovo o non registrato, ma gli utenti registrati che avevano già accesso ai messaggi avranno ancora accesso alla loro copia.",
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Per favore dimenticate tutti i messaggi che ho inviato quando il mio account viene disattivato (Attenzione: gli utenti futuri vedranno un elenco incompleto di conversazioni)", "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Per favore dimenticate tutti i messaggi che ho inviato quando il mio account viene disattivato (<b>Attenzione:</b> gli utenti futuri vedranno un elenco incompleto di conversazioni)",
"To continue, please enter your password:": "Per continuare, inserisci la tua password:", "To continue, please enter your password:": "Per continuare, inserisci la tua password:",
"Can't leave Server Notices room": "Impossibile abbandonare la stanza Notifiche Server", "Can't leave Server Notices room": "Impossibile abbandonare la stanza Notifiche Server",
"This room is used for important messages from the Homeserver, so you cannot leave it.": "Questa stanza viene usata per messaggi importanti dall'homeserver, quindi non puoi lasciarla.", "This room is used for important messages from the Homeserver, so you cannot leave it.": "Questa stanza viene usata per messaggi importanti dall'homeserver, quindi non puoi lasciarla.",
@ -833,7 +833,7 @@
"The email field must not be blank.": "Il campo email non deve essere vuoto.", "The email field must not be blank.": "Il campo email non deve essere vuoto.",
"The phone number field must not be blank.": "Il campo telefono non deve essere vuoto.", "The phone number field must not be blank.": "Il campo telefono non deve essere vuoto.",
"The password field must not be blank.": "Il campo passwordl non deve essere vuoto.", "The password field must not be blank.": "Il campo passwordl non deve essere vuoto.",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Non è possibile inviare alcun messaggio fino a quando non si esaminano e si accettano <consentLink> i nostri termini e condizioni </ permissionLink>.", "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Non puoi inviare alcun messaggio fino a quando non leggi ed accetti <consentLink>i nostri termini e condizioni</consentLink>.",
"A call is currently being placed!": "Attualmente c'è una chiamata in corso!", "A call is currently being placed!": "Attualmente c'è una chiamata in corso!",
"System Alerts": "Avvisi di sistema", "System Alerts": "Avvisi di sistema",
"Failed to remove widget": "Rimozione del widget fallita", "Failed to remove widget": "Rimozione del widget fallita",
@ -893,7 +893,7 @@
"Predictable substitutions like '@' instead of 'a' don't help very much": "Sostituzioni prevedibili come '@' al posto di 'a' non aiutano molto", "Predictable substitutions like '@' instead of 'a' don't help very much": "Sostituzioni prevedibili come '@' al posto di 'a' non aiutano molto",
"Add another word or two. Uncommon words are better.": "Aggiungi ancora una o due parole. Meglio parole non comuni.", "Add another word or two. Uncommon words are better.": "Aggiungi ancora una o due parole. Meglio parole non comuni.",
"Repeats like \"aaa\" are easy to guess": "Ripetizioni come \"aaa\" sono facili da indovinare", "Repeats like \"aaa\" are easy to guess": "Ripetizioni come \"aaa\" sono facili da indovinare",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetizioni come \"abcabcabc\" sono solo leggermente più difficili da indovinare di \"abc\"", "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetizioni come \"abcabcabc\" sono solo leggermente più difficili da indovinare di \"abc\"",
"Sequences like abc or 6543 are easy to guess": "Sequenze come abc o 6543 sono facili da indovinare", "Sequences like abc or 6543 are easy to guess": "Sequenze come abc o 6543 sono facili da indovinare",
"Recent years are easy to guess": "Gli anni recenti sono facili da indovinare", "Recent years are easy to guess": "Gli anni recenti sono facili da indovinare",
"Dates are often easy to guess": "Le date sono spesso facili da indovinare", "Dates are often easy to guess": "Le date sono spesso facili da indovinare",
@ -2564,5 +2564,289 @@
"Rate %(brand)s": "Valuta %(brand)s", "Rate %(brand)s": "Valuta %(brand)s",
"Feedback sent": "Feedback inviato", "Feedback sent": "Feedback inviato",
"%(senderName)s ended the call": "%(senderName)s ha terminato la chiamata", "%(senderName)s ended the call": "%(senderName)s ha terminato la chiamata",
"You ended the call": "Hai terminato la chiamata" "You ended the call": "Hai terminato la chiamata",
"Now, let's help you get started": "Alcuni consigli per iniziare",
"Welcome %(name)s": "Benvenuto/a %(name)s",
"Add a photo so people know it's you.": "Aggiungi una foto in modo che le persone ti riconoscano.",
"Great, that'll help people know it's you": "Ottimo, ciò aiuterà le persone a capire che sei tu",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Invita qualcuno usando il suo nome, indirizzo email, nome utente (come <userId/>) o <a>condividi questa stanza</a>.",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Inizia una conversazione con qualcuno usando il suo nome, indirizzo email o nome utente (come <userId/>).",
"Invite by email": "Invita per email",
"Use the + to make a new room or explore existing ones below": "Usa la + per creare una nuova stanza o esplorare quelle esistenti sotto",
"New version of %(brand)s is available": "Nuova versione di %(brand)s disponibile",
"Update %(brand)s": "Aggiorna %(brand)s",
"Enable desktop notifications": "Attiva le notifiche desktop",
"Don't miss a reply": "Non perdere una risposta",
"Modal Widget": "Widget modale",
"%(creator)s created this DM.": "%(creator)s ha creato questo MD.",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "I messaggi in questa stanza sono cifrati end-to-end. Quando qualcuno entra puoi verificarlo nel suo profilo, ti basta toccare il suo avatar.",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Qui i messaggi sono cifrati end-to-end. Verifica %(displayName)s nel suo profilo - tocca il suo avatar.",
"This is the start of <roomName/>.": "Questo è l'inizio di <roomName/>.",
"Add a photo, so people can easily spot your room.": "Aggiungi una foto, in modo che le persone notino facilmente la stanza.",
"%(displayName)s created this room.": "%(displayName)s ha creato questa stanza.",
"You created this room.": "Hai creato questa stanza.",
"<a>Add a topic</a> to help people know what it is about.": "<a>Aggiungi un argomento</a> per aiutare le persone a capire di cosa si parla.",
"Topic: %(topic)s ": "Argomento: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "Argomento: %(topic)s (<a>modifica</a>)",
"This is the beginning of your direct message history with <displayName/>.": "Questo è l'inizio della tua cronologia di messaggi diretti con <displayName/>.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Solo voi due siete in questa conversazione, a meno che uno di voi non inviti qualcuno.",
"Call Paused": "Chiamata in pausa",
"Takes the call in the current room off hold": "Riprende la chiamata nella stanza attuale",
"Places the call in the current room on hold": "Mette in pausa la chiamata nella stanza attuale",
"Zimbabwe": "Zimbabwe",
"Zambia": "Zambia",
"Yemen": "Yemen",
"Western Sahara": "Sahara Occidentale",
"Wallis & Futuna": "Wallis e Futuna",
"Vietnam": "Vietnam",
"Venezuela": "Venezuela",
"Vatican City": "Città del Vaticano",
"Vanuatu": "Vanuatu",
"Uzbekistan": "Uzbekistan",
"Uruguay": "Uruguay",
"United Arab Emirates": "Emirati Arabi Uniti",
"Ukraine": "Ucraina",
"Uganda": "Uganda",
"U.S. Virgin Islands": "Isole Vergini americane",
"Tuvalu": "Tuvalu",
"Turks & Caicos Islands": "Turks e Caicos",
"Turkmenistan": "Turkmenistan",
"Turkey": "Turchia",
"Tunisia": "Tunisia",
"Trinidad & Tobago": "Trinidad e Tobago",
"Tonga": "Tonga",
"Tokelau": "Tokelau",
"Togo": "Togo",
"Timor-Leste": "Timor Est",
"Thailand": "Tailandia",
"Tanzania": "Tanzania",
"Tajikistan": "Tagikistan",
"Taiwan": "Taiwan",
"São Tomé & Príncipe": "São Tomé e Príncipe",
"Syria": "Siria",
"Switzerland": "Svizzera",
"Sweden": "Svezia",
"Swaziland": "eSwatini",
"Svalbard & Jan Mayen": "Svalbard e Jan Mayen",
"Suriname": "Suriname",
"Sudan": "Sudan",
"St. Vincent & Grenadines": "Saint Vincent e Grenadine",
"St. Pierre & Miquelon": "Saint-Pierre e Miquelon",
"St. Martin": "Saint Martin",
"St. Lucia": "Saint Lucia",
"St. Kitts & Nevis": "Saint Kitts e Nevis",
"St. Helena": "Sant'Elena",
"St. Barthélemy": "Saint-Barthélemy",
"Sri Lanka": "Sri Lanka",
"Spain": "Spagna",
"South Sudan": "Sudan del Sud",
"South Korea": "Corea del Sud",
"South Georgia & South Sandwich Islands": "Georgia del Sud e Isole Sandwich Australi",
"South Africa": "Sudafrica",
"Somalia": "Somalia",
"Solomon Islands": "Isole Solomone",
"Slovenia": "Slovenia",
"Slovakia": "Slovacchia",
"Sint Maarten": "Sint Maarten",
"Singapore": "Singapore",
"Sierra Leone": "Sierra Leone",
"Seychelles": "Seychelles",
"Serbia": "Serbia",
"Senegal": "Senegal",
"Saudi Arabia": "Arabia Saudita",
"San Marino": "San Marino",
"Samoa": "Samoa",
"Réunion": "Riunione",
"Rwanda": "Ruanda",
"Russia": "Russia",
"Romania": "Romania",
"Qatar": "Qatar",
"Puerto Rico": "Puerto Rico",
"Portugal": "Portogallo",
"Poland": "Polonia",
"Pitcairn Islands": "Isole Pitcairn",
"Philippines": "Filippine",
"Peru": "Peru",
"Paraguay": "Paraguay",
"Papua New Guinea": "Papua Nuova Guinea",
"Panama": "Panama",
"Palestine": "Palestina",
"Palau": "Palau",
"Pakistan": "Pakistan",
"Oman": "Oman",
"Norway": "Norvegia",
"Northern Mariana Islands": "Isole Marianne Settentrionali",
"North Korea": "Corea del Nord",
"Norfolk Island": "Isola Norfolk",
"Niue": "Niue",
"Nigeria": "Nigeria",
"Niger": "Niger",
"Nicaragua": "Nicaragua",
"New Zealand": "Nuova Zelanda",
"New Caledonia": "Nuova Caledonia",
"Netherlands": "Paesi Bassi",
"Nepal": "Nepal",
"Nauru": "Nauru",
"Namibia": "Namibia",
"Myanmar": "Birmania",
"Mozambique": "Mozambico",
"Morocco": "Marocco",
"Montserrat": "Montserrat",
"Montenegro": "Montenegro",
"Mongolia": "Mongolia",
"Monaco": "Monaco",
"Moldova": "Moldavia",
"Micronesia": "Micronesia",
"Mexico": "Messico",
"Mayotte": "Maiotta",
"Mauritius": "Mauritius",
"Mauritania": "Mauritania",
"Martinique": "Martinica",
"Marshall Islands": "Isole Marshall",
"Malta": "Malta",
"Mali": "Mali",
"Maldives": "Maldive",
"Malaysia": "Malesia",
"Malawi": "Malawi",
"Madagascar": "Madagascar",
"Macedonia": "Macedonia",
"Macau": "Macau",
"Luxembourg": "Lussemburgo",
"Lithuania": "Lituania",
"Liechtenstein": "Liechtenstein",
"Libya": "Libia",
"Liberia": "Liberia",
"Lesotho": "Lesotho",
"Lebanon": "Libano",
"Latvia": "Lettonia",
"Laos": "Laos",
"Kyrgyzstan": "Kirghizistan",
"Kuwait": "Kuwait",
"Kosovo": "Kosovo",
"Kiribati": "Kiribati",
"Kenya": "Kenya",
"Kazakhstan": "Kazakistan",
"Jordan": "Giordania",
"Jersey": "Baliato di Jersey",
"Japan": "Giappone",
"Jamaica": "Giamaica",
"Italy": "Italia",
"Israel": "Israele",
"Isle of Man": "Isola di Man",
"Ireland": "Irlanda",
"Iraq": "Iraq",
"Iran": "Iran",
"Indonesia": "Indonesia",
"India": "India",
"Iceland": "Islanda",
"Hungary": "Ungheria",
"Hong Kong": "Hong Kong",
"Honduras": "Honduras",
"Heard & McDonald Islands": "Isole Heard e McDonald",
"Haiti": "Haiti",
"Guyana": "Guyana",
"Guinea-Bissau": "Guinea-Bissau",
"Guinea": "Guinea",
"Guernsey": "Guernsey",
"Guatemala": "Guatemala",
"Guam": "Guam",
"Guadeloupe": "Guadalupa",
"Grenada": "Grenada",
"Greenland": "Groenlandia",
"Greece": "Grecia",
"Gibraltar": "Gibilterra",
"Ghana": "Ghana",
"Germany": "Germania",
"Georgia": "Georgia",
"Gambia": "Gambia",
"Gabon": "Gabon",
"French Southern Territories": "Terre australi e antartiche francesi",
"French Polynesia": "Polinesia Francese",
"French Guiana": "Guiana Francese",
"France": "Francia",
"Finland": "Finlandia",
"Fiji": "Figi",
"Faroe Islands": "Isole Faroe",
"Falkland Islands": "Isole Falkland",
"Ethiopia": "Etiopia",
"Estonia": "Estonia",
"Eritrea": "Eritrea",
"Equatorial Guinea": "Guinea Equatoriale",
"El Salvador": "El Salvador",
"Egypt": "Egitto",
"Ecuador": "Ecuador",
"Dominican Republic": "Repubblica Dominicana",
"Dominica": "Dominica",
"Djibouti": "Gibuti",
"Denmark": "Danimarca",
"Côte dIvoire": "Costa d'Avorio",
"Czech Republic": "Repubblica Ceca",
"Cyprus": "Cipro",
"Curaçao": "Curaçao",
"Cuba": "Cuba",
"Croatia": "Croazia",
"Costa Rica": "Costa Rica",
"Cook Islands": "Isole Cook",
"Congo - Kinshasa": "Congo - Kinshasa",
"Congo - Brazzaville": "Congo - Brazzaville",
"Comoros": "Comore",
"Colombia": "Colombia",
"Cocos (Keeling) Islands": "Isole Cocos (Keeling)",
"Christmas Island": "Isola di Natale",
"China": "Cina",
"Chile": "Cile",
"Chad": "Ciad",
"Central African Republic": "Repubblica Centrafricana",
"Cayman Islands": "Isole Cayman",
"Caribbean Netherlands": "Paesi Bassi caraibici",
"Cape Verde": "Capo Verde",
"Canada": "Canada",
"Cameroon": "Camerun",
"Cambodia": "Cambogia",
"Burundi": "Burundi",
"Burkina Faso": "Burkina Faso",
"Bulgaria": "Bulgaria",
"Brunei": "Brunei",
"British Virgin Islands": "Isole Vergini britanniche",
"British Indian Ocean Territory": "Territorio britannico dell'Oceano Indiano",
"Brazil": "Brasile",
"Bouvet Island": "Isola Bouvet",
"Botswana": "Botswana",
"Bosnia": "Bosnia",
"Bolivia": "Bolivia",
"Bhutan": "Bhutan",
"Bermuda": "Bermuda",
"Benin": "Benin",
"Belize": "Belize",
"Belgium": "Belgio",
"Belarus": "Bielorussia",
"Barbados": "Barbados",
"Bangladesh": "Bangladesh",
"Bahrain": "Bahrein",
"Bahamas": "Bahamas",
"Azerbaijan": "Azerbaigian",
"Austria": "Austria",
"Australia": "Australia",
"Aruba": "Aruba",
"Armenia": "Armenia",
"Argentina": "Argentina",
"Antigua & Barbuda": "Antigua e Barbuda",
"Antarctica": "Antartide",
"Anguilla": "Anguilla",
"Angola": "Angola",
"Andorra": "Andorra",
"American Samoa": "Samoa Americane",
"Algeria": "Algeria",
"Albania": "Albania",
"Åland Islands": "Isole Åland",
"Afghanistan": "Afghanistan",
"United States": "Stati Uniti",
"United Kingdom": "Regno Unito",
"Role": "Ruolo",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|one": "Salva in cache i messaggi cifrati localmente in modo che appaiano nei risultati di ricerca, usando %(size)s per salvarli da %(count)s stanza.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|other": "Salva in cache i messaggi cifrati localmente in modo che appaiano nei risultati di ricerca, usando %(size)s per salvarli da %(count)s stanze.",
"Filter rooms and people": "Filtra stanze e persone",
"Open the link in the email to continue registration.": "Apri il link nell'email per continuare la registrazione.",
"A confirmation email has been sent to %(emailAddress)s": "È stata inviata un'email di conferma a %(emailAddress)s",
"Start a new chat": "Inizia una nuova chat"
} }

View file

@ -151,7 +151,7 @@
"Preparing to send logs": "ログを送信する準備をしています", "Preparing to send logs": "ログを送信する準備をしています",
"Explore Account Data": "アカウントのデータを調べる", "Explore Account Data": "アカウントのデータを調べる",
"The server may be unavailable or overloaded": "サーバは使用できないか、オーバーロードされています", "The server may be unavailable or overloaded": "サーバは使用できないか、オーバーロードされています",
"Reject": "やめる", "Reject": "拒否する",
"Failed to set Direct Message status of room": "部屋のダイレクトメッセージステータスの設定に失敗しました", "Failed to set Direct Message status of room": "部屋のダイレクトメッセージステータスの設定に失敗しました",
"Remove from Directory": "ディレクトリから消去する", "Remove from Directory": "ディレクトリから消去する",
"Enable them now": "今有効化する", "Enable them now": "今有効化する",
@ -649,7 +649,7 @@
"Incorrect password": "間違ったパスワード", "Incorrect password": "間違ったパスワード",
"Deactivate Account": "アカウントを無効にする", "Deactivate Account": "アカウントを無効にする",
"This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. <b>This action is irreversible.</b>": "これにより、あなたのアカウントは永久に使用できなくなります。ログインできなくなり、誰も同じユーザーIDを再登録できなくなります。これにより、参加しているすべてのルームから退室し、 IDサーバからあなたのアカウントの詳細が削除されます。<b>この操作は元に戻すことができません。</b>", "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. <b>This action is irreversible.</b>": "これにより、あなたのアカウントは永久に使用できなくなります。ログインできなくなり、誰も同じユーザーIDを再登録できなくなります。これにより、参加しているすべてのルームから退室し、 IDサーバからあなたのアカウントの詳細が削除されます。<b>この操作は元に戻すことができません。</b>",
"Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "アカウントを無効にしても、<b>送信されたメッセージはデフォルトではなくなりません。</b>メッセージを忘れてしまった場合は、下のボックスにチェックを入れてください。", "Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "アカウントを無効にしても、<b>送信されたメッセージはデフォルトでは忘れられません。</b>メッセージを忘れさせたい場合は、下のボックスにチェックを入れてください。",
"Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Matrixのメッセージの可視性は電子メールと似ています。メッセージを忘れると、新規または未登録のユーザーと共有することができませんが、既にこれらのメッセージにアクセスしている登録ユーザーは、依然としてそのコピーにアクセスできます。", "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Matrixのメッセージの可視性は電子メールと似ています。メッセージを忘れると、新規または未登録のユーザーと共有することができませんが、既にこれらのメッセージにアクセスしている登録ユーザーは、依然としてそのコピーにアクセスできます。",
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "アカウントを無効する際、送信したすべてのメッセージを削除(<b>警告:</b>これにより、今後のユーザーは会話履歴の全文を見ることができなくなります)", "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "アカウントを無効する際、送信したすべてのメッセージを削除(<b>警告:</b>これにより、今後のユーザーは会話履歴の全文を見ることができなくなります)",
"To continue, please enter your password:": "続行するには、パスワードを入力してください:", "To continue, please enter your password:": "続行するには、パスワードを入力してください:",
@ -1433,5 +1433,38 @@
"Go back": "戻る", "Go back": "戻る",
"To help avoid duplicate issues, please <existingIssuesLink>view existing issues</existingIssuesLink> first (and add a +1) or <newIssueLink>create a new issue</newIssueLink> if you can't find it.": "重複した issue の報告が発生しないようにするため、まず<existingIssuesLink>既存の issue を確認</existingIssuesLink>してあなたが行おうとしているのと同様の報告が見つかった場合はその issue を +1 してください。見つからなかった場合は、<newIssueLink>新しい issue を作成</newIssueLink>して報告を行ってください。", "To help avoid duplicate issues, please <existingIssuesLink>view existing issues</existingIssuesLink> first (and add a +1) or <newIssueLink>create a new issue</newIssueLink> if you can't find it.": "重複した issue の報告が発生しないようにするため、まず<existingIssuesLink>既存の issue を確認</existingIssuesLink>してあなたが行おうとしているのと同様の報告が見つかった場合はその issue を +1 してください。見つからなかった場合は、<newIssueLink>新しい issue を作成</newIssueLink>して報告を行ってください。",
"If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "バグが発生したり、共有したいフィードバックがある場合は、GitHub でお知らせください。", "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "バグが発生したり、共有したいフィードバックがある場合は、GitHub でお知らせください。",
"Report bugs & give feedback": "バグ報告とフィードバック" "Report bugs & give feedback": "バグ報告とフィードバック",
"Everyone in this room is verified": "この部屋内の全員を検証済み",
"Verify all users in a room to ensure it's secure.": "この部屋内のすべてのユーザーが安全であることを確認しました。",
"You've successfully verified %(displayName)s!": "%(displayName)s は正常に検証されました。",
"You've successfully verified %(deviceName)s (%(deviceId)s)!": "%(deviceName)s (%(deviceId)s) は正常に検証されました。",
"You've successfully verified your device!": "このデバイスは正常に検証されました。",
"You've successfully verified this user.": "このユーザーは正常に検証されました。",
"Reject & Ignore user": "拒否した上でこのユーザーを無視する",
"<userName/> invited you": "<userName/> があなたを招待しています",
"Do you want to join %(roomName)s?": "%(roomName)s に参加しますか?",
"Start chatting": "チャットを開始",
"<userName/> wants to chat": "<userName/> がチャット開始を求めています",
"Do you want to chat with %(user)s?": "%(user)s とのチャットを開始しますか?",
"Use the <a>Desktop app</a> to search encrypted messages": "<a>デスクトップアプリ</a>を使用すると暗号化されたメッセージを検索できます",
"You have no visible notifications in this room.": "この部屋に確認すべき通知はありません。",
"Youre all caught up": "確認するものはありません",
"Got it": "了解",
"Got It": "了解",
"Accepting…": "了承中…",
"Waiting for %(displayName)s to verify…": "%(displayName)s が検証するのを待っています…",
"Waiting for %(displayName)s to accept…": "%(displayName)s が了承するのを待っています…",
"Room avatar": "部屋のアバター",
"Start Verification": "検証を開始",
"For extra security, verify this user by checking a one-time code on both of your devices.": "セキュリティ強化するために、両者のデバイスでワンタイムコードを確認し、このユーザーを検証することができます。",
"Your messages are secured and only you and the recipient have the unique keys to unlock them.": "あなたのメッセージは保護されており、あなたと宛先だけが保護を解除してメッセージを閲覧するための固有の鍵を持っています。",
"%(name)s wants to verify": "%(name)s が検証を求めています",
"You sent a verification request": "あなたが検証リクエストを送信しました",
"This account has been deactivated.": "このアカウントは、無効化されています。",
"Forget Room": "部屋を忘れる",
"Forget this room": "部屋を忘れる",
"Recently Direct Messaged": "最近ダイレクトメッセージで会話したユーザー",
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.": "この部屋に誰かを招待したい場合は、招待したいユーザーの名前、( <userId/> の様な)ユーザー名、またはメールアドレスを指定するか、<a>この部屋を共有</a>してください。",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "この部屋に誰かを招待したい場合は、招待したいユーザーの名前、メールアドレス、または( <userId/> の様な)ユーザー名を指定するか、<a>この部屋を共有</a>してください。",
"Upgrade your encryption": "暗号化をアップグレード"
} }

View file

@ -692,7 +692,7 @@
"Unable to reject invite": "Nie udało się odrzucić zaproszenia", "Unable to reject invite": "Nie udało się odrzucić zaproszenia",
"Share Message": "Udostępnij wiadomość", "Share Message": "Udostępnij wiadomość",
"Collapse Reply Thread": "Zwiń wątek odpowiedzi", "Collapse Reply Thread": "Zwiń wątek odpowiedzi",
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>Strona HTML dla Twojej Społeczności</h1>\n<p>\n Skorzystaj z długiego opisu aby wprowadzić nowych członków do Społeczności lub rozpowszechnić ważne <a href=\"blabla\">linki</a>.\n</p>\n<p>\n Możesz nawet używać tagów 'img'.\n</p>\n", "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>Strona HTML dla Twojej Społeczności</h1>\n<p>\n Skorzystaj z długiego opisu aby wprowadzić nowych członków do Społeczności lub rozpowszechnić\n ważne <a href=\"blabla\">linki</a>.\n</p>\n<p>\n Możesz nawet używać tagów 'img'.\n</p>\n",
"Add rooms to the community summary": "Dodaj pokoje do podsumowania Społeczności", "Add rooms to the community summary": "Dodaj pokoje do podsumowania Społeczności",
"Which rooms would you like to add to this summary?": "Które pokoje chcesz dodać do tego podsumowania?", "Which rooms would you like to add to this summary?": "Które pokoje chcesz dodać do tego podsumowania?",
"Add to summary": "Dodaj do podsumowania", "Add to summary": "Dodaj do podsumowania",
@ -1081,7 +1081,7 @@
"%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s zmienił(a) zasadę dołączania na %(rule)s", "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s zmienił(a) zasadę dołączania na %(rule)s",
"%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s pozwolił(a) by goście dołączali do pokoju.", "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s pozwolił(a) by goście dołączali do pokoju.",
"%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s zabronił(a) gościom dołączać do pokoju.", "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s zabronił(a) gościom dołączać do pokoju.",
"%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s zmienił dostęp gościnny dla %(rule)s", "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s zmienił dostęp gościnny na %(rule)s",
"%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s aktywował Flair dla %(groups)s w tym pokoju.", "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s aktywował Flair dla %(groups)s w tym pokoju.",
"%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s dezaktywował Flair dla %(groups)s w tym pokoju.", "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s dezaktywował Flair dla %(groups)s w tym pokoju.",
"%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s aktywował Flair dla %(newGroups)s i dezaktywował Flair dla %(oldGroups)s w tym pokoju.", "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s aktywował Flair dla %(newGroups)s i dezaktywował Flair dla %(oldGroups)s w tym pokoju.",
@ -1505,7 +1505,7 @@
"Use Single Sign On to continue": "Użyj pojedynczego logowania, aby kontynuować", "Use Single Sign On to continue": "Użyj pojedynczego logowania, aby kontynuować",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Potwierdź dodanie tego adresu e-mail przez użycie pojedynczego logowania, aby potwierdzić swoją tożsamość.", "Confirm adding this email address by using Single Sign On to prove your identity.": "Potwierdź dodanie tego adresu e-mail przez użycie pojedynczego logowania, aby potwierdzić swoją tożsamość.",
"Single Sign On": "Pojedyncze logowanie", "Single Sign On": "Pojedyncze logowanie",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Potwierdź dodanie tego numeru telefonu przez użycie pojedynczego logowania, aby potwierdzić swoją tożsamość.", "Confirm adding this phone number by using Single Sign On to prove your identity.": "Potwierdź dodanie tego numeru telefonu przy użyciu pojedynczego logowania, aby potwierdzić swoją tożsamość.",
"Learn More": "Dowiedz się więcej", "Learn More": "Dowiedz się więcej",
"Light": "Jasny", "Light": "Jasny",
"Dark": "Ciemny", "Dark": "Ciemny",
@ -1531,5 +1531,58 @@
"Switch to light mode": "Przełącz na tryb jasny", "Switch to light mode": "Przełącz na tryb jasny",
"Switch to dark mode": "Przełącz na tryb ciemny", "Switch to dark mode": "Przełącz na tryb ciemny",
"Switch theme": "Przełącz motyw", "Switch theme": "Przełącz motyw",
"All settings": "Wszystkie ustawienia" "All settings": "Wszystkie ustawienia",
"This requires the latest %(brand)s on your other devices:": "To wymaga najnowszy %(brand)s na pozostałych urządzeniach:",
"%(brand)s Desktop": "%(brand)s na komputer",
"%(brand)s Web": "%(brand)s w przeglądarce",
"%(brand)s iOS": "%(brand)s na iOS",
"%(brand)s Android": "%(brand)s na Android",
"You're signed out": "Wylogowano",
"That matches!": "Zgadza się!",
"New Recovery Method": "Nowy sposób odzyskiwania",
"If disabled, messages from encrypted rooms won't appear in search results.": "Jeśli wyłączone, wiadomości z szyfrowanych pokojów nie pojawią się w wynikach wyszukiwania.",
"%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s z %(totalRooms)s",
"Super": "Super",
"Toggle video on/off": "Włącz/wyłącz wideo",
"Jump to room search": "Przejdź do szukania pokoju",
"Upload a file": "Wyślij plik",
"Unknown (user, session) pair:": "Nieznana para (użytkownik, sesja):",
"Verifies a user, session, and pubkey tuple": "Weryfikuje użytkownika, sesję oraz klucz publiczny",
"Find other public servers or use a custom server": "Znajdź inne publiczne serwery lub podaj własny",
"Join millions for free on the largest public server": "Dołącz do milionów za darmo na największym publicznym serwerze",
"Free": "Za darmo",
"Enter your password to sign in and regain access to your account.": "Podaj hasło, aby zalogować się i odzyskać dostęp do swojego konta.",
"Regain access to your account and recover encryption keys stored in this session. Without them, you wont be able to read all of your secure messages in any session.": "Odzyskaj dostęp do swojego konta i klucze zachowane w tej sesji. Bez nich nie uda się odczytać bezpiecznych wiadomości w żadnej sesji.",
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "Ci użytkownicy mogą nie istnieć lub są nieprawidłowi, i nie mogą zostać zaproszeni: %(csvNames)s",
"Failed to find the following users": "Nie udało się znaleźć tych użytkowników",
"We couldn't invite those users. Please check the users you want to invite and try again.": "Nie udało się zaprosić tych użytkowników. Proszę sprawdzić zaproszonych użytkowników i spróbować ponownie.",
"Something went wrong trying to invite the users.": "Coś poszło nie tak podczas zapraszania użytkowników.",
"We couldn't create your DM. Please check the users you want to invite and try again.": "Nie udało się utworzyć wiadomości. Proszę sprawdzić zaproszonych użytkowników i spróbować ponownie.",
"Failed to invite the following users to chat: %(csvUsers)s": "Nie udało się zaprosić tych użytkowników do rozmowy: %(csvUsers)s",
"Invite by email": "Zaproś przez e-mail",
"Invite anyway and never warn me again": "Zaproś mimo to i nie ostrzegaj ponownie",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Nie znaleziono profilów wymienionych ID Matriksa — czy zaprosić ich mimo to?",
"The following users may not exist": "Tych użytkowników może nie być",
"Use a different passphrase?": "Użyć innego hasła?",
"Emoji picker": "Wybór emoji",
"Widgets": "Widżety",
"The call could not be established": "Nie udało się nawiązać połączenia",
"Answered Elsewhere": "Odebrane gdzie indziej",
"The call was answered on another device.": "Połączenie zostało odebrane na innym urządzeniu.",
"The other party declined the call.": "Połączenie zostało odrzucone przez drugą stronę.",
"Call Declined": "Połączenie odrzucone",
"Messages in this room are end-to-end encrypted.": "Wiadomości w tym pokoju są szyfrowane end-to-end.",
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Klucz podpisujący, który podano jest taki sam jak klucz podpisujący otrzymany od %(userId)s oraz sesji %(deviceId)s. Sesja została oznaczona jako zweryfikowana.",
"Sends a message to the given user": "Wysyła wiadomość do wybranego użytkownika",
"Opens chat with the given user": "Otwiera rozmowę z wybranym użytkownikiem",
"Please supply a widget URL or embed code": "Proszę podać adres URL widżetu lub embed code",
"Command failed": "Wykonywanie komendy nie powiodło się",
"Unrecognised room address:": "Nieznany adres pokoju:",
"Joins room with given address": "Dołącz do pokoju o wybranym adresie",
"Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Dodaje ( ͡° ͜ʖ ͡°) na początku wiadomości tekstowej",
"Are you sure you want to cancel entering passphrase?": "Czy na pewno chcesz anulować wpisywanie hasła?",
"Cancel entering passphrase?": "Anulować wpisywanie hasła?",
"Room name or address": "Nazwa lub adres pokoju",
"This will end the conference for everyone. Continue?": "Czy na pewno chcesz zakończyc połączenie grupowe? To zakończy je dla wszystkich uczestnikow.",
"End conference": "Zakończ połączenie grupowe"
} }

View file

@ -300,7 +300,7 @@
"Ongoing conference call%(supportedText)s.": "Chamada em grupo em andamento%(supportedText)s.", "Ongoing conference call%(supportedText)s.": "Chamada em grupo em andamento%(supportedText)s.",
"Online": "Conectada/o", "Online": "Conectada/o",
"Idle": "Ocioso", "Idle": "Ocioso",
"Offline": "Desconectado", "Offline": "Offline",
"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.": "O arquivo exportado irá permitir a qualquer pessoa que o acesse a descriptografar qualquer uma das mensagens criptografadas que você veja, portanto seja bastante cuidadosa(o) em manter este arquivo seguro. Para deixar este arquivo mais protegido, recomendamos que você insira uma senha abaixo, que será usada para criptografar o arquivo. Só será possível importar os dados usando exatamente a mesma senha.", "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.": "O arquivo exportado irá permitir a qualquer pessoa que o acesse a descriptografar qualquer uma das mensagens criptografadas que você veja, portanto seja bastante cuidadosa(o) em manter este arquivo seguro. Para deixar este arquivo mais protegido, recomendamos que você insira uma senha abaixo, que será usada para criptografar o arquivo. Só será possível importar os dados usando exatamente a mesma senha.",
"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.": "Este processo faz com que você possa importar as chaves de criptografia que tinha previamente exportado de outro cliente Matrix. Você poderá então descriptografar todas as mensagens que o outro cliente pôde criptografar.", "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.": "Este processo faz com que você possa importar as chaves de criptografia que tinha previamente exportado de outro cliente Matrix. Você poderá então descriptografar todas as mensagens que o outro cliente pôde criptografar.",
"Start automatically after system login": "Iniciar automaticamente ao iniciar o sistema", "Start automatically after system login": "Iniciar automaticamente ao iniciar o sistema",
@ -461,7 +461,7 @@
"%(duration)sd": "%(duration)sd", "%(duration)sd": "%(duration)sd",
"Online for %(duration)s": "Online há %(duration)s", "Online for %(duration)s": "Online há %(duration)s",
"Idle for %(duration)s": "Inativo há %(duration)s", "Idle for %(duration)s": "Inativo há %(duration)s",
"Offline for %(duration)s": "Desconectado há %(duration)s", "Offline for %(duration)s": "Offline há %(duration)s",
"Unknown for %(duration)s": "Status desconhecido há %(duration)s", "Unknown for %(duration)s": "Status desconhecido há %(duration)s",
"Unknown": "Desconhecido", "Unknown": "Desconhecido",
"Replying": "Em resposta a", "Replying": "Em resposta a",
@ -1431,7 +1431,7 @@
"%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.": "%(brand)s não consegue pesquisar as mensagens criptografadas armazenadas localmente em um navegador de internet. Use o <desktopLink>%(brand)s para Computador</desktopLink> para que as mensagens criptografadas sejam exibidas nos resultados de buscas.", "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.": "%(brand)s não consegue pesquisar as mensagens criptografadas armazenadas localmente em um navegador de internet. Use o <desktopLink>%(brand)s para Computador</desktopLink> para que as mensagens criptografadas sejam exibidas nos resultados de buscas.",
"Connecting to integration manager...": "Conectando ao gestor de integrações...", "Connecting to integration manager...": "Conectando ao gestor de integrações...",
"Cannot connect to integration manager": "Não foi possível conectar ao gerenciador de integrações", "Cannot connect to integration manager": "Não foi possível conectar ao gerenciador de integrações",
"The integration manager is offline or it cannot reach your homeserver.": "Ou o gerenciador de integrações está desconectado, ou ele não conseguiu acessar o seu servidor.", "The integration manager is offline or it cannot reach your homeserver.": "Ou o gerenciador de integrações está indisponível, ou ele não conseguiu acessar o seu servidor.",
"This session is backing up your keys. ": "Esta sessão está fazendo backup das suas chaves. ", "This session is backing up your keys. ": "Esta sessão está fazendo backup das suas chaves. ",
"This session is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.": "Esta sessão <b>não está fazendo backup de suas chaves</b>, mas você tem um backup existente que pode restaurar para continuar.", "This session is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.": "Esta sessão <b>não está fazendo backup de suas chaves</b>, mas você tem um backup existente que pode restaurar para continuar.",
"Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "Autorize esta sessão a fazer o backup de chaves antes de se desconectar, para evitar perder chaves que possam estar apenas nesta sessão.", "Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "Autorize esta sessão a fazer o backup de chaves antes de se desconectar, para evitar perder chaves que possam estar apenas nesta sessão.",
@ -1781,7 +1781,7 @@
"Disconnect identity server": "Desconectar servidor de identidade", "Disconnect identity server": "Desconectar servidor de identidade",
"Disconnect from the identity server <idserver />?": "Desconectar-se do servidor de identidade <idserver />?", "Disconnect from the identity server <idserver />?": "Desconectar-se do servidor de identidade <idserver />?",
"Disconnect": "Desconectar", "Disconnect": "Desconectar",
"You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.": "Você deve <b>remover seus dados pessoais</b> do servidor de identidade <idserver /> antes de desconectar. Infelizmente, o servidor de identidade <idserver /> ou está desconectado no momento, ou não pode ser acessado.", "You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.": "Você deve <b>remover seus dados pessoais</b> do servidor de identidade <idserver /> antes de desconectar. Infelizmente, o servidor de identidade <idserver /> ou está indisponível no momento, ou não pode ser acessado.",
"You should:": "Você deveria:", "You should:": "Você deveria:",
"check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "verifique se há extensões no seu navegador que possam bloquear o servidor de identidade (por exemplo, Privacy Badger)", "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "verifique se há extensões no seu navegador que possam bloquear o servidor de identidade (por exemplo, Privacy Badger)",
"contact the administrators of identity server <idserver />": "entre em contato com os administradores do servidor de identidade <idserver />", "contact the administrators of identity server <idserver />": "entre em contato com os administradores do servidor de identidade <idserver />",
@ -1829,7 +1829,7 @@
"Change settings": "Alterar configurações", "Change settings": "Alterar configurações",
"Send %(eventType)s events": "Enviar eventos de %(eventType)s", "Send %(eventType)s events": "Enviar eventos de %(eventType)s",
"Roles & Permissions": "Papeis & Permissões", "Roles & Permissions": "Papeis & Permissões",
"Select the roles required to change various parts of the room": "Selecione as permissões necessárias para alterar várias partes da sala", "Select the roles required to change various parts of the room": "Selecione os papeis necessários para alterar várias partes da sala",
"Emoji picker": "Enviar emoji", "Emoji picker": "Enviar emoji",
"Room %(name)s": "Sala %(name)s", "Room %(name)s": "Sala %(name)s",
"No recently visited rooms": "Nenhuma sala foi visitada recentemente", "No recently visited rooms": "Nenhuma sala foi visitada recentemente",
@ -1918,7 +1918,7 @@
"Collapse room list section": "Esconder seção da lista de salas", "Collapse room list section": "Esconder seção da lista de salas",
"Expand room list section": "Mostrar seção da lista de salas", "Expand room list section": "Mostrar seção da lista de salas",
"The person who invited you already left the room.": "A pessoa que convidou você já saiu da sala.", "The person who invited you already left the room.": "A pessoa que convidou você já saiu da sala.",
"The person who invited you already left the room, or their server is offline.": "A pessoa que convidou você já saiu da sala, ou o servidor dela está desconectado.", "The person who invited you already left the room, or their server is offline.": "A pessoa que convidou você já saiu da sala, ou o servidor dela está indisponível.",
"Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Use o Gerenciador de Integrações em <b>(%(serverName)s)</b> para gerenciar bots, widgets e pacotes de figurinhas.", "Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Use o Gerenciador de Integrações em <b>(%(serverName)s)</b> para gerenciar bots, widgets e pacotes de figurinhas.",
"Use an Integration Manager to manage bots, widgets, and sticker packs.": "Use o Gerenciador de Integrações para gerenciar bots, widgets e pacotes de figurinhas.", "Use an Integration Manager to manage bots, widgets, and sticker packs.": "Use o Gerenciador de Integrações para gerenciar bots, widgets e pacotes de figurinhas.",
"Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "O Gerenciador de Integrações recebe dados de configuração e pode modificar widgets, enviar convites para salas e definir níveis de permissão em seu nome.", "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "O Gerenciador de Integrações recebe dados de configuração e pode modificar widgets, enviar convites para salas e definir níveis de permissão em seu nome.",
@ -2493,5 +2493,284 @@
"Tell us below how you feel about %(brand)s so far.": "Conte-nos abaixo o que você sente sobre o %(brand)s até o momento.", "Tell us below how you feel about %(brand)s so far.": "Conte-nos abaixo o que você sente sobre o %(brand)s até o momento.",
"Rate %(brand)s": "Avalie o %(brand)s", "Rate %(brand)s": "Avalie o %(brand)s",
"%(senderName)s ended the call": "%(senderName)s encerrou a chamada", "%(senderName)s ended the call": "%(senderName)s encerrou a chamada",
"You ended the call": "Você encerrou a chamada" "You ended the call": "Você encerrou a chamada",
"Now, let's help you get started": "Agora, vamos começar",
"Don't miss a reply": "Não perca uma resposta",
"Enable desktop notifications": "Ativar notificações na área de trabalho",
"Welcome %(name)s": "Boas-vindas, %(name)s",
"Add a photo so people know it's you.": "Adicione uma foto para as pessoas identificarem você.",
"Great, that'll help people know it's you": "Ótimo, agora as pessoas identificarão você",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Convide alguém a partir do nome, e-mail ou nome de usuário (por exemplo: <userId/>) ou <a>compartilhe esta sala</a>.",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Comece uma conversa, a partir do nome, e-mail ou nome de usuário de alguém (por exemplo: <userId/>).",
"Invite by email": "Convidar por e-mail",
"Use the + to make a new room or explore existing ones below": "Clique em + para criar uma nova sala ou explore as salas existentes abaixo",
"New version of %(brand)s is available": "Uma nova versão do %(brand)s está disponível",
"Update %(brand)s": "Atualizar o %(brand)s",
"Jordan": "Jordânia",
"Japan": "Japão",
"Jamaica": "Jamaica",
"Italy": "Itália",
"Israel": "Israel",
"Ireland": "Irlanda",
"Iraq": "Iraque",
"Iran": "Irã",
"Indonesia": "Indonésia",
"India": "Índia",
"Iceland": "Islândia",
"Hungary": "Hungria",
"Hong Kong": "Hong Kong",
"Honduras": "Honduras",
"Haiti": "Haiti",
"Guyana": "Guiana",
"Guinea-Bissau": "Guiné-Bissau",
"Comoros": "Comores",
"Vietnam": "Vietnã",
"Venezuela": "Venezuela",
"Uruguay": "Uruguai",
"United Arab Emirates": "Emirados Árabes Unidos",
"Ukraine": "Ucrânia",
"Uganda": "Uganda",
"Turkey": "Turquia",
"Spain": "Espanha",
"South Sudan": "Sudão do Sul",
"South Korea": "Coreia do Sul",
"South Africa": "África do Sul",
"Somalia": "Somália",
"Solomon Islands": "Ilhas Salomão",
"Slovenia": "Eslovênia",
"Slovakia": "Eslováquia",
"Singapore": "Singapura",
"Sierra Leone": "Serra Leoa",
"Serbia": "Sérvia",
"Senegal": "Senegal",
"Saudi Arabia": "Arábia Saudita",
"Russia": "Rússia",
"Romania": "Romênia",
"Puerto Rico": "Porto Rico",
"Portugal": "Portugal",
"Poland": "Polônia",
"Peru": "Peru",
"Paraguay": "Paraguai",
"Panama": "Panamá",
"Palestine": "Palestina",
"Pakistan": "Paquistão",
"Norway": "Noruega",
"North Korea": "Coreia do Norte",
"Niger": "Níger",
"Nigeria": "Nigéria",
"Nicaragua": "Nicarágua",
"New Zealand": "Nova Zelândia",
"Nepal": "Nepal",
"Nauru": "Nauru",
"Zambia": "Zâmbia",
"Zimbabwe": "Zimbábue",
"France": "França",
"Egypt": "Egito",
"Ecuador": "Equador",
"Denmark": "Dinamarca",
"Côte dIvoire": "Costa do Marfim",
"Cyprus": "Chipre",
"Cuba": "Cuba",
"Croatia": "Croácia",
"Costa Rica": "Costa Rica",
"Colombia": "Colômbia",
"China": "China",
"Chile": "Chile",
"Chad": "Chade",
"Cape Verde": "Cabo Verde",
"Canada": "Canadá",
"Cameroon": "Camarões",
"Cambodia": "Camboja",
"Burundi": "Burundi",
"Burkina Faso": "Burkina Faso",
"Bulgaria": "Bulgária",
"Brunei": "Brunei",
"British Virgin Islands": "Ilhas Virgens Britânicas",
"British Indian Ocean Territory": "Território Britânico do Oceano Índico",
"Brazil": "Brasil",
"Bouvet Island": "Ilha Bouvet",
"Botswana": "Botsuana",
"Bosnia": "Bósnia e Herzegovina",
"Bolivia": "Bolívia",
"Bhutan": "Butão",
"Bermuda": "Bermudas",
"Benin": "Benim",
"Belize": "Belize",
"Belgium": "Bélgica",
"Belarus": "Bielorrússia",
"Barbados": "Barbados",
"Bangladesh": "Bangladesh",
"Bahrain": "Bahrein",
"Bahamas": "Bahamas",
"Azerbaijan": "Azerbaijão",
"Austria": "Áustria",
"Australia": "Austrália",
"Aruba": "Aruba",
"Armenia": "Armênia",
"Argentina": "Argentina",
"Antigua & Barbuda": "Antígua e Barbuda",
"Antarctica": "Antártica",
"Anguilla": "Anguilla",
"Angola": "Angola",
"Andorra": "Andorra",
"American Samoa": "Samoa Americana",
"Algeria": "Argélia",
"Albania": "Albânia",
"Åland Islands": "Ilhas Aland",
"Afghanistan": "Afeganistão",
"United States": "Estados Unidos",
"United Kingdom": "Reino Unido",
"French Southern Territories": "Territórios Austrais e Antárticos Franceses",
"Congo - Brazzaville": "Congo",
"Czech Republic": "República Tcheca",
"Congo - Kinshasa": "República Democrática do Congo",
"U.S. Virgin Islands": "Ilhas Virgens Americanas",
"Tuvalu": "Tuvalu",
"Turks & Caicos Islands": "Ilhas Turcas e Caicos",
"St. Pierre & Miquelon": "São Pedro e Miquelon",
"Turkmenistan": "Turcomenistão",
"Tokelau": "Tokelau",
"Tajikistan": "Tajiquistão",
"Swaziland": "Suazilândia",
"Svalbard & Jan Mayen": "Svalbard e Jan Mayen",
"St. Vincent & Grenadines": "São Vicente e Granadinas",
"St. Martin": "São Martinho",
"St. Kitts & Nevis": "São Cristóvão e Nevis",
"Seychelles": "Seychelles",
"Netherlands": "Países Baixos",
"Kazakhstan": "Cazaquistão",
"Jersey": "Jersey",
"Heard & McDonald Islands": "Ilha Heard e Ilhas McDonald",
"Dominica": "Dominica",
"Caribbean Netherlands": "Países Baixos Caribenhos",
"South Georgia & South Sandwich Islands": "Ilhas Geórgia do Sul e Sandwich do Sul",
"Sint Maarten": "São Martinho",
"Libya": "Líbia",
"Liberia": "Libéria",
"Lesotho": "Lesoto",
"Lebanon": "Líbano",
"Latvia": "Letônia",
"Laos": "Laos",
"Kyrgyzstan": "Quirguistão",
"Kuwait": "Kuwait",
"Kosovo": "Kosovo",
"Kiribati": "Kiribati",
"Tunisia": "Tunísia",
"Trinidad & Tobago": "Trindade e Tobago",
"Tonga": "Tonga",
"Togo": "Togo",
"Timor-Leste": "Timor-Leste",
"Thailand": "Tailândia",
"Tanzania": "Tanzânia",
"Taiwan": "Taiwan",
"São Tomé & Príncipe": "São Tomé e Príncipe",
"Syria": "Síria",
"Switzerland": "Suíça",
"Sweden": "Suécia",
"Suriname": "Suriname",
"Sudan": "Sudão",
"St. Lucia": "Santa Lúcia",
"St. Helena": "Santa Helena",
"St. Barthélemy": "São Bartolomeu",
"Sri Lanka": "Sri Lanka",
"San Marino": "San Marino",
"Samoa": "Samoa",
"Réunion": "Reunião",
"Rwanda": "Ruanda",
"Qatar": "Catar",
"Pitcairn Islands": "Ilhas Pitcairn",
"Philippines": "Filipinas",
"Montserrat": "Montserrat",
"Macedonia": "Macedônia",
"Papua New Guinea": "Papua-Nova Guiné",
"Palau": "Palau",
"Oman": "Omã",
"Northern Mariana Islands": "Ilhas Marianas do Norte",
"Norfolk Island": "Ilha Norfolk",
"Niue": "Niue",
"New Caledonia": "Nova Caledônia",
"Namibia": "Namíbia",
"Myanmar": "Myanmar",
"Mozambique": "Moçambique",
"Morocco": "Marrocos",
"Montenegro": "Montenegro",
"Mongolia": "Mongólia",
"Monaco": "Mônaco",
"Moldova": "Moldávia",
"Micronesia": "Micronésia",
"Mexico": "México",
"Mayotte": "Mayotte",
"Mauritius": "Maurício",
"Mauritania": "Mauritânia",
"Martinique": "Martinica",
"Marshall Islands": "Ilhas Marshall",
"Malta": "Malta",
"Mali": "Mali",
"Maldives": "Maldivas",
"Malaysia": "Malásia",
"Malawi": "Malawi",
"Madagascar": "Madagascar",
"Macau": "Macau",
"Luxembourg": "Luxemburgo",
"Lithuania": "Lituânia",
"Liechtenstein": "Liechtenstein",
"Kenya": "Quênia",
"Isle of Man": "Ilha de Man",
"Guinea": "Guiné",
"Guernsey": "Guernsey",
"Guatemala": "Guatemala",
"Guam": "Guam",
"Guadeloupe": "Guadalupe",
"Grenada": "Granada",
"Greenland": "Groenlândia",
"Greece": "Grécia",
"Gibraltar": "Gibraltar",
"Ghana": "Gana",
"Germany": "Alemanha",
"Georgia": "Geórgia",
"Gambia": "Gâmbia",
"Gabon": "Gabão",
"French Polynesia": "Polinésia Francesa",
"French Guiana": "Guiana Francesa",
"Finland": "Finlândia",
"Fiji": "Fiji",
"Faroe Islands": "Ilhas Faroé",
"Falkland Islands": "Ilhas Malvinas",
"Ethiopia": "Etiópia",
"Estonia": "Estônia",
"Eritrea": "Eritreia",
"Equatorial Guinea": "Guiné Equatorial",
"El Salvador": "El Salvador",
"Dominican Republic": "República Dominicana",
"Djibouti": "Djibouti",
"Curaçao": "Curaçao",
"Cook Islands": "Ilhas Cook",
"Cocos (Keeling) Islands": "Ilhas Cocos (Keeling)",
"Christmas Island": "Ilha Christmas",
"Central African Republic": "República Centro-Africana",
"Cayman Islands": "Ilhas Cayman",
"%(creator)s created this DM.": "%(creator)s criou esta conversa.",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "As mensagens nesta sala são criptografadas de ponta a ponta. Quando as pessoas entrarem na conversa, você poderá confirmá-las em seus perfis. Basta clicar em suas fotos de perfil.",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "As mensagens aqui são criptografadas de ponta a ponta. Confirme o perfil de %(displayName)s - clique em sua foto de perfil.",
"This is the start of <roomName/>.": "Este é o início de <roomName/>.",
"Add a photo, so people can easily spot your room.": "Adicione uma imagem para que as pessoas possam identificar facilmente sua sala.",
"%(displayName)s created this room.": "%(displayName)s criou esta sala.",
"You created this room.": "Você criou esta sala.",
"<a>Add a topic</a> to help people know what it is about.": "<a>Adicione uma descrição</a> para ajudar as pessoas a saber do que se trata essa conversa.",
"Topic: %(topic)s ": "Descrição: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "Descrição: %(topic)s (<a>editar</a>)",
"This is the beginning of your direct message history with <displayName/>.": "Este é o início do seu histórico da conversa com <displayName/>.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Apenas vocês dois estão nesta conversa, a menos que algum de vocês convide mais alguém.",
"Call Paused": "Chamada em pausa",
"Takes the call in the current room off hold": "Retoma a chamada na sala atual",
"Places the call in the current room on hold": "Pausa a chamada na sala atual",
"Yemen": "Iêmen",
"Western Sahara": "Saara Ocidental",
"Wallis & Futuna": "Wallis e Futuna",
"Vatican City": "Cidade do Vaticano",
"Vanuatu": "Vanuatu",
"Uzbekistan": "Uzbequistão",
"Role": "Função",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|one": "Armazene localmente com segurança as mensagens criptografadas para que apareçam nos resultados da pesquisa, usando %(size)s para armazenar mensagens de %(count)s sala.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|other": "Armazene localmente com segurança as mensagens criptografadas para que apareçam nos resultados da pesquisa, usando %(size)s para armazenar mensagens de %(count)s salas."
} }

View file

@ -20,5 +20,10 @@
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Potrdite dodajanje te telefonske številke z enkratno prijavo, da dokažete svojo identiteto.", "Confirm adding this phone number by using Single Sign On to prove your identity.": "Potrdite dodajanje te telefonske številke z enkratno prijavo, da dokažete svojo identiteto.",
"Confirm adding phone number": "Potrdi dodajanje telefonske številke", "Confirm adding phone number": "Potrdi dodajanje telefonske številke",
"Click the button below to confirm adding this phone number.": "Pritisnite gumb spodaj da potrdite dodajanje te telefonske številke.", "Click the button below to confirm adding this phone number.": "Pritisnite gumb spodaj da potrdite dodajanje te telefonske številke.",
"Add Phone Number": "Dodaj telefonsko številko" "Add Phone Number": "Dodaj telefonsko številko",
"Analytics": "Analitika",
"Call Declined": "Klic zavrnjen",
"Call Failed": "Klic ni uspel",
"Your homeserver's URL": "URL domačega strežnika",
"End": "Konec"
} }

View file

@ -2556,5 +2556,283 @@
"Please go into as much detail as you like, so we can track down the problem.": "Ju lutemi, shkoni aq thellë sa doni, që të mund të ndjekim problemin.", "Please go into as much detail as you like, so we can track down the problem.": "Ju lutemi, shkoni aq thellë sa doni, që të mund të ndjekim problemin.",
"Tell us below how you feel about %(brand)s so far.": "Tregonani më poshtë se si ndiheni rreth %(brand)s deri këtu.", "Tell us below how you feel about %(brand)s so far.": "Tregonani më poshtë se si ndiheni rreth %(brand)s deri këtu.",
"Rate %(brand)s": "Vlerësojeni %(brand)s", "Rate %(brand)s": "Vlerësojeni %(brand)s",
"Feedback sent": "Përshtypjet u dërguan" "Feedback sent": "Përshtypjet u dërguan",
"Now, let's help you get started": "Tani, le tju ndihmojmë për tia filluar",
"Welcome %(name)s": "Mirë se vini %(name)s",
"Add a photo so people know it's you.": "Shtoni një foto, që njerëzit ta dinë se jeni ju.",
"Great, that'll help people know it's you": "Bukur, kjo do ti ndihmojë njerëzit ta dinë se jeni ju",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Ftoni dikë duke përdorur emrin e tij, adresën email, emrin e përdoruesit (bie fjala, <userId/>) ose <a>ndani me të këtë dhomë</a>.",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Nisni një bisedë me dikë duke përdorur emrin e tij, adresën email ose emrin e përdoruesit (bie fjala, <userId/>).",
"Invite by email": "Ftojeni me email",
"Use the + to make a new room or explore existing ones below": "Përdorni + për të krijuar një dhomë të re ose eksploroni ato ekzistuese më poshtë",
"%(senderName)s ended the call": "%(senderName)s e përfundoi thirrjen",
"You ended the call": "E përfunduat thirrjen",
"New version of %(brand)s is available": "Ka gati një version të ri të %(brand)s",
"Update %(brand)s": "Përditësoni %(brand)s",
"Enable desktop notifications": "Aktivizoni njoftime desktopi",
"Don't miss a reply": "Mos humbni asnjë përgjigje",
"Paraguay": "Paraguai",
"Guyana": "Guajanë",
"Central African Republic": "Republika e Afrikës Qendrore",
"Nauru": "Nauru",
"Belarus": "Bjellorusi",
"Kyrgyzstan": "Kirgizstan",
"Macedonia": "Maqedoni",
"North Korea": "Kore e Veriut",
"Eritrea": "Eritre",
"Congo - Kinshasa": "Kongo-Kinshasa",
"Panama": "Panama",
"Spain": "Spanjë",
"Liberia": "Liberi",
"Mozambique": "Mozambik",
"Zimbabwe": "Zimbabve",
"China": "Kinë",
"United Kingdom": "Mbretëria e Bashkuar",
"Ethiopia": "Etiopi",
"Swaziland": "Svaziland",
"Marshall Islands": "Ishujt Marshall",
"Haiti": "Haiti",
"Slovakia": "Sllovaki",
"Equatorial Guinea": "Guinea Ekuatoriale",
"Anguilla": "Anguila",
"%(creator)s created this DM.": "%(creator)s krijoi këtë DM.",
"Peru": "Peru",
"Seychelles": "Sejshelle",
"St. Lucia": "Shën-Luçia",
"Solomon Islands": "Ishujt Solomon",
"Micronesia": "Mikronezi",
"Wallis & Futuna": "Uallis & Futuna",
"United States": "Shtetet e Bashkuara",
"Philippines": "Filipine",
"New Zealand": "Zelandë e Re",
"St. Vincent & Grenadines": "Shën Vincent dhe Grenadine",
"Afghanistan": "Afganistan",
"Benin": "Benin",
"Cook Islands": "Ishujt Kuk",
"Bahamas": "Bahamas",
"Yemen": "Jemen",
"Curaçao": "Kurasëo",
"Guam": "Guam",
"Albania": "Shqipëri",
"Tajikistan": "Taxhikistan",
"Moldova": "Moldavi",
"Gambia": "Gambia",
"Nicaragua": "Nikaragua",
"Lebanon": "Liban",
"Armenia": "Armeni",
"%(displayName)s created this room.": "%(displayName)s krijoi këtë dhomë.",
"Romania": "Rumani",
"Kazakhstan": "Kazakistan",
"St. Barthélemy": "Shën Bartolome",
"Sierra Leone": "Sierra Leone",
"Kuwait": "Kuvajt",
"Vanuatu": "Vanuatu",
"Gibraltar": "Gjibraltar",
"Trinidad & Tobago": "Trinidad e Tobago",
"Uruguay": "Uruguaj",
"Croatia": "Kroaci",
"Cocos (Keeling) Islands": "Ishujt Kokos (Kiling)",
"Norfolk Island": "Ishujt Norfolk",
"Somalia": "Somali",
"British Virgin Islands": "Ishujt e Virgjër Britanikë",
"Azerbaijan": "Azerbajxhan",
"Tokelau": "Tokelau",
"Slovenia": "Slloveni",
"Malaysia": "Malajzi",
"Guinea": "Guine",
"Ecuador": "Ekuador",
"St. Kitts & Nevis": "Shën Kits dhe Nevis",
"Vietnam": "Vietnam",
"Nepal": "Nepal",
"Colombia": "Kolumbi",
"Kenya": "Kenia",
"Madagascar": "Madagaskar",
"Italy": "Itali",
"Taiwan": "Taivan",
"Jersey": "Xhërsi",
"Rwanda": "Ruandë",
"Martinique": "Martinikë",
"Denmark": "Danimarkë",
"Bahrain": "Bahrein",
"Places the call in the current room on hold": "E kalon në pritje thirrjen në dhomën aktuale",
"Finland": "Finlandë",
"Papua New Guinea": "Papua Guinea e Re",
"Botswana": "Botsvanë",
"Egypt": "Egjipt",
"Norway": "Norvegji",
"Netherlands": "Hollandë",
"Russia": "Rusi",
"Topic: %(topic)s ": "Temë: %(topic)s ",
"Vatican City": "Vatikan",
"Caribbean Netherlands": "Karaibet Holandeze",
"Tonga": "Tonga",
"Christmas Island": "Ishulli i Krishtlindjeve",
"Poland": "Poloni",
"Tuvalu": "Tuvalu",
"Senegal": "Senegal",
"France": "Francë",
"Niger": "Niger",
"Sint Maarten": "Shën Martin",
"You created this room.": "Krijuat këtë dhomë.",
"Iran": "Iran",
"Burkina Faso": "Burkina Faso",
"Palau": "Palau",
"Nigeria": "Nigeri",
"Chile": "Kili",
"French Southern Territories": "Territoret Frënge Jugore",
"India": "Indi",
"Heard & McDonald Islands": "Ishulli Hërd dhe Ishujt Mekdonald",
"Barbados": "Barbados",
"Réunion": "Reunion",
"Sudan": "Sudan",
"Malta": "Maltë",
"Guernsey": "Gërnsi",
"Brazil": "Brazil",
"Qatar": "Katar",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "Mesazhet në këtë dhomë fshehtëzohen skaj-më-skaj. Kur njerëzit hyjnë, mund ti verifikoni te profili i tyre, thjesht prekni mbi avatarin përkatës.",
"Comoros": "Komore",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Në këtë bisedë jeni vetëm ju të dy, veç nëse cilido qoftë prej jush ftoi dikë tjetër të vijë.",
"Guinea-Bissau": "Guinea-Bisau",
"Dominican Republic": "Republika Dominikane",
"Georgia": "Xhorxhia",
"Faroe Islands": "Ishujt Faroe",
"Guadeloupe": "Guadalupë",
"Czech Republic": "Republika Çeke",
"Topic: %(topic)s (<a>edit</a>)": "Temë: %(topic)s (<a>përpunojeni</a>)",
"Bulgaria": "Bullgari",
"Add a photo, so people can easily spot your room.": "Shtoni një foto, që njerëzit ta dallojnë kollaj dhomën tuaj.",
"El Salvador": "Salvador",
"Zambia": "Zambia",
"Cayman Islands": "Ishujt Kajman",
"Congo - Brazzaville": "Kongo-Brazavil",
"This is the beginning of your direct message history with <displayName/>.": "Ky është fillimi i historikut të mesazheve tuaja të drejtpërdrejta me <displayName/>.",
"Singapore": "Singapor",
"Costa Rica": "Kosta Rika",
"Ghana": "Ganë",
"Call Paused": "Thirrja u Ndal",
"Mayotte": "Majot",
"Cape Verde": "Kepi i Gjelbërt",
"Belize": "Belize",
"Jamaica": "Xhamajkë",
"Indonesia": "Indonezi",
"Mexico": "Meksikë",
"Monaco": "Monako",
"Cuba": "Kubë",
"Uganda": "Ugandë",
"Latvia": "Letoni",
"Namibia": "Namibi",
"Greenland": "Groenlandë",
"Syria": "Siri",
"Svalbard & Jan Mayen": "Svalbard & Jan-Majen",
"Turkmenistan": "Turkmenistan",
"Lesotho": "Lesoto",
"Australia": "Australi",
"Serbia": "Serbi",
"Cameroon": "Kamerun",
"Ireland": "Irlandë",
"Guatemala": "Guatemalë",
"Fiji": "Fixhi",
"Libya": "Libi",
"Tanzania": "Tanzani",
"Lithuania": "Lituani",
"This is the start of <roomName/>.": "Ky është fillimi i <roomName/>.",
"Antarctica": "Antarktidë",
"Germany": "Gjermani",
"<a>Add a topic</a> to help people know what it is about.": "<a>Shtoni një temë</a>, për ti ndihmuar njerëzit se përse bëhet fjalë.",
"Switzerland": "Zvicër",
"Maldives": "Maldive",
"Bhutan": "Butan",
"Luxembourg": "Luksemburg",
"St. Martin": "Shën-Martin",
"Cyprus": "Qipro",
"Niue": "Niue",
"Iraq": "Irak",
"Bermuda": "Bermuda",
"Takes the call in the current room off hold": "E heq nga pritja thirrjen në dhomën aktuale",
"French Polynesia": "Polinezia Frënge",
"Mauritius": "Mauricius",
"Grenada": "Grenadë",
"Portugal": "Portugali",
"Burundi": "Burundi",
"St. Pierre & Miquelon": "Shën Pier dhe Mikelon",
"South Africa": "Afrikë e Jugut",
"Morocco": "Marok",
"Malawi": "Malaui",
"Côte dIvoire": "Bregu i Fildishtë",
"Kosovo": "Kosovë",
"Thailand": "Tailandë",
"Macau": "Makau",
"Montenegro": "Mal i Zi",
"Angola": "Angolë",
"Northern Mariana Islands": "Ishujt Veriorë Mariana",
"Honduras": "Honduras",
"Japan": "Japoni",
"American Samoa": "Samoa Amerikane",
"South Georgia & South Sandwich Islands": "Xhorxhia Jugore dhe Ishujt Snduiç të Jugut",
"Palestine": "Palestinë",
"Austria": "Austri",
"Suriname": "Surinam",
"Kiribati": "Kiribati",
"Iceland": "Islandë",
"St. Helena": "Shën Helenë",
"Sri Lanka": "Sri Lanka",
"Myanmar": "Mianmar",
"Oman": "Oman",
"Western Sahara": "Sahara Perëndimore",
"Bouvet Island": "Ishulli Bouve",
"Bolivia": "Bolivi",
"Israel": "Izrael",
"Timor-Leste": "Timori Lindor",
"Belgium": "Belgjikë",
"Ukraine": "Ukrainë",
"Turks & Caicos Islands": "Ishujt Turks & Kaikos",
"Montserrat": "Monserrat",
"Samoa": "Samoa",
"United Arab Emirates": "Emiratet e Bashkuara Arabe",
"British Indian Ocean Territory": "Territoret Britanike të Oqeanit Indian",
"Pakistan": "Pakistan",
"South Korea": "Kore e Jugut",
"Jordan": "Jordani",
"Puerto Rico": "Porto Riko",
"Turkey": "Turqi",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Mesazhet këtu fshehtëzohen skaj-më-skaj. Verifikoni %(displayName)s te profili përkatës - prekni mbi avatarin përkatës.",
"Antigua & Barbuda": "Antigua e Barbuda",
"French Guiana": "Guajana Frënge",
"Hong Kong": "Hong Kong",
"Mongolia": "Mongoli",
"Canada": "Kanada",
"Greece": "Greqi",
"Tunisia": "Tunizi",
"Liechtenstein": "Lihtenshtein",
"Algeria": "Algjeri",
"Åland Islands": "Ishujt Aland",
"Mali": "Mali",
"Pitcairn Islands": "Ishujt Pitkern",
"Andorra": "Andorrë",
"Hungary": "Hungari",
"Bosnia": "Bosnjë-Hercegovinë",
"Argentina": "Argjentinë",
"Togo": "Togo",
"Djibouti": "Xhibut",
"Aruba": "Aruba",
"Chad": "Çad",
"Estonia": "Estoni",
"Laos": "Laos",
"São Tomé & Príncipe": "Sao-Tome e Prinsipe",
"San Marino": "San Marino",
"Cambodia": "Kamboxhia",
"Uzbekistan": "Uzbekistan",
"Gabon": "Gabon",
"Brunei": "Brunei",
"South Sudan": "Sudan i Jugut",
"Venezuela": "Venezuelë",
"New Caledonia": "Kaledoni e Re",
"Saudi Arabia": "Arabi Saudite",
"Isle of Man": "Ishulli Man",
"Dominica": "Dominikë",
"U.S. Virgin Islands": "Ishujt e Virgjër Amerikanë",
"Mauritania": "Mauritani",
"Bangladesh": "Bangladesh",
"Falkland Islands": "Ishujt Falkland",
"Sweden": "Suedi"
} }

View file

@ -2493,5 +2493,286 @@
"Please go into as much detail as you like, so we can track down the problem.": "Vänligen gå in i hur mycket detalj du vill, så att vi kan hitta problemet.", "Please go into as much detail as you like, so we can track down the problem.": "Vänligen gå in i hur mycket detalj du vill, så att vi kan hitta problemet.",
"Tell us below how you feel about %(brand)s so far.": "Berätta för oss vad du tycker om %(brand)s än så länge.", "Tell us below how you feel about %(brand)s so far.": "Berätta för oss vad du tycker om %(brand)s än så länge.",
"Rate %(brand)s": "Betygsätt %(brand)s", "Rate %(brand)s": "Betygsätt %(brand)s",
"Feedback sent": "Återkoppling skickad" "Feedback sent": "Återkoppling skickad",
"Canada": "Kanada",
"Cameroon": "Kamerun",
"Cambodia": "Kambodja",
"Burundi": "Burundi",
"Burkina Faso": "Burkina Faso",
"Bulgaria": "Bulgarien",
"Brunei": "Brunei",
"British Virgin Islands": "Brittiska Jungfruöarna",
"British Indian Ocean Territory": "Brittiska territoriet i Indiska oceanen",
"Brazil": "Brasilien",
"Bouvet Island": "Bouvetön",
"Botswana": "Botswana",
"Bosnia": "Bosnien",
"Bolivia": "Bolivia",
"Bhutan": "Bhutan",
"Bermuda": "Bermuda",
"Benin": "Benin",
"Belize": "Belize",
"Belgium": "Belgien",
"Belarus": "Belarus",
"Barbados": "Barbados",
"Bangladesh": "Bangladesh",
"Bahrain": "Bahrain",
"Bahamas": "Bahamas",
"Azerbaijan": "Azerbajdzjan",
"Austria": "Österrike",
"Australia": "Australien",
"Aruba": "Aruba",
"Armenia": "Armenien",
"Argentina": "Argentina",
"Antigua & Barbuda": "Antigua och Barbuda",
"United Kingdom": "Förenade kungadömet",
"Antarctica": "Antarktis",
"Anguilla": "Anguilla",
"Angola": "Angola",
"Andorra": "Andorra",
"American Samoa": "Amerikanska Samoa",
"Algeria": "Algeriet",
"Albania": "Albanien",
"Åland Islands": "Åland",
"Afghanistan": "Afghanistan",
"United States": "USA",
"%(creator)s created this DM.": "%(creator)s skapade den här DM:en.",
"Now, let's help you get started": "Låt oss hjälpa dig komma igång",
"Welcome %(name)s": "Välkommen %(name)s",
"Add a photo so people know it's you.": "Lägg till en bild för att folk ska veta att det är du.",
"Great, that'll help people know it's you": "Fantastiskt, det kommer att hjälpa folk att veta att det är du",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "Bjud in någon med deras namn, e-postadress eller användarnamn (som <userId/>) eller <a>dela det här rummet</a>.",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Starta en konversation med någon med deras namn, e-postadress eller användarnamn (som <userId/>).",
"Invite by email": "Bjud in via e-post",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "Meddelanden i det här rummet är totalsträckskrypterade. När personer går med så kan du verifiera dem i deras profil, bara klicka på deras avatar.",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Meddelanden här är totalsträckskrypterade. Verifiera %(displayName)s i deras profil - klicka på deras avatar.",
"Role": "Roll",
"Use the + to make a new room or explore existing ones below": "Använd + för att skapa ett nytt rum eller utforska existerande nedan",
"This is the start of <roomName/>.": "Det här är början på <roomName/>.",
"Add a photo, so people can easily spot your room.": "Lägg till en bild, så att folk lätt kan se ditt rum.",
"%(displayName)s created this room.": "%(displayName)s skapade det här rummet.",
"You created this room.": "Du skapade det här rummet.",
"<a>Add a topic</a> to help people know what it is about.": "<a>Lägg till ett ämne</a> för att låta folk veta vad det handlar om.",
"Topic: %(topic)s ": "Ämne: %(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "Ämne: %(topic)s (<a>redigera</a>)",
"This is the beginning of your direct message history with <displayName/>.": "Det här är början på din direktmeddelandehistorik med <displayName/>.",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "Bara ni två är i den här konversationen, om inte någon av er bjuder in någon annan.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|one": "Cacha säkert krypterade meddelande lokalt för att de ska visas i sökresultat, och använd %(size)s för att lagra meddelanden från %(count)s rum.",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|other": "Cacha säkert krypterade meddelande lokalt för att de ska visas i sökresultat, och använd %(size)s för att lagra meddelanden från %(count)s rum.",
"Call Paused": "Samtal pausat",
"%(senderName)s ended the call": "%(senderName)s avslutade samtalet",
"You ended the call": "Du avslutade samtalet",
"New version of %(brand)s is available": "Ny version av %(brand)s är tillgänglig",
"Update %(brand)s": "Uppdatera %(brand)s",
"Enable desktop notifications": "Aktivera skrivbordsaviseringar",
"Don't miss a reply": "Missa inte ett svar",
"Takes the call in the current room off hold": "Avslutar parkering av samtalet i det nuvarande samtalet",
"Places the call in the current room on hold": "Parkerar samtalet i det aktuella rummet",
"Zimbabwe": "Zimbabwe",
"Zambia": "Zambia",
"Yemen": "Jemen",
"Western Sahara": "Västsahara",
"Wallis & Futuna": "Wallis- och Futunaöarna",
"Vietnam": "Vietnam",
"Venezuela": "Venezuela",
"Vatican City": "Vatikanstaten",
"Vanuatu": "Vanuatu",
"Uzbekistan": "Uzbekistan",
"Uruguay": "Uruguay",
"United Arab Emirates": "Förenade Arabemiraten",
"Ukraine": "Ukraina",
"Uganda": "Uganda",
"U.S. Virgin Islands": "Amerikanska Jungfruöarna",
"Tuvalu": "Tuvalu",
"Turks & Caicos Islands": "Turks- och Caicosöarna",
"Turkmenistan": "Turkmenistan",
"Turkey": "Turkiet",
"Tunisia": "Tunisien",
"Trinidad & Tobago": "Trinidad och Tobago",
"Tonga": "Tonga",
"Tokelau": "Tokelau",
"Togo": "Togo",
"Timor-Leste": "Östtimor",
"Thailand": "Thailand",
"Tanzania": "Tanzania",
"Tajikistan": "Tadzjikistan",
"Taiwan": "Taiwan",
"São Tomé & Príncipe": "São Tomé och Príncipe",
"Syria": "Syrien",
"Switzerland": "Schweiz",
"Sweden": "Sverige",
"Swaziland": "Swaziland",
"Svalbard & Jan Mayen": "Svalbard och Jan Mayen",
"Suriname": "Surinam",
"Sudan": "Sudan",
"St. Vincent & Grenadines": "Saint Vincent och Grenadinerna",
"St. Pierre & Miquelon": "Saint-Pierre och Miquelon",
"St. Martin": "Saint Martin",
"St. Lucia": "Saint Lucia",
"St. Kitts & Nevis": "Saint Kitts och Nevis",
"St. Helena": "Sankta Helena",
"St. Barthélemy": "Saint-Barthélemy",
"Sri Lanka": "Sri Lanka",
"Spain": "Spanien",
"South Sudan": "Sydsudan",
"South Korea": "Sydkorea",
"South Georgia & South Sandwich Islands": "Sydgeorgien och Sydsandwichöarna",
"South Africa": "Sydafrika",
"Somalia": "Somalia",
"Solomon Islands": "Salomonöarna",
"Slovenia": "Slovenien",
"Slovakia": "Slovakien",
"Sint Maarten": "Sint Maarten",
"Singapore": "Singapore",
"Sierra Leone": "Sierra Leone",
"Seychelles": "Seychellerna",
"Serbia": "Serbien",
"Senegal": "Senegal",
"Saudi Arabia": "Saudiarabien",
"San Marino": "San Marino",
"Samoa": "Samoa",
"Réunion": "Réunion",
"Rwanda": "Rwanda",
"Russia": "Ryssland",
"Romania": "Rumänien",
"Qatar": "Qatar",
"Puerto Rico": "Puerto Rico",
"Portugal": "Portugal",
"Poland": "Polen",
"Pitcairn Islands": "Pitcairnöarna",
"Philippines": "Filippinerna",
"Peru": "Peru",
"Paraguay": "Paraguay",
"Papua New Guinea": "Papua Nya Guinea",
"Panama": "Panama",
"Palestine": "Palestina",
"Palau": "Palau",
"Pakistan": "Pakistan",
"Oman": "Oman",
"Norway": "Norge",
"Northern Mariana Islands": "Nordmarianerna",
"North Korea": "Nordkorea",
"Norfolk Island": "Norfolkön",
"Niue": "Niue",
"Nigeria": "Nigeria",
"Niger": "Niger",
"Nicaragua": "Nicaragua",
"New Zealand": "Nya Zeeland",
"New Caledonia": "Nya Kaledonien",
"Netherlands": "Nederländerna",
"Nepal": "Nepal",
"Nauru": "Nauru",
"Namibia": "Namibia",
"Myanmar": "Myanmar",
"Mozambique": "Moçambique",
"Morocco": "Marocko",
"Montserrat": "Montserrat",
"Montenegro": "Montenegro",
"Mongolia": "Mongoliet",
"Monaco": "Monaco",
"Moldova": "Moldavien",
"Micronesia": "Mikronesien",
"Mexico": "Mexiko",
"Mayotte": "Mayotte",
"Mauritius": "Mauritius",
"Mauritania": "Mauretanien",
"Martinique": "Martinique",
"Marshall Islands": "Marshallöarna",
"Malta": "Malta",
"Mali": "Mali",
"Maldives": "Maldivierna",
"Malaysia": "Malaysia",
"Malawi": "Malawi",
"Madagascar": "Madagaskar",
"Macedonia": "Nordmakedonien",
"Macau": "Macao",
"Luxembourg": "Luxemburg",
"Lithuania": "Litauen",
"Liechtenstein": "Liechtenstein",
"Libya": "Libyen",
"Liberia": "Liberia",
"Lesotho": "Lesotho",
"Lebanon": "Libanon",
"Latvia": "Lettland",
"Laos": "Laos",
"Kyrgyzstan": "Kirgizistan",
"Kuwait": "Kuwait",
"Kosovo": "Kosovo",
"Kiribati": "Kiribati",
"Kenya": "Kenya",
"Kazakhstan": "Kazakstan",
"Jordan": "Jordanien",
"Jersey": "Jersey",
"Japan": "Japan",
"Jamaica": "Jamaica",
"Italy": "Italien",
"Israel": "Israel",
"Isle of Man": "Isle of Man",
"Ireland": "Irland",
"Iraq": "Irak",
"Iran": "Iran",
"Indonesia": "Indonesien",
"India": "Indien",
"Iceland": "Island",
"Hungary": "Ungern",
"Hong Kong": "Hongkong",
"Honduras": "Honduras",
"Heard & McDonald Islands": "Heard- och McDonaldöarna",
"Haiti": "Haiti",
"Guyana": "Guyana",
"Guinea-Bissau": "Guinea-Bissau",
"Guinea": "Guinea",
"Guernsey": "Guernsey",
"Guatemala": "Guatemala",
"Guam": "Guam",
"Guadeloupe": "Guadeloupe",
"Grenada": "Grenada",
"Greenland": "Grönland",
"Greece": "Grekland",
"Gibraltar": "Gibraltar",
"Ghana": "Ghana",
"Germany": "Tyskland",
"Georgia": "Georgien",
"Gambia": "Gambia",
"Gabon": "Gabon",
"French Southern Territories": "Franska sydterritorierna",
"French Polynesia": "Franska Polynesien",
"French Guiana": "Franska Guinea",
"France": "Frankrike",
"Finland": "Finland",
"Fiji": "Fiji",
"Faroe Islands": "Färöarna",
"Falkland Islands": "Falklandsöarna",
"Ethiopia": "Etiopien",
"Estonia": "Estland",
"Eritrea": "Eritrea",
"Equatorial Guinea": "Ekvatorialguinea",
"El Salvador": "El Salvador",
"Egypt": "Egypten",
"Ecuador": "Ecuador",
"Dominican Republic": "Dominikanska republiken",
"Dominica": "Dominica",
"Djibouti": "Djibouti",
"Denmark": "Danmark",
"Côte dIvoire": "Elfenbenskusten",
"Czech Republic": "Tjeckien",
"Cyprus": "Cypern",
"Curaçao": "Curaçao",
"Cuba": "Kuba",
"Croatia": "Kroatien",
"Costa Rica": "Costa Rica",
"Cook Islands": "Cooköarna",
"Congo - Kinshasa": "Kongo-Kinshasa",
"Congo - Brazzaville": "Kongo-Brazzaville",
"Comoros": "Komorerna",
"Colombia": "Colombia",
"Cocos (Keeling) Islands": "Kokosöarna",
"Christmas Island": "Julön",
"China": "Kina",
"Chile": "Chile",
"Chad": "Tchad",
"Central African Republic": "Centralafrikanska republiken",
"Cayman Islands": "Caymanöarna",
"Caribbean Netherlands": "Karibiska Nederländerna",
"Cape Verde": "Kap Verde"
} }

View file

@ -584,7 +584,7 @@
"Please enter the code it contains:": "请输入其包含的代码:", "Please enter the code it contains:": "请输入其包含的代码:",
"Matrix ID": "Matrix ID", "Matrix ID": "Matrix ID",
"Matrix Room ID": "Matrix 聊天室 ID", "Matrix Room ID": "Matrix 聊天室 ID",
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>社区页面的 HTML 代码</h1>\n<p>\n 你可以给社区的新成员们写些长长的社区简介来引导他们,或者放置\n 一些重要的<a href=\"foo\">链接</a>\n</p>\n<p>\n 你甚至可以使用 <img> 标签\n</p>\n", "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "",
"Add rooms to the community summary": "将聊天室添加到社区简介中", "Add rooms to the community summary": "将聊天室添加到社区简介中",
"Which rooms would you like to add to this summary?": "您想要将哪个聊天室添加到社区简介?", "Which rooms would you like to add to this summary?": "您想要将哪个聊天室添加到社区简介?",
"Add to summary": "添加到简介", "Add to summary": "添加到简介",
@ -819,7 +819,7 @@
"Link to selected message": "选中消息的链接", "Link to selected message": "选中消息的链接",
"Changes made to your community <bold1>name</bold1> and <bold2>avatar</bold2> might not be seen by other users for up to 30 minutes.": "至多半个小时内,其他用户可能看不到您社区的 <bold1>名称</bold1> 与 <bold2>头像</bold2> 的变化。", "Changes made to your community <bold1>name</bold1> and <bold2>avatar</bold2> might not be seen by other users for up to 30 minutes.": "至多半个小时内,其他用户可能看不到您社区的 <bold1>名称</bold1> 与 <bold2>头像</bold2> 的变化。",
"These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "这些聊天室对社区成员可见。社区成员可通过点击来加入它们。", "These rooms are displayed to community members on the community page. Community members can join the rooms by clicking on them.": "这些聊天室对社区成员可见。社区成员可通过点击来加入它们。",
"Your community hasn't got a Long Description, a HTML page to show to community members.<br />Click here to open settings and give it one!": "您的社区还没有详细介绍,一个展示给社区成员的 HTML 页面。<br>点击这里即可打开设置添加详细介绍!", "Your community hasn't got a Long Description, a HTML page to show to community members.<br />Click here to open settings and give it one!": "你的社区没有一个很长的描述一个HTML页面可以展示给社区成员。<br />点击这里即可打开设置添加详细介绍!",
"Failed to load %(groupId)s": "%(groupId)s 加载失败", "Failed to load %(groupId)s": "%(groupId)s 加载失败",
"This room is not public. You will not be able to rejoin without an invite.": "此聊天室不是公开聊天室。如果没有成员邀请,您将无法重新加入。", "This room is not public. You will not be able to rejoin without an invite.": "此聊天室不是公开聊天室。如果没有成员邀请,您将无法重新加入。",
"Can't leave Server Notices room": "无法退出服务器公告聊天室", "Can't leave Server Notices room": "无法退出服务器公告聊天室",
@ -1124,7 +1124,7 @@
"Go back": "返回", "Go back": "返回",
"Room Settings - %(roomName)s": "聊天室设置 - %(roomName)s", "Room Settings - %(roomName)s": "聊天室设置 - %(roomName)s",
"A username can only contain lower case letters, numbers and '=_-./'": "用户名只能包含小写字母、数字和 '=_-./'", "A username can only contain lower case letters, numbers and '=_-./'": "用户名只能包含小写字母、数字和 '=_-./'",
"Failed to decrypt %(failedCount)s sessions!": "%(failedCount)s 会话解密失败", "Failed to decrypt %(failedCount)s sessions!": "%(failedCount)s 会话解密失败",
"<b>Warning</b>: you should only set up key backup from a trusted computer.": "<b>警告</b>:您应该只在受信任的电脑上设置密钥备份。", "<b>Warning</b>: you should only set up key backup from a trusted computer.": "<b>警告</b>:您应该只在受信任的电脑上设置密钥备份。",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "通过输入恢复密码来访问您的安全消息历史记录和设置安全通信。", "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "通过输入恢复密码来访问您的安全消息历史记录和设置安全通信。",
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "如果忘记了恢复密码,您可以 <button1>使用恢复密钥</button1> 或者 <button2>设置新的恢复选项</button2>", "If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "如果忘记了恢复密码,您可以 <button1>使用恢复密钥</button1> 或者 <button2>设置新的恢复选项</button2>",
@ -1530,9 +1530,9 @@
"Backup has a <validity>valid</validity> signature from this session": "备份有来自此会话的<validity>有效</validity>签名", "Backup has a <validity>valid</validity> signature from this session": "备份有来自此会话的<validity>有效</validity>签名",
"Backup has an <validity>invalid</validity> signature from this session": "备份有来自此会话的<validity>无效</validity>签名", "Backup has an <validity>invalid</validity> signature from this session": "备份有来自此会话的<validity>无效</validity>签名",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> session <device></device>": "备份有一个<validity>有效的签名</validity>,它来自<verify>已验证</verify>的会话<device></device>", "Backup has a <validity>valid</validity> signature from <verify>verified</verify> session <device></device>": "备份有一个<validity>有效的签名</validity>,它来自<verify>已验证</verify>的会话<device></device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> session <device></device>": "备份有一个<validity>有效的</validity>签名,它来自<verify>未验证的</verify>会话<device>\n</device>", "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> session <device></device>": "备份有一个<validity>有效的</validity>签名,它来自<verify>未验证的</verify>会话<device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> session <device></device>": "备份有一个<validity>无效的</validity>签名,它来自<verify>已验证的</verify>会话<device>\n</device>", "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> session <device></device>": "备份有一个<validity>无效的</validity>签名,它来自<verify>已验证的</verify>会话<device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> session <device></device>": "备份有一个<validity>无效的</validity>签名,它来自<verify>未验证的</verify>会话<device>\n</device>", "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> session <device></device>": "备份有一个<validity>无效的</validity>签名,它来自<verify>未验证的</verify>会话<device></device>",
"Backup is not signed by any of your sessions": "备份没有被您的任何一个会话签名", "Backup is not signed by any of your sessions": "备份没有被您的任何一个会话签名",
"This backup is trusted because it has been restored on this session": "此备份是受信任的因为它被恢复到了此会话上", "This backup is trusted because it has been restored on this session": "此备份是受信任的因为它被恢复到了此会话上",
"Backup key stored: ": "存储的备份密钥: ", "Backup key stored: ": "存储的备份密钥: ",
@ -1553,7 +1553,7 @@
"Disconnect identity server": "断开身份服务器连接", "Disconnect identity server": "断开身份服务器连接",
"Disconnect from the identity server <idserver />?": "从身份服务器 <idserver /> 断开连接吗?", "Disconnect from the identity server <idserver />?": "从身份服务器 <idserver /> 断开连接吗?",
"Disconnect": "断开连接", "Disconnect": "断开连接",
"You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.": "断开连接前,你应当<b>删除你的个人信息</b>从身份服务器<idserver />。\n不幸的是,身份服务器<idserver />当前处于离线状态或无法访问。", "You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.": "断开连接前,你应当<b>删除你的个人信息</b>从身份服务器<idserver />。不幸的是,身份服务器<idserver />当前处于离线状态或无法访问。",
"You should:": "您应该:", "You should:": "您应该:",
"contact the administrators of identity server <idserver />": "联系身份服务器 <idserver /> 的管理员", "contact the administrators of identity server <idserver />": "联系身份服务器 <idserver /> 的管理员",
"wait and try again later": "等待并稍后重试", "wait and try again later": "等待并稍后重试",
@ -2287,7 +2287,7 @@
"Alt": "Alt", "Alt": "Alt",
"Alt Gr": "Alt Gr", "Alt Gr": "Alt Gr",
"Shift": "Shift", "Shift": "Shift",
"Super": "", "Super": "超级",
"Ctrl": "Ctrl", "Ctrl": "Ctrl",
"New line": "换行", "New line": "换行",
"Jump to start/end of the composer": "跳转到编辑器的开始/结束", "Jump to start/end of the composer": "跳转到编辑器的开始/结束",

View file

@ -2565,5 +2565,284 @@
"Rate %(brand)s": "評價 %(brand)s", "Rate %(brand)s": "評價 %(brand)s",
"Feedback sent": "已傳送回饋", "Feedback sent": "已傳送回饋",
"%(senderName)s ended the call": "%(senderName)s 結束了通話", "%(senderName)s ended the call": "%(senderName)s 結束了通話",
"You ended the call": "您結束了通話" "You ended the call": "您結束了通話",
"Now, let's help you get started": "現在,讓我們協助您開始",
"Welcome %(name)s": "歡迎 %(name)s",
"Add a photo so people know it's you.": "新增照片以讓其他人知道是您。",
"Great, that'll help people know it's you": "太好了,這會讓人們知道是您",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this room</a>.": "使用某人的名字、電子郵件地址或使用者名稱來與他們開始對話(如 <userId/>)或是<a>分享此聊天室</a>。",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "使用某人的名字、電子郵件地址或使用者名稱來與他們開始對話(如 <userId/>)。",
"Invite by email": "透過電子郵件邀請",
"Use the + to make a new room or explore existing ones below": "使用 + 建立新的聊天室或在下方探索既有的聊天室",
"New version of %(brand)s is available": "%(brand)s 的新版本已可使用",
"Update %(brand)s": "更新 %(brand)s",
"Enable desktop notifications": "啟用桌面通知",
"Don't miss a reply": "不要錯過回覆",
"Zimbabwe": "辛巴威",
"Zambia": "尚比亞",
"Yemen": "葉門",
"Western Sahara": "西撒哈拉",
"Wallis & Futuna": "瓦利斯和富圖那",
"Vietnam": "越南",
"Venezuela": "委內瑞拉",
"Vatican City": "梵蒂岡",
"Vanuatu": "萬那杜",
"Uzbekistan": "烏茲別克",
"Uruguay": "烏拉圭",
"United Arab Emirates": "阿拉伯聯合大公國",
"Ukraine": "烏克蘭",
"Uganda": "烏干達",
"U.S. Virgin Islands": "美屬維京群島",
"Tuvalu": "吐瓦魯",
"Turks & Caicos Islands": "土克凱可群島",
"Turkmenistan": "土庫曼",
"Turkey": "土耳其",
"Tunisia": "突尼西亞",
"Trinidad & Tobago": "千里達及托巴哥",
"Tonga": "東加",
"Tokelau": "托克勞",
"Togo": "多哥",
"Timor-Leste": "東帝汶",
"Thailand": "泰國",
"Tanzania": "坦尚尼亞",
"Tajikistan": "塔吉克",
"Taiwan": "台灣",
"São Tomé & Príncipe": "聖多美普林西比",
"Syria": "敘利亞",
"Switzerland": "瑞士",
"Sweden": "瑞典",
"Swaziland": "史瓦帝尼",
"Svalbard & Jan Mayen": "斯瓦巴和揚馬延",
"Suriname": "蘇利南",
"Sudan": "蘇丹",
"St. Vincent & Grenadines": "聖文森及格瑞那丁",
"St. Pierre & Miquelon": "聖皮埃與密克隆",
"St. Martin": "聖馬丁",
"St. Lucia": "聖露西亞",
"St. Kitts & Nevis": "聖克里斯多福及尼維斯",
"St. Helena": "聖赫勒拿",
"St. Barthélemy": "聖巴瑟米",
"Sri Lanka": "斯里蘭卡",
"Spain": "西班牙",
"South Sudan": "南蘇丹",
"South Korea": "南韓",
"South Georgia & South Sandwich Islands": "南喬治亞與南桑威奇群島",
"South Africa": "南非",
"Somalia": "索馬利亞",
"Solomon Islands": "索羅門群島",
"Slovenia": "斯洛維尼亞",
"Slovakia": "斯洛伐克",
"Sint Maarten": "荷屬聖馬丁",
"Singapore": "新加坡",
"Sierra Leone": "獅子山",
"Seychelles": "塞席爾",
"Serbia": "塞爾維亞",
"Senegal": "塞內加爾",
"Saudi Arabia": "沙烏地阿拉伯",
"San Marino": "聖馬利諾",
"Samoa": "薩摩亞",
"Réunion": "留尼旺",
"Rwanda": "盧安達",
"Russia": "俄羅斯",
"Romania": "羅馬尼亞",
"Qatar": "卡達",
"Puerto Rico": "波多黎各",
"Portugal": "葡萄牙",
"Poland": "波蘭",
"Pitcairn Islands": "皮特肯群島",
"Philippines": "菲律賓",
"Peru": "秘魯",
"Paraguay": "巴拉圭",
"Papua New Guinea": "巴布亞紐幾內亞",
"Panama": "巴拿馬",
"Palestine": "巴勒斯坦",
"Palau": "帛琉",
"Pakistan": "巴基斯坦",
"Oman": "阿曼",
"Norway": "挪威",
"Northern Mariana Islands": "北馬利安納群島",
"North Korea": "北韓",
"Norfolk Island": "諾福克島",
"Niue": "紐埃",
"Nigeria": "奈及利亞",
"Niger": "尼日",
"Nicaragua": "尼加拉瓜",
"New Zealand": "紐西蘭",
"New Caledonia": "新喀里多尼亞",
"Netherlands": "荷蘭",
"Nepal": "尼泊爾",
"Nauru": "諾魯",
"Namibia": "納米比亞",
"Myanmar": "緬甸",
"Mozambique": "莫三比克",
"Morocco": "摩洛哥",
"Montserrat": "蒙哲臘",
"Montenegro": "蒙特內哥羅",
"Mongolia": "蒙古",
"Monaco": "摩納哥",
"Moldova": "摩爾多瓦",
"Micronesia": "密克羅尼西亞",
"Mexico": "墨西哥",
"Mayotte": "馬約特",
"Mauritius": "模里西斯",
"Mauritania": "茅利塔尼亞",
"Martinique": "馬丁尼克",
"Marshall Islands": "馬紹爾群島",
"Malta": "馬爾他",
"Mali": "馬利",
"Maldives": "馬爾地夫",
"Malaysia": "馬來西亞",
"Malawi": "馬拉威",
"Madagascar": "馬達加斯加",
"Macedonia": "馬其頓",
"Macau": "澳門",
"Luxembourg": "盧森堡",
"Lithuania": "立陶宛",
"Liechtenstein": "列支敦斯登",
"Libya": "利比亞",
"Liberia": "賴比瑞亞",
"Lesotho": "賴索托",
"Lebanon": "黎巴嫩",
"Latvia": "拉脫維亞",
"Laos": "寮國",
"Kyrgyzstan": "吉爾吉斯",
"Kuwait": "科威特",
"Kosovo": "科索沃",
"Kiribati": "吉里巴斯",
"Kenya": "肯亞",
"Kazakhstan": "哈薩克",
"Jordan": "約旦",
"Jersey": "澤西",
"Japan": "日本",
"Jamaica": "牙買加",
"Italy": "義大利",
"Israel": "以色列",
"Isle of Man": "曼島",
"Ireland": "愛爾蘭",
"Iraq": "伊拉克",
"Iran": "伊朗",
"Indonesia": "印度尼西亞",
"India": "印度",
"Iceland": "冰島",
"Hungary": "匈牙利",
"Hong Kong": "香港",
"Honduras": "宏都拉斯",
"Heard & McDonald Islands": "赫德島和麥克唐納群島",
"Haiti": "海地",
"Guyana": "蓋亞那",
"Guinea-Bissau": "幾內亞比索",
"Guinea": "幾內亞",
"Guernsey": "根西",
"Guatemala": "瓜地馬拉",
"Guam": "關島",
"Guadeloupe": "瓜地洛普",
"Grenada": "格瑞那達",
"Greenland": "格陵蘭",
"Greece": "希臘",
"Gibraltar": "直布羅陀",
"Ghana": "迦納",
"Germany": "德國",
"Georgia": "喬治亞",
"Gambia": "甘比亞",
"Gabon": "加彭",
"French Southern Territories": "法屬南部領地",
"French Polynesia": "法屬玻里尼西亞",
"French Guiana": "法屬圭亞那",
"France": "法國",
"Finland": "芬蘭",
"Fiji": "斐濟",
"Faroe Islands": "法羅群島",
"Falkland Islands": "福克蘭群島",
"Ethiopia": "衣索比亞",
"Estonia": "愛沙尼亞",
"Eritrea": "厄利垂亞",
"Equatorial Guinea": "赤道幾內亞",
"El Salvador": "薩爾瓦多",
"Egypt": "埃及",
"Ecuador": "厄瓜多",
"Dominican Republic": "多明尼加",
"Dominica": "多米尼克",
"Djibouti": "吉布地",
"Denmark": "丹麥",
"Côte dIvoire": "象牙海岸",
"Czech Republic": "捷克",
"Cyprus": "賽普勒斯",
"Curaçao": "古拉索",
"Cuba": "古巴",
"Croatia": "克羅埃西亞",
"Costa Rica": "哥斯大黎加",
"Cook Islands": "庫克群島",
"Congo - Kinshasa": "剛果 - 金夏沙",
"Congo - Brazzaville": "剛果 - 布拉薩",
"Comoros": "葛摩",
"Colombia": "哥倫比亞",
"Cocos (Keeling) Islands": "科科斯(基林)群島",
"Christmas Island": "聖誕島",
"China": "中國",
"Chile": "智利",
"Chad": "查德",
"Central African Republic": "中非共和國",
"Cayman Islands": "開曼群島",
"Caribbean Netherlands": "荷屬加勒比",
"Cape Verde": "維德角",
"Canada": "加拿大",
"Cameroon": "喀麥隆",
"Cambodia": "柬埔寨",
"Burundi": "蒲隆地",
"Burkina Faso": "布吉納法索",
"Bulgaria": "保加利亞",
"Brunei": "汶萊",
"British Virgin Islands": "英屬維京群島",
"British Indian Ocean Territory": "英屬印度洋屬地",
"Brazil": "巴西",
"Bouvet Island": "布威島",
"Botswana": "波札那",
"Bosnia": "波士尼亞",
"Bolivia": "玻利維亞",
"Bhutan": "不丹",
"Bermuda": "百慕達",
"Benin": "貝南",
"Belize": "貝里斯",
"Belgium": "比利時",
"Belarus": "白俄羅斯",
"Barbados": "巴貝多",
"Bangladesh": "孟加拉",
"Bahrain": "巴林",
"Bahamas": "巴哈馬",
"Azerbaijan": "亞塞拜然",
"Austria": "奧地利",
"Australia": "澳洲",
"Aruba": "阿魯巴",
"Armenia": "亞美尼亞",
"Argentina": "阿根廷",
"Antigua & Barbuda": "安地卡及巴布達",
"Antarctica": "南極洲",
"Anguilla": "安吉拉",
"Angola": "安哥拉",
"Andorra": "安道爾",
"American Samoa": "美屬薩摩亞",
"Algeria": "阿爾及利亞",
"Albania": "阿爾巴尼亞",
"Åland Islands": "奧蘭",
"Afghanistan": "阿富汗",
"United States": "美國",
"United Kingdom": "英國",
"%(creator)s created this DM.": "%(creator)s 建立了此直接訊息。",
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "此聊天適中的訊息為端到端加密。當人們加入,您可以在他們的個人檔案中驗證他們,只要點擊他們的大頭照就可以了。",
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "此處的訊息為端到端加密。請在他們的個人檔案中驗證 %(displayName)s只要點擊他們的大頭照就可以了。",
"This is the start of <roomName/>.": "這是 <roomName/> 的開頭。",
"Add a photo, so people can easily spot your room.": "新增圖片,這樣人們就可以輕鬆發現您的聊天室。",
"%(displayName)s created this room.": "%(displayName)s 建立了此聊天室。",
"You created this room.": "您建立了此聊天室。",
"<a>Add a topic</a> to help people know what it is about.": "<a>新增主題</a>以協助人們了解這裡在做什麼。",
"Topic: %(topic)s ": "主題:%(topic)s ",
"Topic: %(topic)s (<a>edit</a>)": "主題:%(topic)s<a>編輯</a>",
"This is the beginning of your direct message history with <displayName/>.": "這是使用 <displayName/> 傳送的您的直接訊息歷史紀錄的開頭。",
"Only the two of you are in this conversation, unless either of you invites anyone to join.": "除非你們兩個其中一個邀請任何人加入,否則只會有你們兩個在此對話中。",
"Call Paused": "通話已暫停",
"Takes the call in the current room off hold": "讓目前聊天室中的通話保持等候接聽的狀態",
"Places the call in the current room on hold": "在目前的聊天室撥打通話並等候接聽",
"Role": "角色",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|one": "使用 %(size)s 儲存來自 %(count)s 個聊天室的訊息,在本機安全地快取已加密的訊息以讓它們可以在搜尋結果中出現。",
"Securely cache encrypted messages locally for them to appear in search results, using %(size)s to store messages from %(count)s rooms.|other": "使用 %(size)s 儲存來自 %(count)s 個聊天室的訊息,在本機安全地快取已加密的訊息以讓它們可以在搜尋結果中出現。"
} }

View file

@ -25,6 +25,7 @@ export interface IToast<C extends ComponentClass> {
title: string; title: string;
icon?: string; icon?: string;
component: C; component: C;
className?: string;
props?: Omit<React.ComponentProps<C>, "toastKey">; // toastKey is injected by ToastContainer props?: Omit<React.ComponentProps<C>, "toastKey">; // toastKey is injected by ToastContainer
} }

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