Merge branch 'develop' into gsouquet/fix-18132

This commit is contained in:
Germain Souquet 2021-07-29 10:27:00 +02:00
commit e140dd6ba1
98 changed files with 2565 additions and 735 deletions

View file

@ -104,8 +104,8 @@ a:visited {
input[type=text],
input[type=search],
input[type=password] {
font-family: inherit;
padding: 9px;
font-family: $font-family;
font-size: $font-14px;
font-weight: 600;
min-width: 0;
@ -146,7 +146,6 @@ input[type=text], input[type=password], textarea {
/* Required by Firefox */
textarea {
font-family: $font-family;
color: $primary-fg-color;
}

View file

@ -269,6 +269,7 @@
@import "./views/voip/_CallPreview.scss";
@import "./views/voip/_CallView.scss";
@import "./views/voip/_CallViewForRoom.scss";
@import "./views/voip/_CallViewSidebar.scss";
@import "./views/voip/_DialPad.scss";
@import "./views/voip/_DialPadContextMenu.scss";
@import "./views/voip/_DialPadModal.scss";

View file

@ -190,7 +190,6 @@ limitations under the License.
position: relative;
padding: 8px 16px;
border-radius: 8px;
min-height: 56px;
box-sizing: border-box;
display: grid;

View file

@ -29,7 +29,6 @@ limitations under the License.
.mx_AddressPickerDialog_input:focus {
height: 26px;
font-size: $font-14px;
font-family: $font-family;
padding-left: 12px;
padding-right: 12px;
margin: 0 !important;

View file

@ -34,7 +34,6 @@ limitations under the License.
}
.mx_ConfirmUserActionDialog_reasonField {
font-family: $font-family;
font-size: $font-14px;
color: $primary-fg-color;
background-color: $primary-bg-color;

View file

@ -55,22 +55,6 @@ limitations under the License.
padding-right: 24px;
}
.mx_DevTools_inputCell {
display: table-cell;
width: 240px;
}
.mx_DevTools_inputCell input {
display: inline-block;
border: 0;
border-bottom: 1px solid $input-underline-color;
padding: 0;
width: 240px;
color: $input-fg-color;
font-family: $font-family;
font-size: $font-16px;
}
.mx_DevTools_textarea {
font-size: $font-12px;
max-width: 684px;
@ -139,7 +123,6 @@ limitations under the License.
+ .mx_DevTools_tgl-btn {
padding: 2px;
transition: all .2s ease;
font-family: sans-serif;
perspective: 100px;
&::after,
&::before {

View file

@ -16,57 +16,43 @@ limitations under the License.
.mx_desktopCapturerSourcePicker {
overflow: hidden;
}
.mx_desktopCapturerSourcePicker_tabLabels {
display: flex;
padding: 0 0 8px 0;
}
.mx_desktopCapturerSourcePicker_tab {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-start;
height: 500px;
overflow: overlay;
}
.mx_desktopCapturerSourcePicker_tabLabel,
.mx_desktopCapturerSourcePicker_tabLabel_selected {
width: 100%;
text-align: center;
border-radius: 8px;
padding: 8px 0;
font-size: $font-13px;
}
.mx_desktopCapturerSourcePicker_source {
display: flex;
flex-direction: column;
margin: 8px;
}
.mx_desktopCapturerSourcePicker_tabLabel_selected {
background-color: $tab-label-active-bg-color;
color: $tab-label-active-fg-color;
}
.mx_desktopCapturerSourcePicker_source_thumbnail {
margin: 4px;
padding: 4px;
width: 312px;
border-width: 2px;
border-radius: 8px;
border-style: solid;
border-color: transparent;
.mx_desktopCapturerSourcePicker_panel {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-start;
height: 500px;
overflow: overlay;
}
&.mx_desktopCapturerSourcePicker_source_thumbnail_selected,
&:hover,
&:focus {
border-color: $accent-color;
}
}
.mx_desktopCapturerSourcePicker_stream_button {
display: flex;
flex-direction: column;
margin: 8px;
border-radius: 4px;
}
.mx_desktopCapturerSourcePicker_stream_button:hover,
.mx_desktopCapturerSourcePicker_stream_button:focus {
background: $roomtile-selected-bg-color;
}
.mx_desktopCapturerSourcePicker_stream_thumbnail {
margin: 4px;
width: 312px;
}
.mx_desktopCapturerSourcePicker_stream_name {
margin: 0 4px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 312px;
.mx_desktopCapturerSourcePicker_source_name {
margin: 0 4px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 312px;
}
}

View file

@ -39,7 +39,6 @@ limitations under the License.
.mx_Field select,
.mx_Field textarea {
font-weight: normal;
font-family: $font-family;
font-size: $font-14px;
border: none;
// Even without a border here, we still need this avoid overlapping the rounded

View file

@ -43,6 +43,14 @@ limitations under the License.
}
}
&.mx_CallEvent_voice.mx_CallEvent_missed .mx_CallEvent_type_icon::before {
mask-image: url('$(res)/img/voip/missed-voice.svg');
}
&.mx_CallEvent_video.mx_CallEvent_missed .mx_CallEvent_type_icon::before {
mask-image: url('$(res)/img/voip/missed-video.svg');
}
.mx_CallEvent_info {
display: flex;
flex-direction: row;

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
.mx_EventTile[data-layout=bubble],
.mx_EventTile[data-layout=bubble] ~ .mx_EventListSummary {
.mx_EventListSummary[data-layout=bubble] {
--avatarSize: 32px;
--gutterSize: 11px;
--cornerRadius: 12px;
@ -224,100 +224,6 @@ limitations under the License.
border-left-color: $eventbubble-reply-color;
}
&.mx_EventTile_bubbleContainer,
&.mx_EventTile_info,
& ~ .mx_EventListSummary[data-expanded=false] {
--backgroundColor: transparent;
--gutterSize: 0;
display: flex;
align-items: center;
justify-content: start;
padding: 5px 0;
.mx_EventTile_avatar {
position: static;
order: -1;
margin-right: 5px;
}
.mx_EventTile_e2eIcon {
margin-left: 9px;
}
.mx_EventTile_line > a {
right: auto;
top: -15px;
left: -68px;
}
}
& ~ .mx_EventListSummary {
--maxWidth: 80%;
margin-left: calc(var(--avatarSize) + var(--gutterSize));
margin-right: calc(var(--gutterSize) + var(--avatarSize));
.mx_EventListSummary_toggle {
float: none;
margin: 0;
order: 9;
margin-left: 5px;
}
.mx_EventListSummary_avatars {
padding-top: 0;
}
&::after {
content: "";
clear: both;
}
.mx_EventTile {
margin: 0 6px;
}
.mx_EventTile_line {
margin: 0 5px;
> a {
left: auto;
right: 0;
transform: translateX(calc(100% + 5px));
}
}
.mx_MessageActionBar {
transform: translate3d(90%, 0, 0);
}
}
& ~ .mx_EventListSummary[data-expanded=false] {
padding: 0 34px;
}
/* events that do not require bubble layout */
& ~ .mx_EventListSummary,
&.mx_EventTile_bad {
.mx_EventTile_line {
background: transparent;
}
&:hover {
&::before {
background: transparent;
}
}
}
& + .mx_EventListSummary {
.mx_EventTile {
margin-top: 0;
padding: 2px 0;
}
}
.mx_EventListSummary_toggle {
margin-right: 55px;
}
/* Special layout scenario for "Unable To Decrypt (UTD)" events */
&.mx_EventTile_bad > .mx_EventTile_line {
display: grid;
@ -352,3 +258,88 @@ limitations under the License.
max-width: 100%;
}
}
.mx_EventTile.mx_EventTile_bubbleContainer[data-layout=bubble],
.mx_EventTile.mx_EventTile_info[data-layout=bubble],
.mx_EventListSummary[data-layout=bubble][data-expanded=false] {
--backgroundColor: transparent;
--gutterSize: 0;
display: flex;
align-items: center;
justify-content: start;
padding: 5px 0;
.mx_EventTile_avatar {
position: static;
order: -1;
margin-right: 5px;
}
.mx_EventTile_e2eIcon {
margin-left: 9px;
}
.mx_EventTile_line > a {
right: auto;
top: -15px;
left: -68px;
}
}
.mx_EventListSummary[data-layout=bubble] {
--maxWidth: 80%;
margin-left: calc(var(--avatarSize) + var(--gutterSize));
margin-right: calc(var(--gutterSize) + var(--avatarSize));
.mx_EventListSummary_toggle {
float: none;
margin: 0;
order: 9;
margin-left: 5px;
margin-right: 55px;
}
.mx_EventListSummary_avatars {
padding-top: 0;
}
&::after {
content: "";
clear: both;
}
.mx_EventTile {
margin: 0 6px;
padding: 2px 0;
}
.mx_EventTile_line {
margin: 0 5px;
> a {
left: auto;
right: 0;
transform: translateX(calc(100% + 5px));
}
}
.mx_MessageActionBar {
transform: translate3d(90%, 0, 0);
}
}
.mx_EventListSummary[data-expanded=false][data-layout=bubble] {
padding: 0 34px;
}
/* events that do not require bubble layout */
.mx_EventListSummary[data-layout=bubble],
.mx_EventTile.mx_EventTile_bad[data-layout=bubble] {
.mx_EventTile_line {
background: transparent;
}
&:hover {
&::before {
background: transparent;
}
}
}

View file

@ -132,15 +132,6 @@ $hover-select-border: 4px;
}
}
&.mx_EventTile_info .mx_EventTile_line,
& ~ .mx_EventListSummary .mx_EventTile_avatar ~ .mx_EventTile_line {
padding-left: calc($left-gutter + 18px);
}
& ~ .mx_EventListSummary .mx_EventTile_line {
padding-left: calc($left-gutter);
}
&.mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line {
padding-left: calc($left-gutter + 18px - $hover-select-border);
}
@ -276,10 +267,19 @@ $hover-select-border: 4px;
.mx_ReactionsRow {
margin: 0;
padding: 6px 60px;
padding: 4px 64px;
}
}
.mx_EventTile:not([data-layout=bubble]).mx_EventTile_info .mx_EventTile_line,
.mx_EventListSummary:not([data-layout=bubble]) > :not(.mx_EventTile) .mx_EventTile_avatar ~ .mx_EventTile_line {
padding-left: calc($left-gutter + 18px);
}
.mx_EventListSummary:not([data-layout=bubble]) .mx_EventTile_line {
padding-left: calc($left-gutter);
}
/* all the overflow-y: hidden; are to trap Zalgos -
but they introduce an implicit overflow-x: auto.
so make that explicitly hidden too to avoid random
@ -573,6 +573,12 @@ $hover-select-border: 4px;
color: $accent-color-alt;
}
.mx_EventTile_content .markdown-body blockquote {
border-left: 2px solid $blockquote-bar-color;
border-radius: 2px;
padding: 0 10px;
}
.mx_EventTile_content .markdown-body .hljs {
display: inline !important;
}

View file

@ -165,8 +165,6 @@ limitations under the License.
font-size: $font-14px;
max-height: 120px;
overflow: auto;
/* needed for FF */
font-family: $font-family;
}
/* hack for FF as vertical alignment of custom placeholder text is broken */

View file

@ -60,8 +60,6 @@ limitations under the License.
$reply-lines: 2;
$line-height: $font-22px;
pointer-events: none;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;

View file

@ -36,7 +36,6 @@ limitations under the License.
.mx_SettingsTab_subheading {
font-size: $font-16px;
display: block;
font-family: $font-family;
font-weight: 600;
color: $primary-fg-color;
margin-bottom: 10px;

View file

@ -67,7 +67,26 @@ limitations under the License.
.mx_CallView_content {
position: relative;
display: flex;
justify-content: center;
border-radius: 8px;
> .mx_VideoFeed {
width: 100%;
height: 100%;
&.mx_VideoFeed_voice {
// We don't want to collide with the call controls that have 52px of height
padding-bottom: 52px;
background-color: $inverted-bg-color;
display: flex;
justify-content: center;
align-items: center;
}
&.mx_VideoFeed_video {
background-color: #000;
}
}
}
.mx_CallView_voice {
@ -260,7 +279,7 @@ limitations under the License.
max-width: 240px;
}
.mx_CallView_header_phoneIcon {
.mx_CallView_header_callTypeIcon {
display: inline-block;
margin-right: 6px;
height: 16px;
@ -274,12 +293,19 @@ limitations under the License.
height: 16px;
width: 16px;
background-color: $warning-color;
background-color: $secondary-fg-color;
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
}
&.mx_CallView_header_callTypeIcon_voice::before {
mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
}
&.mx_CallView_header_callTypeIcon_video::before {
mask-image: url('$(res)/img/element-icons/call/video-call.svg');
}
}
.mx_CallView_callControls {
@ -287,9 +313,9 @@ limitations under the License.
display: flex;
justify-content: center;
bottom: 5px;
width: 100%;
opacity: 1;
transition: opacity 0.5s;
z-index: 200; // To be above _all_ feeds
}
.mx_CallView_callControls_hidden {
@ -297,10 +323,29 @@ limitations under the License.
pointer-events: none;
}
.mx_CallView_presenting {
opacity: 1;
transition: opacity 0.5s;
position: absolute;
margin-top: 18px;
padding: 4px 8px;
border-radius: 4px;
// Same on both themes
color: white;
background-color: #17191c;
}
.mx_CallView_presenting_hidden {
opacity: 0.001; // opacity 0 can cause a re-layout
pointer-events: none;
}
.mx_CallView_callControls_button {
cursor: pointer;
margin-left: 8px;
margin-right: 8px;
margin-left: 2px;
margin-right: 2px;
&::before {
@ -317,17 +362,11 @@ limitations under the License.
}
.mx_CallView_callControls_dialpad {
margin-right: auto;
&::before {
background-image: url('$(res)/img/voip/dialpad.svg');
}
}
.mx_CallView_callControls_button_dialpad_hidden {
margin-right: auto;
cursor: initial;
}
.mx_CallView_callControls_button_micOn {
&::before {
background-image: url('$(res)/img/voip/mic-on.svg');
@ -352,6 +391,30 @@ limitations under the License.
}
}
.mx_CallView_callControls_button_screensharingOn {
&::before {
background-image: url('$(res)/img/voip/screensharing-on.svg');
}
}
.mx_CallView_callControls_button_screensharingOff {
&::before {
background-image: url('$(res)/img/voip/screensharing-off.svg');
}
}
.mx_CallView_callControls_button_sidebarOn {
&::before {
background-image: url('$(res)/img/voip/sidebar-on.svg');
}
}
.mx_CallView_callControls_button_sidebarOff {
&::before {
background-image: url('$(res)/img/voip/sidebar-off.svg');
}
}
.mx_CallView_callControls_button_hangup {
&::before {
background-image: url('$(res)/img/voip/hangup.svg');
@ -359,17 +422,11 @@ limitations under the License.
}
.mx_CallView_callControls_button_more {
margin-left: auto;
&::before {
background-image: url('$(res)/img/voip/more.svg');
}
}
.mx_CallView_callControls_button_more_hidden {
margin-left: auto;
cursor: initial;
}
.mx_CallView_callControls_button_invisible {
visibility: hidden;
pointer-events: none;

View file

@ -0,0 +1,52 @@
/*
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
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_CallViewSidebar {
position: absolute;
right: 16px;
bottom: 16px;
z-index: 100; // To be above the primary feed
overflow: auto;
height: calc(100% - 32px); // Subtract the top and bottom padding
width: 20%;
display: flex;
flex-direction: column-reverse;
justify-content: flex-start;
align-items: flex-end;
gap: 12px;
> .mx_VideoFeed {
width: 100%;
&.mx_VideoFeed_voice {
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 16 / 9;
}
}
&.mx_CallViewSidebar_pipMode {
top: 16px;
bottom: unset;
justify-content: flex-end;
gap: 4px;
}
}

View file

@ -14,32 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_VideoFeed_voice {
background-color: $inverted-bg-color;
}
.mx_VideoFeed_remote {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
&.mx_VideoFeed_video {
background-color: #000;
}
}
.mx_VideoFeed_local {
max-width: 25%;
max-height: 25%;
position: absolute;
right: 10px;
top: 10px;
z-index: 100;
.mx_VideoFeed {
border-radius: 4px;
&.mx_VideoFeed_voice {
background-color: $inverted-bg-color;
}
&.mx_VideoFeed_video {
background-color: transparent;
}

View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 4.81815C0 3.76379 0.89543 2.90906 2 2.90906H9.33333C10.4379 2.90906 11.3333 3.76379 11.3333 4.81815V11.1818C11.3333 12.2361 10.4379 13.0909 9.33333 13.0909H2C0.895429 13.0909 0 12.2361 0 11.1818V4.81815ZM12.6667 6.09089L14.9169 4.37255C15.3534 4.03921 16 4.33587 16 4.86947V11.1305C16 11.6641 15.3534 11.9607 14.9169 11.6274L12.6667 9.90907V6.09089ZM3.68584 8.54792C3.68584 8.82819 3.45653 9.05751 3.17625 9.05751C2.89598 9.05751 2.66667 8.82819 2.66667 8.54792V6.50957C2.66667 6.22929 2.89598 5.99998 3.17625 5.99998H5.2146C5.49488 5.99998 5.72419 6.22929 5.72419 6.50957C5.72419 6.78984 5.49488 7.01916 5.2146 7.01916H4.39926L6.2083 8.82819L8.73076 6.30573C8.9295 6.10699 9.25054 6.10699 9.44928 6.30573C9.64802 6.50447 9.64802 6.82551 9.44928 7.02425L6.56501 9.90852C6.36627 10.1073 6.04523 10.1073 5.84649 9.90852L3.68584 7.74787V8.54792Z" fill="#8D97A5"/>
</svg>

After

Width:  |  Height:  |  Size: 1,016 B

View file

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.00016 6C4.36683 6 4.66683 5.7 4.66683 5.33333V4.28667L7.4935 7.11333C7.7535 7.37333 8.1735 7.37333 8.4335 7.11333L12.2068 3.34C12.4668 3.08 12.4668 2.66 12.2068 2.4C11.9468 2.14 11.5268 2.14 11.2668 2.4L7.96683 5.7L5.60016 3.33333H6.66683C7.0335 3.33333 7.3335 3.03333 7.3335 2.66667C7.3335 2.3 7.0335 2 6.66683 2H4.00016C3.6335 2 3.3335 2.3 3.3335 2.66667V5.33333C3.3335 5.7 3.6335 6 4.00016 6Z" fill="#8D97A5"/>
<path d="M8.00557 8.67107C6.88076 8.62784 4.56757 8.91974 4.0052 9.06763C3.97195 9.07638 3.93363 9.08616 3.89078 9.0971C3.02734 9.31746 0.321813 10.008 0.0294949 12.1958C-0.196977 13.8909 0.937169 14.4039 1.50412 14.3258C1.89653 14.2766 3.02006 14.0989 4.05816 13.9127C5.07753 13.7298 5.07701 13.0573 5.07666 12.6026C5.07665 12.5943 5.07664 12.586 5.07664 12.5778L5.07665 11.6636C5.07665 11.4308 5.29543 11.2962 5.5972 11.2598C6.66548 11.1147 7.5573 11.1143 8.00369 11.1143L8.00745 11.1143C8.45377 11.1143 9.33453 11.1147 10.4028 11.2598C10.7046 11.2962 10.9234 11.4308 10.9234 11.6636L10.9234 12.5778C10.9234 12.586 10.9233 12.5943 10.9233 12.6026C10.923 13.0573 10.9225 13.7298 11.9418 13.9127C12.9799 14.099 14.1035 14.2766 14.4959 14.3258C15.0628 14.4039 16.197 13.8909 15.9705 12.1958C15.6782 10.008 12.9727 9.31747 12.1092 9.0971C12.0664 9.08617 12.0281 9.07639 11.9948 9.06764C11.4324 8.91975 9.13037 8.62783 8.00557 8.67107Z" fill="#8D97A5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,18 @@
<svg width="50" height="49" viewBox="0 0 50 49" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<circle cx="25" cy="20" r="20" fill="white"/>
</g>
<rect x="14.6008" y="12.8" width="20.8" height="14.4" rx="1.6" fill="white" stroke="#737D8C" stroke-width="1.6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.3617 23.36C24.3617 23.7135 24.6483 24 25.0017 24C25.3552 24 25.6417 23.7135 25.6417 23.36L25.6417 18.1851L27.6692 20.2125C27.9191 20.4625 28.3243 20.4625 28.5743 20.2125C28.8242 19.9626 28.8242 19.5574 28.5743 19.3075L25.4543 16.1875C25.2043 15.9375 24.7991 15.9375 24.5492 16.1875L21.4292 19.3075C21.1792 19.5574 21.1792 19.9626 21.4292 20.2125C21.6791 20.4625 22.0843 20.4625 22.3343 20.2125L24.3617 18.1851L24.3617 23.36Z" fill="#737D8C"/>
<defs>
<filter id="filter0_d" x="0.947663" y="0" width="48.1047" height="48.1047" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4.05234"/>
<feGaussianBlur stdDeviation="2.02617"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,18 @@
<svg width="50" height="49" viewBox="0 0 50 49" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<circle cx="25" cy="20" r="20" fill="#0DBD8B"/>
</g>
<rect x="14.6008" y="12.8" width="20.8" height="14.4" rx="1.6" fill="#0DBD8B" stroke="white" stroke-width="1.6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.3617 23.36C24.3617 23.7135 24.6483 24 25.0017 24C25.3552 24 25.6417 23.7135 25.6417 23.36L25.6417 18.1851L27.6692 20.2125C27.9191 20.4625 28.3243 20.4625 28.5743 20.2125C28.8242 19.9626 28.8242 19.5574 28.5743 19.3075L25.4543 16.1875C25.2043 15.9375 24.7991 15.9375 24.5492 16.1875L21.4292 19.3075C21.1792 19.5574 21.1792 19.9626 21.4292 20.2125C21.6791 20.4625 22.0843 20.4625 22.3343 20.2125L24.3617 18.1851L24.3617 23.36Z" fill="white"/>
<defs>
<filter id="filter0_d" x="0.947663" y="0" width="48.1047" height="48.1047" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4.05234"/>
<feGaussianBlur stdDeviation="2.02617"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,20 @@
<svg width="48" height="47" viewBox="0 0 48 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<circle cx="24" cy="20" r="20" fill="#737D8C"/>
</g>
<rect x="12.5618" y="12.8992" width="20.3525" height="14.4496" rx="2.43819" fill="white" stroke="#737D8C" stroke-width="1.12362"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.9132 20.5009C33.2675 20.5009 34.3655 19.4205 34.3655 18.0876C34.3655 16.7548 33.2675 15.6743 31.9132 15.6743C30.5589 15.6743 29.4609 16.7548 29.4609 18.0876C29.4609 19.4205 30.5589 20.5009 31.9132 20.5009ZM27.8242 26.132C27.8282 23.7187 28.976 21.3054 31.9113 21.3054C34.7818 21.3054 35.9984 23.7187 35.9984 26.132C35.9984 28.5453 32.7288 28.5453 31.9113 28.5453C31.0939 28.5453 27.8206 28.3403 27.8242 26.132Z" fill="white"/>
<path d="M27.8242 26.132L28.386 26.1329L27.8242 26.132ZM35.9984 26.132H35.4366H35.9984ZM33.8037 18.0876C33.8037 19.1017 32.9658 19.9391 31.9132 19.9391V21.0627C33.5693 21.0627 34.9273 19.7392 34.9273 18.0876H33.8037ZM31.9132 16.2361C32.9658 16.2361 33.8037 17.0735 33.8037 18.0876H34.9273C34.9273 16.4361 33.5693 15.1125 31.9132 15.1125V16.2361ZM30.0227 18.0876C30.0227 17.0735 30.8606 16.2361 31.9132 16.2361V15.1125C30.2571 15.1125 28.8991 16.4361 28.8991 18.0876H30.0227ZM31.9132 19.9391C30.8606 19.9391 30.0227 19.1017 30.0227 18.0876H28.8991C28.8991 19.7392 30.2571 21.0627 31.9132 21.0627V19.9391ZM31.9113 20.7436C30.2659 20.7436 29.0747 21.4314 28.3132 22.4845C27.5693 23.5133 27.2645 24.8471 27.2624 26.1311L28.386 26.1329C28.3879 25.0036 28.659 23.924 29.2238 23.1429C29.771 22.386 30.6214 21.8672 31.9113 21.8672V20.7436ZM36.5602 26.132C36.5602 24.8414 36.2364 23.5081 35.4845 22.4817C34.7168 21.4338 33.5275 20.7436 31.9113 20.7436V21.8672C33.1657 21.8672 34.0199 22.3836 34.5781 23.1457C35.1521 23.9293 35.4366 25.0093 35.4366 26.132H36.5602ZM31.9113 29.1071C32.3157 29.1071 33.4213 29.1105 34.4365 28.7775C34.9481 28.6096 35.4778 28.3438 35.8839 27.9122C36.3025 27.4673 36.5602 26.8767 36.5602 26.132H35.4366C35.4366 26.594 35.2857 26.9083 35.0656 27.1422C34.8331 27.3893 34.4943 27.576 34.0863 27.7098C33.2623 27.9801 32.3244 27.9835 31.9113 27.9835V29.1071ZM27.2624 26.1311C27.26 27.5996 28.3757 28.3418 29.3716 28.6961C30.3797 29.0547 31.4763 29.1071 31.9113 29.1071V27.9835C31.5289 27.9835 30.5802 27.9334 29.7482 27.6375C28.9039 27.3371 28.3848 26.8728 28.386 26.1329L27.2624 26.1311Z" fill="#737D8C"/>
<rect x="0.0339116" y="-0.787426" width="29.1443" height="3.36793" rx="1.68396" transform="matrix(0.681883 0.731461 -0.742244 0.670129 13.0943 8.71545)" fill="white" stroke="#737D8C" stroke-width="1.12362"/>
<defs>
<filter id="filter0_d" x="0.589744" y="0" width="46.8205" height="46.8205" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="3.41026"/>
<feGaussianBlur stdDeviation="1.70513"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,19 @@
<svg width="48" height="47" viewBox="0 0 48 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<circle cx="24" cy="20" r="20" fill="white"/>
</g>
<rect x="12.5" y="12.5" width="20.4763" height="15.3319" rx="2.5" fill="#737D8C" stroke="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.912 20.5618C33.2664 20.5618 34.3643 19.4287 34.3643 18.0309C34.3643 16.6331 33.2664 15.5 31.912 15.5C30.5577 15.5 29.4598 16.6331 29.4598 18.0309C29.4598 19.4287 30.5577 20.5618 31.912 20.5618ZM27.8242 26.467C27.8282 23.9361 28.976 21.4052 31.9113 21.4052C34.7818 21.4052 35.9985 23.9361 35.9985 26.467C35.9985 28.9978 32.7288 28.9978 31.9114 28.9978C31.0939 28.9978 27.8206 28.7829 27.8242 26.467Z" fill="#737D8C"/>
<path d="M27.8242 26.467L27.3242 26.4662L27.8242 26.467ZM35.9985 26.467H36.4985H35.9985ZM33.8643 18.0309C33.8643 19.1675 32.9755 20.0618 31.912 20.0618V21.0618C33.5573 21.0618 34.8643 19.6898 34.8643 18.0309H33.8643ZM31.912 16C32.9755 16 33.8643 16.8943 33.8643 18.0309H34.8643C34.8643 16.372 33.5573 15 31.912 15V16ZM29.9598 18.0309C29.9598 16.8943 30.8486 16 31.912 16V15C30.2668 15 28.9598 16.372 28.9598 18.0309H29.9598ZM31.912 20.0618C30.8486 20.0618 29.9598 19.1675 29.9598 18.0309H28.9598C28.9598 19.6898 30.2668 21.0618 31.912 21.0618V20.0618ZM31.9113 20.9052C30.2753 20.9052 29.1023 21.622 28.3569 22.7032C27.6274 23.7612 27.3263 25.1361 27.3242 26.4662L28.3242 26.4677C28.3261 25.2669 28.6009 24.1109 29.1802 23.2708C29.7434 22.4538 30.612 21.9052 31.9113 21.9052V20.9052ZM36.4985 26.467C36.4985 25.1313 36.1789 23.7567 35.4412 22.7007C34.6893 21.6242 33.5177 20.9052 31.9113 20.9052V21.9052C33.1755 21.9052 34.0475 22.4516 34.6214 23.2733C35.2097 24.1154 35.4985 25.2717 35.4985 26.467H36.4985ZM31.9114 29.4978C32.3162 29.4978 33.416 29.5011 34.4241 29.1543C34.9326 28.9794 35.4519 28.7044 35.847 28.264C36.2515 27.8131 36.4985 27.2184 36.4985 26.467H35.4985C35.4985 26.9809 35.3367 27.3354 35.1026 27.5962C34.8591 27.8677 34.5099 28.0673 34.0988 28.2087C33.2677 28.4946 32.3239 28.4978 31.9114 28.4978V29.4978ZM27.3242 26.4662C27.3219 27.9345 28.3854 28.6964 29.3851 29.0693C30.3864 29.4429 31.4779 29.4978 31.9114 29.4978V28.4978C31.5274 28.4978 30.5735 28.4453 29.7346 28.1324C28.8943 27.8189 28.3229 27.3153 28.3242 26.4677L27.3242 26.4662Z" fill="white"/>
<defs>
<filter id="filter0_d" x="0.589744" y="0" width="46.8205" height="46.8205" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="3.41026"/>
<feGaussianBlur stdDeviation="1.70513"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -56,7 +56,6 @@ limitations under the License.
import React from 'react';
import { MatrixClientPeg } from './MatrixClientPeg';
import PlatformPeg from './PlatformPeg';
import Modal from './Modal';
import { _t } from './languageHandler';
import dis from './dispatcher/dispatcher';
@ -80,7 +79,6 @@ import CountlyAnalytics from "./CountlyAnalytics";
import { UIFeature } from "./settings/UIFeature";
import { CallError } from "matrix-js-sdk/src/webrtc/call";
import { logger } from 'matrix-js-sdk/src/logger';
import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker";
import { Action } from './dispatcher/actions';
import VoipUserMapper from './VoipUserMapper';
import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid';
@ -129,14 +127,9 @@ interface ThirdpartyLookupResponse {
fields: ThirdpartyLookupResponseFields;
}
// Unlike 'CallType' in js-sdk, this one includes screen sharing
// (because a screen sharing call is only a screen sharing call to the caller,
// to the callee it's just a video call, at least as far as the current impl
// is concerned).
export enum PlaceCallType {
Voice = 'voice',
Video = 'video',
ScreenSharing = 'screensharing',
}
export enum CallHandlerEvent {
@ -491,28 +484,18 @@ export default class CallHandler extends EventEmitter {
break;
case CallState.Ended:
{
Analytics.trackEvent('voip', 'callEnded', 'hangupReason', call.hangupReason);
const hangupReason = call.hangupReason;
Analytics.trackEvent('voip', 'callEnded', 'hangupReason', hangupReason);
this.removeCallForRoom(mappedRoomId);
if (oldState === CallState.InviteSent && (
call.hangupParty === CallParty.Remote ||
(call.hangupParty === CallParty.Local && call.hangupReason === CallErrorCode.InviteTimeout)
)) {
if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) {
this.play(AudioID.Busy);
let title;
let description;
if (call.hangupReason === CallErrorCode.UserHangup) {
title = _t("Call Declined");
description = _t("The other party declined the call.");
} else if (call.hangupReason === CallErrorCode.UserBusy) {
// TODO: We should either do away with these or figure out a copy for each code (expect user_hangup...)
if (call.hangupReason === CallErrorCode.UserBusy) {
title = _t("User Busy");
description = _t("The user you called is busy.");
} else if (call.hangupReason === CallErrorCode.InviteTimeout) {
title = _t("Call Failed");
// XXX: full stop appended as some relic here, but these
// strings need proper input from design anyway, so let's
// not change this string until we have a proper one.
description = _t('The remote side failed to pick up') + '.';
} else {
} else if (hangupReason && ![CallErrorCode.UserHangup, "user hangup"].includes(hangupReason)) {
title = _t("Call Failed");
description = _t("The call could not be established");
}
@ -521,7 +504,7 @@ export default class CallHandler extends EventEmitter {
title, description,
});
} else if (
call.hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting
hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting
) {
Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, {
title: _t("Answered Elsewhere"),
@ -738,25 +721,6 @@ export default class CallHandler extends EventEmitter {
call.placeVoiceCall();
} else if (type === 'video') {
call.placeVideoCall();
} else if (type === PlaceCallType.ScreenSharing) {
const screenCapErrorString = PlatformPeg.get().screenCaptureErrorString();
if (screenCapErrorString) {
this.removeCallForRoom(roomId);
console.log("Can't capture screen: " + screenCapErrorString);
Modal.createTrackedDialog('Call Handler', 'Unable to capture screen', ErrorDialog, {
title: _t('Unable to capture screen'),
description: screenCapErrorString,
});
return;
}
call.placeScreenSharingCall(
async (): Promise<DesktopCapturerSource> => {
const { finished } = Modal.createDialog(DesktopCapturerSourcePicker);
const [source] = await finished;
return source;
},
);
} else {
console.error("Unknown conf call type: " + type);
}

View file

@ -74,6 +74,14 @@ export default class CallEventGrouper extends EventEmitter {
return this.hangup?.getContent()?.reason;
}
public get rejectParty(): string {
return this.reject?.getSender();
}
public get gotRejected(): boolean {
return Boolean(this.reject);
}
/**
* Returns true if there are only events from the other side - we missed the call
*/

View file

@ -618,7 +618,15 @@ export default class MessagePanel extends React.Component<IProps, IState> {
for (const Grouper of groupers) {
if (Grouper.canStartGroup(this, mxEv)) {
grouper = new Grouper(this, mxEv, prevEvent, lastShownEvent, nextEvent, nextTile);
grouper = new Grouper(
this,
mxEv,
prevEvent,
lastShownEvent,
this.props.layout,
nextEvent,
nextTile,
);
}
}
if (!grouper) {
@ -981,6 +989,7 @@ abstract class BaseGrouper {
public readonly event: MatrixEvent,
public readonly prevEvent: MatrixEvent,
public readonly lastShownEvent: MatrixEvent,
protected readonly layout: Layout,
public readonly nextEvent?: MatrixEvent,
public readonly nextEventTile?: MatrixEvent,
) {
@ -1107,6 +1116,7 @@ class CreationGrouper extends BaseGrouper {
onToggle={panel.onHeightChanged} // Update scroll state
summaryMembers={[ev.sender]}
summaryText={summaryText}
layout={this.layout}
>
{ eventTiles }
</EventListSummary>,
@ -1134,10 +1144,11 @@ class RedactionGrouper extends BaseGrouper {
ev: MatrixEvent,
prevEvent: MatrixEvent,
lastShownEvent: MatrixEvent,
layout: Layout,
nextEvent: MatrixEvent,
nextEventTile: MatrixEvent,
) {
super(panel, ev, prevEvent, lastShownEvent, nextEvent, nextEventTile);
super(panel, ev, prevEvent, lastShownEvent, layout, nextEvent, nextEventTile);
this.events = [ev];
}
@ -1202,6 +1213,7 @@ class RedactionGrouper extends BaseGrouper {
onToggle={panel.onHeightChanged} // Update scroll state
summaryMembers={Array.from(senders)}
summaryText={_t("%(count)s messages deleted.", { count: eventTiles.length })}
layout={this.layout}
>
{ eventTiles }
</EventListSummary>,
@ -1230,8 +1242,9 @@ class MemberGrouper extends BaseGrouper {
public readonly event: MatrixEvent,
public readonly prevEvent: MatrixEvent,
public readonly lastShownEvent: MatrixEvent,
protected readonly layout: Layout,
) {
super(panel, event, prevEvent, lastShownEvent);
super(panel, event, prevEvent, lastShownEvent, layout);
this.events = [event];
}
@ -1306,6 +1319,7 @@ class MemberGrouper extends BaseGrouper {
events={this.events}
onToggle={panel.onHeightChanged} // Update scroll state
startExpanded={highlightInMels}
layout={this.layout}
>
{ eventTiles }
</MemberEventListSummary>,

View file

@ -183,8 +183,14 @@ export default class ScrollPanel extends React.Component<IProps> {
private readonly itemlist = createRef<HTMLOListElement>();
private unmounted = false;
private scrollTimeout: Timer;
// Are we currently trying to backfill?
private isFilling: boolean;
// Is the current fill request caused by a props update?
private isFillingDueToPropsUpdate = false;
// Did another request to check the fill state arrive while we were trying to backfill?
private fillRequestWhileRunning: boolean;
// Is that next fill request scheduled because of a props update?
private pendingFillDueToPropsUpdate: boolean;
private scrollState: IScrollState;
private preventShrinkingState: IPreventShrinkingState;
private unfillDebouncer: number;
@ -213,7 +219,7 @@ export default class ScrollPanel extends React.Component<IProps> {
// adding events to the top).
//
// This will also re-check the fill state, in case the paginate was inadequate
this.checkScroll();
this.checkScroll(true);
this.updatePreventShrinking();
}
@ -251,12 +257,12 @@ export default class ScrollPanel extends React.Component<IProps> {
// after an update to the contents of the panel, check that the scroll is
// where it ought to be, and set off pagination requests if necessary.
public checkScroll = () => {
public checkScroll = (isFromPropsUpdate = false) => {
if (this.unmounted) {
return;
}
this.restoreSavedScrollState();
this.checkFillState();
this.checkFillState(0, isFromPropsUpdate);
};
// return true if the content is fully scrolled down right now; else false.
@ -319,7 +325,7 @@ export default class ScrollPanel extends React.Component<IProps> {
}
// check the scroll state and send out backfill requests if necessary.
public checkFillState = async (depth = 0): Promise<void> => {
public checkFillState = async (depth = 0, isFromPropsUpdate = false): Promise<void> => {
if (this.unmounted) {
return;
}
@ -355,14 +361,20 @@ export default class ScrollPanel extends React.Component<IProps> {
// don't allow more than 1 chain of calls concurrently
// do make a note when a new request comes in while already running one,
// so we can trigger a new chain of calls once done.
// However, we make an exception for when we're already filling due to a
// props (or children) update, because very often the children include
// spinners to say whether we're paginating or not, so this would cause
// infinite paginating.
if (isFirstCall) {
if (this.isFilling) {
if (this.isFilling && !this.isFillingDueToPropsUpdate) {
debuglog("isFilling: not entering while request is ongoing, marking for a subsequent request");
this.fillRequestWhileRunning = true;
this.pendingFillDueToPropsUpdate = isFromPropsUpdate;
return;
}
debuglog("isFilling: setting");
this.isFilling = true;
this.isFillingDueToPropsUpdate = isFromPropsUpdate;
}
const itemlist = this.itemlist.current;
@ -393,11 +405,14 @@ export default class ScrollPanel extends React.Component<IProps> {
if (isFirstCall) {
debuglog("isFilling: clearing");
this.isFilling = false;
this.isFillingDueToPropsUpdate = false;
}
if (this.fillRequestWhileRunning) {
const refillDueToPropsUpdate = this.pendingFillDueToPropsUpdate;
this.fillRequestWhileRunning = false;
this.checkFillState();
this.pendingFillDueToPropsUpdate = false;
this.checkFillState(0, refillDueToPropsUpdate);
}
};

View file

@ -250,7 +250,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
&nbsp;
{ _t("You can change this at any time from room settings.") }
</p>;
} else if (this.state.joinRule === JoinRule.Public) {
} else if (this.state.joinRule === JoinRule.Public && this.props.parentSpace) {
publicPrivateLabel = <p>
{ _t(
"Anyone will be able to find and join this room, not just members of <SpaceName/>.", {}, {
@ -260,6 +260,12 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
&nbsp;
{ _t("You can change this at any time from room settings.") }
</p>;
} else if (this.state.joinRule === JoinRule.Public) {
publicPrivateLabel = <p>
{ _t("Anyone will be able to find and join this room.") }
&nbsp;
{ _t("You can change this at any time from room settings.") }
</p>;
} else if (this.state.joinRule === JoinRule.Invite) {
publicPrivateLabel = <p>
{ _t(

View file

@ -17,9 +17,12 @@ limitations under the License.
import React from 'react';
import { _t } from '../../../languageHandler';
import BaseDialog from "..//dialogs/BaseDialog";
import DialogButtons from "./DialogButtons";
import classNames from 'classnames';
import AccessibleButton from './AccessibleButton';
import { getDesktopCapturerSources } from "matrix-js-sdk/src/webrtc/call";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import TabbedView, { Tab, TabLocation } from '../../structures/TabbedView';
export interface DesktopCapturerSource {
id: string;
@ -28,62 +31,70 @@ export interface DesktopCapturerSource {
}
export enum Tabs {
Screens = "screens",
Windows = "windows",
Screens = "screen",
Windows = "window",
}
export interface DesktopCapturerSourceIProps {
export interface ExistingSourceIProps {
source: DesktopCapturerSource;
onSelect(source: DesktopCapturerSource): void;
selected: boolean;
}
export class ExistingSource extends React.Component<DesktopCapturerSourceIProps> {
constructor(props) {
export class ExistingSource extends React.Component<ExistingSourceIProps> {
constructor(props: ExistingSourceIProps) {
super(props);
}
onClick = (ev) => {
private onClick = (): void => {
this.props.onSelect(this.props.source);
};
render() {
const thumbnailClasses = classNames({
mx_desktopCapturerSourcePicker_source_thumbnail: true,
mx_desktopCapturerSourcePicker_source_thumbnail_selected: this.props.selected,
});
return (
<AccessibleButton
className="mx_desktopCapturerSourcePicker_stream_button"
className="mx_desktopCapturerSourcePicker_source"
title={this.props.source.name}
onClick={this.onClick}
>
<img
className="mx_desktopCapturerSourcePicker_stream_thumbnail"
className={thumbnailClasses}
src={this.props.source.thumbnailURL}
/>
<span className="mx_desktopCapturerSourcePicker_stream_name">{ this.props.source.name }</span>
<span className="mx_desktopCapturerSourcePicker_source_name">{ this.props.source.name }</span>
</AccessibleButton>
);
}
}
export interface DesktopCapturerSourcePickerIState {
export interface PickerIState {
selectedTab: Tabs;
sources: Array<DesktopCapturerSource>;
selectedSource: DesktopCapturerSource | null;
}
export interface DesktopCapturerSourcePickerIProps {
export interface PickerIProps {
onFinished(source: DesktopCapturerSource): void;
}
@replaceableComponent("views.elements.DesktopCapturerSourcePicker")
export default class DesktopCapturerSourcePicker extends React.Component<
DesktopCapturerSourcePickerIProps,
DesktopCapturerSourcePickerIState
> {
interval;
PickerIProps,
PickerIState
> {
interval: number;
constructor(props) {
constructor(props: PickerIProps) {
super(props);
this.state = {
selectedTab: Tabs.Screens,
sources: [],
selectedSource: null,
};
}
@ -107,69 +118,61 @@ export default class DesktopCapturerSourcePicker extends React.Component<
clearInterval(this.interval);
}
onSelect = (source) => {
this.props.onFinished(source);
private onSelect = (source: DesktopCapturerSource): void => {
this.setState({ selectedSource: source });
};
onScreensClick = (ev) => {
this.setState({ selectedTab: Tabs.Screens });
private onShare = (): void => {
this.props.onFinished(this.state.selectedSource);
};
onWindowsClick = (ev) => {
this.setState({ selectedTab: Tabs.Windows });
private onTabChange = (): void => {
this.setState({ selectedSource: null });
};
onCloseClick = (ev) => {
private onCloseClick = (): void => {
this.props.onFinished(null);
};
render() {
let sources;
if (this.state.selectedTab === Tabs.Screens) {
sources = this.state.sources
.filter((source) => {
return source.id.startsWith("screen");
})
.map((source) => {
return <ExistingSource source={source} onSelect={this.onSelect} key={source.id} />;
});
} else {
sources = this.state.sources
.filter((source) => {
return source.id.startsWith("window");
})
.map((source) => {
return <ExistingSource source={source} onSelect={this.onSelect} key={source.id} />;
});
}
private getTab(type: "screen" | "window", label: string): Tab {
const sources = this.state.sources.filter((source) => source.id.startsWith(type)).map((source) => {
return (
<ExistingSource
selected={this.state.selectedSource?.id === source.id}
source={source}
onSelect={this.onSelect}
key={source.id}
/>
);
});
const buttonStyle = "mx_desktopCapturerSourcePicker_tabLabel";
const screensButtonStyle = buttonStyle + ((this.state.selectedTab === Tabs.Screens) ? "_selected" : "");
const windowsButtonStyle = buttonStyle + ((this.state.selectedTab === Tabs.Windows) ? "_selected" : "");
return new Tab(type, label, null, (
<div className="mx_desktopCapturerSourcePicker_tab">
{ sources }
</div>
));
}
render() {
const tabs = [
this.getTab("screen", _t("Share entire screen")),
this.getTab("window", _t("Application window")),
];
return (
<BaseDialog
className="mx_desktopCapturerSourcePicker"
onFinished={this.onCloseClick}
title={_t("Share your screen")}
title={_t("Share content")}
>
<div className="mx_desktopCapturerSourcePicker_tabLabels">
<AccessibleButton
className={screensButtonStyle}
onClick={this.onScreensClick}
>
{ _t("Screens") }
</AccessibleButton>
<AccessibleButton
className={windowsButtonStyle}
onClick={this.onWindowsClick}
>
{ _t("Windows") }
</AccessibleButton>
</div>
<div className="mx_desktopCapturerSourcePicker_panel">
{ sources }
</div>
<TabbedView tabs={tabs} tabLocation={TabLocation.TOP} onChange={this.onTabChange} />
<DialogButtons
primaryButton={_t("Share")}
hasCancel={true}
onCancel={this.onCloseClick}
onPrimaryButtonClick={this.onShare}
primaryDisabled={!this.state.selectedSource}
/>
</BaseDialog>
);
}

View file

@ -22,6 +22,7 @@ import MemberAvatar from '../avatars/MemberAvatar';
import { _t } from '../../../languageHandler';
import { useStateToggle } from "../../../hooks/useStateToggle";
import AccessibleButton from "./AccessibleButton";
import { Layout } from '../../../settings/Layout';
interface IProps {
// An array of member events to summarise
@ -38,6 +39,8 @@ interface IProps {
children: ReactNode[];
// Called when the event list expansion is toggled
onToggle?(): void;
// The layout currently used
layout?: Layout;
}
const EventListSummary: React.FC<IProps> = ({
@ -48,6 +51,7 @@ const EventListSummary: React.FC<IProps> = ({
startExpanded,
summaryMembers = [],
summaryText,
layout,
}) => {
const [expanded, toggleExpanded] = useStateToggle(startExpanded);
@ -63,7 +67,7 @@ const EventListSummary: React.FC<IProps> = ({
// If we are only given few events then just pass them through
if (events.length < threshold) {
return (
<li className="mx_EventListSummary" data-scroll-tokens={eventIds} data-expanded={true}>
<li className="mx_EventListSummary" data-scroll-tokens={eventIds} data-expanded={true} data-layout={layout}>
{ children }
</li>
);
@ -92,7 +96,7 @@ const EventListSummary: React.FC<IProps> = ({
}
return (
<li className="mx_EventListSummary" data-scroll-tokens={eventIds} data-expanded={expanded + ""}>
<li className="mx_EventListSummary" data-scroll-tokens={eventIds} data-expanded={expanded + ""} data-layout={layout}>
<AccessibleButton className="mx_EventListSummary_toggle" onClick={toggleExpanded} aria-expanded={expanded}>
{ expanded ? _t('collapse') : _t('expand') }
</AccessibleButton>
@ -103,6 +107,7 @@ const EventListSummary: React.FC<IProps> = ({
EventListSummary.defaultProps = {
startExpanded: false,
layout: Layout.Group,
};
export default EventListSummary;

View file

@ -25,12 +25,15 @@ import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
import { isValid3pidInvite } from "../../../RoomInvite";
import EventListSummary from "./EventListSummary";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { Layout } from '../../../settings/Layout';
interface IProps extends Omit<ComponentProps<typeof EventListSummary>, "summaryText" | "summaryMembers"> {
// The maximum number of names to show in either each summary e.g. 2 would result "A, B and 234 others left"
summaryLength?: number;
// The maximum number of avatars to display in the summary
avatarsMaxLength?: number;
// The currently selected layout
layout: Layout;
}
interface IUserEvents {
@ -67,6 +70,7 @@ export default class MemberEventListSummary extends React.Component<IProps> {
summaryLength: 1,
threshold: 3,
avatarsMaxLength: 5,
layout: Layout.Group,
};
shouldComponentUpdate(nextProps) {
@ -453,6 +457,7 @@ export default class MemberEventListSummary extends React.Component<IProps> {
startExpanded={this.props.startExpanded}
children={this.props.children}
summaryMembers={[...latestUserAvatarMember.values()]}
layout={this.props.layout}
summaryText={this.generateSummary(aggregate.names, orderedTransitionSequences)} />;
}
}

View file

@ -25,6 +25,7 @@ import { CallErrorCode, CallState } from 'matrix-js-sdk/src/webrtc/call';
import InfoTooltip, { InfoTooltipKind } from '../elements/InfoTooltip';
import classNames from 'classnames';
import AccessibleTooltipButton from '../elements/AccessibleTooltipButton';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
interface IProps {
mxEvent: MatrixEvent;
@ -69,6 +70,18 @@ export default class CallEvent extends React.Component<IProps, IState> {
this.setState({ callState: newState });
};
private renderCallBackButton(text: string): JSX.Element {
return (
<AccessibleButton
className="mx_CallEvent_content_button mx_CallEvent_content_button_callBack"
onClick={this.props.callEventGrouper.callBack}
kind="primary"
>
<span> { text } </span>
</AccessibleButton>
);
}
private renderContent(state: CallState | CustomCallState): JSX.Element {
if (state === CallState.Ringing) {
const silenceClass = classNames({
@ -103,8 +116,18 @@ export default class CallEvent extends React.Component<IProps, IState> {
}
if (state === CallState.Ended) {
const hangupReason = this.props.callEventGrouper.hangupReason;
const gotRejected = this.props.callEventGrouper.gotRejected;
const rejectParty = this.props.callEventGrouper.rejectParty;
if ([CallErrorCode.UserHangup, "user hangup"].includes(hangupReason) || !hangupReason) {
if (gotRejected) {
const weDeclinedCall = MatrixClientPeg.get().getUserId() === rejectParty;
return (
<div className="mx_CallEvent_content">
{ weDeclinedCall ? _t("You declined this call") : _t("They declined this call") }
{ this.renderCallBackButton(weDeclinedCall ? _t("Call back") : _t("Call again")) }
</div>
);
} else if (([CallErrorCode.UserHangup, "user hangup"].includes(hangupReason) || !hangupReason)) {
// workaround for https://github.com/vector-im/element-web/issues/5178
// it seems Android randomly sets a reason of "user hangup" which is
// interpreted as an error code :(
@ -116,6 +139,13 @@ export default class CallEvent extends React.Component<IProps, IState> {
{ _t("This call has ended") }
</div>
);
} else if (hangupReason === CallErrorCode.InviteTimeout) {
return (
<div className="mx_CallEvent_content">
{ _t("They didn't pick up") }
{ this.renderCallBackButton(_t("Call again")) }
</div>
);
}
let reason;
@ -133,8 +163,6 @@ export default class CallEvent extends React.Component<IProps, IState> {
// (as opposed to an error code they gave but we don't know about,
// in which case we show the error code)
reason = _t("An unknown error occurred");
} else if (hangupReason === CallErrorCode.InviteTimeout) {
reason = _t("No answer");
} else if (hangupReason === CallErrorCode.UserBusy) {
reason = _t("The user you called is busy.");
} else {
@ -163,13 +191,7 @@ export default class CallEvent extends React.Component<IProps, IState> {
return (
<div className="mx_CallEvent_content">
{ _t("You missed this call") }
<AccessibleButton
className="mx_CallEvent_content_button mx_CallEvent_content_button_callBack"
onClick={this.props.callEventGrouper.callBack}
kind="primary"
>
<span> { _t("Call back") } </span>
</AccessibleButton>
{ this.renderCallBackButton(_t("Call back")) }
</div>
);
}
@ -186,11 +208,17 @@ export default class CallEvent extends React.Component<IProps, IState> {
const sender = event.sender ? event.sender.name : event.getSender();
const isVoice = this.props.callEventGrouper.isVoice;
const callType = isVoice ? _t("Voice call") : _t("Video call");
const content = this.renderContent(this.state.callState);
const callState = this.state.callState;
const hangupReason = this.props.callEventGrouper.hangupReason;
const content = this.renderContent(callState);
const className = classNames({
mx_CallEvent: true,
mx_CallEvent_voice: isVoice,
mx_CallEvent_video: !isVoice,
mx_CallEvent_missed: (
callState === CustomCallState.Missed ||
(callState === CallState.Ended && hangupReason === CallErrorCode.InviteTimeout)
),
});
return (

View file

@ -342,8 +342,11 @@ export default class MessageComposer extends React.Component<IProps, IState> {
private onVoiceStoreUpdate = () => {
const recording = VoiceRecordingStore.instance.activeRecording;
this.setState({ haveRecording: !!recording });
if (recording) {
// Delay saying we have a recording until it is started, as we might not yet have A/V permissions
recording.on(RecordingState.Started, () => {
this.setState({ haveRecording: !!VoiceRecordingStore.instance.activeRecording });
});
// We show a little heads up that the recording is about to automatically end soon. The 3s
// display time is completely arbitrary. Note that we don't need to deregister the listener
// because the recording instance will clean that up for us.
@ -351,6 +354,8 @@ export default class MessageComposer extends React.Component<IProps, IState> {
this.setState({ recordingTimeLeftSeconds: secondsLeft });
setTimeout(() => this.setState({ recordingTimeLeftSeconds: null }), 3000);
});
} else {
this.setState({ haveRecording: false });
}
};

View file

@ -67,15 +67,21 @@ export default class ReplyTile extends React.PureComponent<IProps> {
};
private onClick = (e: React.MouseEvent): void => {
// This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Riot when clicked.
e.preventDefault();
dis.dispatch({
action: 'view_room',
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
});
const clickTarget = e.target as HTMLElement;
// Following a link within a reply should not dispatch the `view_room` action
// so that the browser can direct the user to the correct location
// The exception being the link wrapping the reply
if (clickTarget.tagName.toLowerCase() !== "a" || clickTarget.closest("a") === null) {
// This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Riot when clicked.
e.preventDefault();
dis.dispatch({
action: 'view_room',
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
});
}
};
render() {

View file

@ -29,6 +29,8 @@ import RoomTopic from "../elements/RoomTopic";
import RoomName from "../elements/RoomName";
import { PlaceCallType } from "../../../CallHandler";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import Modal from '../../../Modal';
import InfoDialog from "../dialogs/InfoDialog";
import { throttle } from 'lodash';
import { MatrixEvent, Room, RoomState } from 'matrix-js-sdk/src';
import { E2EStatus } from '../../../utils/ShieldUtils';
@ -87,6 +89,14 @@ export default class RoomHeader extends React.Component<IProps> {
this.forceUpdate();
}, 500, { leading: true, trailing: true });
private displayInfoDialogAboutScreensharing() {
Modal.createDialog(InfoDialog, {
title: _t("Screen sharing is here!"),
description: _t("You can now share your screen by pressing the \"screen share\" " +
"button during a call. You can even do this in audio calls if both sides support it!"),
});
}
public render() {
let searchStatus = null;
@ -185,8 +195,8 @@ export default class RoomHeader extends React.Component<IProps> {
videoCallButton =
<AccessibleTooltipButton
className="mx_RoomHeader_button mx_RoomHeader_videoCallButton"
onClick={(ev) => this.props.onCallPlaced(
ev.shiftKey ? PlaceCallType.ScreenSharing : PlaceCallType.Video)}
onClick={(ev) => ev.shiftKey ?
this.displayInfoDialogAboutScreensharing() : this.props.onCallPlaced(PlaceCallType.Video)}
title={_t("Video call")} />;
}

View file

@ -23,9 +23,21 @@ interface IProps {
feed: CallFeed;
}
export default class AudioFeed extends React.Component<IProps> {
interface IState {
audioMuted: boolean;
}
export default class AudioFeed extends React.Component<IProps, IState> {
private element = createRef<HTMLAudioElement>();
constructor(props: IProps) {
super(props);
this.state = {
audioMuted: this.props.feed.isAudioMuted(),
};
}
componentDidMount() {
MediaDeviceHandler.instance.addListener(
MediaDeviceHandlerEvent.AudioOutputChanged,
@ -62,6 +74,7 @@ export default class AudioFeed extends React.Component<IProps> {
private playMedia() {
const element = this.element.current;
if (!element) return;
this.onAudioOutputChanged(MediaDeviceHandler.getAudioOutput());
element.muted = false;
element.srcObject = this.props.feed.stream;
@ -85,6 +98,7 @@ export default class AudioFeed extends React.Component<IProps> {
private stopMedia() {
const element = this.element.current;
if (!element) return;
element.pause();
element.src = null;
@ -96,10 +110,16 @@ export default class AudioFeed extends React.Component<IProps> {
}
private onNewStream = () => {
this.setState({
audioMuted: this.props.feed.isAudioMuted(),
});
this.playMedia();
};
render() {
// Do not render the audio element if there is no audio track
if (this.state.audioMuted) return null;
return (
<audio ref={this.element} />
);

View file

@ -146,7 +146,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
document.addEventListener("mousemove", this.onMoving);
document.addEventListener("mouseup", this.onEndMoving);
window.addEventListener("resize", this.snap);
window.addEventListener("resize", this.onResize);
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on(CallEvent.RemoteHoldUnhold, this.onCallRemoteHold);
}
@ -156,7 +156,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
MatrixClientPeg.get().removeListener(CallEvent.RemoteHoldUnhold, this.onCallRemoteHold);
document.removeEventListener("mousemove", this.onMoving);
document.removeEventListener("mouseup", this.onEndMoving);
window.removeEventListener("resize", this.snap);
window.removeEventListener("resize", this.onResize);
if (this.roomStoreToken) {
this.roomStoreToken.remove();
}
@ -164,6 +164,10 @@ export default class CallPreview extends React.Component<IProps, IState> {
SettingsStore.unwatchSetting(this.settingsWatcherRef);
}
private onResize = (): void => {
this.snap(false);
};
private animationCallback = () => {
// If the PiP isn't being dragged and there is only a tiny difference in
// the desiredTranslation and translation, quit the animationCallback
@ -207,7 +211,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
}
}
private snap = () => {
private snap(animate?: boolean): void {
const translationX = this.desiredTranslationX;
const translationY = this.desiredTranslationY;
// We subtract the PiP size from the window size in order to calculate
@ -236,10 +240,17 @@ export default class CallPreview extends React.Component<IProps, IState> {
this.desiredTranslationY = PADDING.top;
}
// We start animating here because we want the PiP to move when we're
// resizing the window
this.scheduledUpdate.mark();
};
if (animate) {
// We start animating here because we want the PiP to move when we're
// resizing the window
this.scheduledUpdate.mark();
} else {
this.setState({
translationX: this.desiredTranslationX,
translationY: this.desiredTranslationY,
});
}
}
private onRoomViewStoreUpdate = () => {
if (RoomViewStore.getRoomId() === this.state.roomId) return;
@ -310,7 +321,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
private onEndMoving = () => {
this.moving = false;
this.snap();
this.snap(true);
};
public render() {
@ -333,6 +344,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
secondaryCall={this.state.secondaryCall}
pipMode={true}
onMouseDownOnHeader={this.onStartMoving}
onResize={this.onResize}
/>
</div>
);

View file

@ -1,6 +1,7 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -32,6 +33,10 @@ import { avatarUrlForMember } from '../../../Avatar';
import DialpadContextMenu from '../context_menus/DialpadContextMenu';
import { CallFeed } from 'matrix-js-sdk/src/webrtc/callFeed';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import DesktopCapturerSourcePicker from "../elements/DesktopCapturerSourcePicker";
import Modal from '../../../Modal';
import { SDPStreamMetadataPurpose } from 'matrix-js-sdk/src/webrtc/callEventTypes';
import CallViewSidebar from './CallViewSidebar';
interface IProps {
// The call for us to display
@ -59,11 +64,15 @@ interface IState {
isRemoteOnHold: boolean;
micMuted: boolean;
vidMuted: boolean;
screensharing: boolean;
callState: CallState;
controlsVisible: boolean;
hoveringControls: boolean;
showMoreMenu: boolean;
showDialpad: boolean;
feeds: CallFeed[];
primaryFeed: CallFeed;
secondaryFeeds: Array<CallFeed>;
sidebarShown: boolean;
}
function getFullScreenElement() {
@ -94,7 +103,7 @@ function exitFullscreen() {
if (exitMethod) exitMethod.call(document);
}
const CONTROLS_HIDE_DELAY = 1000;
const CONTROLS_HIDE_DELAY = 2000;
// Height of the header duplicated from CSS because we need to subtract it from our max
// height to get the max height of the video
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)
@ -110,16 +119,22 @@ export default class CallView extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
const { primary, secondary } = this.getOrderedFeeds(this.props.call.getFeeds());
this.state = {
isLocalOnHold: this.props.call.isLocalOnHold(),
isRemoteOnHold: this.props.call.isRemoteOnHold(),
micMuted: this.props.call.isMicrophoneMuted(),
vidMuted: this.props.call.isLocalVideoMuted(),
screensharing: this.props.call.isScreensharing(),
callState: this.props.call.state,
controlsVisible: true,
hoveringControls: false,
showMoreMenu: false,
showDialpad: false,
feeds: this.props.call.getFeeds(),
primaryFeed: primary,
secondaryFeeds: secondary,
sidebarShown: true,
};
this.updateCallListeners(null, this.props.call);
@ -194,7 +209,11 @@ export default class CallView extends React.Component<IProps, IState> {
};
private onFeedsChanged = (newFeeds: Array<CallFeed>) => {
this.setState({ feeds: newFeeds });
const { primary, secondary } = this.getOrderedFeeds(newFeeds);
this.setState({
primaryFeed: primary,
secondaryFeeds: secondary,
});
};
private onCallLocalHoldUnhold = () => {
@ -227,6 +246,7 @@ export default class CallView extends React.Component<IProps, IState> {
};
private onControlsHideTimer = () => {
if (this.state.hoveringControls || this.state.showDialpad || this.state.showMoreMenu) return;
this.controlsHideTimer = null;
this.setState({
controlsVisible: false,
@ -237,7 +257,30 @@ export default class CallView extends React.Component<IProps, IState> {
this.showControls();
};
private showControls() {
private getOrderedFeeds(feeds: Array<CallFeed>): { primary: CallFeed, secondary: Array<CallFeed> } {
let primary;
// Try to use a screensharing as primary, a remote one if possible
const screensharingFeeds = feeds.filter((feed) => feed.purpose === SDPStreamMetadataPurpose.Screenshare);
primary = screensharingFeeds.find((feed) => !feed.isLocal()) || screensharingFeeds[0];
// If we didn't find remote screen-sharing stream, try to find any remote stream
if (!primary) {
primary = feeds.find((feed) => !feed.isLocal());
}
const secondary = [...feeds];
// Remove the primary feed from the array
if (primary) secondary.splice(secondary.indexOf(primary), 1);
secondary.sort((a, b) => {
if (a.isLocal() && !b.isLocal()) return -1;
if (!a.isLocal() && b.isLocal()) return 1;
return 0;
});
return { primary, secondary };
}
private showControls(): void {
if (this.state.showMoreMenu || this.state.showDialpad) return;
if (!this.state.controlsVisible) {
@ -251,73 +294,62 @@ export default class CallView extends React.Component<IProps, IState> {
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
}
private onDialpadClick = () => {
private onDialpadClick = (): void => {
if (!this.state.showDialpad) {
if (this.controlsHideTimer) {
clearTimeout(this.controlsHideTimer);
this.controlsHideTimer = null;
}
this.setState({
showDialpad: true,
controlsVisible: true,
});
this.setState({ showDialpad: true });
this.showControls();
} else {
if (this.controlsHideTimer !== null) {
clearTimeout(this.controlsHideTimer);
}
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
this.setState({
showDialpad: false,
});
this.setState({ showDialpad: false });
}
};
private onMicMuteClick = () => {
private onMicMuteClick = (): void => {
const newVal = !this.state.micMuted;
this.props.call.setMicrophoneMuted(newVal);
this.setState({ micMuted: newVal });
};
private onVidMuteClick = () => {
private onVidMuteClick = (): void => {
const newVal = !this.state.vidMuted;
this.props.call.setLocalVideoMuted(newVal);
this.setState({ vidMuted: newVal });
};
private onMoreClick = () => {
if (this.controlsHideTimer) {
clearTimeout(this.controlsHideTimer);
this.controlsHideTimer = null;
}
private onScreenshareClick = async (): Promise<void> => {
const isScreensharing = await this.props.call.setScreensharingEnabled(
!this.state.screensharing,
async (): Promise<DesktopCapturerSource> => {
const { finished } = Modal.createDialog(DesktopCapturerSourcePicker);
const [source] = await finished;
return source;
},
);
this.setState({
showMoreMenu: true,
controlsVisible: true,
sidebarShown: true,
screensharing: isScreensharing,
});
};
private closeDialpad = () => {
this.setState({
showDialpad: false,
});
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
private onMoreClick = (): void => {
this.setState({ showMoreMenu: true });
this.showControls();
};
private closeContextMenu = () => {
this.setState({
showMoreMenu: false,
});
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
private closeDialpad = (): void => {
this.setState({ showDialpad: false });
};
private closeContextMenu = (): void => {
this.setState({ showMoreMenu: false });
};
// we register global shortcuts here, they *must not conflict* with local shortcuts elsewhere or both will fire
// Note that this assumes we always have a CallView on screen at any given time
// CallHandler would probably be a better place for this
private onNativeKeyDown = ev => {
private onNativeKeyDown = (ev): void => {
let handled = false;
const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
@ -347,7 +379,16 @@ export default class CallView extends React.Component<IProps, IState> {
}
};
private onRoomAvatarClick = () => {
private onCallControlsMouseEnter = (): void => {
this.setState({ hoveringControls: true });
this.showControls();
};
private onCallControlsMouseLeave = (): void => {
this.setState({ hoveringControls: false });
};
private onRoomAvatarClick = (): void => {
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
dis.dispatch({
action: 'view_room',
@ -355,7 +396,7 @@ export default class CallView extends React.Component<IProps, IState> {
});
};
private onSecondaryRoomAvatarClick = () => {
private onSecondaryRoomAvatarClick = (): void => {
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.secondaryCall);
dis.dispatch({
@ -364,50 +405,30 @@ export default class CallView extends React.Component<IProps, IState> {
});
};
private onCallResumeClick = () => {
private onCallResumeClick = (): void => {
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
CallHandler.sharedInstance().setActiveCallRoomId(userFacingRoomId);
};
private onTransferClick = () => {
private onTransferClick = (): void => {
const transfereeCall = CallHandler.sharedInstance().getTransfereeForCallId(this.props.call.callId);
this.props.call.transferToCall(transfereeCall);
};
public render() {
const client = MatrixClientPeg.get();
const callRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
const secondaryCallRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.secondaryCall);
const callRoom = client.getRoom(callRoomId);
const secCallRoom = this.props.secondaryCall ? client.getRoom(secondaryCallRoomId) : null;
private onHangupClick = (): void => {
dis.dispatch({
action: 'hangup',
room_id: CallHandler.sharedInstance().roomIdForCall(this.props.call),
});
};
let dialPad;
let contextMenu;
if (this.state.showDialpad) {
dialPad = <DialpadContextMenu
{...alwaysAboveRightOf(
this.dialpadButton.current.getBoundingClientRect(),
ChevronFace.None,
CONTEXT_MENU_VPADDING,
)}
onFinished={this.closeDialpad}
call={this.props.call}
/>;
}
if (this.state.showMoreMenu) {
contextMenu = <CallContextMenu
{...alwaysAboveLeftOf(
this.contextMenuButton.current.getBoundingClientRect(),
ChevronFace.None,
CONTEXT_MENU_VPADDING,
)}
onFinished={this.closeContextMenu}
call={this.props.call}
/>;
}
private onToggleSidebar = (): void => {
this.setState({
sidebarShown: !this.state.sidebarShown,
});
};
private renderCallControls(): JSX.Element {
const micClasses = classNames({
mx_CallView_callControls_button: true,
mx_CallView_callControls_button_micOn: !this.state.micMuted,
@ -420,6 +441,18 @@ export default class CallView extends React.Component<IProps, IState> {
mx_CallView_callControls_button_vidOff: this.state.vidMuted,
});
const screensharingClasses = classNames({
mx_CallView_callControls_button: true,
mx_CallView_callControls_button_screensharingOn: this.state.screensharing,
mx_CallView_callControls_button_screensharingOff: !this.state.screensharing,
});
const sidebarButtonClasses = classNames({
mx_CallView_callControls_button: true,
mx_CallView_callControls_button_sidebarOn: this.state.sidebarShown,
mx_CallView_callControls_button_sidebarOff: !this.state.sidebarShown,
});
// Put the other states of the mic/video icons in the document to make sure they're cached
// (otherwise the icon disappears briefly when toggled)
const micCacheClasses = classNames({
@ -441,59 +474,121 @@ export default class CallView extends React.Component<IProps, IState> {
mx_CallView_callControls_hidden: !this.state.controlsVisible,
});
const vidMuteButton = this.props.call.type === CallType.Video ? <AccessibleButton
className={vidClasses}
onClick={this.onVidMuteClick}
/> : null;
// We don't support call upgrades (yet) so hide the video mute button in voice calls
let vidMuteButton;
if (this.props.call.type === CallType.Video) {
vidMuteButton = (
<AccessibleButton
className={vidClasses}
onClick={this.onVidMuteClick}
/>
);
}
// Screensharing is possible, if we can send a second stream and
// identify it using SDPStreamMetadata or if we can replace the already
// existing usermedia track by a screensharing track. We also need to be
// connected to know the state of the other side
let screensharingButton;
if (
(this.props.call.opponentSupportsSDPStreamMetadata() || this.props.call.type === CallType.Video) &&
this.props.call.state === CallState.Connected
) {
screensharingButton = (
<AccessibleButton
className={screensharingClasses}
onClick={this.onScreenshareClick}
/>
);
}
// To show the sidebar we need secondary feeds, if we don't have them,
// we can hide this button. If we are in PiP, sidebar is also hidden, so
// we can hide the button too
let sidebarButton;
if (
!this.props.pipMode &&
(
this.state.primaryFeed?.purpose === SDPStreamMetadataPurpose.Screenshare ||
this.props.call.isScreensharing()
)
) {
sidebarButton = (
<AccessibleButton
className={sidebarButtonClasses}
onClick={this.onToggleSidebar}
/>
);
}
// The dial pad & 'more' button actions are only relevant in a connected call
// When not connected, we have to put something there to make the flexbox alignment correct
const dialpadButton = this.state.callState === CallState.Connected ? <ContextMenuButton
className="mx_CallView_callControls_button mx_CallView_callControls_dialpad"
inputRef={this.dialpadButton}
onClick={this.onDialpadClick}
isExpanded={this.state.showDialpad}
/> : <div className="mx_CallView_callControls_button mx_CallView_callControls_button_dialpad_hidden" />;
let contextMenuButton;
if (this.state.callState === CallState.Connected) {
contextMenuButton = (
<ContextMenuButton
className="mx_CallView_callControls_button mx_CallView_callControls_button_more"
onClick={this.onMoreClick}
inputRef={this.contextMenuButton}
isExpanded={this.state.showMoreMenu}
/>
);
}
let dialpadButton;
if (this.state.callState === CallState.Connected && this.props.call.opponentSupportsDTMF()) {
dialpadButton = (
<ContextMenuButton
className="mx_CallView_callControls_button mx_CallView_callControls_dialpad"
inputRef={this.dialpadButton}
onClick={this.onDialpadClick}
isExpanded={this.state.showDialpad}
/>
);
}
const contextMenuButton = this.state.callState === CallState.Connected ? <ContextMenuButton
className="mx_CallView_callControls_button mx_CallView_callControls_button_more"
onClick={this.onMoreClick}
inputRef={this.contextMenuButton}
isExpanded={this.state.showMoreMenu}
/> : <div className="mx_CallView_callControls_button mx_CallView_callControls_button_more_hidden" />;
// in the near future, the dial pad button will go on the left. For now, it's the nothing button
// because something needs to have margin-right: auto to make the alignment correct.
const callControls = <div className={callControlsClasses}>
{ dialpadButton }
<AccessibleButton
className={micClasses}
onClick={this.onMicMuteClick}
/>
<AccessibleButton
className="mx_CallView_callControls_button mx_CallView_callControls_button_hangup"
onClick={() => {
dis.dispatch({
action: 'hangup',
room_id: callRoomId,
});
}}
/>
{ vidMuteButton }
<div className={micCacheClasses} />
<div className={vidCacheClasses} />
{ contextMenuButton }
</div>;
return (
<div
className={callControlsClasses}
onMouseEnter={this.onCallControlsMouseEnter}
onMouseLeave={this.onCallControlsMouseLeave}
>
{ dialpadButton }
<AccessibleButton
className={micClasses}
onClick={this.onMicMuteClick}
/>
{ vidMuteButton }
<div className={micCacheClasses} />
<div className={vidCacheClasses} />
{ screensharingButton }
{ sidebarButton }
{ contextMenuButton }
<AccessibleButton
className="mx_CallView_callControls_button mx_CallView_callControls_button_hangup"
onClick={this.onHangupClick}
/>
</div>
);
}
public render() {
const client = MatrixClientPeg.get();
const callRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
const secondaryCallRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.secondaryCall);
const callRoom = client.getRoom(callRoomId);
const secCallRoom = this.props.secondaryCall ? client.getRoom(secondaryCallRoomId) : null;
const avatarSize = this.props.pipMode ? 76 : 160;
// The 'content' for the call, ie. the videos for a video call and profile picture
// for voice calls (fills the bg)
let contentView: React.ReactNode;
const transfereeCall = CallHandler.sharedInstance().getTransfereeForCallId(this.props.call.callId);
const isOnHold = this.state.isLocalOnHold || this.state.isRemoteOnHold;
const isScreensharing = this.props.call.isScreensharing();
const sidebarShown = this.state.sidebarShown;
const someoneIsScreensharing = this.props.call.getFeeds().some((feed) => {
return feed.purpose === SDPStreamMetadataPurpose.Screenshare;
});
const isVideoCall = this.props.call.type === CallType.Video;
let contentView: React.ReactNode;
let holdTransferContent;
if (transfereeCall) {
const transferTargetRoom = MatrixClientPeg.get().getRoom(
CallHandler.sharedInstance().roomIdForCall(this.props.call),
@ -539,9 +634,25 @@ export default class CallView extends React.Component<IProps, IState> {
</div>;
}
let sidebar;
if (
!isOnHold &&
!transfereeCall &&
sidebarShown &&
(isVideoCall || someoneIsScreensharing)
) {
sidebar = (
<CallViewSidebar
feeds={this.state.secondaryFeeds}
call={this.props.call}
pipMode={this.props.pipMode}
/>
);
}
// This is a bit messy. I can't see a reason to have two onHold/transfer screens
if (isOnHold || transfereeCall) {
if (this.props.call.type === CallType.Video) {
if (isVideoCall) {
const containerClasses = classNames({
mx_CallView_content: true,
mx_CallView_video: true,
@ -560,7 +671,7 @@ export default class CallView extends React.Component<IProps, IState> {
<div className={containerClasses} ref={this.contentRef} onMouseMove={this.onMouseMove}>
{ onHoldBackground }
{ holdTransferContent }
{ callControls }
{ this.renderCallControls() }
</div>
);
} else {
@ -585,7 +696,7 @@ export default class CallView extends React.Component<IProps, IState> {
</div>
</div>
{ holdTransferContent }
{ callControls }
{ this.renderCallControls() }
</div>
);
}
@ -599,77 +710,91 @@ export default class CallView extends React.Component<IProps, IState> {
mx_CallView_voice: true,
});
const feeds = this.props.call.getLocalFeeds().map((feed, i) => {
// Here we check to hide local audio feeds to achieve the same UI/UX
// as before. But once again this might be subject to change
if (feed.isVideoMuted()) return;
return (
<VideoFeed
key={i}
feed={feed}
call={this.props.call}
pipMode={this.props.pipMode}
onResize={this.props.onResize}
/>
);
});
// Saying "Connecting" here isn't really true, but the best thing
// I can come up with, but this might be subject to change as well
contentView = <div className={classes} onMouseMove={this.onMouseMove}>
{ feeds }
<div className="mx_CallView_voice_avatarsContainer">
<div className="mx_CallView_voice_avatarContainer" style={{ width: avatarSize, height: avatarSize }}>
<RoomAvatar
room={callRoom}
height={avatarSize}
width={avatarSize}
/>
contentView = (
<div
className={classes}
onMouseMove={this.onMouseMove}
>
{ sidebar }
<div className="mx_CallView_voice_avatarsContainer">
<div
className="mx_CallView_voice_avatarContainer"
style={{ width: avatarSize, height: avatarSize }}
>
<RoomAvatar
room={callRoom}
height={avatarSize}
width={avatarSize}
/>
</div>
</div>
<div className="mx_CallView_holdTransferContent">{ _t("Connecting") }</div>
{ this.renderCallControls() }
</div>
<div className="mx_CallView_holdTransferContent">{ _t("Connecting") }</div>
{ callControls }
</div>;
);
} else {
const containerClasses = classNames({
mx_CallView_content: true,
mx_CallView_video: true,
});
// TODO: Later the CallView should probably be reworked to support
// any number of feeds but now we can always expect there to be two
// feeds. This is because the js-sdk ignores any new incoming streams
const feeds = this.state.feeds.map((feed, i) => {
// Here we check to hide local audio feeds to achieve the same UI/UX
// as before. But once again this might be subject to change
if (feed.isVideoMuted() && feed.isLocal()) return;
return (
let toast;
if (someoneIsScreensharing) {
const presentingClasses = classNames({
mx_CallView_presenting: true,
mx_CallView_presenting_hidden: !this.state.controlsVisible,
});
const sharerName = this.state.primaryFeed.getMember().name;
let text = isScreensharing
? _t("You are presenting")
: _t('%(sharerName)s is presenting', { sharerName });
if (!this.state.sidebarShown && isVideoCall) {
text += " • " + (this.props.call.isLocalVideoMuted()
? _t("Your camera is turned off")
: _t("Your camera is still enabled"));
}
toast = (
<div className={presentingClasses}>
{ text }
</div>
);
}
contentView = (
<div
className={containerClasses}
ref={this.contentRef}
onMouseMove={this.onMouseMove}
>
{ toast }
{ sidebar }
<VideoFeed
key={i}
feed={feed}
feed={this.state.primaryFeed}
call={this.props.call}
pipMode={this.props.pipMode}
onResize={this.props.onResize}
primary={true}
/>
);
});
contentView = <div className={containerClasses} ref={this.contentRef} onMouseMove={this.onMouseMove}>
{ feeds }
{ callControls }
</div>;
{ this.renderCallControls() }
</div>
);
}
const callTypeText = this.props.call.type === CallType.Video ? _t("Video Call") : _t("Voice Call");
const callTypeText = isVideoCall ? _t("Video Call") : _t("Voice Call");
let myClassName;
let fullScreenButton;
if (this.props.call.type === CallType.Video && !this.props.pipMode) {
fullScreenButton = <div
className="mx_CallView_header_button mx_CallView_header_button_fullscreen"
onClick={this.onFullscreenClick}
title={_t("Fill Screen")}
/>;
if (!this.props.pipMode) {
fullScreenButton = (
<div
className="mx_CallView_header_button mx_CallView_header_button_fullscreen"
onClick={this.onFullscreenClick}
title={_t("Fill Screen")}
/>
);
}
let expandButton;
@ -686,10 +811,15 @@ export default class CallView extends React.Component<IProps, IState> {
{ expandButton }
</div>;
const callTypeIconClassName = classNames("mx_CallView_header_callTypeIcon", {
"mx_CallView_header_callTypeIcon_voice": !isVideoCall,
"mx_CallView_header_callTypeIcon_video": isVideoCall,
});
let header: React.ReactNode;
if (!this.props.pipMode) {
header = <div className="mx_CallView_header">
<div className="mx_CallView_header_phoneIcon" />
<div className={callTypeIconClassName} />
<span className="mx_CallView_header_callType">{ callTypeText }</span>
{ headerControls }
</div>;
@ -728,6 +858,32 @@ export default class CallView extends React.Component<IProps, IState> {
myClassName = 'mx_CallView_pip';
}
let dialPad;
if (this.state.showDialpad) {
dialPad = <DialpadContextMenu
{...alwaysAboveRightOf(
this.dialpadButton.current.getBoundingClientRect(),
ChevronFace.None,
CONTEXT_MENU_VPADDING,
)}
onFinished={this.closeDialpad}
call={this.props.call}
/>;
}
let contextMenu;
if (this.state.showMoreMenu) {
contextMenu = <CallContextMenu
{...alwaysAboveLeftOf(
this.contextMenuButton.current.getBoundingClientRect(),
ChevronFace.None,
CONTEXT_MENU_VPADDING,
)}
onFinished={this.closeContextMenu}
call={this.props.call}
/>;
}
return <div className={"mx_CallView " + myClassName}>
{ header }
{ contentView }

View file

@ -0,0 +1,53 @@
/*
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
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 { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import { CallFeed } from "matrix-js-sdk/src/webrtc/callFeed";
import VideoFeed from "./VideoFeed";
import classNames from "classnames";
interface IProps {
feeds: Array<CallFeed>;
call: MatrixCall;
pipMode: boolean;
}
export default class CallViewSidebar extends React.Component<IProps> {
render() {
const feeds = this.props.feeds.map((feed) => {
return (
<VideoFeed
key={feed.stream.id}
feed={feed}
call={this.props.call}
primary={false}
pipMode={this.props.pipMode}
/>
);
});
const className = classNames("mx_CallViewSidebar", {
mx_CallViewSidebar_pipMode: this.props.pipMode,
});
return (
<div className={className}>
{ feeds }
</div>
);
}
}

View file

@ -16,7 +16,7 @@ limitations under the License.
import classnames from 'classnames';
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import React, { createRef } from 'react';
import React from 'react';
import SettingsStore from "../../../settings/SettingsStore";
import { CallFeed, CallFeedEvent } from 'matrix-js-sdk/src/webrtc/callFeed';
import { logger } from 'matrix-js-sdk/src/logger';
@ -37,6 +37,8 @@ interface IProps {
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize?: (e: Event) => void;
primary: boolean;
}
interface IState {
@ -46,7 +48,7 @@ interface IState {
@replaceableComponent("views.voip.VideoFeed")
export default class VideoFeed extends React.Component<IProps, IState> {
private element = createRef<HTMLVideoElement>();
private element: HTMLVideoElement;
constructor(props: IProps) {
super(props);
@ -58,18 +60,50 @@ export default class VideoFeed extends React.Component<IProps, IState> {
}
componentDidMount() {
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
this.updateFeed(null, this.props.feed);
this.playMedia();
}
componentWillUnmount() {
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
this.element.current?.removeEventListener('resize', this.onResize);
this.stopMedia();
this.updateFeed(this.props.feed, null);
}
componentDidUpdate(prevProps: IProps) {
this.updateFeed(prevProps.feed, this.props.feed);
}
static getDerivedStateFromProps(props: IProps) {
return {
audioMuted: props.feed.isAudioMuted(),
videoMuted: props.feed.isVideoMuted(),
};
}
private setElementRef = (element: HTMLVideoElement): void => {
if (!element) {
this.element?.removeEventListener('resize', this.onResize);
return;
}
this.element = element;
element.addEventListener('resize', this.onResize);
};
private updateFeed(oldFeed: CallFeed, newFeed: CallFeed) {
if (oldFeed === newFeed) return;
if (oldFeed) {
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
this.stopMedia();
}
if (newFeed) {
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
this.playMedia();
}
}
private playMedia() {
const element = this.element.current;
const element = this.element;
if (!element) return;
// We play audio in AudioFeed, not here
element.muted = true;
@ -92,7 +126,7 @@ export default class VideoFeed extends React.Component<IProps, IState> {
}
private stopMedia() {
const element = this.element.current;
const element = this.element;
if (!element) return;
element.pause();
@ -121,8 +155,6 @@ export default class VideoFeed extends React.Component<IProps, IState> {
render() {
const videoClasses = {
mx_VideoFeed: true,
mx_VideoFeed_local: this.props.feed.isLocal(),
mx_VideoFeed_remote: !this.props.feed.isLocal(),
mx_VideoFeed_voice: this.state.videoMuted,
mx_VideoFeed_video: !this.state.videoMuted,
mx_VideoFeed_mirror: (
@ -131,9 +163,15 @@ export default class VideoFeed extends React.Component<IProps, IState> {
),
};
const { pipMode, primary } = this.props;
if (this.state.videoMuted) {
const member = this.props.feed.getMember();
const avatarSize = this.props.pipMode ? 76 : 160;
let avatarSize;
if (pipMode && primary) avatarSize = 76;
else if (pipMode && !primary) avatarSize = 16;
else if (!pipMode && primary) avatarSize = 160;
else; // TBD
return (
<div className={classnames(videoClasses)}>
@ -146,7 +184,7 @@ export default class VideoFeed extends React.Component<IProps, IState> {
);
} else {
return (
<video className={classnames(videoClasses)} ref={this.element} />
<video className={classnames(videoClasses)} ref={this.setElementRef} />
);
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Populate this class with the details of your customisations when copying it.
import { ITemplateParams } from "matrix-widget-api";
/**
* Provides a partial set of the variables needed to render any widget. If
* variables are missing or not provided then they will be filled with the
* application-determined defaults.
*
* This will not be called until after isReady() resolves.
* @returns {Partial<Omit<ITemplateParams, "widgetRoomId">>} The variables.
*/
function provideVariables(): Partial<Omit<ITemplateParams, "widgetRoomId">> {
return {};
}
/**
* Resolves to whether or not the customisation point is ready for variables
* to be provided. This will block widgets being rendered.
* @returns {Promise<boolean>} Resolves when ready.
*/
async function isReady(): Promise<void> {
return; // default no waiting
}
// This interface summarises all available customisation points and also marks
// them all as optional. This allows customisers to only define and export the
// customisations they need while still maintaining type safety.
export interface IWidgetVariablesCustomisations {
provideVariables?: typeof provideVariables;
// If not provided, the app will assume that the customisation is always ready.
isReady?: typeof isReady;
}
// A real customisation module will define and export one or more of the
// customisation points that make up the interface above.
export const WidgetVariableCustomisations: IWidgetVariablesCustomisations = {};

View file

@ -1552,5 +1552,15 @@
"Too Many Calls": "مكالمات كثيرة جدا",
"Call failed because webcam or microphone could not be accessed. Check that:": "فشلت المكالمة لعدم امكانية الوصل للميكروفون او الكاميرا , من فضلك قم بالتأكد.",
"Call failed because microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "فشلت المكالمة لعدم امكانية الوصل للميكروفون , تأكد من ان المكروفون متصل وتم اعداده بشكل صحيح.",
"Explore rooms": "استكشِف الغرف"
"Explore rooms": "استكشِف الغرف",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "قد يؤدي استخدام عنصر واجهة المستخدم هذا إلى مشاركة البيانات <helpIcon /> مع %(widgetDomain)s ومدير التكامل الخاص بك.",
"Identity server is": "خادم الهوية هو",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "يتلقى مديرو التكامل بيانات الضبط ، ويمكنهم تعديل عناصر واجهة المستخدم ، وإرسال دعوات الغرف ، وتعيين مستويات القوة نيابة عنك.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "استخدم مدير التكامل لإدارة الروبوتات وعناصر الواجهة وحزم الملصقات.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "استخدم مدير التكامل <b>(%(serverName)s)</b> لإدارة الروبوتات وعناصر الواجهة وحزم الملصقات.",
"Identity server": "خادم الهوية",
"Identity server (%(server)s)": "خادمة الهوية (%(server)s)",
"Could not connect to identity server": "تعذر الاتصال بخادم هوية",
"Not a valid identity server (status code %(code)s)": "خادم هوية مردود (رقم الحال %(code)s)",
"Identity server URL must be HTTPS": "يجب أن يكون رابط (URL) خادم الهوية HTTPS"
}

View file

@ -383,5 +383,7 @@
"%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "Bu otaqda %(newGroups)s üçün aktiv və %(oldGroups)s üçün %(senderDisplayName)s deaktiv oldu.",
"Create Account": "Hesab Aç",
"Explore rooms": "Otaqları kəşf edin",
"Sign In": "Daxil ol"
"Sign In": "Daxil ol",
"Identity server is": "Eyniləşdirmənin serveri bu",
"Identity server": "Eyniləşdirmənin serveri"
}

View file

@ -2897,5 +2897,17 @@
"Already in call": "Вече в разговор",
"You're already in a call with this person.": "Вече сте в разговор в този човек.",
"Too Many Calls": "Твърде много повиквания",
"Call failed because microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "Неуспешно повикване поради неуспешен достъп до микрофон. Проверете дали микрофонът е включен и настроен правилно."
"Call failed because microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "Неуспешно повикване поради неуспешен достъп до микрофон. Проверете дали микрофонът е включен и настроен правилно.",
"Integration manager": "Мениджър на интеграции",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Вашият %(brand)s не позволява да използвате мениджъра на интеграции за да направите това. Свържете се с администратор.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Използването на това приспособление може да сподели данни <helpIcon /> с %(widgetDomain)s и с мениджъра на интеграции.",
"Identity server is": "Сървър за самоличност:",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Мениджърът на интеграции получава конфигурационни данни, може да модифицира приспособления, да изпраща покани за стаи и да настройва нива на достъп от ваше име.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Използвай мениджър на интеграции за управление на ботове, приспособления и стикери.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Използвай мениджър на интеграции <b>%(serverName)s</b> за управление на ботове, приспособления и стикери.",
"Identity server": "Сървър за самоличност",
"Identity server (%(server)s)": "Сървър за самоличност (%(server)s)",
"Could not connect to identity server": "Неуспешна връзка със сървъра за самоличност",
"Not a valid identity server (status code %(code)s)": "Невалиден сървър за самоличност (статус код %(code)s)",
"Identity server URL must be HTTPS": "Адресът на сървъра за самоличност трябва да бъде HTTPS"
}

View file

@ -1 +1,4 @@
{}
{
"Integration manager": "ইন্টিগ্রেশন ম্যানেজার",
"Identity server": "পরিচয় সার্ভার"
}

View file

@ -1 +1,4 @@
{}
{
"Integration manager": "ইন্টিগ্রেশন ম্যানেজার",
"Identity server": "পরিচয় সার্ভার"
}

View file

@ -2,5 +2,6 @@
"Dismiss": "Odbaci",
"Create Account": "Otvori račun",
"Sign In": "Prijavite se",
"Explore rooms": "Istražite sobe"
"Explore rooms": "Istražite sobe",
"Identity server": "Identifikacioni Server"
}

View file

@ -953,5 +953,10 @@
"Unable to access microphone": "No s'ha pogut accedir al micròfon",
"Explore rooms": "Explora sales",
"%(oneUser)smade no changes %(count)s times|one": "%(oneUser)sno ha fet canvis",
"%(oneUser)smade no changes %(count)s times|other": "%(oneUser)sno ha fet canvis %(count)s cops"
"%(oneUser)smade no changes %(count)s times|other": "%(oneUser)sno ha fet canvis %(count)s cops",
"Integration manager": "Gestor d'integracions",
"Identity server is": "El servidor d'identitat és",
"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.",
"Identity server": "Servidor d'identitat",
"Could not connect to identity server": "No s'ha pogut connectar amb el servidor d'identitat"
}

View file

@ -857,7 +857,7 @@
"Failed to upgrade room": "Nepovedlo se upgradeovat místnost",
"The room upgrade could not be completed": "Upgrade místnosti se nepovedlo dokončit",
"Upgrade this room to version %(version)s": "Upgradování místnosti na verzi %(version)s",
"Security & Privacy": "Zabezpečení",
"Security & Privacy": "Zabezpečení a soukromí",
"Encryption": "Šifrování",
"Once enabled, encryption cannot be disabled.": "Po zapnutí, už nepůjde šifrování vypnout.",
"Encrypted": "Šifrováno",
@ -1061,7 +1061,7 @@
"Anchor": "Kotva",
"Headphones": "Sluchátka",
"Folder": "Desky",
"Pin": "Připínáček",
"Pin": "Připnout",
"Yes": "Ano",
"No": "Ne",
"Never lose encrypted messages": "Nikdy nepřijdete o šifrované zprávy",
@ -2250,7 +2250,7 @@
"Send feedback": "Odeslat zpětnou vazbu",
"Feedback": "Zpětná vazba",
"Feedback sent": "Zpětná vazba byla odeslána",
"Security & privacy": "Zabezpečení",
"Security & privacy": "Zabezpečení a soukromí",
"All settings": "Všechna nastavení",
"Start a conversation with someone using their name, email address or username (like <userId/>).": "Napište jméno nebo emailovou adresu uživatele se kterým chcete začít konverzaci (např. <userId/>).",
"Start a new chat": "Založit novou konverzaci",
@ -3322,7 +3322,7 @@
"You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Kliknutím na avatar na panelu filtrů můžete kdykoli zobrazit pouze místnosti a lidi spojené s danou komunitou.",
"Move down": "Posun dolů",
"Move up": "Posun nahoru",
"Report": "Zpráva",
"Report": "Nahlásit",
"Collapse reply thread": "Sbalit vlákno odpovědi",
"Show preview": "Zobrazit náhled",
"View source": "Zobrazit zdroj",
@ -3400,5 +3400,107 @@
"Some invites couldn't be sent": "Některé pozvánky nebylo možné odeslat",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "Poslali jsme ostatním, ale níže uvedení lidé nemohli být pozváni do <RoomName/>",
"Visibility": "Viditelnost",
"Address": "Adresa"
"Address": "Adresa",
"To view all keyboard shortcuts, click here.": "Pro zobrazení všech klávesových zkratek, klikněte zde.",
"Unnamed audio": "Nepojmenovaný audio soubor",
"Error processing audio message": "Došlo k chybě při zpracovávání hlasové zprávy",
"Images, GIFs and videos": "Obrázky, GIFy a videa",
"Code blocks": "Bloky kódu",
"Displaying time": "Zobrazování času",
"Keyboard shortcuts": "Klávesové zkratky",
"Use Ctrl + F to search timeline": "Stiskněte Ctrl + F k vyhledávání v časové ose",
"Use Command + F to search timeline": "Stiskněte Command + F k vyhledávání v časové ose",
"Integration manager": "Správce integrací",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Váš %(brand)s neumožňuje použít správce integrací. Kontaktujte prosím správce.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Použití tohoto widgetu může sdílet data <helpIcon /> s %(widgetDomain)s a vaším správcem integrací.",
"Identity server is": "Server identity je",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Správci integrace přijímají konfigurační data a mohou vaším jménem upravovat widgety, odesílat pozvánky do místností a nastavovat úrovně oprávnění.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Použít správce integrací na správu botů, widgetů a samolepek.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Použít správce integrací <b>(%(serverName)s)</b> na správu botů, widgetů a samolepek.",
"Identity server": "Server identit",
"Identity server (%(server)s)": "Server identit (%(server)s)",
"Could not connect to identity server": "Nepodařilo se připojit k serveru identit",
"Not a valid identity server (status code %(code)s)": "Toto není platný server identit (stavový kód %(code)s)",
"Identity server URL must be HTTPS": "Adresa serveru identit musí být na HTTPS",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>Upozorňujeme, že aktualizací vznikne nová verze místnosti</b>. Všechny aktuální zprávy zůstanou v této archivované místnosti.",
"Automatically invite members from this room to the new one": "Automaticky pozve členy této místnosti do nové místnosti",
"These are likely ones other room admins are a part of.": "Pravděpodobně se jedná o ty, kterých se účastní i ostatní správci místností.",
"Other spaces or rooms you might not know": "Další prostory nebo místnosti, které možná neznáte",
"Spaces you know that contain this room": "Prostory, které znáte a které obsahují tuto místnost",
"Search spaces": "Hledat prostory",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.": "Rozhodněte, které prostory mají přístup do této místnosti. Pokud je vybrán prostor, mohou jeho členové najít <RoomName/> a připojit se k němu.",
"Select spaces": "Vybrané prostory",
"You're removing all spaces. Access will default to invite only": "Odstraňujete všechny prostory. Přístup bude ve výchozím nastavení pouze na pozvánky",
"User Directory": "Adresář uživatelů",
"Connected": "Připojeno",
"& %(count)s more|other": "a %(count)s dalších",
"Only invited people can join.": "Připojit se mohou pouze pozvané osoby.",
"Private (invite only)": "Soukromé (pouze pro pozvané)",
"This upgrade will allow members of selected spaces access to this room without an invite.": "Tato změna umožní členům vybraných prostorů přístup do této místnosti bez pozvánky.",
"There was an error loading your notification settings.": "Došlo k chybě při načítání nastavení oznámení.",
"Global": "Globální",
"Enable email notifications for %(email)s": "Povolení e-mailových oznámení pro %(email)s",
"Enable for this account": "Povolit pro tento účet",
"An error occurred whilst saving your notification preferences.": "Při ukládání předvoleb oznámení došlo k chybě.",
"Error saving notification preferences": "Chyba při ukládání předvoleb oznámení",
"Messages containing keywords": "Zprávy obsahující klíčová slova",
"This makes it easy for rooms to stay private to a space, while letting people in the space find and join them. All new rooms in a space will have this option available.": "Díky tomuto mohou místnosti zůstat soukromé a zároveň je mohou lidé v prostoru najít a připojit se k nim. Všechny nové místnosti v prostoru budou mít tuto možnost k dispozici.",
"To help space members find and join a private room, go to that room's Security & Privacy settings.": "Chcete-li členům prostoru pomoci najít soukromou místnost a připojit se k ní, přejděte do nastavení Zabezpečení a soukromí dané místnosti.",
"Error downloading audio": "Chyba při stahování audia",
"Unknown failure: %(reason)s)": "Neznámá chyba: %(reason)s",
"No answer": "Žádná odpověď",
"An unknown error occurred": "Došlo k neznámé chybě",
"Their device couldn't start the camera or microphone": "Jejich zařízení nemohlo spustit kameru nebo mikrofon",
"Connection failed": "Spojení se nezdařilo",
"Could not connect media": "Nepodařilo se připojit média",
"This call has ended": "Tento hovor byl ukončen",
"Unable to copy a link to the room to the clipboard.": "Nelze zkopírovat odkaz na místnost do schránky.",
"Unable to copy room link": "Nelze zkopírovat odkaz na místnost",
"This call has failed": "Toto volání se nezdařilo",
"Anyone can find and join.": "Kdokoliv může najít a připojit se.",
"Room visibility": "Viditelnost místnosti",
"Visible to space members": "Viditelné pro členy prostoru",
"Public room": "Veřejná místnost",
"Private room (invite only)": "Soukromá místnost (pouze pro pozvané)",
"Create a room": "Vytvořit místnost",
"Only people invited will be able to find and join this room.": "Tuto místnost budou moci najít a připojit se k ní pouze pozvaní lidé.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Tuto místnost bude moci najít a připojit se k ní kdokoli, nejen členové <SpaceName/>.",
"You can change this at any time from room settings.": "Tuto hodnotu můžete kdykoli změnit v nastavení místnosti.",
"Everyone in <SpaceName/> will be able to find and join this room.": "Všichni v <SpaceName/> budou moci tuto místnost najít a připojit se k ní.",
"Image": "Obrázek",
"Sticker": "Nálepka",
"Downloading": "Stahování",
"The call is in an unknown state!": "Hovor je v neznámém stavu!",
"Call back": "Zavolat zpět",
"You missed this call": "Zmeškali jste tento hovor",
"The voice message failed to upload.": "Hlasovou zprávu se nepodařilo nahrát.",
"Copy Room Link": "Kopírovat odkaz na místnost",
"Show %(count)s other previews|one": "Zobrazit %(count)s další náhled",
"Show %(count)s other previews|other": "Zobrazit %(count)s dalších náhledů",
"Access": "Přístup",
"People with supported clients will be able to join the room without having a registered account.": "Lidé s podporovanými klienty se budou moci do místnosti připojit, aniž by měli registrovaný účet.",
"Decide who can join %(roomName)s.": "Rozhodněte, kdo se může připojit k %(roomName)s.",
"Space members": "Členové prostoru",
"Anyone in %(spaceName)s can find and join. You can select other spaces too.": "Každý, kdo se nachází v prostoru %(spaceName)s, ho může najít a připojit se k němu. Můžete vybrat i jiné prostory.",
"Anyone in a space can find and join. You can select multiple spaces.": "Každý, kdo se nachází v prostoru, ho může najít a připojit se k němu. Můžete vybrat více prostorů.",
"Spaces with access": "Prostory s přístupem",
"Anyone in a space can find and join. <a>Edit which spaces can access here.</a>": "Každý, kdo se nachází v prostoru, ho může najít a připojit se k němu. <a>Zde upravte, ke kterým prostorům lze přistupovat.</a>",
"Currently, %(count)s spaces have access|other": "V současné době má %(count)s prostorů přístup k",
"Upgrade required": "Vyžadována aktualizace",
"Mentions & keywords": "Zmínky a klíčová slova",
"Message bubbles": "Bubliny zpráv",
"IRC": "IRC",
"New keyword": "Nové klíčové slovo",
"Keyword": "Klíčové slovo",
"New layout switcher (with message bubbles)": "Nový přepínač rozložení (s bublinami zpráv)",
"Help space members find private rooms": "Pomoci členům prostorů najít soukromé místnosti",
"Help people in spaces to find and join private rooms": "Pomoci lidem v prostorech najít soukromé místnosti a připojit se k nim",
"New in the Spaces beta": "Nové v betaverzi Spaces",
"User %(userId)s is already invited to the room": "Uživatel %(userId)s je již pozván do místnosti",
"Transfer Failed": "Přepojení se nezdařilo",
"Unable to transfer call": "Nelze přepojit hovor",
"They didn't pick up": "Nezvedli to",
"Call again": "Volat znova",
"They declined this call": "Odmítli tento hovor",
"You declined this call": "Odmítli jste tento hovor"
}

View file

@ -11,5 +11,6 @@
"Sign In": "Mewngofnodi",
"Create Account": "Creu Cyfrif",
"Dismiss": "Wfftio",
"Explore rooms": "Archwilio Ystafelloedd"
"Explore rooms": "Archwilio Ystafelloedd",
"Identity server": "Gweinydd Adnabod"
}

View file

@ -15,7 +15,7 @@
"Bans user with given id": "Verbannt den Benutzer mit der angegebenen ID",
"Deops user with given id": "Setzt das Berechtigungslevel beim Benutzer mit der angegebenen ID zurück",
"Invites user with given id to current room": "Lädt den Benutzer mit der angegebenen ID in den aktuellen Raum ein",
"Kicks user with given id": "Benutzer mit der angegebenen ID kicken",
"Kicks user with given id": "Benutzer mit der angegebenen ID entfernen",
"Changes your display nickname": "Ändert deinen Anzeigenamen",
"Change Password": "Passwort ändern",
"Searches DuckDuckGo for results": "Verwendet DuckDuckGo zum Suchen",
@ -204,14 +204,14 @@
"Failed to ban user": "Verbannen des Benutzers fehlgeschlagen",
"Failed to change power level": "Ändern der Berechtigungsstufe fehlgeschlagen",
"Failed to join room": "Betreten des Raumes ist fehlgeschlagen",
"Failed to kick": "Rauswurf fehlgeschlagen",
"Failed to kick": "Entfernen fehlgeschlagen",
"Failed to mute user": "Stummschalten des Nutzers fehlgeschlagen",
"Failed to reject invite": "Ablehnen der Einladung ist fehlgeschlagen",
"Failed to set display name": "Anzeigename konnte nicht geändert werden",
"Fill screen": "Fülle Bildschirm",
"Incorrect verification code": "Falscher Verifizierungscode",
"Join Room": "Raum beitreten",
"Kick": "Rausschmeißen",
"Kick": "Entfernen",
"not specified": "nicht angegeben",
"No more results": "Keine weiteren Ergebnisse",
"No results": "Keine Ergebnisse",
@ -539,10 +539,10 @@
"were banned %(count)s times|one": "wurden verbannt",
"was banned %(count)s times|other": "wurde %(count)s-mal verbannt",
"was banned %(count)s times|one": "wurde verbannt",
"were kicked %(count)s times|other": "wurden %(count)s-mal rausgeworfen",
"were kicked %(count)s times|one": "wurden rausgeworfen",
"was kicked %(count)s times|other": "wurde %(count)s-mal rausgeworfen",
"was kicked %(count)s times|one": "wurde rausgeworfen",
"were kicked %(count)s times|other": "wurden %(count)s-mal entfernt",
"were kicked %(count)s times|one": "wurden entfernt",
"was kicked %(count)s times|other": "wurde %(count)s-mal entfernt",
"was kicked %(count)s times|one": "wurde entfernt",
"%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)shaben %(count)s-mal ihren Namen geändert",
"%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)shaben ihren Namen geändert",
"%(oneUser)schanged their name %(count)s times|other": "%(oneUser)shat %(count)s-mal den Namen geändert",
@ -551,7 +551,7 @@
"%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)shat das Profilbild %(count)s-mal geändert",
"%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)shat das Profilbild geändert",
"Disinvite this user?": "Einladung für diesen Benutzer zurückziehen?",
"Kick this user?": "Diesen Benutzer rausschmeißen?",
"Kick this user?": "Diesen Benutzer entfernen?",
"Unban this user?": "Verbannung für diesen Benutzer aufheben?",
"Ban this user?": "Diesen Benutzer verbannen?",
"Members only (since the point in time of selecting this option)": "Mitglieder",
@ -979,7 +979,7 @@
"Render simple counters in room header": "Einfache Zähler in Raumkopfzeile anzeigen",
"Enable Emoji suggestions while typing": "Emojivorschläge während Eingabe",
"Show a placeholder for removed messages": "Platzhalter für gelöschte Nachrichten",
"Show join/leave messages (invites/kicks/bans unaffected)": "Betreten oder Verlassen von Benutzern (ausgen. Einladungen/Rauswürfe/Banne)",
"Show join/leave messages (invites/kicks/bans unaffected)": "Betreten oder Verlassen von Benutzern (ausgen. Einladungen/Entfernen/Banne)",
"Show avatar changes": "Avataränderungen",
"Show display name changes": "Änderungen von Anzeigenamen",
"Send typing notifications": "Tippbenachrichtigungen senden",
@ -1211,7 +1211,7 @@
"Send messages": "Nachrichten senden",
"Invite users": "Benutzer einladen",
"Change settings": "Einstellungen ändern",
"Kick users": "Benutzer kicken",
"Kick users": "Benutzer entfernen",
"Ban users": "Benutzer verbannen",
"Remove messages": "Nachrichten löschen",
"Notify everyone": "Jeden benachrichtigen",
@ -1644,7 +1644,7 @@
"Failed to set topic": "Das Festlegen des Themas ist fehlgeschlagen",
"Command failed": "Befehl fehlgeschlagen",
"Could not find user in room": "Benutzer konnte nicht im Raum gefunden werden",
"Click the button below to confirm adding this email address.": "Klicke unten auf die Schaltfläche, um die hinzugefügte E-Mail-Adresse zu bestätigen.",
"Click the button below to confirm adding this email address.": "Klicke unten auf den Knopf, um die hinzugefügte E-Mail-Adresse zu bestätigen.",
"Confirm adding phone number": "Hinzugefügte Telefonnummer bestätigen",
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s ändert eine Ausschlussregel für Server von %(oldGlob)s nach %(newGlob)s wegen %(reason)s",
"%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s erneuert eine Ausschlussregel von %(oldGlob)s nach %(newGlob)s wegen %(reason)s",
@ -3371,8 +3371,8 @@
"See when people join, leave, or are invited to your active room": "Anzeigen, wenn Leute den aktuellen Raum betreten, verlassen oder in ihn eingeladen werden",
"Teammates might not be able to view or join any private rooms you make.": "Mitglieder werden private Räume möglicherweise weder sehen noch betreten können.",
"Error - Mixed content": "Fehler - Uneinheitlicher Inhalt",
"Kick, ban, or invite people to your active room, and make you leave": "Den aktiven Raum verlassen, Leute einladen, kicken oder bannen",
"Kick, ban, or invite people to this room, and make you leave": "Diesen Raum verlassen, Leute einladen, kicken oder bannen",
"Kick, ban, or invite people to your active room, and make you leave": "Den aktiven Raum verlassen, Leute einladen, entfernen oder bannen",
"Kick, ban, or invite people to this room, and make you leave": "Diesen Raum verlassen, Leute einladen, entfernen oder bannen",
"View source": "Rohdaten anzeigen",
"What this user is writing is wrong.\nThis will be reported to the room moderators.": "Die Person verbreitet Falschinformation.\nDies wird an die Raummoderation gemeldet.",
"[number]": "[Nummer]",
@ -3427,8 +3427,8 @@
"Show all rooms in Home": "Alle Räume auf der Startseite zeigen",
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Inhalte an Mods melden. In Räumen, die Moderation unterstützen, kannst du so unerwünschte Inhalte direkt der Raummoderation melden",
"%(senderName)s changed the <a>pinned messages</a> for the room.": "%(senderName)s hat die <a>angehefteten Nachrichten</a> geändert.",
"%(senderName)s kicked %(targetName)s": "%(senderName)s hat %(targetName)s gekickt",
"%(senderName)s kicked %(targetName)s: %(reason)s": "%(senderName)s hat %(targetName)s gekickt: %(reason)s",
"%(senderName)s kicked %(targetName)s": "%(senderName)s hat %(targetName)s entfernt",
"%(senderName)s kicked %(targetName)s: %(reason)s": "%(senderName)s hat %(targetName)s entfernt: %(reason)s",
"%(senderName)s withdrew %(targetName)s's invitation": "%(senderName)s hat die Einladung für %(targetName)s zurückgezogen",
"%(senderName)s withdrew %(targetName)s's invitation: %(reason)s": "%(senderName)s hat die Einladung für %(targetName)s zurückgezogen: %(reason)s",
"%(senderName)s unbanned %(targetName)s": "%(senderName)s hat %(targetName)s entbannt",
@ -3442,7 +3442,7 @@
"%(senderName)s removed their profile picture": "%(senderName)s hat das Profilbild entfernt",
"%(senderName)s removed their display name (%(oldDisplayName)s)": "%(senderName)s hat den alten Nicknamen %(oldDisplayName)s entfernt",
"%(senderName)s set their display name to %(displayName)s": "%(senderName)s hat den Nicknamen zu %(displayName)s geändert",
"%(oldDisplayName)s changed their display name to %(displayName)s": "%(oldDisplayName)s hat den Nicknamen zu%(displayName)s geändert",
"%(oldDisplayName)s changed their display name to %(displayName)s": "%(oldDisplayName)s hat den Nicknamen zu %(displayName)s geändert",
"%(senderName)s banned %(targetName)s": "%(senderName)s hat %(targetName)s gebannt",
"%(senderName)s banned %(targetName)s: %(reason)s": "%(senderName)s hat %(targetName)s gebannt: %(reason)s",
"%(targetName)s accepted an invitation": "%(targetName)s hat die Einladung akzeptiert",
@ -3452,5 +3452,63 @@
"Message search initialisation failed, check <a>your settings</a> for more information": "Initialisierung der Nachrichtensuche fehlgeschlagen. Öffne <a>die Einstellungen</a> für mehr Information.",
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\n This will be reported to the administrators of %(homeserver)s.": "Der Raum beinhaltet illegale oder toxische Nachrichten und die Raummoderation verhindert es nicht.\nDies wird an die Betreiber von %(homeserver)s gemeldet werden.",
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\nThis will be reported to the administrators of %(homeserver)s. The administrators will NOT be able to read the encrypted content of this room.": "Der Raum beinhaltet illegale oder toxische Nachrichten und die Raummoderation verhindert es nicht.\nDies wird an die Betreiber von %(homeserver)s gemeldet werden. Diese können jedoch die verschlüsselten Nachrichten nicht lesen.",
"This user is displaying illegal behaviour, for instance by doxing people or threatening violence.\nThis will be reported to the room moderators who may escalate this to legal authorities.": "Diese Person zeigt illegales Verhalten, beispielsweise das Leaken persönlicher Daten oder Gewaltdrohungen.\nDies wird an die Raummoderation gemeldet, welche dies an die Justiz weitergeben kann."
"This user is displaying illegal behaviour, for instance by doxing people or threatening violence.\nThis will be reported to the room moderators who may escalate this to legal authorities.": "Diese Person zeigt illegales Verhalten, beispielsweise das Leaken persönlicher Daten oder Gewaltdrohungen.\nDies wird an die Raummoderation gemeldet, welche dies an die Justiz weitergeben kann.",
"Unnamed audio": "Unbenannte Audiodatei",
"Show %(count)s other previews|one": "%(count)s andere Vorschau zeigen",
"Show %(count)s other previews|other": "%(count)s andere Vorschauen zeigen",
"Images, GIFs and videos": "Mediendateien",
"To view all keyboard shortcuts, click here.": "Alle Tastenkombinationen anzeigen",
"Keyboard shortcuts": "Tastenkombinationen",
"User %(userId)s is already invited to the room": "%(userId)s ist schon eingeladen",
"Unable to copy a link to the room to the clipboard.": "Der Link zum Raum konnte nicht kopiert werden.",
"Unable to copy room link": "Raumlink konnte nicht kopiert werden",
"Integration manager": "Integrationsverwaltung",
"User Directory": "Benutzerverzeichnis",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Dein %(brand)s erlaubt dir nicht, eine Integrationsverwaltung zu verwenden, um dies zu tun. Bitte kontaktiere einen Administrator.",
"Copy Link": "Link kopieren",
"Transfer Failed": "Übertragen fehlgeschlagen",
"Unable to transfer call": "Übertragen des Anrufs fehlgeschlagen",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Wenn du dieses Widget verwendest, können Daten <helpIcon /> zu %(widgetDomain)s und deinem Integrationsserver übertragen werden.",
"Identity server is": "Der Identitätsserver ist",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integrationsverwalter erhalten Konfigurationsdaten und können Widgets modifizieren, Raumeinladungen verschicken und in deinem Namen Berechtigungslevel setzen.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Verwende einen Integrationsverwalter, um Bots, Widgets und Stickerpakete zu verwalten.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Nutze einen Integrationsverwalter <b>(%(serverName)s)</b>, um Bots, Widgets und Stickerpakete zu verwalten.",
"Identity server": "Identitätsserver",
"Identity server (%(server)s)": "Identitätsserver (%(server)s)",
"Could not connect to identity server": "Verbindung zum Identitätsserver konnte nicht hergestellt werden",
"Not a valid identity server (status code %(code)s)": "Ungültiger Identitätsserver (Fehlercode %(code)s)",
"Identity server URL must be HTTPS": "Der Identitätsserver muss über HTTPS erreichbar sein",
"Error processing audio message": "Fehler beim Verarbeiten der Audionachricht",
"Copy Room Link": "Raumlink kopieren",
"Code blocks": "Codeblöcke",
"There was an error loading your notification settings.": "Fehler beim Laden der Benachrichtigungseinstellungen.",
"Mentions & keywords": "Erwähnungen und Schlüsselwörter",
"Global": "Global",
"New keyword": "Neues Schlüsselwort",
"Keyword": "Schlüsselwort",
"Enable email notifications for %(email)s": "E-Mail-Benachrichtigungen für %(email)s aktivieren",
"Enable for this account": "Für dieses Konto aktivieren",
"An error occurred whilst saving your notification preferences.": "Beim Speichern der Benachrichtigungseinstellungen ist ein Fehler aufgetreten.",
"Error saving notification preferences": "Fehler beim Speichern der Benachrichtigungseinstellungen",
"Messages containing keywords": "Nachrichten mit Schlüsselwörtern",
"Show notification badges for People in Spaces": "Benachrichtigungssymbol für Personen in Spaces zeigen",
"Use Ctrl + F to search timeline": "Nutze STRG + F, um den Verlauf zu durchsuchen",
"Downloading": "Herunterladen",
"The call is in an unknown state!": "Dieser Anruf ist in einem unbekannten Zustand!",
"Call back": "Zurückrufen",
"You missed this call": "Du hast einen Anruf verpasst",
"This call has failed": "Anruf fehlgeschlagen",
"Unknown failure: %(reason)s)": "Unbekannter Fehler: %(reason)s",
"Connection failed": "Verbindung fehlgeschlagen",
"This call has ended": "Anruf beendet",
"Connected": "Verbunden",
"IRC": "IRC",
"Silence call": "Anruf stummschalten",
"Error downloading audio": "Fehler beim Herunterladen der Audiodatei",
"Image": "Bild",
"Sticker": "Sticker",
"An unknown error occurred": "Ein unbekannter Fehler ist aufgetreten",
"Message bubbles": "Nachrichtenblasen",
"New layout switcher (with message bubbles)": "Layout ändern erlauben (mit Nachrichtenblasen)",
"New in the Spaces beta": "Neues in der Spaces Beta"
}

View file

@ -925,5 +925,6 @@
"Done": "Τέλος",
"Not Trusted": "Μη Έμπιστο",
"You're already in a call with this person.": "Είστε ήδη σε κλήση με αυτόν τον χρήστη.",
"Already in call": "Ήδη σε κλήση"
"Already in call": "Ήδη σε κλήση",
"Identity server is": "Ο διακομιστής ταυτοποίησης είναι"
}

View file

@ -35,11 +35,8 @@
"Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.",
"Dismiss": "Dismiss",
"Call Failed": "Call Failed",
"Call Declined": "Call Declined",
"The other party declined the call.": "The other party declined the call.",
"User Busy": "User Busy",
"The user you called is busy.": "The user you called is busy.",
"The remote side failed to pick up": "The remote side failed to pick up",
"The call could not be established": "The call could not be established",
"Answered Elsewhere": "Answered Elsewhere",
"The call was answered on another device.": "The call was answered on another device.",
@ -55,7 +52,6 @@
"A microphone and webcam are plugged in and set up correctly": "A microphone and webcam are plugged in and set up correctly",
"Permission is granted to use the webcam": "Permission is granted to use the webcam",
"No other application is using the webcam": "No other application is using the webcam",
"Unable to capture screen": "Unable to capture screen",
"VoIP is unsupported": "VoIP is unsupported",
"You cannot place VoIP calls in this browser.": "You cannot place VoIP calls in this browser.",
"Too Many Calls": "Too Many Calls",
@ -801,9 +797,6 @@
"Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.",
"Your feedback will help make spaces better. The more detail you can go into, the better.": "Your feedback will help make spaces better. The more detail you can go into, the better.",
"Show all rooms in Home": "Show all rooms in Home",
"Show people in spaces": "Show people in spaces",
"If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.": "If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.",
"Show notification badges for People in Spaces": "Show notification badges for People in Spaces",
"Show options to enable 'Do not disturb' mode": "Show options to enable 'Do not disturb' mode",
"Send and receive voice messages": "Send and receive voice messages",
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
@ -906,6 +899,10 @@
"You held the call <a>Resume</a>": "You held the call <a>Resume</a>",
"%(peerName)s held the call": "%(peerName)s held the call",
"Connecting": "Connecting",
"You are presenting": "You are presenting",
"%(sharerName)s is presenting": "%(sharerName)s is presenting",
"Your camera is turned off": "Your camera is turned off",
"Your camera is still enabled": "Your camera is still enabled",
"Video Call": "Video Call",
"Voice Call": "Voice Call",
"Fill Screen": "Fill Screen",
@ -1573,6 +1570,8 @@
"Unnamed room": "Unnamed room",
"World readable": "World readable",
"Guests can join": "Guests can join",
"Screen sharing is here!": "Screen sharing is here!",
"You can now share your screen by pressing the \"screen share\" button during a call. You can even do this in audio calls if both sides support it!": "You can now share your screen by pressing the \"screen share\" button during a call. You can even do this in audio calls if both sides support it!",
"(~%(count)s results)|other": "(~%(count)s results)",
"(~%(count)s results)|one": "(~%(count)s result)",
"Join Room": "Join Room",
@ -1862,16 +1861,19 @@
"Verification cancelled": "Verification cancelled",
"Compare emoji": "Compare emoji",
"Connected": "Connected",
"You declined this call": "You declined this call",
"They declined this call": "They declined this call",
"Call back": "Call back",
"Call again": "Call again",
"This call has ended": "This call has ended",
"They didn't pick up": "They didn't pick up",
"Could not connect media": "Could not connect media",
"Connection failed": "Connection failed",
"Their device couldn't start the camera or microphone": "Their device couldn't start the camera or microphone",
"An unknown error occurred": "An unknown error occurred",
"No answer": "No answer",
"Unknown failure: %(reason)s)": "Unknown failure: %(reason)s)",
"This call has failed": "This call has failed",
"You missed this call": "You missed this call",
"Call back": "Call back",
"The call is in an unknown state!": "The call is in an unknown state!",
"Sunday": "Sunday",
"Monday": "Monday",
@ -1998,9 +2000,9 @@
"Use the <a>Desktop app</a> to search encrypted messages": "Use the <a>Desktop app</a> to search encrypted messages",
"This version of %(brand)s does not support viewing some encrypted files": "This version of %(brand)s does not support viewing some encrypted files",
"This version of %(brand)s does not support searching encrypted messages": "This version of %(brand)s does not support searching encrypted messages",
"Share your screen": "Share your screen",
"Screens": "Screens",
"Windows": "Windows",
"Share entire screen": "Share entire screen",
"Application window": "Application window",
"Share content": "Share content",
"Join": "Join",
"No results": "No results",
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.": "Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.",
@ -2195,6 +2197,7 @@
"Everyone in <SpaceName/> will be able to find and join this room.": "Everyone in <SpaceName/> will be able to find and join this room.",
"You can change this at any time from room settings.": "You can change this at any time from room settings.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Anyone will be able to find and join this room, not just members of <SpaceName/>.",
"Anyone will be able to find and join this room.": "Anyone will be able to find and join this room.",
"Only people invited will be able to find and join this room.": "Only people invited will be able to find and join this room.",
"You cant disable this later. Bridges & most bots wont work yet.": "You cant disable this later. Bridges & most bots wont work yet.",
"Your server requires encryption to be enabled in private rooms.": "Your server requires encryption to be enabled in private rooms.",

View file

@ -3326,5 +3326,16 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Provu aliajn vortojn aŭ kontorolu, ĉu vi ne tajperaris. Iuj rezultoj eble ne videblos, ĉar ili estas privataj kaj vi bezonus inviton por aliĝi.",
"No results for \"%(query)s\"": "Neniuj rezultoj por «%(query)s»",
"The user you called is busy.": "La uzanto, kiun vi vokis, estas okupata.",
"User Busy": "Uzanto estas okupata"
"User Busy": "Uzanto estas okupata",
"Integration manager": "Kunigilo",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Via %(brand)so ne permesas al vi uzi kunigilon por tio. Bonvolu kontakti administranton.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Uzo de tiu ĉi fenestraĵo eble havigos datumojn <helpIcon /> kun %(widgetDomain)s kaj via kunigilo.",
"Identity server is": "Identiga servilo estas",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Kunigiloj ricevas agordajn datumojn, kaj povas modifi fenestraĵojn, sendi invitojn al ĉambroj, kaj vianome agordi povnivelojn.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Uzu kunigilon por administrado de robotoj, fenestraĵoj, kaj glumarkaroj.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Uzu kunigilon <b>(%(serverName)s)</b> por administrado de robotoj, fenestraĵoj, kaj glumarkaroj.",
"Identity server": "Identiga servilo",
"Identity server (%(server)s)": "Identiga servilo (%(server)s)",
"Could not connect to identity server": "Ne povis konektiĝi al identiga servilo",
"Not a valid identity server (status code %(code)s)": "Nevalida identiga servilo (statkodo %(code)s)"
}

View file

@ -1706,7 +1706,7 @@
"Encrypted by an unverified session": "Cifrado por una sesión no verificada",
"Unencrypted": "Sin cifrar",
"Encrypted by a deleted session": "Cifrado por una sesión eliminada",
"Invite only": "Sólamente por invitación",
"Invite only": "Solo por invitación",
"Scroll to most recent messages": "Ir a los mensajes más recientes",
"Close preview": "Cerrar vista previa",
"No recent messages by %(user)s found": "No se han encontrado mensajes recientes de %(user)s",
@ -3254,7 +3254,7 @@
"Enter your Security Phrase a second time to confirm it.": "Escribe tu frase de seguridad de nuevo para confirmarla.",
"Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "Elige salas o conversaciones para añadirlas. Este espacio es solo para ti, no informaremos a nadie. Puedes añadir más más tarde.",
"What do you want to organise?": "¿Qué quieres organizar?",
"Filter all spaces": "Filtrar todos los espacios",
"Filter all spaces": "Filtrar espacios",
"%(count)s results in all spaces|one": "%(count)s resultado en todos los espacios",
"%(count)s results in all spaces|other": "%(count)s resultados en todos los espacios",
"You have no ignored users.": "No has ignorado a nadie.",
@ -3420,5 +3420,62 @@
"%(targetName)s accepted an invitation": "%(targetName)s ha aceptado una invitación",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s ha aceptado la invitación a %(displayName)s",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "Hemos enviado el resto, pero no hemos podido invitar las siguientes personas a la sala <RoomName/>",
"Some invites couldn't be sent": "No se han podido enviar algunas invitaciones"
"Some invites couldn't be sent": "No se han podido enviar algunas invitaciones",
"Integration manager": "Gestor de integración",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "%(brand)s no utilizar un \"gestor de integración\" para hacer esto. Por favor, contacta con un administrador.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Usar este widget puede resultar en que se compartan datos <helpIcon /> con %(widgetDomain)s y su administrador de integración.",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Los administradores de integración reciben datos de configuración, y pueden modificar widgets, enviar invitaciones de sala, y establecer niveles de poder en tu nombre.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Utiliza un administrador de integración para gestionar los bots, los widgets y los paquetes de pegatinas.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Usar un gestor de integraciones <b>(%(serverName)s)</b> para manejar los bots, widgets y paquetes de pegatinas.",
"Identity server": "Servidor de identidad",
"Identity server (%(server)s)": "Servidor de identidad %(server)s",
"Could not connect to identity server": "No se ha podido conectar al servidor de identidad",
"Not a valid identity server (status code %(code)s)": "No es un servidor de identidad válido (código de estado %(code)s)",
"Identity server URL must be HTTPS": "La URL del servidor de identidad debe ser tipo HTTPS",
"Unable to copy a link to the room to the clipboard.": "No se ha podido copiar el enlace a la sala.",
"Unable to copy room link": "No se ha podido copiar el enlace a la sala",
"Unnamed audio": "Audio sin título",
"User Directory": "Lista de usuarios",
"Error processing audio message": "Error al procesar el mensaje de audio",
"Copy Link": "Copiar enlace",
"Show %(count)s other previews|one": "Ver otras %(count)s vistas previas",
"Show %(count)s other previews|other": "Ver %(count)s otra vista previa",
"Images, GIFs and videos": "Imágenes, GIFs y vídeos",
"Code blocks": "Bloques de código",
"To view all keyboard shortcuts, click here.": "Para ver todos los atajos de teclado, haz clic aquí.",
"Keyboard shortcuts": "Atajos de teclado",
"Identity server is": "El servidor de identidad es",
"There was an error loading your notification settings.": "Ha ocurrido un error al cargar tus ajustes de notificaciones",
"Mentions & keywords": "Menciones y palabras clave",
"Global": "Global",
"New keyword": "Nueva palabra clave",
"Keyword": "Palabra clave",
"Enable email notifications for %(email)s": "Activar notificaciones por correo electrónico para %(email)s",
"Enable for this account": "Activar para esta cuenta",
"An error occurred whilst saving your notification preferences.": "Ha ocurrido un error al guardar las tus preferencias de notificaciones.",
"Error saving notification preferences": "Error al guardar las preferencias de notificaciones",
"Messages containing keywords": "Mensajes que contengan",
"Use Command + F to search timeline": "Usa Control + F para buscar",
"Transfer Failed": "La transferencia ha fallado",
"Unable to transfer call": "No se ha podido transferir la llamada",
"This call has ended": "La llamada ha terminado",
"Could not connect media": "No se ha podido conectar con los dispositivos multimedia",
"Their device couldn't start the camera or microphone": "El dispositivo de la otra persona no ha podido iniciar la cámara o micrófono",
"Error downloading audio": "Error al descargar el audio",
"Image": "Imagen",
"Sticker": "Pegatina",
"Downloading": "Descargando",
"The call is in an unknown state!": "La llamada está en un estado desconocido",
"Call back": "Devolver",
"You missed this call": "No has cogido esta llamada",
"This call has failed": "Esta llamada ha fallado",
"Unknown failure: %(reason)s)": "Fallo desconocido: %(reason)s)",
"No answer": "Sin respuesta",
"An unknown error occurred": "Ha ocurrido un error desconocido",
"Connection failed": "Ha fallado la conexión",
"Connected": "Conectado",
"Copy Room Link": "Copiar enlace a la sala",
"Displaying time": "Mostrando la hora",
"IRC": "IRC",
"Use Ctrl + F to search timeline": "Usa Control + F para buscar dentro de la conversación"
}

View file

@ -1489,7 +1489,7 @@
"Update any local room aliases to point to the new room": "uuendame kõik jututoa aliased nii, et nad viitaks uuele jututoale",
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "ei võimalda kasutajatel enam vanas jututoas suhelda ning avaldame seal teate, mis soovitab kõigil kolida uude jututuppa",
"Put a link back to the old room at the start of the new room so people can see old messages": "selleks et saaks vanu sõnumeid lugeda, paneme uue jututoa algusesse viite vanale jututoale",
"Automatically invite users": "Kutsu kasutajad automaatselt",
"Automatically invite users": "Kutsu automaatselt kasutajaid",
"Upgrade private room": "Uuenda omavaheline jututuba",
"Upgrade public room": "Uuenda avalik jututuba",
"Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.": "Jututoa uuendamine on keerukas toiming ning tavaliselt soovitatakse seda teha vaid siis, kui jututuba on vigade tõttu halvasti kasutatav, sealt on puudu vajalikke funktsionaalsusi või seal ilmneb turvavigu.",
@ -2829,7 +2829,7 @@
"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.",
"Add a photo, so people can easily spot your room.": "Selleks, 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>.",
@ -3450,5 +3450,76 @@
"This user is spamming the room with ads, links to ads or to propaganda.\nThis will be reported to the room moderators.": "See kasutaja spämmib jututuba reklaamidega, reklaamlinkidega või propagandaga.\nJututoa moderaatorid saavad selle kohta teate.",
"This user is displaying toxic behaviour, for instance by insulting other users or sharing adult-only content in a family-friendly room or otherwise violating the rules of this room.\nThis will be reported to the room moderators.": "Selle kasutaja tegevus on äärmiselt ebasobilik, milleks võib olla teiste jututoas osalejate solvamine, peresõbralikku jututuppa täiskasvanutele mõeldud sisu lisamine või muul viisil jututoa reeglite rikkumine.\nJututoa moderaatorid saavad selle kohta teate.",
"Please provide an address": "Palun sisesta aadress",
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Meie esimene katsetus modereerimisega. Kui jututoas on modereerimine toetatud, siis „Teata moderaatorile“ nupust võid saada teate ebasobiliku sisu kohta"
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Meie esimene katsetus modereerimisega. Kui jututoas on modereerimine toetatud, siis „Teata moderaatorile“ nupust võid saada teate ebasobiliku sisu kohta",
"Unnamed audio": "Nimetu helifail",
"Code blocks": "Lähtekoodi lõigud",
"Images, GIFs and videos": "Pildid, gif'id ja videod",
"Show %(count)s other previews|other": "Näita %(count)s muud eelvaadet",
"Show %(count)s other previews|one": "Näita veel %(count)s eelvaadet",
"Error processing audio message": "Viga häälsõnumi töötlemisel",
"Integration manager": "Lõiminguhaldur",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Sinu %(brand)s ei võimalda selle tegevuse jaoks kasutada lõiminguhaldurit. Palun küsi lisateavet serveri haldajalt.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Selle vidina kasutamisel võidakse jagada andmeid <helpIcon /> %(widgetDomain)s saitidega ning sinu lõiminguhalduriga.",
"Identity server is": "Isikutuvastusserver on",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Lõiminguhalduritel on laiad volitused - nad võivad sinu nimel lugeda seadistusi, kohandada vidinaid, saata jututubade kutseid ning määrata õigusi.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Robotite, vidinate ja kleepsupakkide seadistamiseks kasuta lõiminguhaldurit.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Robotite, vidinate ja kleepsupakkide jaoks kasuta lõiminguhaldurit <b>(%(serverName)s)</b>.",
"Identity server": "Isikutuvastusserver",
"Identity server (%(server)s)": "Isikutuvastusserver %(server)s",
"Could not connect to identity server": "Ei saanud ühendust isikutuvastusserveriga",
"Not a valid identity server (status code %(code)s)": "See ei ole sobilik isikutuvastusserver (staatuskood %(code)s)",
"Identity server URL must be HTTPS": "Isikutuvastusserveri URL peab kasutama HTTPS-protokolli",
"User %(userId)s is already invited to the room": "Kasutaja %(userId)s sai juba kutse sellesse jututuppa",
"Use Command + F to search timeline": "Ajajoonelt otsimiseks kasuta Command+F klahve",
"Use Ctrl + F to search timeline": "Ajajoonelt otsimiseks kasuta Ctrl+F klahve",
"Keyboard shortcuts": "Kiirklahvid",
"To view all keyboard shortcuts, click here.": "Vaata siit kõiki kiirklahve.",
"Copy Link": "Kopeeri link",
"User Directory": "Kasutajate kataloog",
"Unable to copy room link": "Jututoa lingi kopeerimine ei õnnestu",
"Unable to copy a link to the room to the clipboard.": "Jututoa lingi kopeerimine lõikelauale ei õnnestunud.",
"Messages containing keywords": "Sõnumid, mis sisaldavad märksõnu",
"Error saving notification preferences": "Viga teavistuste eelistuste salvestamisel",
"An error occurred whilst saving your notification preferences.": "Sinu teavituste eelistuste salvestamisel tekkis viga.",
"Enable for this account": "Võta sellel kontol kasutusele",
"Enable email notifications for %(email)s": "Saada teavitusi %(email)s e-posti aadressile",
"Keyword": "Märksõnad",
"Mentions & keywords": "Mainimised ja märksõnad",
"New keyword": "Uus märksõna",
"Global": "Üldised",
"There was an error loading your notification settings.": "Sinu teavituste seadistuste laadimisel tekkis viga.",
"Transfer Failed": "Edasisuunamine ei õnnestunud",
"Unable to transfer call": "Kõne edasisuunamine ei õnnestunud",
"Downloading": "Laadin alla",
"The call is in an unknown state!": "Selle kõne oleks on teadmata!",
"Call back": "Helista tagasi",
"This call has failed": "Kõne ühendamine ei õnnestunud",
"You missed this call": "Sa ei võtnud kõnet vastu",
"Unknown failure: %(reason)s)": "Tundmatu viga: %(reason)s",
"No answer": "Keegi ei vasta kõnele",
"You're removing all spaces. Access will default to invite only": "Sa oled eemaldamas kõiki kogukonnakeskuseid. Edaspidine ligipääs eeldab kutse olemasolu",
"Select spaces": "Vali kogukonnakeskused",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.": "Vali missugustel kogukonnakeskustel on sellele jututoale ligipääs. Kui kogukonnakeskus on valitud, siis selle liikmed saavad <RoomName/> jututuba leida ja temaga liituda.",
"Search spaces": "Otsi kogukonnakeskusi",
"Spaces you know that contain this room": "Sulle teadaolevad kogukonnakeskused, millesse kuulub see jututuba",
"Other spaces or rooms you might not know": "Sellised muud jututoad ja kogukonnakeskused, mida sa ei pruugi teada",
"Automatically invite members from this room to the new one": "Kutsu jututoa senised liikmed automaatselt uude jututuppa",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>Palun arvesta, et uuendusega tehakse jututoast uus variant</b>. Kõik senised sõnumid jäävad sellesse jututuppa arhiveeritud olekus.",
"Only people invited will be able to find and join this room.": "See jututuba on leitav vaid kutse olemasolul ning liitumine on võimalik vaid kutse alusel.",
"Create a room": "Loo jututuba",
"Private room (invite only)": "Privaatne jututuba (kutse alusel)",
"Public room": "Avalik jututuba",
"Visible to space members": "Nähtav kogukonnakeskuse liikmetele",
"Room visibility": "Jututoa nähtavus",
"Spaces with access": "Ligipääsuga kogukonnakeskused",
"Anyone in %(spaceName)s can find and join. You can select other spaces too.": "Kõik %(spaceName)s kogukonnakeskuse liikmed saavad leida ja liituda. Sa võid valida muid kogukonnakeskuseid.",
"Anyone in a space can find and join. You can select multiple spaces.": "Kõik kogukonnakeskuse liikmed saavad leida ja liituda. Sa võid valida ka mitu kogukonnakeskust.",
"Space members": "Kogukonnakeskuse liikmed",
"Decide who can join %(roomName)s.": "Vali, kes saavad liituda %(roomName)s jututoaga.",
"People with supported clients will be able to join the room without having a registered account.": "Kõik kes kasutavad sobilikke klientrakendusi, saavad jututoaga liituda ilma kasutajakonto registreerimiseta.",
"Access": "Ligipääs",
"The voice message failed to upload.": "Häälsõnumi üleslaadimine ei õnnestunud.",
"Everyone in <SpaceName/> will be able to find and join this room.": "Kõik <SpaceName/> kogukonna liikmed saavad seda jututuba leida ning võivad temaga liituda.",
"You can change this at any time from room settings.": "Sa saad seda alati jututoa seadistustest muuta.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Mitte ainult <SpaceName/> kogukonna liikmed, vaid kõik saavad seda jututuba leida ja võivad temaga liituda."
}

View file

@ -2293,5 +2293,17 @@
"Wrong file type": "Okerreko fitxategi-mota",
"Looks good!": "Itxura ona du!",
"Search rooms": "Bilatu gelak",
"User menu": "Erabiltzailea-menua"
"User menu": "Erabiltzailea-menua",
"Integration manager": "Integrazio-kudeatzailea",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Zure %(brand)s aplikazioak ez dizu hau egiteko integrazio kudeatzaile bat erabiltzen uzten. Kontaktatu administratzaileren batekin.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Trepeta hau erabiltzean <helpIcon /> %(widgetDomain)s domeinuarekin eta zure integrazio kudeatzailearekin datuak partekatu daitezke.",
"Identity server is": "Identitate zerbitzaria",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integrazio kudeatzaileek konfigurazio datuak jasotzen dituzte, eta trepetak aldatu ditzakete, gelara gonbidapenak bidali, eta botere mailak zure izenean ezarri.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Erabili integrazio kudeatzaile bat botak, trepetak eta eranskailu multzoak kudeatzeko.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Erabili <b>(%(serverName)s)</b> integrazio kudeatzailea botak, trepetak eta eranskailu multzoak kudeatzeko.",
"Identity server": "Identitate zerbitzaria",
"Identity server (%(server)s)": "Identitate-zerbitzaria (%(server)s)",
"Could not connect to identity server": "Ezin izan da identitate-zerbitzarira konektatu",
"Not a valid identity server (status code %(code)s)": "Ez da identitate zerbitzari baliogarria (egoera-mezua %(code)s)",
"Identity server URL must be HTTPS": "Identitate zerbitzariaren URL-a HTTPS motakoa izan behar du"
}

View file

@ -3007,5 +3007,19 @@
"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 نیستند نیز شود"
"May include members not in %(communityName)s": "ممکن شامل اعضایی که در %(communityName)s نیستند نیز شود",
"Integration manager": "مدیر یکپارچگی",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "%(brand)s شما اجازهٔ استفاده از یک مدیر یکپارچگی را برای این کار نمی دهد. لطفاً با مدیری تماس بگیرید.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "استفاده از این ابزارک ممکن است داده‌هایی <helpIcon /> را با %(widgetDomain)s و مدیر یکپارچگیتان هم رسانی کند.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "برای مدیریت بات‌ها، ابزارک‌ها و بسته‌های برچسب، از یک مدیر پکپارچه‌سازی استفاده کنید.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "برای مدیریت بات‌ها، ابزارک‌ها و بسته‌های برچسب، از یک مدیر پکپارچه‌سازی <b>(%(serverName)s)</b> استفاده کنید.",
"Identity server": "کارساز هویت",
"Identity server (%(server)s)": "کارساز هویت (%(server)s)",
"Could not connect to identity server": "نتوانست به کارساز هویت وصل شود",
"Not a valid identity server (status code %(code)s)": "کارساز هویت معتبر نیست (کد وضعیت %(code)s)",
"Identity server URL must be HTTPS": "نشانی کارساز هویت باید HTTPS باشد",
"Transfer Failed": "انتقال شکست خورد",
"Unable to transfer call": "ناتوان در انتقال تماس",
"The user you called is busy.": "کاربر موردنظر مشغول است.",
"User Busy": "کاربر مشغول"
}

View file

@ -3003,5 +3003,17 @@
"Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Salli vertaisyhteydet 1:1-puheluille (jos otat tämän käyttöön, toinen osapuoli saattaa nähdä IP-osoitteesi)",
"Send and receive voice messages": "Lähetä ja vastaanota ääniviestejä",
"Show options to enable 'Do not disturb' mode": "Näytä asetukset Älä häiritse -tilan ottamiseksi käyttöön",
"%(deviceId)s from %(ip)s": "%(deviceId)s osoitteesta %(ip)s"
"%(deviceId)s from %(ip)s": "%(deviceId)s osoitteesta %(ip)s",
"Integration manager": "Integraatioiden lähde",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "%(brand)s-instanssisi ei salli sinun käyttävän integraatioiden lähdettä tämän tekemiseen. Ota yhteys ylläpitäjääsi.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Tämän sovelman käyttäminen saattaa jakaa tietoa <helpIcon /> osoitteille %(widgetDomain)s ja käyttämällesi integraatioiden lähteelle.",
"Identity server is": "Identiteettipalvelin on",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integraatioiden lähteet vastaanottavat asetusdataa ja voivat muokata sovelmia, lähettää kutsuja huoneeseen ja asettaa oikeustasoja puolestasi.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Käytä integraatioiden lähdettä bottien, sovelmien ja tarrapakettien hallintaan.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Käytä integraatioiden lähdettä <b>(%(serverName)s)</b> bottien, sovelmien ja tarrapakettien hallintaan.",
"Identity server": "Identiteettipalvelin",
"Identity server (%(server)s)": "Identiteettipalvelin (%(server)s)",
"Could not connect to identity server": "Identiteettipalvelimeen ei saatu yhteyttä",
"Not a valid identity server (status code %(code)s)": "Ei kelvollinen identiteettipalvelin (tilakoodi %(code)s)",
"Identity server URL must be HTTPS": "Identiteettipalvelimen URL-osoitteen täytyy olla HTTPS-alkuinen"
}

View file

@ -427,7 +427,7 @@
"You are no longer ignoring %(userId)s": "Vous nignorez plus %(userId)s",
"Invite to Community": "Inviter dans la communauté",
"Communities": "Communautés",
"Message Pinning": "Épingler un message",
"Message Pinning": "Messages épinglés",
"Mention": "Mentionner",
"Unignore": "Ne plus ignorer",
"Ignore": "Ignorer",
@ -3456,5 +3456,42 @@
"%(targetName)s accepted an invitation": "%(targetName)s a accepté une invitation",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s a accepté linvitation pour %(displayName)s",
"Some invites couldn't be sent": "Certaines invitations nont pas pu être envoyées",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "Nous avons envoyé les invitations, mais les personnes ci-dessous nont pas pu être invitées à rejoindre <RoomName/>"
"We sent the others, but the below people couldn't be invited to <RoomName/>": "Nous avons envoyé les invitations, mais les personnes ci-dessous nont pas pu être invitées à rejoindre <RoomName/>",
"Integration manager": "Gestionnaire dintégration",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Votre %(brand)s ne vous autorise pas à utiliser un gestionnaire dintégrations pour faire ça. Contactez un administrateur.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Lutilisation de ce widget pourrait partager des données <helpIcon /> avec %(widgetDomain)s et votre gestionnaire dintégrations.",
"Identity server is": "Le serveur d'identité est",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Les gestionnaires dintégrations reçoivent les données de configuration et peuvent modifier les widgets, envoyer des invitations aux salons et définir les rangs à votre place.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Utilisez un gestionnaire dintégrations pour gérer les robots, les widgets et les jeux dautocollants.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Utilisez un gestionnaire dintégrations <b>(%(serverName)s)</b> pour gérer les robots, les widgets et les jeux dautocollants.",
"Identity server": "Serveur didentité",
"Identity server (%(server)s)": "Serveur didentité (%(server)s)",
"Could not connect to identity server": "Impossible de se connecter au serveur didentité",
"Not a valid identity server (status code %(code)s)": "Serveur didentité non valide (code de statut %(code)s)",
"Identity server URL must be HTTPS": "LURL du serveur didentité doit être en HTTPS",
"User Directory": "Répertoire utilisateur",
"Error processing audio message": "Erreur lors du traitement du message audio",
"Copy Link": "Copier le lien",
"Show %(count)s other previews|one": "Afficher %(count)s autre aperçu",
"Show %(count)s other previews|other": "Afficher %(count)s autres aperçus",
"Images, GIFs and videos": "Images, GIF et vidéos",
"Code blocks": "Blocs de code",
"Displaying time": "Affichage de lheure",
"To view all keyboard shortcuts, click here.": "Pour afficher tous les raccourcis clavier, cliquez ici.",
"Keyboard shortcuts": "Raccourcis clavier",
"There was an error loading your notification settings.": "Une erreur est survenue lors du chargement de vos paramètres de notification.",
"Mentions & keywords": "Mentions et mots-clés",
"Global": "Global",
"New keyword": "Nouveau mot-clé",
"Keyword": "Mot-clé",
"Enable email notifications for %(email)s": "Activer les notifications par e-mail pour %(email)s",
"Enable for this account": "Activer pour ce compte",
"An error occurred whilst saving your notification preferences.": "Une erreur est survenue lors de la sauvegarde de vos préférences de notification.",
"Error saving notification preferences": "Erreur lors de la sauvegarde des préférences de notification",
"Messages containing keywords": "Message contenant les mots-clés",
"Use Ctrl + F to search timeline": "Utilisez Ctrl + F pour rechercher dans le fil de discussion",
"Use Command + F to search timeline": "Utilisez Commande + F pour rechercher dans le fil de discussion",
"User %(userId)s is already invited to the room": "Lutilisateur %(userId)s est déjà invité dans le salon",
"Transfer Failed": "Échec du transfert",
"Unable to transfer call": "Impossible de transférer lappel"
}

View file

@ -3398,5 +3398,147 @@
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Se tes permisos, abre o menú en calquera mensaxe e elixe <b>Fixar</b> para pegalos aquí.",
"Nothing pinned, yet": "Nada fixado, por agora",
"End-to-end encryption isn't enabled": "Non está activado o cifrado de extremo-a-extremo",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "As túas mensaxes privadas normalmente están cifradas, pero esta sala non. Habitualmente esto é debido a que se utiliza un dispositivo ou métodos no soportados, como convites por email. <a>Activa o cifrado nos axustes.</a>"
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "As túas mensaxes privadas normalmente están cifradas, pero esta sala non. Habitualmente esto é debido a que se utiliza un dispositivo ou métodos no soportados, como convites por email. <a>Activa o cifrado nos axustes.</a>",
"Integration manager": "Xestor de Integracións",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "O teu %(brand)s non permite que uses o Xestor de Integracións, contacta coa administración.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Ao utilizar este widget poderías compartir datos <helpIcon /> con %(widgetDomain)s e o teu Xestor de integracións.",
"Identity server is": "O servidor de identidade é",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Os xestores de integracións reciben datos de configuración, e poden modificar os widgets, enviar convites das salas, e establecer roles no teu nome.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Usa un Xestor de Integracións para xestionar bots, widgets e paquetes de adhesivos.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Usa un Xestor de Integración <b>(%(serverName)s)</b> para xestionar bots, widgets e paquetes de adhesivos.",
"Identity server": "Servidor de identidade",
"Identity server (%(server)s)": "Servidor de Identidade (%(server)s)",
"Could not connect to identity server": "Non hai conexión co Servidor de Identidade",
"Not a valid identity server (status code %(code)s)": "Servidor de Identidade non válido (código de estado %(code)s)",
"Identity server URL must be HTTPS": "O URL do servidor de identidade debe comezar HTTPS",
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\nThis will be reported to the administrators of %(homeserver)s. The administrators will NOT be able to read the encrypted content of this room.": "Esta sala está dedicada a contido ilegal ou tóxico ou a moderación non modera os contidos tóxicos ou ilegais.\nEsto vaise denunciar ante a administración de %(homeserver)s. As administradoras NON poderán ler o contido cifrado desta sala.",
"This user is spamming the room with ads, links to ads or to propaganda.\nThis will be reported to the room moderators.": "Esta usuaria está facendo spam na sala con anuncios, ligazóns a anuncios ou propaganda.\nEsto vai ser denunciado ante a moderación da sala.",
"This user is displaying illegal behaviour, for instance by doxing people or threatening violence.\nThis will be reported to the room moderators who may escalate this to legal authorities.": "Esta usuaria está a comportarse dun xeito ilegal, por exemplo ameazando a persoas ou exhibindo violencia.\nEsto vaise denunciar ante a moderación da sala que podería presentar o caso ante as autoridades legais.",
"This user is displaying toxic behaviour, for instance by insulting other users or sharing adult-only content in a family-friendly room or otherwise violating the rules of this room.\nThis will be reported to the room moderators.": "Esta usuaria ten un comportamento tóxico, por exemplo insultar a outras usuarias o compartir contido adulto nunha sala de contido familiar ou faltando doutro xeito ás regras desta sala.\nVai ser denunciada ante a moderación da sala.",
"What this user is writing is wrong.\nThis will be reported to the room moderators.": "O que escribe esta usuaria non é correcto.\nSerá denunciado á moderación da sala.",
"User Directory": "Directorio de Usuarias",
"Please provide an address": "Proporciona un enderezo",
"%(oneUser)schanged the server ACLs %(count)s times|one": "%(oneUser)s cambiou ACLs do servidor",
"%(oneUser)schanged the server ACLs %(count)s times|other": "%(oneUser)s cambiou o ACLs do servidor %(count)s veces",
"%(severalUsers)schanged the server ACLs %(count)s times|one": "%(severalUsers)s cambiaron o ACLs do servidor",
"%(severalUsers)schanged the server ACLs %(count)s times|other": "%(severalUsers)s cambiaron ACLs do servidor %(count)s veces",
"Message search initialisation failed, check <a>your settings</a> for more information": "Fallou a inicialización da busca de mensaxes, comproba <a>os axustes</a> para máis información",
"Error processing audio message": "Erro ao procesar a mensaxe de audio",
"Set addresses for this space so users can find this space through your homeserver (%(localDomain)s)": "Establecer enderezos para este espazo para que as usuarias poidan atopar o espazo no servidor (%(localDomain)s)",
"To publish an address, it needs to be set as a local address first.": "Para publicar un enderezo, primeiro debe establecerse como enderezo local.",
"Published addresses can be used by anyone on any server to join your room.": "Os enderezos publicados poden ser utilizados por calquera en calquera servidor para unirse á túa sala.",
"Published addresses can be used by anyone on any server to join your space.": "Os enderezos publicados podense usar por calquera en calquera servidor para unirse ao teu espazo.",
"This space has no local addresses": "Este espazo non ten enderezos locais",
"Copy Link": "Copiar Ligazón",
"Show %(count)s other previews|one": "Mostrar %(count)s outra vista previa",
"Show %(count)s other previews|other": "Mostrar outras %(count)s vistas previas",
"Space information": "Información do Espazo",
"Images, GIFs and videos": "Imaxes, GIFs e vídeos",
"Code blocks": "Bloques de código",
"Displaying time": "Mostrar hora",
"To view all keyboard shortcuts, click here.": "Para ver os atallos do teclado preme aquí.",
"Keyboard shortcuts": "Atallos de teclado",
"There was an error loading your notification settings.": "Houbo un erro ao cargar os axustes de notificación.",
"Mentions & keywords": "Mencións e palabras chave",
"Global": "Global",
"New keyword": "Nova palabra chave",
"Keyword": "Palabra chave",
"Enable email notifications for %(email)s": "Activar notificacións de email para %(email)s",
"Enable for this account": "Activar para esta conta",
"An error occurred whilst saving your notification preferences.": "Algo fallou ao gardar as túas preferencias de notificación.",
"Error saving notification preferences": "Erro ao gardar os axustes de notificación",
"Messages containing keywords": "Mensaxes coas palabras chave",
"Collapse": "Pechar",
"Expand": "Despregar",
"Recommended for public spaces.": "Recomendado para espazos públicos.",
"Allow people to preview your space before they join.": "Permitir que sexa visible o espazo antes de unirte a el.",
"Preview Space": "Vista previa do Espazo",
"only invited people can view and join": "só poden ver e unirse persoas que foron convidadas",
"anyone with the link can view and join": "calquera coa ligazón pode ver e unirse",
"Decide who can view and join %(spaceName)s.": "Decidir quen pode ver e unirse a %(spaceName)s.",
"Visibility": "Visibilidade",
"This may be useful for public spaces.": "Esto podería ser útil para espazos públicos.",
"Guests can join a space without having an account.": "As convidadas poden unirse ao espazo sen ter unha conta.",
"Enable guest access": "Activar acceso de convidadas",
"Failed to update the history visibility of this space": "Fallou a actualización da visibilidade do historial do espazo",
"Failed to update the guest access of this space": "Fallou a actualización do acceso de convidadas ao espazo",
"Failed to update the visibility of this space": "Fallou a actualización da visibilidade do espazo",
"Address": "Enderezo",
"e.g. my-space": "ex. o-meu-espazo",
"Silence call": "Acalar chamada",
"Sound on": "Son activado",
"Use Ctrl + F to search timeline": "Usar Ctrl + F para buscar na cronoloxía",
"Use Command + F to search timeline": "Usar Command + F para buscar na cronoloxía",
"Show notification badges for People in Spaces": "Mostra insignia de notificación para Persoas en Espazos",
"If disabled, you can still add Direct Messages to Personal Spaces. If enabled, you'll automatically see everyone who is a member of the Space.": "Se está desactivado tamén poderás engadir as Mensaxes Directas aos Espazos personais. Se activado, verás automáticamente quen é membro do Espazo.",
"Show people in spaces": "Mostrar persoas nos Espazos",
"Show all rooms in Home": "Mostrar tódalas salas no Inicio",
"User %(userId)s is already invited to the room": "A usuaria %(userId)s xa ten un convite para a sala",
"%(senderName)s changed the <a>pinned messages</a> for the room.": "%(senderName)s cambiou a <a>mensaxe fixada</a> da sala.",
"%(senderName)s kicked %(targetName)s": "%(senderName)s expulsou a %(targetName)s",
"%(senderName)s kicked %(targetName)s: %(reason)s": "%(senderName)s expulsou a %(targetName)s: %(reason)s",
"%(senderName)s withdrew %(targetName)s's invitation": "%(senderName)s retirou o convite para %(targetName)s",
"%(senderName)s withdrew %(targetName)s's invitation: %(reason)s": "%(senderName)s retirou o convite para %(targetName)s: %(reason)s",
"%(senderName)s unbanned %(targetName)s": "%(senderName)s retiroulle o veto a %(targetName)s",
"%(targetName)s left the room": "%(targetName)s saíu da sala",
"%(targetName)s left the room: %(reason)s": "%(targetName)s saíu da sala: %(reason)s",
"%(targetName)s rejected the invitation": "%(targetName)s rexeitou o convite",
"%(targetName)s joined the room": "%(targetName)s uniuse á sala",
"%(senderName)s made no change": "%(senderName)s non fixo cambios",
"%(senderName)s set a profile picture": "%(senderName)s estableceu a foto de perfil",
"%(senderName)s changed their profile picture": "%(senderName)s cambiou a súa foto de perfil",
"%(senderName)s removed their profile picture": "%(senderName)s eliminou a súa foto de perfil",
"%(senderName)s removed their display name (%(oldDisplayName)s)": "%(senderName)s eliminou o seu nome público (%(oldDisplayName)s)",
"%(senderName)s set their display name to %(displayName)s": "%(senderName)s estableceu o seu nome público como %(displayName)s",
"%(oldDisplayName)s changed their display name to %(displayName)s": "%(oldDisplayName)s cambiou o seu nome público a %(displayName)s",
"%(senderName)s banned %(targetName)s": "%(senderName)s vetou %(targetName)s",
"%(senderName)s banned %(targetName)s: %(reason)s": "%(senderName)s vetou %(targetName)s: %(reason)s",
"%(targetName)s accepted an invitation": "%(targetName)s aceptou o convite",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s aceptou o convite a %(displayName)s",
"Some invites couldn't be sent": "Non se puideron enviar algúns convites",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "Convidamos as outras, pero as persoas de aquí embaixo non foron convidadas a <RoomName/>",
"Transfer Failed": "Fallou a transferencia",
"Unable to transfer call": "Non se puido transferir a chamada",
"[number]": "[número]",
"To view %(spaceName)s, you need an invite": "Para ver %(spaceName)s precisas un convite",
"You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Podes premer en calquera momento nun avatar no panel de filtros para ver só salas e persoas asociadas con esa comunidade.",
"Unable to copy a link to the room to the clipboard.": "Non se copiou a ligazón da sala ao portapapeis.",
"Unable to copy room link": "Non se puido copiar ligazón da sala",
"Unnamed audio": "Audio sen nome",
"Move down": "Ir abaixo",
"Move up": "Ir arriba",
"Report": "Denunciar",
"Collapse reply thread": "Contraer fío de resposta",
"Show preview": "Ver vista previa",
"View source": "Ver fonte",
"Forward": "Reenviar",
"Settings - %(spaceName)s": "Axustes - %(spaceName)s",
"Report the entire room": "Denunciar a toda a sala",
"Spam or propaganda": "Spam ou propaganda",
"Illegal Content": "Contido ilegal",
"Toxic Behaviour": "Comportamento tóxico",
"Disagree": "En desacordo",
"Please pick a nature and describe what makes this message abusive.": "Escolle unha opción e describe a razón pola que esta é unha mensaxe abusiva.",
"Any other reason. Please describe the problem.\nThis will be reported to the room moderators.": "Outra razón. Por favor, describe o problema.\nInformaremos disto á moderación da sala.",
"This room is dedicated to illegal or toxic content or the moderators fail to moderate illegal or toxic content.\n This will be reported to the administrators of %(homeserver)s.": "Esta sala está dedicada a contido tóxico ou ilegal ou a moderación non é quen de moderar contido ilegal ou tóxico.\nImos informar disto á administración de %(homeserver)s.",
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Modelo de denuncia ante a moderación. Nas salas que teñen moderación, o botón `denuncia`permíteche denunciar un abuso á moderación da sala",
"Copy Room Link": "Copiar Ligazón da sala",
"Downloading": "Descargando",
"The call is in an unknown state!": "Esta chamada ten un estado descoñecido!",
"Call back": "Devolver a chamada",
"You missed this call": "Perdeches esta chamada",
"This call has failed": "A chamada fallou",
"Unknown failure: %(reason)s)": "Fallo descoñecido: %(reason)s",
"No answer": "Sen resposta",
"An unknown error occurred": "Aconteceu un fallo descoñecido",
"Their device couldn't start the camera or microphone": "O seu dispositivo non puido acender a cámara ou micrófono",
"Connection failed": "Fallou a conexión",
"Could not connect media": "Non se puido conectar o multimedia",
"This call has ended": "A chamada rematou",
"Connected": "Conectado",
"Message bubbles": "Burbullas con mensaxes",
"IRC": "IRC",
"New layout switcher (with message bubbles)": "Nova disposición do control (con burbullas con mensaxes)",
"Image": "Imaxe",
"Sticker": "Adhesivo"
}

View file

@ -2097,7 +2097,7 @@
"You do not have permission to create rooms in this community.": "אין לך הרשאה ליצור חדרים בקהילה זו.",
"Cannot create rooms in this community": "לא ניתן ליצור חדרים בקהילה זו",
"Failed to reject invitation": "דחיית ההזמנה נכשלה",
"Explore rooms": "שיטוט בחדרים",
"Explore rooms": "גלה חדרים",
"Create a Group Chat": "צור צ'אט קבוצתי",
"Explore Public Rooms": "חקור חדרים ציבוריים",
"Send a Direct Message": "שלח הודעה ישירה",
@ -2785,5 +2785,20 @@
"Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.": "לא ניתן היה להגיע לשרת הבית שלך ולא היה ניתן להתחבר. נסה שוב. אם זה נמשך, אנא פנה למנהל שרת הבית שלך.",
"Try again": "נסה שוב",
"We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.": "ביקשנו מהדפדפן לזכור באיזה שרת בית אתה משתמש כדי לאפשר לך להיכנס, אך למרבה הצער הדפדפן שלך שכח אותו. עבור לדף הכניסה ונסה שוב.",
"We couldn't log you in": "לא הצלחנו להתחבר אליך"
"We couldn't log you in": "לא הצלחנו להתחבר אליך",
"Integration manager": "מנהל אינטגרציה",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "%(brand)s שלכם אינו מאפשר לך להשתמש במנהל שילוב לשם כך. אנא צרו קשר עם מנהל מערכת.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "שימוש ביישומון זה עשוי לשתף נתונים <helpIcon /> עם %(widgetDomain)s ומנהל האינטגרציה שלך.",
"Identity server is": "שרת ההזדהות הינו",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "מנהלי שילוב מקבלים נתוני תצורה ויכולים לשנות ווידג'טים, לשלוח הזמנות לחדר ולהגדיר רמות הספק מטעמכם.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "השתמש במנהל שילוב לניהול בוטים, ווידג'טים וחבילות מדבקות.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "השתמש במנהל שילוב <b> (%(serverName)s) </b> לניהול בוטים, ווידג'טים וחבילות מדבקות.",
"Identity server": "שרת הזדהות",
"Identity server (%(server)s)": "שרת הזדהות (%(server)s)",
"Could not connect to identity server": "לא ניתן להתחבר אל שרת הזיהוי",
"Not a valid identity server (status code %(code)s)": "שרת זיהוי לא מאושר(קוד סטטוס %(code)s)",
"Identity server URL must be HTTPS": "הזיהוי של כתובת השרת חייבת להיות מאובטחת ב- HTTPS",
"Enter Security Phrase": "הזן ביטוי אבטחה",
"Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.": "לא ניתן לפענח גיבוי עם ביטוי אבטחה זה: אנא ודא שהזנת את ביטוי האבטחה הנכון.",
"Incorrect Security Phrase": "ביטוי אבטחה שגוי"
}

View file

@ -588,5 +588,6 @@
"The user must be unbanned before they can be invited.": "उपयोगकर्ता को आमंत्रित करने से पहले उन्हें प्रतिबंधित किया जाना चाहिए।",
"Explore rooms": "रूम का अन्वेषण करें",
"Sign In": "साइन करना",
"Create Account": "खाता बनाएं"
"Create Account": "खाता बनाएं",
"Identity server is": "आइडेंटिटी सर्वर हैं"
}

View file

@ -205,5 +205,8 @@
"Add Email Address": "Dodaj email adresu",
"Confirm": "Potvrdi",
"Click the button below to confirm adding this email address.": "Kliknite gumb ispod da biste potvrdili dodavanje ove email adrese.",
"Confirm adding email": "Potvrdite dodavanje email adrese"
"Confirm adding email": "Potvrdite dodavanje email adrese",
"Integration manager": "Upravitelj integracijama",
"Identity server": "Poslužitelj identiteta",
"Could not connect to identity server": "Nije moguće spojiti se na poslužitelja identiteta"
}

View file

@ -3476,5 +3476,29 @@
"Address": "Cím",
"e.g. my-space": "pl. én-terem",
"Silence call": "Némít",
"Sound on": "Hang be"
"Sound on": "Hang be",
"Use Command + F to search timeline": "Command + F az idővonalon való kereséshez",
"Unnamed audio": "Névtelen hang",
"Error processing audio message": "Hiba a hangüzenet feldolgozásánál",
"Show %(count)s other previews|one": "%(count)s további előnézet megjelenítése",
"Show %(count)s other previews|other": "%(count)s további előnézet megjelenítése",
"Images, GIFs and videos": "Képek, GIFek és videók",
"Code blocks": "Kód blokkok",
"Displaying time": "Idő megjelenítése",
"To view all keyboard shortcuts, click here.": "A billentyűzet kombinációk megjelenítéséhez kattintson ide.",
"Keyboard shortcuts": "Billentyűzet kombinációk",
"Use Ctrl + F to search timeline": "Ctrl + F az idővonalon való kereséshez",
"User %(userId)s is already invited to the room": "%(userId)s felhasználó már kapott meghívót a szobába",
"Integration manager": "Integrációs Menedzser",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "A %(brand)sod nem használhat ehhez Integrációs Menedzsert. Kérlek vedd fel a kapcsolatot az adminisztrátorral.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Ennek a kisalkalmazásnak a használata adatot oszthat meg <helpIcon /> a(z) %(widgetDomain)s oldallal és az Integrációkezelővel.",
"Identity server is": "Azonosítási szerver",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integrációs Menedzser megkapja a konfigurációt, módosíthat kisalkalmazásokat, szobához meghívót küldhet és a hozzáférési szintet beállíthatja helyetted.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Használj Integrációs Menedzsert a botok, kisalkalmazások és matrica csomagok kezeléséhez.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Használj Integrációs Menedzsert <b>(%(serverName)s)</b> a botok, kisalkalmazások és matrica csomagok kezeléséhez.",
"Identity server": "Azonosító szerver",
"Identity server (%(server)s)": "Azonosítási kiszolgáló (%(server)s)",
"Could not connect to identity server": "Az Azonosítási Szerverhez nem lehet csatlakozni",
"Not a valid identity server (status code %(code)s)": "Az Azonosítási Szerver nem érvényes (státusz kód: %(code)s)",
"Identity server URL must be HTTPS": "Az Azonosítási Szerver URL-jének HTTPS-nek kell lennie"
}

View file

@ -279,5 +279,9 @@
"A call is currently being placed!": "Sedang melakukan panggilan sekarang!",
"A call is already in progress!": "Masih ada panggilan berlangsung!",
"Permission Required": "Permisi Dibutuhkan",
"You do not have permission to start a conference call in this room": "Anda tidak memiliki permisi untuk memulai panggilan massal di ruang ini"
"You do not have permission to start a conference call in this room": "Anda tidak memiliki permisi untuk memulai panggilan massal di ruang ini",
"Explore rooms": "Jelajahi ruang",
"Sign In": "Masuk",
"Create Account": "Buat Akun",
"Identity server": "Server Identitas"
}

View file

@ -728,5 +728,7 @@
"Explore all public rooms": "Kanna öll almenningsherbergi",
"Liberate your communication": "Frelsaðu samskipti þín",
"Welcome to <name/>": "Velkomin til <name/>",
"Welcome to %(appName)s": "Velkomin til %(appName)s"
"Welcome to %(appName)s": "Velkomin til %(appName)s",
"Identity server is": "Auðkennisþjónn er",
"Identity server": "Auðkennisþjónn"
}

View file

@ -564,7 +564,7 @@
"Click to mute audio": "Clicca per silenziare l'audio",
"Clear filter": "Annulla filtro",
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Si è tentato di caricare un punto specifico nella cronologia della stanza, ma non hai l'autorizzazione per vedere il messaggio in questione.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Si è tentato di caricare un punto specifico nella cronologia della stanza, ma non si è trovato.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Si è tentato di caricare un punto specifico nella cronologia della stanza, ma non è stato trovato.",
"Failed to load timeline position": "Caricamento posizione cronologica fallito",
"Uploading %(filename)s and %(count)s others|other": "Invio di %(filename)s e altri %(count)s",
"Uploading %(filename)s and %(count)s others|zero": "Invio di %(filename)s",
@ -1266,7 +1266,7 @@
"Sends the given message coloured as a rainbow": "Invia il messaggio dato colorato come un arcobaleno",
"Sends the given emote coloured as a rainbow": "Invia l'emoticon dato colorato come un arcobaleno",
"The user's homeserver does not support the version of the room.": "L'homeserver dell'utente non supporta la versione della stanza.",
"Show hidden events in timeline": "Mostra eventi nascosti nella timeline",
"Show hidden events in timeline": "Mostra eventi nascosti nella linea temporale",
"When rooms are upgraded": "Quando le stanze vengono aggiornate",
"this room": "questa stanza",
"View older messages in %(roomName)s.": "Vedi messaggi più vecchi in %(roomName)s.",
@ -1485,7 +1485,7 @@
"Error changing power level requirement": "Errore nella modifica del livello dei permessi",
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "C'é stato un errore nel cambio di libelli dei permessi. Assicurati di avere i permessi necessari e riprova.",
"No recent messages by %(user)s found": "Non sono stati trovati messaggi recenti dell'utente %(user)s",
"Try scrolling up in the timeline to see if there are any earlier ones.": "Prova a scorrere la timeline per vedere se ce ne sono di precedenti.",
"Try scrolling up in the timeline to see if there are any earlier ones.": "Prova a scorrere la linea temporale per vedere se ce ne sono di precedenti.",
"Remove recent messages by %(user)s": "Rimuovi gli ultimi messaggi di %(user)s",
"You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|other": "Stai per rimuovere %(count)s messaggi di %(user)s. L'azione é irreversibile. Vuoi continuare?",
"For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.": "Se i messaggi sono tanti può volerci un po' di tempo. Nel frattempo, per favore, non fare alcun refresh.",
@ -2043,7 +2043,7 @@
"Collapse room list section": "Riduci sezione elenco stanze",
"Expand room list section": "Espandi sezione elenco stanze",
"Clear room list filter field": "Svuota campo filtri elenco stanze",
"Scroll up/down in the timeline": "Scorri su/giù nella cronologia",
"Scroll up/down in the timeline": "Scorri su/giù nella linea temporale",
"Toggle the top left menu": "Attiva/disattiva menu in alto a sinistra",
"Close dialog or context menu": "Chiudi finestra o menu contestuale",
"Activate selected button": "Attiva pulsante selezionato",
@ -3481,5 +3481,107 @@
"%(senderName)s changed their profile picture": "%(senderName)s ha cambiato la propria immagine del profilo",
"%(senderName)s removed their profile picture": "%(senderName)s ha rimosso la propria immagine del profilo",
"%(senderName)s removed their display name (%(oldDisplayName)s)": "%(senderName)s ha rimosso il proprio nome (%(oldDisplayName)s)",
"%(senderName)s set their display name to %(displayName)s": "%(senderName)s ha impostato il proprio nome a %(displayName)s"
"%(senderName)s set their display name to %(displayName)s": "%(senderName)s ha impostato il proprio nome a %(displayName)s",
"Integration manager": "Gestore di integrazioni",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Il tuo %(brand)s non ti permette di usare il gestore di integrazioni per questa azione. Contatta un amministratore.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Usando questo widget i dati possono essere condivisi <helpIcon /> con %(widgetDomain)s e il tuo gestore di integrazioni.",
"Identity server is": "Il server di identità è",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "I gestori di integrazione ricevono dati di configurazione e possono modificare widget, inviare inviti alla stanza, assegnare permessi a tuo nome.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Usa un gestore di integrazioni per gestire bot, widget e pacchetti di adesivi.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Usa un gestore di integrazioni <b>(%(serverName)s)</b> per gestire bot, widget e pacchetti di adesivi.",
"Identity server": "Server di identità",
"Identity server (%(server)s)": "Server di identità (%(server)s)",
"Could not connect to identity server": "Impossibile connettersi al server di identità",
"Not a valid identity server (status code %(code)s)": "Non è un server di identità valido (codice di stato %(code)s)",
"Identity server URL must be HTTPS": "L'URL del server di identità deve essere HTTPS",
"Unable to copy a link to the room to the clipboard.": "Impossibile copiare un collegamento alla stanza negli appunti.",
"Unable to copy room link": "Impossibile copiare il link della stanza",
"Unnamed audio": "Audio senza nome",
"Error processing audio message": "Errore elaborazione messaggio audio",
"Copy Link": "Copia collegamento",
"Show %(count)s other previews|one": "Mostra %(count)s altra anteprima",
"Show %(count)s other previews|other": "Mostra altre %(count)s anteprime",
"Images, GIFs and videos": "Immagini, GIF e video",
"Code blocks": "Blocchi di codice",
"To view all keyboard shortcuts, click here.": "Per vedere tutte le scorciatoie, clicca qui.",
"Keyboard shortcuts": "Scorciatoie da tastiera",
"There was an error loading your notification settings.": "Si è verificato un errore caricando le tue impostazioni di notifica.",
"Mentions & keywords": "Menzioni e parole chiave",
"Global": "Globale",
"New keyword": "Nuova parola chiave",
"Keyword": "Parola chiave",
"Enable email notifications for %(email)s": "Attive le notifiche email per %(email)s",
"Enable for this account": "Attiva per questo account",
"An error occurred whilst saving your notification preferences.": "Si è verificato un errore durante il salvataggio delle tue preferenze di notifica.",
"Error saving notification preferences": "Errore nel salvataggio delle preferenze di notifica",
"Messages containing keywords": "Messaggi contenenti parole chiave",
"Use Ctrl + F to search timeline": "Usa Ctrl + F per cercare nella linea temporale",
"Use Command + F to search timeline": "Usa Command + F per cercare nella linea temporale",
"User %(userId)s is already invited to the room": "L'utente %(userId)s è già stato invitato nella stanza",
"Transfer Failed": "Trasferimento fallito",
"Unable to transfer call": "Impossibile trasferire la chiamata",
"New layout switcher (with message bubbles)": "Nuovo commutatore disposizione (con nuvolette dei messaggi)",
"Error downloading audio": "Errore di scaricamento dell'audio",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>Nota che aggiornare creerà una nuova versione della stanza</b>. Tutti i messaggi attuali resteranno in questa stanza archiviata.",
"Automatically invite members from this room to the new one": "Invita automaticamente i membri da questa stanza a quella nuova",
"These are likely ones other room admins are a part of.": "Questi sono probabilmente quelli di cui fanno parte gli altri amministratori delle stanze.",
"Other spaces or rooms you might not know": "Altri spazi o stanze che potresti non conoscere",
"Spaces you know that contain this room": "Spazi di cui sai che contengono questa stanza",
"Search spaces": "Cerca spazi",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.": "Decidi quali spazi possono accedere a questa stanza. Se uno spazio è selezionato, i suoi membri possono trovare ed entrare in <RoomName/>.",
"Select spaces": "Seleziona spazi",
"You're removing all spaces. Access will default to invite only": "Stai rimuovendo tutti gli spazi. L'accesso tornerà solo su invito",
"User Directory": "Elenco utenti",
"Room visibility": "Visibilità stanza",
"Visible to space members": "Visibile ai membri dello spazio",
"Public room": "Stanza pubblica",
"Private room (invite only)": "Stanza privata (solo a invito)",
"Create a room": "Crea una stanza",
"Only people invited will be able to find and join this room.": "Solo le persone invitate potranno trovare ed entrare in questa stanza.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Chiunque potrà trovare ed entrare in questa stanza, non solo i membri di <SpaceName/>.",
"You can change this at any time from room settings.": "Puoi cambiarlo in qualsiasi momento dalle impostazioni della stanza.",
"Everyone in <SpaceName/> will be able to find and join this room.": "Chiunque in <SpaceName/> potrà trovare ed entrare in questa stanza.",
"Image": "Immagine",
"Sticker": "Sticker",
"Downloading": "Scaricamento",
"The call is in an unknown state!": "La chiamata è in uno stato sconosciuto!",
"Call back": "Richiama",
"You missed this call": "Hai perso questa chiamata",
"This call has failed": "Questa chiamata è fallita",
"Unknown failure: %(reason)s)": "Errore sconosciuto: %(reason)s)",
"No answer": "Nessuna risposta",
"An unknown error occurred": "Si è verificato un errore sconosciuto",
"Their device couldn't start the camera or microphone": "Il suo dispositivo non ha potuto avviare la fotocamera o il microfono",
"Connection failed": "Connessione fallita",
"Could not connect media": "Connessione del media fallita",
"This call has ended": "Questa chiamata è terminata",
"Connected": "Connesso",
"The voice message failed to upload.": "Invio del messaggio vocale fallito.",
"Copy Room Link": "Copia collegamento stanza",
"Access": "Accesso",
"People with supported clients will be able to join the room without having a registered account.": "Le persone con client supportati potranno entrare nella stanza senza avere un account registrato.",
"Decide who can join %(roomName)s.": "Decidi chi può entrare in %(roomName)s.",
"Space members": "Membri dello spazio",
"Anyone in a space can find and join. You can select multiple spaces.": "Chiunque in uno spazio può trovare ed entrare. Puoi selezionare più spazi.",
"Anyone in %(spaceName)s can find and join. You can select other spaces too.": "Chiunque in %(spaceName)s può trovare ed entrare. Puoi selezionare anche altri spazi.",
"Spaces with access": "Spazi con accesso",
"Anyone in a space can find and join. <a>Edit which spaces can access here.</a>": "Chiunque in uno spazio può trovare ed entrare. <a>Modifica quali spazi possono accedere qui.</a>",
"Currently, %(count)s spaces have access|other": "Attualmente, %(count)s spazi hanno accesso",
"& %(count)s more|other": "e altri %(count)s",
"Upgrade required": "Aggiornamento necessario",
"Anyone can find and join.": "Chiunque può trovare ed entrare.",
"Only invited people can join.": "Solo le persone invitate possono entrare.",
"Private (invite only)": "Privato (solo a invito)",
"This upgrade will allow members of selected spaces access to this room without an invite.": "Questo aggiornamento permetterà ai membri di spazi selezionati di accedere alla stanza senza invito.",
"Message bubbles": "Messaggi",
"IRC": "IRC",
"This makes it easy for rooms to stay private to a space, while letting people in the space find and join them. All new rooms in a space will have this option available.": "Ciò rende facile mantenere private le stanze in uno spazio, mentre le persone potranno trovarle ed unirsi. Tutte le stanze nuove in uno spazio avranno questa opzione disponibile.",
"To help space members find and join a private room, go to that room's Security & Privacy settings.": "Per aiutare i membri dello spazio a trovare ed entrare in una stanza privata, vai nelle impostazioni \"Sicurezza e privacy\" di quella stanza.",
"Help space members find private rooms": "Aiuta i membri dello spazio a trovare stanze private",
"Help people in spaces to find and join private rooms": "Aiuta le persone negli spazi a trovare ed entrare nelle stanze private",
"New in the Spaces beta": "Novità nella beta degli spazi",
"They didn't pick up": "Non ha risposto",
"Call again": "Richiama",
"They declined this call": "Ha rifiutato questa chiamata",
"You declined this call": "Hai rifiutato questa chiamata"
}

View file

@ -2504,5 +2504,15 @@
"You can change these anytime.": "ここで入力した情報はいつでも編集できます。",
"Add some details to help people recognise it.": "情報を入力してください。",
"View dev tools": "開発者ツールを表示",
"To view %(spaceName)s, you need an invite": "%(spaceName)s を閲覧するには招待が必要です"
"To view %(spaceName)s, you need an invite": "%(spaceName)s を閲覧するには招待が必要です",
"Integration manager": "インテグレーションマネージャ",
"Identity server is": "アイデンティティ・サーバー",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "インテグレーションマネージャは設定データを受け取り、ユーザーの代わりにウィジェットの変更、部屋への招待の送信、権限レベルの設定を行うことができます。",
"Use an integration manager to manage bots, widgets, and sticker packs.": "インテグレーションマネージャを使用して、ボット、ウィジェット、ステッカーパックを管理します。",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "インテグレーションマネージャ <b>(%(serverName)s)</b> を使用して、ボット、ウィジェット、ステッカーパックを管理します。",
"Identity server": "認証サーバ",
"Identity server (%(server)s)": "identity サーバー (%(server)s)",
"Could not connect to identity server": "identity サーバーに接続できませんでした",
"Not a valid identity server (status code %(code)s)": "有効な identity サーバーではありません (ステータスコード %(code)s)",
"Identity server URL must be HTTPS": "identityサーバーのURLは HTTPS スキーマである必要があります"
}

View file

@ -2754,5 +2754,17 @@
"(an error occurred)": "(tella-d tuccḍa)",
"(connection failed)": "(tuqqna ur teddi ara)",
"🎉 All servers are banned from participating! This room can no longer be used.": "🎉 Iqeddcen akk ttwagedlen seg uttekki! Taxxamt-a dayen ur tettuseqdac ara.",
"Try again": "Ɛreḍ tikkelt-nniḍen"
"Try again": "Ɛreḍ tikkelt-nniḍen",
"Integration manager": "Amsefrak n umsidef",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "%(brand)s-ik·im ur ak·am yefki ara tisirag i useqdec n umsefrak n umsidef i wakken ad tgeḍ aya. Ttxil-k·m nermes anedbal.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Aseqdec n uwiǧit-a yezmer ad yebḍu isefka <helpIcon/> d %(widgetDomain)s & amsefrak-inek·inem n umsidef.",
"Identity server is": "Aqeddac n timagit d",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Imsefrak n yimsidaf remmsen-d isefka n uswel, syen ad uɣalen zemren ad beddlen iwiǧiten, ad aznen tinubgiwin ɣer texxamin, ad yesbadu daɣen tazmert n yiswiren s yiswiren deg ubdil-ik·im.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Seqdec amsefrak n umsidef i usefrek n yibuten, n yiwiǧiten d tɣawsiwin n usenteḍ.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Seqdec amsefrak n umsidef <b>(%(serverName)s)</b> i usefrek n yibuten, n yiwiǧiten d tɣawsiwin n usenteḍ.",
"Identity server": "Aqeddac n timagit",
"Identity server (%(server)s)": "Aqeddac n timagit (%(server)s)",
"Could not connect to identity server": "Ur izmir ara ad yeqqen ɣer uqeddac n timagit",
"Not a valid identity server (status code %(code)s)": "Aqeddac n timagit mačči d ameɣtu (status code %(code)s)",
"Identity server URL must be HTTPS": "URL n uqeddac n timagit ilaq ad yili d HTTPS"
}

View file

@ -1667,5 +1667,13 @@
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "사용자 %(userId)s의 세션 %(deviceId)s에서 받은 서명 키와 당신이 제공한 서명 키가 일치합니다. 세션이 검증되었습니다.",
"Show more": "더 보기",
"Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "비밀번호를 변경한다면 방의 암호화 키를 내보낸 후 다시 가져오지 않는 이상 모든 종단간 암호화 키는 초기화 될 것이고, 암호화된 대화 내역은 읽을 수 없게 될 것입니다. 이 문제는 추후에 개선될 것입니다.",
"Create Account": "계정 만들기"
"Create Account": "계정 만들기",
"Integration manager": "통합 관리자",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "이 위젯을 사용하면 <helpcon /> %(widgetDomain)s & 통합 관리자와 데이터를 공유합니다.",
"Identity server is": "ID 서버:",
"Identity server": "ID 서버",
"Identity server (%(server)s)": "ID 서버 (%(server)s)",
"Could not connect to identity server": "ID 서버에 연결할 수 없음",
"Not a valid identity server (status code %(code)s)": "올바르지 않은 ID 서버 (상태 코드 %(code)s)",
"Identity server URL must be HTTPS": "ID 서버 URL은 HTTPS이어야 함"
}

View file

@ -2421,5 +2421,17 @@
"New Zealand": "Naujoji Zelandija",
"New Caledonia": "Naujoji Kaledonija",
"Netherlands": "Nyderlandai",
"Cayman Islands": "Kaimanų Salos"
"Cayman Islands": "Kaimanų Salos",
"Integration manager": "Integracijų tvarkytuvas",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Jūsų %(brand)s neleidžia jums naudoti integracijų tvarkytuvo tam atlikti. Susisiekite su administratoriumi.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Naudojimasis šiuo valdikliu gali pasidalinti duomenimis <helpIcon /> su %(widgetDomain)s ir jūsų integracijų tvarkytuvu.",
"Identity server is": "Tapatybės serveris yra",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integracijų Tvarkytuvai gauna konfigūracijos duomenis ir jūsų vardu gali keisti valdiklius, siųsti kambario pakvietimus ir nustatyti galios lygius.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Naudokite Integracijų Tvarkytuvą botų, valdiklių ir lipdukų pakuočių tvarkymui.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Naudokite Integracijų Tvarkytuvą <b>(%(serverName)s)</b> botų, valdiklių ir lipdukų pakuočių tvarkymui.",
"Identity server": "Tapatybės serveris",
"Identity server (%(server)s)": "Tapatybės serveris (%(server)s)",
"Could not connect to identity server": "Nepavyko prisijungti prie tapatybės serverio",
"Not a valid identity server (status code %(code)s)": "Netinkamas tapatybės serveris (statuso kodas %(code)s)",
"Identity server URL must be HTTPS": "Tapatybės Serverio URL privalo būti HTTPS"
}

View file

@ -1582,5 +1582,9 @@
"Upload files": "Failu augšupielāde",
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.": "Šie faili <b>pārsniedz</b> augšupielādes izmēra limitu %(limit)s.",
"Upload files (%(current)s of %(total)s)": "Failu augšupielāde (%(current)s no %(total)s)",
"Check your devices": "Pārskatiet savas ierīces"
"Check your devices": "Pārskatiet savas ierīces",
"Integration manager": "Integrācija pārvaldnieks",
"Identity server is": "Indentifikācijas serveris ir",
"Identity server": "Identitāšu serveris",
"Could not connect to identity server": "Neizdevās pieslēgties identitāšu serverim"
}

View file

@ -130,5 +130,7 @@
"Checking for an update...": "അപ്ഡേറ്റ് ഉണ്ടോ എന്ന് തിരയുന്നു...",
"Explore rooms": "മുറികൾ കണ്ടെത്തുക",
"Sign In": "പ്രവേശിക്കുക",
"Create Account": "അക്കൗണ്ട് സൃഷ്ടിക്കുക"
"Create Account": "അക്കൗണ്ട് സൃഷ്ടിക്കുക",
"Integration manager": "സംയോജക മാനേജർ",
"Identity server": "തിരിച്ചറിയൽ സെർവർ"
}

View file

@ -1981,5 +1981,13 @@
"Costa Rica": "Costa Rica",
"Cook Islands": "Cook-øyene",
"All keys backed up": "Alle nøkler er sikkerhetskopiert",
"Secret storage:": "Hemmelig lagring:"
"Secret storage:": "Hemmelig lagring:",
"Integration manager": "Integreringsbehandler",
"Identity server is": "Identitetstjeneren er",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integreringsbehandlere mottar oppsettsdata, og kan endre på moduler, sende rominvitasjoner, og bestemme styrkenivåer på dine vegne.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Bruk en integreringsbehandler til å behandle botter, moduler, og klistremerkepakker.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Bruk en integreringsbehandler <b>(%(serverName)s)</b> til å behandle botter, moduler, og klistremerkepakker.",
"Identity server": "Identitetstjener",
"Identity server (%(server)s)": "Identitetstjener (%(server)s)",
"Could not connect to identity server": "Kunne ikke koble til identitetsserveren"
}

View file

@ -171,7 +171,7 @@
"Fill screen": "Scherm vullen",
"Filter room members": "Gespreksleden filteren",
"Forget room": "Gesprek vergeten",
"For security, this session has been signed out. Please sign in again.": "Wegens veiligheidsredenen is deze sessie uitgelogd. Gelieve opnieuw inloggen.",
"For security, this session has been signed out. Please sign in again.": "Wegens veiligheidsredenen is deze sessie uitgelogd. Log opnieuw in.",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s van %(fromPowerLevel)s naar %(toPowerLevel)s",
"Guests cannot join this room even if explicitly invited.": "Gasten - zelfs speficiek uitgenodigde - kunnen niet aan dit gesprek deelnemen.",
"Hangup": "Ophangen",
@ -1034,12 +1034,12 @@
"Legal": "Juridisch",
"Credits": "Met dank aan",
"For help with using %(brand)s, click <a>here</a>.": "Klik <a>hier</a> voor hulp bij het gebruiken van %(brand)s.",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.": "Klik <a>hier</a> voor hulp bij het gebruiken van %(brand)s, of begin een gesprek met onze robot met de knop hieronder.",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.": "Klik <a>hier</a> voor hulp bij het gebruiken van %(brand)s of begin een gesprek met onze robot met de knop hieronder.",
"Help & About": "Hulp & info",
"Bug reporting": "Bug meldingen",
"FAQ": "FAQ",
"Versions": "Versies",
"Preferences": "Instellingen",
"Preferences": "Voorkeuren",
"Composer": "Opsteller",
"Timeline": "Tijdslijn",
"Room list": "Gesprekslijst",
@ -1199,7 +1199,7 @@
"Invalid homeserver discovery response": "Ongeldig homeserver-vindbaarheids-antwoord",
"Invalid identity server discovery response": "Ongeldig identiteitsserver-vindbaarheidsantwoord",
"General failure": "Algemene fout",
"This homeserver does not support login using email address.": "Deze homeserver biedt geen ondersteuning voor inloggen met e-mailadres.",
"This homeserver does not support login using email address.": "Deze homeserver biedt geen ondersteuning voor inloggen met een e-mailadres.",
"Please <a>contact your service administrator</a> to continue using this service.": "Gelieve <a>contact op te nemen met uw dienstbeheerder</a> om deze dienst te blijven gebruiken.",
"Failed to perform homeserver discovery": "Ontdekken van homeserver is mislukt",
"Sign in with single sign-on": "Inloggen met eenmalig inloggen",
@ -1272,7 +1272,7 @@
"Upload files (%(current)s of %(total)s)": "Bestanden versturen (%(current)s van %(total)s)",
"Upload files": "Bestanden versturen",
"Upload": "Versturen",
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "Dit bestand is <b>te groot</b> om te versturen. De bestandsgroottelimiet is %(limit)s, maar dit bestand is %(sizeOfThisFile)s.",
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "Dit bestand is <b>te groot</b> om te versturen. Het limiet is %(limit)s en dit bestand is %(sizeOfThisFile)s.",
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.": "Deze bestanden zijn <b>te groot</b> om te versturen. De bestandsgroottelimiet is %(limit)s.",
"Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.": "Sommige bestanden zijn <b>te groot</b> om te versturen. De bestandsgroottelimiet is %(limit)s.",
"Upload %(count)s other files|other": "%(count)s overige bestanden versturen",
@ -1402,7 +1402,7 @@
"Summary": "Samenvatting",
"Sign in and regain access to your account.": "Meld u aan en herkrijg toegang tot uw account.",
"You cannot sign in to your account. Please contact your homeserver admin for more information.": "U kunt niet inloggen met uw account. Neem voor meer informatie contact op met de beheerder van uw homeserver.",
"This account has been deactivated.": "Deze account is gesloten.",
"This account has been deactivated.": "Dit account is gesloten.",
"Messages": "Berichten",
"Actions": "Acties",
"Displays list of commands with usages and descriptions": "Toont een lijst van beschikbare opdrachten, met hun gebruiken en beschrijvingen",
@ -1497,7 +1497,7 @@
"Share this email in Settings to receive invites directly in %(brand)s.": "Deel in de instellingen dit e-mailadres om uitnodigingen direct in %(brand)s te ontvangen.",
"Use an identity server to invite by email. <default>Use the default (%(defaultIdentityServerName)s)</default> or manage in <settings>Settings</settings>.": "Gebruik een identiteitsserver om uit te nodigen op e-mailadres. <default>Gebruik de standaardserver (%(defaultIdentityServerName)s)</default> of beheer de server in de <settings>Instellingen</settings>.",
"Use an identity server to invite by email. Manage in <settings>Settings</settings>.": "Gebruik een identiteitsserver om anderen uit te nodigen via e-mail. Beheer de server in de <settings>Instellingen</settings>.",
"Please fill why you're reporting.": "Gelieve aan te geven waarom u deze melding indient.",
"Please fill why you're reporting.": "Geef aan waarom u deze melding indient.",
"Report Content to Your Homeserver Administrator": "Inhoud melden aan de beheerder van uw homeserver",
"Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "Dit bericht melden zal zijn unieke gebeurtenis-ID versturen naar de beheerder van uw homeserver. Als de berichten in dit gesprek versleuteld zijn, zal de beheerder van uw homeserver het bericht niet kunnen lezen, noch enige bestanden of afbeeldingen zien.",
"Send report": "Rapport versturen",
@ -1564,7 +1564,7 @@
"Session already verified!": "Sessie al geverifieerd!",
"WARNING: Session already verified, but keys do NOT MATCH!": "PAS OP: de sessie is al geverifieerd, maar de sleutels komen NIET OVEREEN!",
"WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "PAS OP: sleutelverificatie MISLUKT! De combinatie %(userId)s + sessie %(deviceId)s is ondertekend met %(fprint)s - maar de opgegeven sleutel is %(fingerprint)s. Wellicht worden uw berichten onderschept!",
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "De door u verschafte en de van %(userId)ss sessie %(deviceId)s verkregen sleutels komen overeen. De sessie is daarmee geverifieerd.",
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "De door u verschafte sleutel en de van %(userId)ss sessie %(deviceId)s verkregen sleutels komen overeen. De sessie is daarmee geverifieerd.",
"%(senderName)s placed a voice call.": "%(senderName)s probeert u te bellen.",
"%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s poogt u te bellen, maar uw browser ondersteunt dat niet",
"%(senderName)s placed a video call.": "%(senderName)s doet een video-oproep.",
@ -2333,7 +2333,7 @@
"Switch to dark mode": "Naar donkere modus wisselen",
"Switch to light mode": "Naar lichte modus wisselen",
"Appearance": "Weergave",
"All settings": "Alle instellingen",
"All settings": "Instellingen",
"Error removing address": "Fout bij verwijderen van adres",
"There was an error removing that address. It may no longer exist or a temporary error occurred.": "Er is een fout opgetreden bij het verwijderen van dit adres. Deze bestaat mogelijk niet meer, of er is een tijdelijke fout opgetreden.",
"You don't have permission to delete the address.": "U heeft geen toestemming om het adres te verwijderen.",
@ -2517,7 +2517,7 @@
"You can only pin up to %(count)s widgets|other": "U kunt maar %(count)s widgets vastzetten",
"In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "In versleutelde gesprekken zijn uw berichten beveiligd, enkel de ontvanger en u hebben de unieke sleutels om ze te ontsleutelen.",
"Waiting for you to accept on your other session…": "Wachten totdat u uw uitnodiging in uw andere sessie aanneemt…",
"Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "Stel een adres in zodat gebruikers dit gesprek via uw homeserver (%(localDomain)s) kunnen vinden",
"Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "Stel een adres in zodat personen dit gesprek via uw homeserver (%(localDomain)s) kunnen vinden",
"Local Addresses": "Lokale adressen",
"Local address": "Lokaal adres",
"The server has denied your request.": "De server heeft uw verzoek afgewezen.",
@ -2564,7 +2564,7 @@
"Use app for a better experience": "Gebruik de app voor een betere ervaring",
"Enable desktop notifications": "Bureaubladmeldingen inschakelen",
"Don't miss a reply": "Mis geen antwoord",
"Unknown App": "Onbekende App",
"Unknown App": "Onbekende app",
"Error leaving room": "Fout bij verlaten gesprek",
"Unexpected server error trying to leave the room": "Onverwachte serverfout bij het verlaten van dit gesprek",
"See <b>%(msgtype)s</b> messages posted to your active room": "Zie <b>%(msgtype)s</b>-berichten verstuurd in uw actieve gesprek",
@ -2803,7 +2803,7 @@
"Successfully restored %(sessionCount)s keys": "Succesvol %(sessionCount)s sleutels hersteld",
"Keys restored": "Sleutels hersteld",
"Backup could not be decrypted with this Security Phrase: please verify that you entered the correct Security Phrase.": "Back-up kon niet worden ontsleuteld met dit veiligheidswachtwoord: controleer of u het juiste veiligheidswachtwoord hebt ingevoerd.",
"Incorrect Security Phrase": "Onjuist Veiligheidswachtwoord",
"Incorrect Security Phrase": "Onjuist veiligheidswachtwoord",
"Backup could not be decrypted with this Security Key: please verify that you entered the correct Security Key.": "Back-up kon niet worden ontcijferd met deze veiligheidssleutel: controleer of u de juiste veiligheidssleutel hebt ingevoerd.",
"Security Key mismatch": "Verkeerde veiligheidssleutel",
"%(completed)s of %(total)s keys restored": "%(completed)s van %(total)s sleutels hersteld",
@ -3021,9 +3021,9 @@
"Your message wasn't sent because this homeserver has been blocked by it's administrator. Please <a>contact your service administrator</a> to continue using the service.": "Uw bericht is niet verstuurd, omdat deze homeserver is geblokkeerd door zijn beheerder. Gelieve <a>contact op te nemen met uw beheerder</a> om de dienst te blijven gebruiken.",
"Are you sure you want to leave the space '%(spaceName)s'?": "Weet u zeker dat u de space '%(spaceName)s' wilt verlaten?",
"This space is not public. You will not be able to rejoin without an invite.": "Deze space is niet openbaar. Zonder uitnodiging zult u niet opnieuw kunnen toetreden.",
"Start audio stream": "Audio-stream starten",
"Start audio stream": "Audiostream starten",
"Failed to start livestream": "Starten van livestream is mislukt",
"Unable to start audio streaming.": "Kan audio-streaming niet starten.",
"Unable to start audio streaming.": "Kan audiostream niet starten.",
"Save Changes": "Wijzigingen opslaan",
"Saving...": "Opslaan...",
"View dev tools": "Bekijk dev tools",
@ -3034,7 +3034,7 @@
"Edit settings relating to your space.": "Bewerk instellingen gerelateerd aan uw space.",
"Invite someone using their name, username (like <userId/>) or <a>share this space</a>.": "Nodig iemand uit per naam, gebruikersnaam (zoals <userId/>) of <a>deel deze space</a>.",
"Invite someone using their name, email address, username (like <userId/>) or <a>share this space</a>.": "Nodig iemand uit per naam, e-mailadres, gebruikersnaam (zoals <userId/>) of <a>deel deze space</a>.",
"Unnamed Space": "Naamloze Space",
"Unnamed Space": "Naamloze space",
"Invite to %(spaceName)s": "Voor %(spaceName)s uitnodigen",
"Failed to add rooms to space": "Het toevoegen van gesprekken aan de space is mislukt",
"Apply": "Toepassen",
@ -3158,7 +3158,7 @@
"%(count)s people you know have already joined|other": "%(count)s personen die u kent hebben zijn al geregistreerd",
"Accept on your other login…": "Accepteer op uw andere login…",
"Stop & send recording": "Stop & verstuur opname",
"Record a voice message": "Audiobericht opnemen",
"Record a voice message": "Spraakbericht opnemen",
"Invite messages are hidden by default. Click to show the message.": "Uitnodigingen zijn standaard verborgen. Klik om de uitnodigingen weer te geven.",
"Quick actions": "Snelle acties",
"Invite to just this room": "Uitnodigen voor alleen dit gesprek",
@ -3176,7 +3176,7 @@
"If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "Als u alles reset, zult u opnieuw opstarten zonder vertrouwde sessies, zonder vertrouwde gebruikers, en zult u misschien geen vroegere berichten meer kunnen zien.",
"Only do this if you have no other device to complete verification with.": "Doe dit alleen als u geen ander apparaat hebt om de verificatie mee uit te voeren.",
"Reset everything": "Alles opnieuw instellen",
"Forgotten or lost all recovery methods? <a>Reset all</a>": "Alles vergeten of alle herstelmethoden verloren? <a>Alles opnieuw instellen</a>",
"Forgotten or lost all recovery methods? <a>Reset all</a>": "Alles vergeten en alle herstelmethoden verloren? <a>Alles opnieuw instellen</a>",
"If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated": "Als u dat doet, let wel geen van uw berichten wordt verwijderd, maar de zoekresultaten zullen gedurende enkele ogenblikken verslechteren terwijl de index opnieuw wordt aangemaakt",
"View message": "Bericht bekijken",
"Zoom in": "Inzoomen",
@ -3369,5 +3369,108 @@
"%(targetName)s accepted an invitation": "%(targetName)s accepteerde de uitnodiging",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s accepteerde de uitnodiging voor %(displayName)s",
"Some invites couldn't be sent": "Sommige uitnodigingen konden niet verstuurd worden",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "De anderen zijn verstuurd, maar de volgende mensen konden niet worden uitgenodigd voor <RoomName/>"
"We sent the others, but the below people couldn't be invited to <RoomName/>": "De anderen zijn verstuurd, maar de volgende mensen konden niet worden uitgenodigd voor <RoomName/>",
"Unnamed audio": "Naamloze audio",
"Error processing audio message": "Fout bij verwerking audiobericht",
"Show %(count)s other previews|one": "%(count)s andere preview weergeven",
"Show %(count)s other previews|other": "%(count)s andere previews weergeven",
"Images, GIFs and videos": "Afbeeldingen, GIF's en video's",
"Code blocks": "Codeblokken",
"Displaying time": "Tijdsweergave",
"To view all keyboard shortcuts, click here.": "Om alle sneltoetsen te zien, klik hier.",
"Keyboard shortcuts": "Sneltoetsen",
"Use Ctrl + F to search timeline": "Gebruik Ctrl +F om te zoeken in de tijdlijn",
"Use Command + F to search timeline": "Gebruik Command + F om te zoeken in de tijdlijn",
"User %(userId)s is already invited to the room": "De gebruiker %(userId)s is al uitgenodigd voor dit gesprek",
"Integration manager": "Integratiebeheerder",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Uw %(brand)s laat u geen integratiebeheerder gebruiken om dit te doen. Neem contact op met een beheerder.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Met het gebruik van deze widget deelt u mogelijk gegevens <helpIcon /> met %(widgetDomain)s & uw integratiebeheerder.",
"Identity server is": "Identiteitsserver is",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integratiebeheerders ontvangen configuratie-informatie en kunnen widgets aanpassen, gespreksuitnodigingen versturen en machtsniveaus namens u aanpassen.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Gebruik een integratiebeheerder om bots, widgets en stickerpakketten te beheren.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Gebruik een integratiebeheerder <b>(%(serverName)s)</b> om bots, widgets en stickerpakketten te beheren.",
"Identity server": "Identiteitsserver",
"Identity server (%(server)s)": "Identiteitsserver (%(server)s)",
"Could not connect to identity server": "Kon geen verbinding maken met de identiteitsserver",
"Not a valid identity server (status code %(code)s)": "Geen geldige identiteitsserver (statuscode %(code)s)",
"Identity server URL must be HTTPS": "Identiteitsserver-URL moet HTTPS zijn",
"User Directory": "Gebruikersgids",
"Copy Link": "Link kopieren",
"There was an error loading your notification settings.": "Er was een fout bij het laden van uw meldingsvoorkeuren.",
"Mentions & keywords": "Vermeldingen & trefwoorden",
"Global": "Overal",
"New keyword": "Nieuw trefwoord",
"Keyword": "Trefwoord",
"Enable email notifications for %(email)s": "E-mailmeldingen inschakelen voor %(email)s",
"Enable for this account": "Voor dit account inschakelen",
"An error occurred whilst saving your notification preferences.": "Er is een fout opgetreden tijdens het opslaan van uw meldingsvoorkeuren.",
"Error saving notification preferences": "Fout bij het opslaan van meldingsvoorkeuren",
"Messages containing keywords": "Berichten met trefwoord",
"Transfer Failed": "Doorverbinden is mislukt",
"Unable to transfer call": "Doorverbinden is mislukt",
"Unable to copy a link to the room to the clipboard.": "Kopiëren van gesprekslink naar het klembord is mislukt.",
"Unable to copy room link": "Kopiëren van gesprekslink is mislukt",
"Copy Room Link": "Kopieer gesprekslink",
"Message bubbles": "Berichtenbubbels",
"IRC": "IRC",
"New layout switcher (with message bubbles)": "Nieuwe layout schakelaar (met berichtenbubbels)",
"Downloading": "Downloading",
"The call is in an unknown state!": "Deze oproep heeft een onbekende status!",
"Call back": "Terugbellen",
"You missed this call": "U heeft deze oproep gemist",
"This call has failed": "Deze oproep is mislukt",
"Unknown failure: %(reason)s)": "Onbekende fout: %(reason)s",
"No answer": "Geen antwoord",
"An unknown error occurred": "Er is een onbekende fout opgetreden",
"Their device couldn't start the camera or microphone": "Het andere apparaat kon de camera of microfoon niet starten",
"Connection failed": "Verbinding mislukt",
"Could not connect media": "Mediaverbinding mislukt",
"This call has ended": "Deze oproep is beëindigd",
"Connected": "Verbonden",
"Spaces with access": "Spaces met toegang",
"Anyone in a space can find and join. <a>Edit which spaces can access here.</a>": "Iedereen in een space kan het gesprek vinden en aan deelnemen. <a>Wijzig welke spaces toegang hebben hier.</a>",
"Currently, %(count)s spaces have access|other": "Momenteel hebben %(count)s spaces toegang",
"& %(count)s more|other": "& %(count)s meer",
"Upgrade required": "Upgrade noodzakelijk",
"Anyone can find and join.": "Iedereen kan hem vinden en deelnemen.",
"Only invited people can join.": "Alleen uitgenodigde personen kunnen deelnemen.",
"Private (invite only)": "Privé (alleen op uitnodiging)",
"This upgrade will allow members of selected spaces access to this room without an invite.": "Deze upgrade maakt het mogelijk voor leden van geselecteerde spaces om toegang te krijgen tot dit gesprek zonder een uitnodiging.",
"This makes it easy for rooms to stay private to a space, while letting people in the space find and join them. All new rooms in a space will have this option available.": "Dit maakt het makkelijk om gesprekken privé te houden voor een space, terwijl personen in de space hem kunnen vinden en aan deelnemen. Alle nieuwe gesprekken in deze space hebben deze optie beschikbaar.",
"To help space members find and join a private room, go to that room's Security & Privacy settings.": "Om space leden te helpen met het vinden van en deel te nemen aan privégesprekken, ga naar uw gespreksinstellingen voor veiligheid & privacy.",
"Help space members find private rooms": "Help space leden privégesprekken te vinden",
"Help people in spaces to find and join private rooms": "Help personen in spaces om privégesprekken te vinden en aan deel te nemen",
"New in the Spaces beta": "Nieuw in de spaces beta",
"Everyone in <SpaceName/> will be able to find and join this room.": "Iedereen in <SpaceName/> kan dit gesprek vinden en aan deelnemen.",
"Image": "Afbeelding",
"Sticker": "Sticker",
"They didn't pick up": "Ze hebben niet opgenomen",
"Call again": "Opnieuw bellen",
"They declined this call": "Ze weigerden deze oproep",
"You declined this call": "U heeft deze oproep geweigerd",
"The voice message failed to upload.": "Het spraakbericht versturen is mislukt.",
"Access": "Toegang",
"People with supported clients will be able to join the room without having a registered account.": "Personen met geschikte apps zullen aan de gesprekken kunnen deelnemen zonder een account te hebben.",
"Decide who can join %(roomName)s.": "Kies wie kan deelnemen aan %(roomName)s.",
"Space members": "Space leden",
"Anyone in a space can find and join. You can select multiple spaces.": "Iedereen in een space kan zoeken en deelnemen. U kunt meerdere spaces selecteren.",
"Anyone in %(spaceName)s can find and join. You can select other spaces too.": "Iedereen in %(spaceName)s kan zoeken en deelnemen. U kunt ook andere spaces selecteren.",
"Visible to space members": "Zichtbaar voor space leden",
"Public room": "Openbaar gesprek",
"Private room (invite only)": "Privégesprek (alleen op uitnodiging)",
"Create a room": "Gesprek aanmaken",
"Only people invited will be able to find and join this room.": "Alleen uitgenodigde personen kunnen dit gesprek vinden en aan deelnemen.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Iedereen kan dit gesprek vinden en aan deelnemen, niet alleen leden van <SpaceName/>.",
"You can change this at any time from room settings.": "U kan dit op elk moment wijzigen vanuit de gespreksinstellingen.",
"Error downloading audio": "Fout bij downloaden van audio",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>Let op bijwerken maakt een nieuwe versie van dit gesprek</b>. Alle huidige berichten blijven in dit gearchiveerde gesprek.",
"Automatically invite members from this room to the new one": "Automatisch leden uitnodigen van dit gesprek in de nieuwe",
"These are likely ones other room admins are a part of.": "Er zijn waarschijnlijk gesprekken waar andere gespreksbeheerders deel van uitmaken.",
"Other spaces or rooms you might not know": "Andere spaces of gesprekken die u misschien niet kent",
"Spaces you know that contain this room": "Spaces die u kent met dit gesprek",
"Search spaces": "Spaces zoeken",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.": "Kies welke spaces toegang hebben tot dit gesprek. Als een space is geselecteerd kunnen deze leden <RoomName/> vinden en aan deelnemen.",
"Select spaces": "Spaces selecteren",
"You're removing all spaces. Access will default to invite only": "U verwijderd alle spaces. De toegang zal standaard alleen op uitnodiging zijn",
"Room visibility": "Gesprekszichtbaarheid"
}

View file

@ -1376,5 +1376,12 @@
"Identity Server": "Identitetstenar",
"Email Address": "E-postadresse",
"Go Back": "Gå attende",
"Notification settings": "Varslingsinnstillingar"
"Notification settings": "Varslingsinnstillingar",
"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.": "Du bør <b>fjerne dine personlege data</b> frå identitetstenaren <idserver /> før du koplar frå. Dessverre er identitetstenaren <idserver /> utilgjengeleg og kan ikkje nåast akkurat no.",
"We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.": "Vi tilrår at du slettar personleg informasjon, som e-postadresser og telefonnummer frå identitetstenaren før du koplar frå.",
"Privacy": "Personvern",
"Versions": "Versjonar",
"Legal": "Juridisk",
"Identity server is": "Identitetstenaren er",
"Identity server": "Identitetstenar"
}

View file

@ -2368,5 +2368,15 @@
"Some suggestions may be hidden for privacy.": "Niektóre propozycje mogą być ukryte z uwagi na prywatność.",
"If you can't see who youre looking for, send them your invite link below.": "Jeżeli nie możesz zobaczyć osób, których szukasz, wyślij im poniższy odnośnik z zaproszeniem.",
"Or send invite link": "Lub wyślij odnośnik z zaproszeniem",
"We're working on this as part of the beta, but just want to let you know.": "Pracujemy nad tym w ramach bety, ale chcemy, żebyś wiedział(a)."
"We're working on this as part of the beta, but just want to let you know.": "Pracujemy nad tym w ramach bety, ale chcemy, żebyś wiedział(a).",
"Integration manager": "Menedżer Integracji",
"Identity server is": "Serwer tożsamości to",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Zarządcy integracji otrzymują dane konfiguracji, mogą modyfikować widżety, wysyłać zaproszenia do pokoi i ustawiać poziom uprawnień w Twoim imieniu.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Użyj Zarządcy Integracji aby zarządzać botami, widżetami i pakietami naklejek.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Użyj Zarządcy Integracji <b>%(serverName)s</b> aby zarządzać botami, widżetami i pakietami naklejek.",
"Identity server": "Serwer toższamości",
"Identity server (%(server)s)": "Serwer tożsamości (%(server)s)",
"Could not connect to identity server": "Nie można połączyć z serwerem tożsamości",
"Not a valid identity server (status code %(code)s)": "Nieprawidłowy serwer tożsamości (kod statusu %(code)s)",
"Identity server URL must be HTTPS": "URL serwera tożsamości musi być HTTPS"
}

View file

@ -572,5 +572,7 @@
"Your user agent": "O seu user agent",
"Explore rooms": "Explorar rooms",
"Sign In": "Iniciar sessão",
"Create Account": "Criar conta"
"Create Account": "Criar conta",
"Not a valid identity server (status code %(code)s)": "Servidor de Identidade inválido (código de status %(code)s)",
"Identity server URL must be HTTPS": "O link do servidor de identidade deve começar com HTTPS"
}

View file

@ -3110,5 +3110,17 @@
"Inviting...": "Convidando...",
"Invite by username": "Convidar por nome de usuário",
"Support": "Suporte",
"Original event source": "Fonte do evento original"
"Original event source": "Fonte do evento original",
"Integration manager": "Gerenciador de integrações",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Seu %(brand)s não permite que você use o gerenciador de integrações para fazer isso. Entre em contato com o administrador.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Se você usar esse widget, os dados poderão ser compartilhados <helpIcon /> com %(widgetDomain)s & seu gerenciador de integrações.",
"Identity server is": "O servidor de identificação é",
"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.",
"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 <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.",
"Identity server": "Servidor de identidade",
"Identity server (%(server)s)": "Servidor de identidade (%(server)s)",
"Could not connect to identity server": "Não foi possível conectar-se ao servidor de identidade",
"Not a valid identity server (status code %(code)s)": "Servidor de identidade inválido (código de status %(code)s)",
"Identity server URL must be HTTPS": "O link do servidor de identidade deve começar com HTTPS"
}

View file

@ -3219,5 +3219,17 @@
"Send and receive voice messages": "Отправлять и получать голосовые сообщения",
"%(deviceId)s from %(ip)s": "%(deviceId)s с %(ip)s",
"The user you called is busy.": "Вызываемый пользователь занят.",
"User Busy": "Пользователь занят"
"User Busy": "Пользователь занят",
"Integration manager": "Менеджер интеграции",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Ваш %(brand)s не позволяет вам использовать для этого Менеджер Интеграции. Пожалуйста, свяжитесь с администратором.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Используя этот виджет, вы можете делиться данными <helpIcon /> с %(widgetDomain)s и вашим Менеджером Интеграции.",
"Identity server is": "Сервер идентификации",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Менеджеры интеграции получают данные конфигурации и могут изменять виджеты, отправлять приглашения в комнаты и устанавливать уровни доступа от вашего имени.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Используйте Менеджер интеграциями для управления ботами, виджетами и стикерами.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Используйте менеджер интеграций <b>%(serverName)s</b> для управления ботами, виджетами и стикерами.",
"Identity server": "Сервер идентификаций",
"Identity server (%(server)s)": "Сервер идентификации (%(server)s)",
"Could not connect to identity server": "Не смог подключиться к серверу идентификации",
"Not a valid identity server (status code %(code)s)": "Неправильный Сервер идентификации (код статуса %(code)s)",
"Identity server URL must be HTTPS": "URL-адрес сервера идентификации должен быть HTTPS"
}

View file

@ -2080,5 +2080,14 @@
"The call was answered on another device.": "Hovor bol prijatý na inom zariadení.",
"The call could not be established": "Hovor nemohol byť realizovaný",
"The other party declined the call.": "Druhá strana odmietla hovor.",
"Call Declined": "Hovor odmietnutý"
"Call Declined": "Hovor odmietnutý",
"Integration manager": "Správca integrácií",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integračné servery zhromažďujú údaje nastavení, môžu spravovať widgety, odosielať vo vašom mene pozvánky alebo meniť úroveň moci.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Použiť integračný server na správu botov, widgetov a balíčkov s nálepkami.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Použiť integračný server <b>(%(serverName)s)</b> na správu botov, widgetov a balíčkov s nálepkami.",
"Identity server": "Server totožností",
"Identity server (%(server)s)": "Server totožností (%(server)s)",
"Could not connect to identity server": "Nie je možné sa pripojiť k serveru totožností",
"Not a valid identity server (status code %(code)s)": "Toto nie je funkčný server totožností (kód stavu %(code)s)",
"Identity server URL must be HTTPS": "URL adresa servera totožností musí začínať HTTPS"
}

View file

@ -3447,7 +3447,7 @@
"Show all rooms in Home": "Shfaq krejt dhomat te Home",
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Prototip “Njoftojuani moderatorëve”. Në dhoma që mbulojnë moderim, butoni `raportojeni` do tju lejojë tu njoftoni abuzim moderatorëve të dhomës",
"%(senderName)s changed the <a>pinned messages</a> for the room.": "%(senderName)s ndryshoi <a>mesazhin e fiksuar</a> për këtë dhomë.",
"%(senderName)s kicked %(targetName)s": "%(senderName)s përzuri %(targetName)s.",
"%(senderName)s kicked %(targetName)s": "%(senderName)s përzuri %(targetName)s",
"%(senderName)s kicked %(targetName)s: %(reason)s": "%(senderName)s përzuri %(targetName)s: %(reason)s",
"%(senderName)s withdrew %(targetName)s's invitation": "%(senderName)s tërhoqi mbrapsht ftesën për %(targetName)s",
"%(senderName)s withdrew %(targetName)s's invitation: %(reason)s": "%(senderName)s tërhoqi mbrapsht ftesën për %(targetName)s: %(reason)s",
@ -3460,13 +3460,113 @@
"%(senderName)s set a profile picture": "%(senderName)s caktoi një foto profili",
"%(senderName)s changed their profile picture": "%(senderName)s ndryshoi foton e vet të profilit",
"%(senderName)s removed their profile picture": "%(senderName)s hoqi foton e vet të profilit",
"%(senderName)s removed their display name (%(oldDisplayName)s)": "%(senderName)s hoqi emrin e vet në ekran (%(oldDisplayName)s).",
"%(senderName)s removed their display name (%(oldDisplayName)s)": "%(senderName)s hoqi emrin e vet në ekran (%(oldDisplayName)s)",
"%(senderName)s set their display name to %(displayName)s": "%(senderName)s caktoi për veten emër ekrani %(displayName)s",
"%(oldDisplayName)s changed their display name to %(displayName)s": "%(oldDisplayName)s ndryshoi emrin e vet në ekran si %(displayName)s",
"%(senderName)s banned %(targetName)s": "%(senderName)s dëboi %(targetName)s.",
"%(senderName)s banned %(targetName)s": "%(senderName)s dëboi %(targetName)s",
"%(senderName)s banned %(targetName)s: %(reason)s": "%(senderName)s dëboi %(targetName)s: %(reason)s",
"%(targetName)s accepted an invitation": "%(targetName)s pranoi një ftesë",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s pranoi ftesën për %(displayName)s",
"Some invites couldn't be sent": "Su dërguan dot disa nga ftesat",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "I dërguam të tjerat, por personat më poshtë su ftuan dot te <RoomName/>"
"We sent the others, but the below people couldn't be invited to <RoomName/>": "I dërguam të tjerat, por personat më poshtë su ftuan dot te <RoomName/>",
"Unnamed audio": "Audio pa emër",
"Forward": "Përcille",
"Sent": "U dërgua",
"Error processing audio message": "Gabim në përpunim mesazhi audio",
"Show %(count)s other previews|one": "Shfaq %(count)s paraparje tjetër",
"Show %(count)s other previews|other": "Shfaq %(count)s paraparje të tjera",
"Images, GIFs and videos": "Figura, GIF-e dhe video",
"Code blocks": "Blloqe kodi",
"To view all keyboard shortcuts, click here.": "Që të shihni krejt shkurtoret e tastierës, klikoni këtu.",
"Keyboard shortcuts": "Shkurtore tastiere",
"Use Ctrl + F to search timeline": "Përdorni Ctrl + F që të kërkohet te rrjedha kohore",
"Use Command + F to search timeline": "Përdorni Command + F që të kërkohet te rrjedha kohore",
"User %(userId)s is already invited to the room": "Përdoruesi %(userId)s është ftuar tashmë te dhoma",
"Integration manager": "Përgjegjës integrimesh",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "%(brand)s-i juaj nuk ju lejon të përdorni një përgjegjës integrimesh për të bërë këtë. Ju lutemi, lidhuni me përgjegjësin.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Përdorimi i këtij widget-i mund të sjellë ndarje të dhënash <helpIcon /> me %(widgetDomain)s & përgjegjësin tuaj të integrimeve.",
"Identity server is": "Shërbyes identitetesh është",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Përgjegjësit e integrimeve marrin të dhëna formësimi, dhe mund të ndryshojnë widget-e, të dërgojnë ftesa dhome, dhe të caktojnë shkallë pushteti në emër tuajin.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Përdorni një përgjegjës integrimesh që të administroni robotë, widget-e dhe paketa ngjitësish.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Përdorni një përgjegjës integrimesh <b>(%(serverName)s)</b> që të administroni robotë, widget-e dhe paketa ngjitësish.",
"Identity server": "Shërbyes identitetesh",
"Identity server (%(server)s)": "Shërbyes identitetesh (%(server)s)",
"Could not connect to identity server": "Su lidh dot te shërbyes identitetesh",
"Not a valid identity server (status code %(code)s)": "Shërbyes identitetesh i pavlefshëm (kod gjendjeje %(code)s)",
"Identity server URL must be HTTPS": "URL-ja e shërbyesit të identiteteve duhet të jetë HTTPS",
"Unable to transfer call": "Sarrihet të shpërngulet thirrje",
"Unable to copy a link to the room to the clipboard.": "Sarrihet të kopjohet në të papastër një lidhje për te dhoma.",
"Unable to copy room link": "Sarrihet të kopjohet lidhja e dhomës",
"User Directory": "Drejtori Përdoruesi",
"Copy Link": "Kopjoji Lidhjen",
"Displaying time": "Kohë shfaqjeje",
"There was an error loading your notification settings.": "Pati një gabim në ngarkimin e rregullimeve tuaja për njoftimet.",
"Mentions & keywords": "Përmendje & fjalëkyçe",
"Global": "Global",
"New keyword": "Fjalëkyç i ri",
"Keyword": "Fjalëkyç",
"Enable email notifications for %(email)s": "Aktivizo njoftime me email për %(email)s",
"Enable for this account": "Aktivizoje për këtë llogari",
"An error occurred whilst saving your notification preferences.": "Ndodhi një gabim teksa ruheshin parapëlqimet tuaja për njoftimet.",
"Error saving notification preferences": "Gabim në ruajtje parapëlqimesh për njoftimet",
"Messages containing keywords": "Mesazhe që përmbajnë fjalëkyçe",
"Transfer Failed": "Shpërngulja Dështoi",
"Copy Room Link": "Kopjo Lidhje Dhome",
"Message bubbles": "Flluska mesazhesh",
"IRC": "IRC",
"New layout switcher (with message bubbles)": "Këmbyes i ri skemash (me flluska mesazhesh)",
"Connected": "E lidhur",
"Downloading": "Po shkarkohet",
"The call is in an unknown state!": "Thirrja gjendet në një gjendje të panjohur!",
"Call back": "Thirreni ju",
"You missed this call": "E humbët këtë thirrje",
"This call has failed": "Kjo thirrje ka dështuar",
"Unknown failure: %(reason)s)": "Dështim i panjohur: %(reason)s)",
"No answer": "Ska përgjigje",
"An unknown error occurred": "Ndodhi një gabim i panjohur",
"Their device couldn't start the camera or microphone": "Pajisja e tyre snisi dot kamerën ose mikrofonin",
"Connection failed": "Lidhja dështoi",
"Could not connect media": "Su lidh dot me median",
"This call has ended": "Kjo thirrje ka përfunduar",
"Error downloading audio": "Gabim në shkarkim audioje",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>Ju lutemi, kini parasysh se përmirësimi do të prodhojë një version të ri të dhomës</b>. Krejt mesazhet e tanishëm do të mbeten në këtë dhomë të arkivuar.",
"Automatically invite members from this room to the new one": "Fto automatikisht anëtarë prej kësaj dhome te e reja",
"These are likely ones other room admins are a part of.": "Këto ka shumë mundësi të jetë ato ku përgjegjës të tjerë dhomash janë pjesë.",
"Other spaces or rooms you might not know": "Hapësira ose dhoma të tjera që mund të mos i dini",
"Spaces you know that contain this room": "Hapësira që e dini se përmbajnë këtë dhomë",
"Search spaces": "Kërkoni në hapësira",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.": "Vendosni se prej cilave hapësira mund të hyhet në këtë dhomë. Nëse përzgjidhet një hapësirë, anëtarët e saj do të mund ta gjejnë dhe hyjnë te <RoomName/>.",
"Select spaces": "Përzgjidhni hapësira",
"Room visibility": "Dukshmëri dhome",
"Visible to space members": "I dukshëm për anëtarë të hapësirë",
"Public room": "Dhomë publike",
"Private room (invite only)": "Dhomë private (vetëm me ftesa)",
"Create a room": "Krijoni një dhomë",
"Only people invited will be able to find and join this room.": "Vetëm personat e ftuar do të jenë në gjendje ta gjejnë dhe hyjnë në këtë dhomë.",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "Cilido do të jetë në gjendje të gjejë dhe hyjë në këtë dhomë, jo thjesht vetëm anëtarët e <SpaceName/>.",
"You can change this at any time from room settings.": "Këtë mund ta ndryshoni kurdo, që nga rregullimet e dhomës.",
"Everyone in <SpaceName/> will be able to find and join this room.": "Cilido te <SpaceName/> do të jetë në gjendje të gjejë dhe hyjë në këtë dhomë.",
"Image": "Figurë",
"Sticker": "Ngjitës",
"The voice message failed to upload.": "Dështoi ngarkimi i mesazhit zanor.",
"Access": "Hyrje",
"People with supported clients will be able to join the room without having a registered account.": "Persona me klientë të mbuluar do të jenë në gjendje të hyjnë te dhoma pa pasur ndonjë llogari të regjistruar.",
"Decide who can join %(roomName)s.": "Vendosni se cilët mund të hyjnë te %(roomName)s.",
"Space members": "Anëtarë hapësire",
"Anyone in a space can find and join. You can select multiple spaces.": "Mund të përzgjidhni një hapësirë që mund të gjejë dhe hyjë. Mund të përzgjidhni disa hapësira.",
"Anyone in %(spaceName)s can find and join. You can select other spaces too.": "Cilido te %(spaceName)s mund ta gjejë dhe hyjë. Mund të përzgjidhni edhe hapësira të tjera.",
"Spaces with access": "Hapësira me hyrje",
"Anyone in a space can find and join. <a>Edit which spaces can access here.</a>": "Cilido në një hapësirë mund ta gjejë dhe hyjë. <a>Përpunoni se cilat hapësira kanë hyrje këtu.</a>",
"Currently, %(count)s spaces have access|other": "Deri tani, %(count)s hapësira kanë hyrje",
"& %(count)s more|other": "& %(count)s më tepër",
"Upgrade required": "Lypset domosdo përmirësim",
"Anyone can find and join.": "Kushdo mund ta gjejë dhe hyjë në të.",
"Only invited people can join.": "Vetëm personat e ftuar mund të hyjnë.",
"Private (invite only)": "Private (vetëm me ftesa)",
"This upgrade will allow members of selected spaces access to this room without an invite.": "Ky përmirësim do tu lejojë anëtarëve të hapësirave të përzgjedhura të hyjnë në këtë dhomë pa ndonjë ftesë.",
"This makes it easy for rooms to stay private to a space, while letting people in the space find and join them. All new rooms in a space will have this option available.": "Kjo e bën të lehtë mbajtjen private të dhomave në një hapësirë, ndërkohë që u lejon njerëzve në hapësirë të gjejnë dhe hyjnë në të tilla. Krejt dhomat e reja në një hapësirë do ta ofrojnë këtë mundësi.",
"To help space members find and join a private room, go to that room's Security & Privacy settings.": "Që të ndihmoni anëtarë hapësirash të gjejnë dhe hyjnë në një dhomë private, kaloni te rregullimet e Sigurisë & Privatësisë së dhomës.",
"Help space members find private rooms": "Ndihmoni anëtarë hapësirash të gjejnë dhoma private",
"Help people in spaces to find and join private rooms": "Ndihmoni persona në hapësira të gjejnë dhe hyjnë në dhoma private",
"New in the Spaces beta": "E re në Hapësira beta"
}

View file

@ -1760,5 +1760,7 @@
"You're already in a call with this person.": "Већ разговарате са овом особом.",
"Already in call": "Већ у позиву",
"Whether you're using %(brand)s as an installed Progressive Web App": "Без обзира да ли користите %(brand)s као инсталирану Прогресивну веб апликацију",
"Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Без обзира да ли користите функцију „breadcrumbs“ (аватари изнад листе соба)"
"Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Без обзира да ли користите функцију „breadcrumbs“ (аватари изнад листе соба)",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Коришћење овог виџета може да дели податке <helpIcon /> са %(widgetDomain)s и вашим интеграционим менаџером.",
"Identity server is": "Идентитетски сервер је"
}

View file

@ -3356,5 +3356,16 @@
"We sent the others, but the below people couldn't be invited to <RoomName/>": "Vi skickade de andra, men personerna nedan kunde inte bjudas in till <RoomName/>",
"What this user is writing is wrong.\nThis will be reported to the room moderators.": "Vad användaren skriver är fel.\nDet här kommer att anmälas till rumsmoderatorerna.",
"Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Prototyp av anmälan till moderatorer. I rum som söder moderering så kommer `anmäl`-knappen att låta dig anmäla olämpligt beteende till rummets moderatorer",
"Report": "Rapportera"
"Report": "Rapportera",
"Integration manager": "Integrationshanterare",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Din %(brand)s tillåter dig inte att använda en integrationshanterare för att göra detta. Vänligen kontakta en administratör.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Att använda denna widget kan dela data <helpIcon /> med %(widgetDomain)s och din integrationshanterare.",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integrationshanterare får konfigurationsdata och kan ändra widgetar, skicka rumsinbjudningar och ställa in behörighetsnivåer å dina vägnar.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Använd en integrationshanterare för att hantera bottar, widgets och dekalpaket.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Använd en integrationshanterare <b>(%(serverName)s)</b> för att hantera bottar, widgets och dekalpaket.",
"Identity server": "Identitetsserver",
"Identity server (%(server)s)": "Identitetsserver (%(server)s)",
"Could not connect to identity server": "Kunde inte ansluta till identitetsservern",
"Not a valid identity server (status code %(code)s)": "Inte en giltig identitetsserver (statuskod %(code)s)",
"Identity server URL must be HTTPS": "URL för identitetsserver måste vara HTTPS"
}

View file

@ -101,7 +101,7 @@
"Failed to set display name": "Görünür ismi ayarlama başarısız oldu",
"Failed to unban": "Yasağı kaldırmak başarısız oldu",
"Failed to upload profile picture!": "Profil resmi yükleme başarısız oldu!",
"Failed to verify email address: make sure you clicked the link in the email": "Eposta adresini doğrulamadı: epostadaki bağlantıya tıkladığınızdan emin olun",
"Failed to verify email address: make sure you clicked the link in the email": "E-posta adresi doğrulanamadı: E-postadaki bağlantıya tıkladığınızdan emin olun",
"Failure to create room": "Oda oluşturulamadı",
"Favourite": "Favori",
"Favourites": "Favoriler",
@ -1695,7 +1695,7 @@
"Visibility in Room List": "Oda Listesindeki Görünürlük",
"Confirm adding email": "E-posta adresini eklemeyi onayla",
"Click the button below to confirm adding this email address.": "E-posta adresini eklemeyi kabul etmek için aşağıdaki tuşa tıklayın.",
"Confirm adding phone number": "Telefon numayasını ekleyi onayla",
"Confirm adding phone number": "Telefon numarası eklemeyi onayla",
"Click the button below to confirm adding this phone number.": "Telefon numarasını eklemeyi kabul etmek için aşağıdaki tuşa tıklayın.",
"Are you sure you want to cancel entering passphrase?": "Parola girmeyi iptal etmek istediğinizden emin misiniz?",
"Room name or address": "Oda adı ya da adresi",
@ -2544,5 +2544,47 @@
"We couldn't log you in": "Sizin girişinizi yapamadık",
"You're already in a call with this person.": "Bu kişi ile halihazırda çağrıdasınız.",
"The user you called is busy.": "Aradığınız kullanıcı meşgul.",
"User Busy": "Kullanıcı Meşgul"
"User Busy": "Kullanıcı Meşgul",
"Got it": "Anlaşıldı",
"Verified": "Doğrulanmış",
"You've successfully verified %(displayName)s!": "%(displayName)s başarıyla doğruladınız!",
"You've successfully verified %(deviceName)s (%(deviceId)s)!": "%(deviceName)s (%(deviceId)s) başarıyla doğruladınız!",
"You've successfully verified your device!": "Cihazınızı başarıyla doğruladınız!",
"Edit devices": "Cihazları düzenle",
"Delete recording": "Kaydı sil",
"Stop the recording": "Kaydı durdur",
"We didn't find a microphone on your device. Please check your settings and try again.": "Cihazınızda bir mikrofon bulamadık. Lütfen ayarlarınızı kontrol edin ve tekrar deneyin.",
"No microphone found": "Mikrofon bulunamadı",
"Empty room": "Boş oda",
"Suggested Rooms": "Önerilen Odalar",
"View message": "Mesajı görüntüle",
"Invite to just this room": "Sadece bu odaya davet et",
"%(seconds)ss left": "%(seconds)s saniye kaldı",
"Send message": "Mesajı gönder",
"Your message was sent": "Mesajınız gönderildi",
"Encrypting your message...": "Mesajınız şifreleniyor...",
"Sending your message...": "Mesajınız gönderiliyor...",
"Code blocks": "Kod blokları",
"Displaying time": "Zamanı görüntüle",
"To view all keyboard shortcuts, click here.": "Tüm klavye kısayollarını görmek için buraya tıklayın.",
"Keyboard shortcuts": "Klavye kısayolları",
"Visibility": "Görünürlük",
"Save Changes": "Değişiklikleri Kaydet",
"Saving...": "Kaydediliyor...",
"Invite with email or username": "E-posta veya kullanıcı adı ile davet et",
"Invite people": "İnsanları davet et",
"Share invite link": "Davet bağlantısını paylaş",
"Click to copy": "Kopyalamak için tıklayın",
"You can change these anytime.": "Bunları istediğiniz zaman değiştirebilirsiniz.",
"You can change this later": "Bunu daha sonra değiştirebilirsiniz",
"Change which room, message, or user you're viewing": "Görüntülediğiniz odayı, mesajı veya kullanıcıyı değiştirin",
"%(targetName)s accepted an invitation": "%(targetName)s daveti kabul etti",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s, %(displayName)s kişisinin davetini kabul etti",
"Integration manager": "Bütünleştirme Yöneticisi",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Botları, görsel bileşenleri ve çıkartma paketlerini yönetmek için bir entegrasyon yöneticisi kullanın.",
"Identity server": "Kimlik sunucusu",
"Identity server (%(server)s)": "(%(server)s) Kimlik Sunucusu",
"Could not connect to identity server": "Kimlik Sunucusuna bağlanılamadı",
"Not a valid identity server (status code %(code)s)": "Geçerli bir Kimlik Sunucu değil ( durum kodu %(code)s )",
"Identity server URL must be HTTPS": "Kimlik Sunucu URL adresi HTTPS olmak zorunda"
}

View file

@ -506,7 +506,7 @@
"Upload Error": "Помилка відвантаження",
"Failed to upload image": "Не вдалось відвантажити зображення",
"Upload avatar": "Завантажити аватар",
"For security, this session has been signed out. Please sign in again.": "З метою безпеки вашу сесію було завершено. Зайдіть, будь ласка, знову.",
"For security, this session has been signed out. Please sign in again.": "З метою безпеки ваш сеанс було завершено. Увійдіть знову.",
"Upload an avatar:": "Завантажити аватар:",
"Custom (%(level)s)": "Власний (%(level)s)",
"Error upgrading room": "Помилка оновлення кімнати",
@ -541,7 +541,7 @@
"Cancel entering passphrase?": "Скасувати введення парольної фрази?",
"Enter passphrase": "Введіть парольну фразу",
"Setting up keys": "Налаштовування ключів",
"Verify this session": "Звірити цю сесію",
"Verify this session": "Звірити цей сеанс",
"Sign In or Create Account": "Увійти або створити обліковий запис",
"Use your account or create a new one to continue.": "Скористайтесь вашим обліковим записом або створіть нову, щоб продовжити.",
"Create Account": "Створити обліковий запис",
@ -564,10 +564,10 @@
"For help with using %(brand)s, click <a>here</a>.": "Якщо необхідна допомога у користуванні %(brand)s'ом, клацніть <a>тут</a>.",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.": "Якщо необхідна допомога у користуванні %(brand)s'ом, клацніть <a>тут</a> або розпочніть балачку з нашим ботом, клацнувши на кнопці нижче.",
"Join the conversation with an account": "Приєднатись до бесіди з обліковим записом",
"Unable to restore session": "Неможливо відновити сесію",
"We encountered an error trying to restore your previous session.": "Ми натрапили на помилку, намагаючись відновити вашу попередню сесію.",
"Unable to restore session": "Не вдалося відновити сеанс",
"We encountered an error trying to restore your previous session.": "Ми натрапили на помилку, намагаючись відновити ваш попередній сеанс.",
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Для найкращих вражень від користування встановіть, будь ласка, <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, або <safariLink>Safari</safariLink>.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Ваш обліковий запис має перехресно-підписувану ідентичність у таємному сховищі, але вона ще не є довіреною у цій сесії.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Ваш обліковий запис має перехресно-підписувану ідентичність у таємному сховищі, але воно ще не є довіреним у цьому сеансі.",
"in account data": "у даних облікового запису",
"Clear notifications": "Очистити сповіщення",
"Add an email address to configure email notifications": "Додати адресу е-пошти для налаштування поштових сповіщень",
@ -585,8 +585,8 @@
"Confirm account deactivation": "Підтвердьте знедіювання облікового запису",
"To continue, please enter your password:": "Щоб продовжити, введіть, будь ласка, ваш пароль:",
"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. Це призведе до виходу вашого облікового запису з усіх кімнат та до видалення деталей вашого облікового запису з вашого серверу ідентифікації. <b>Ця дія є безповоротною.</b>",
"Verify session": "Звірити сесію",
"Session name": "Назва сесії",
"Verify session": "Звірити сеанс",
"Session name": "Назва сеансу",
"Session ID": "ID сеансу",
"Session key": "Ключ сеансу",
"%(count)s of your messages have not been sent.|one": "Ваше повідомлення не було надіслано.",
@ -697,7 +697,7 @@
"You signed in to a new session without verifying it:": "Ви увійшли в новий сеанс, не підтвердивши його:",
"Verify your other session using one of the options below.": "Перевірте інший сеанс за допомогою одного із варіантів знизу.",
"%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) починає новий сеанс без його підтвердження:",
"Ask this user to verify their session, or manually verify it below.": "Попросіть цього користувача підтвердити сесію, або підтвердіть її власноруч нижче.",
"Ask this user to verify their session, or manually verify it below.": "Попросіть цього користувача підтвердити сеанс, або підтвердьте його власноруч унизу.",
"Not Trusted": "Недовірене",
"Manually Verify by Text": "Ручна перевірка за допомогою тексту",
"Interactively verify by Emoji": "Інтерактивно звірити за допомогою емодзі",
@ -973,10 +973,10 @@
"not found": "не знайдено",
"Cross-signing private keys:": "Приватні ключі для кросс-підпису:",
"exists": "існує",
"Delete sessions|other": "Видалити сесії",
"Delete sessions|one": "Видалити сесію",
"Delete %(count)s sessions|other": "Видалити %(count)s сесій",
"Delete %(count)s sessions|one": "Видалити %(count)s сесій",
"Delete sessions|other": "Видалити сеанси",
"Delete sessions|one": "Видалити сеанс",
"Delete %(count)s sessions|other": "Видалити %(count)s сеансів",
"Delete %(count)s sessions|one": "Видалити %(count)s сеансів",
"ID": "ID",
"Public Name": "Публічне ім'я",
" to store messages from ": " зберігання повідомлень від ",
@ -1630,5 +1630,16 @@
"Send text messages as you in this room": "Надіслати текстові повідомлення у цю кімнату від свого імені",
"Send messages as you in your active room": "Надіслати повідомлення у свою активну кімнату від свого імені",
"Send messages as you in this room": "Надіслати повідомлення у цю кімнату від свого імені",
"Sends the given message as a spoiler": "Надсилає вказане повідомлення згорненим"
"Sends the given message as a spoiler": "Надсилає вказане повідомлення згорненим",
"Integration manager": "Менеджер інтеграцій",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Ваш %(brand)s не дозволяє вам користуватись для цього менеджером інтеграцій. Зверніться до адміністратора.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Користування цим знадобом може призвести до поширення ваших даних <helpIcon /> з %(widgetDomain)s та вашим менеджером інтеграцій.",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Менеджери інтеграцій отримують дані конфігурації та можуть змінювати знадоби, надсилати запрошення у кімнати й встановлювати рівні повноважень від вашого імені.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Використовувати менеджер інтеграцій для керування ботами, знадобами та паками наліпок.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Використовувати менеджер інтеграцій <b>%(serverName)s</b> для керування ботами, знадобами та паками наліпок.",
"Identity server": "Сервер ідентифікації",
"Identity server (%(server)s)": "Сервер ідентифікації (%(server)s)",
"Could not connect to identity server": "Не вдалося під'єднатись до сервера ідентифікації",
"There was an error looking up the phone number": "Сталася помилка під час пошуку номеру телефону",
"Unable to look up phone number": "Неможливо знайти номер телефону"
}

View file

@ -342,5 +342,19 @@
"Confirm adding email": "Xác nhận việc thêm email",
"Add Phone Number": "Thêm Số Điện Thoại",
"Click the button below to confirm adding this phone number.": "Nhấn vào nút dưới đây để xác nhận việc thêm số điện thoại này.",
"Confirm": "Xác nhận"
"Confirm": "Xác nhận",
"No other application is using the webcam": "Không có ứng dụng nào khác đang sử dụng webcam",
"Permission is granted to use the webcam": "Quyền được cấp để sử dụng webcam",
"A microphone and webcam are plugged in and set up correctly": "Micro và webcam đã được cắm và thiết lập đúng cách",
"Call failed because webcam or microphone could not be accessed. Check that:": "Cuộc gọi không thành công vì không thể truy cập webcam hoặc micrô. Kiểm tra xem:",
"Unable to access webcam / microphone": "Không thể truy cập webcam / micro",
"The call could not be established": "Không thể thiết lập cuộc gọi",
"The user you called is busy.": "Người dùng mà bạn gọi đang bận",
"User Busy": "Người dùng đang bận",
"The other party declined the call.": "Bên kia đã từ chối cuộc gọi.",
"Call Declined": "Cuộc gọi bị từ chối",
"Your user agent": "Hành động của bạn",
"Single Sign On": "Single Sign On",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Xác nhận việc thêm địa chỉ email này bằng cách sử dụng Single Sign On để chứng minh danh tính của bạn.",
"Use Single Sign On to continue": "Sử dụng Signle Sign On để tiếp tục"
}

View file

@ -1445,5 +1445,11 @@
"Remove %(email)s?": "%(email)s verwydern?",
"Remove %(phone)s?": "%(phone)s verwydern?",
"Explore rooms": "Gesprekkn ountdekkn",
"Create Account": "Account anmoakn"
"Create Account": "Account anmoakn",
"Integration manager": "Integroasjebeheerder",
"Identity server": "Identiteitsserver",
"Identity server (%(server)s)": "Identiteitsserver (%(server)s)",
"Could not connect to identity server": "Kostege geen verbindienge moakn me den identiteitsserver",
"Not a valid identity server (status code %(code)s)": "Geen geldigen identiteitsserver (statuscode %(code)s)",
"Identity server URL must be HTTPS": "Den identiteitsserver-URL moet HTTPS zyn"
}

View file

@ -3383,5 +3383,17 @@
"%(targetName)s accepted an invitation": "%(targetName)s 已接受邀请",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s 已接受 %(displayName)s 的邀请",
"Some invites couldn't be sent": "部分邀请无法送达",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "我们已向其他人发送邀请,除了以下无法邀请至 <RoomName/> 的人"
"We sent the others, but the below people couldn't be invited to <RoomName/>": "我们已向其他人发送邀请,除了以下无法邀请至 <RoomName/> 的人",
"Integration manager": "集成管理器",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "你的 %(brand)s 不允许你使用集成管理器来完成此操作。请联系管理员。",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "使用此挂件可能会和 %(widgetDomain)s 及您的集成管理器共享数据 <helpIcon />。",
"Identity server is": "身份认证服务器是",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "集成管理器接收配置数据,并可以以你的名义修改挂件、发送聊天室邀请及设置权限级别。",
"Use an integration manager to manage bots, widgets, and sticker packs.": "使用集成管理器以管理机器人、挂件和贴纸包。",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "使用集成管理器 <b>%(serverName)s</b> 以管理机器人、挂件和贴纸包。",
"Identity server": "身份服务器",
"Identity server (%(server)s)": "身份服务器(%(server)s",
"Could not connect to identity server": "无法连接到身份服务器",
"Not a valid identity server (status code %(code)s)": "不是有效的身份服务器(状态码 %(code)s",
"Identity server URL must be HTTPS": "身份服务器连接必须是 HTTPS"
}

View file

@ -3484,5 +3484,104 @@
"%(targetName)s accepted an invitation": "%(targetName)s 接受了邀請",
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s 已接受 %(displayName)s 的邀請",
"Some invites couldn't be sent": "部份邀請無法傳送",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "我們已將邀請傳送給其他人,但以下的人無法邀請至 <RoomName/>"
"We sent the others, but the below people couldn't be invited to <RoomName/>": "我們已將邀請傳送給其他人,但以下的人無法邀請至 <RoomName/>",
"Unnamed audio": "未命名的音訊",
"Error processing audio message": "處理音訊訊息時出現問題",
"Show %(count)s other previews|one": "顯示 %(count)s 個其他預覽",
"Show %(count)s other previews|other": "顯示 %(count)s 個其他預覽",
"Images, GIFs and videos": "圖片、GIF 與影片",
"Code blocks": "程式碼區塊",
"Displaying time": "顯示時間",
"To view all keyboard shortcuts, click here.": "要檢視所有鍵盤快捷鍵,請點擊此處。",
"Keyboard shortcuts": "鍵盤快捷鍵",
"Use Ctrl + F to search timeline": "使用 Ctrl + F 來搜尋時間軸",
"Use Command + F to search timeline": "使用 Command + F 來搜尋時間軸",
"User %(userId)s is already invited to the room": "使用者 %(userId)s 已被邀請至聊天室",
"Integration manager": "整合管理員",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "您的 %(brand)s 不允許您使用整合管理員來執行此動作。請聯絡管理員。",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "使用這個小工具可能會與 %(widgetDomain)s 以及您的整合管理員分享資料 <helpIcon />。",
"Identity server is": "身分認證伺服器是",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "整合管理員接收設定資料,並可以代表您可以修改小工具、傳送聊天室邀請並設定權限等級。",
"Use an integration manager to manage bots, widgets, and sticker packs.": "使用整合管理員以管理機器人、小工具與貼紙包。",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "使用整合管理員 <b>(%(serverName)s)</b> 以管理機器人、小工具與貼紙包。",
"Identity server": "身份識別伺服器",
"Identity server (%(server)s)": "身份識別伺服器 (%(server)s)",
"Could not connect to identity server": "無法連線至身份識別伺服器",
"Not a valid identity server (status code %(code)s)": "不是有效的身份識別伺服器(狀態碼 %(code)s",
"Identity server URL must be HTTPS": "身份識別伺服器 URL 必須為 HTTPS",
"Unable to copy a link to the room to the clipboard.": "無法複製聊天室連結至剪貼簿。",
"Unable to copy room link": "無法複製聊天室連結",
"User Directory": "使用者目錄",
"Copy Link": "複製連結",
"There was an error loading your notification settings.": "載入您的通知設定時發生錯誤。",
"Mentions & keywords": "提及與關鍵字",
"Global": "全域",
"New keyword": "新關鍵字",
"Keyword": "關鍵字",
"Enable email notifications for %(email)s": "為 %(email)s 啟用電子郵件通知",
"Enable for this account": "為此帳號啟用",
"An error occurred whilst saving your notification preferences.": "儲存您的通知偏好設定時遇到錯誤。",
"Error saving notification preferences": "儲存通知偏好設定時發生問題",
"Messages containing keywords": "包含關鍵字的訊息",
"Transfer Failed": "轉接失敗",
"Unable to transfer call": "無法轉接通話",
"Copy Room Link": "複製聊天室連結",
"Downloading": "正在下載",
"The call is in an unknown state!": "通話處於未知狀態!",
"Call back": "回撥",
"You missed this call": "您錯過了此通話",
"This call has failed": "此通話失敗",
"Unknown failure: %(reason)s)": "未知的錯誤:%(reason)s",
"No answer": "無回應",
"An unknown error occurred": "出現未知錯誤",
"Their device couldn't start the camera or microphone": "他們的裝置無法啟動攝影機或麥克風",
"Connection failed": "連線失敗",
"Could not connect media": "無法連結媒體",
"This call has ended": "此通話已結束",
"Connected": "已連線",
"Message bubbles": "訊息泡泡",
"IRC": "IRC",
"New layout switcher (with message bubbles)": "新的佈局切換器(帶有訊息泡泡)",
"Image": "圖片",
"Sticker": "貼紙",
"Error downloading audio": "下載音訊時發生錯誤",
"Anyone in a space can find and join. <a>Edit which spaces can access here.</a>": "任何在空間中的人都可以找到並加入。<a>編輯哪些空間可以存取這個地方。</a>",
"<b>Please note upgrading will make a new version of the room</b>. All current messages will stay in this archived room.": "<b>請注意,升級會讓聊天是變成全新的版本</b>。目前所有的訊息都只會留在被封存的聊天室。",
"Automatically invite members from this room to the new one": "自動將該聊天室的成員邀請至新的聊天室",
"These are likely ones other room admins are a part of.": "這些可能是其他聊天室管理員的一部分。",
"Other spaces or rooms you might not know": "您可能不知道的其他空間或聊天室",
"Spaces you know that contain this room": "您知道的包含此聊天是的空間",
"Search spaces": "搜尋空間",
"Decide which spaces can access this room. If a space is selected, its members can find and join <RoomName/>.": "決定哪些空間可以存取此聊天室。若選取了空間,其成員就可以找到並加入 <RoomName/>。",
"Select spaces": "選取空間",
"You're removing all spaces. Access will default to invite only": "您正在移除所有空間。存取權限將會預設為僅邀請",
"Room visibility": "聊天室能見度",
"Visible to space members": "對空間成員可見",
"Public room": "公開聊天室",
"Private room (invite only)": "私人聊天室(僅邀請)",
"Create a room": "建立聊天室",
"Only people invited will be able to find and join this room.": "僅被邀請的夥伴才能找到並加入此聊天室。",
"Anyone will be able to find and join this room, not just members of <SpaceName/>.": "任何人都將可以找到並加入此聊天室,而不只是 <SpaceName/> 的成員。",
"You can change this at any time from room settings.": "您隨時都可以從聊天室設定變更此設定。",
"Everyone in <SpaceName/> will be able to find and join this room.": "每個在 <SpaceName/> 中的人都將可以找到並加入此聊天室。",
"The voice message failed to upload.": "語音訊息上傳失敗。",
"Access": "存取",
"People with supported clients will be able to join the room without having a registered account.": "有受支援的客戶端的夥伴不需要註冊帳號就可以加入聊天室。",
"Decide who can join %(roomName)s.": "決定誰可以加入 %(roomName)s。",
"Space members": "空間成員",
"Anyone in a space can find and join. You can select multiple spaces.": "空間中的任何人都可以找到並加入。您可以選取多個空間。",
"Anyone in %(spaceName)s can find and join. You can select other spaces too.": "任何在 %(spaceName)s 的人都可以找到並加入。您也可以選取其他空間。",
"Spaces with access": "可存取的空間",
"Currently, %(count)s spaces have access|other": "目前,%(count)s 個空間可存取",
"& %(count)s more|other": "以及 %(count)s 個",
"Upgrade required": "必須升級",
"Anyone can find and join.": "任何人都可以找到並加入。",
"Only invited people can join.": "僅被邀請的夥伴可以加入。",
"Private (invite only)": "私人(僅邀請)",
"This upgrade will allow members of selected spaces access to this room without an invite.": "此升級讓選定空間的成員不需要邀請就可以存取此聊天室。",
"This makes it easy for rooms to stay private to a space, while letting people in the space find and join them. All new rooms in a space will have this option available.": "這同時可以讓聊天室對空間保持隱密,又讓空間中的夥伴可以找到並加入這些聊天室。空間中的所有新聊天室都有此選項。",
"To help space members find and join a private room, go to that room's Security & Privacy settings.": "要協助空間成員尋找並加入私人聊天室,請到該聊天室的「安全與隱私」設定。",
"Help space members find private rooms": "協助空間成員尋找私人聊天室",
"Help people in spaces to find and join private rooms": "協助空間中的夥伴尋找並加入私人聊天室",
"New in the Spaces beta": "Spaces 測試版的新功能"
}

View file

@ -181,8 +181,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
feedbackLabel: "spaces-feedback",
extraSettings: [
"feature_spaces.all_rooms",
"feature_spaces.space_member_dms",
"feature_spaces.space_dm_badges",
],
},
},
@ -192,20 +190,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
default: true,
controller: new ReloadOnChangeController(),
},
"feature_spaces.space_member_dms": {
displayName: _td("Show people in spaces"),
description: _td("If disabled, you can still add Direct Messages to Personal Spaces. " +
"If enabled, you'll automatically see everyone who is a member of the Space."),
supportedLevels: LEVELS_FEATURE,
default: true,
controller: new ReloadOnChangeController(),
},
"feature_spaces.space_dm_badges": {
displayName: _td("Show notification badges for People in Spaces"),
supportedLevels: LEVELS_FEATURE,
default: false,
controller: new ReloadOnChangeController(),
},
"feature_dnd": {
isFeature: true,
displayName: _td("Show options to enable 'Do not disturb' mode"),

View file

@ -72,8 +72,6 @@ const MAX_SUGGESTED_ROOMS = 20;
// All of these settings cause the page to reload and can be costly if read frequently, so read them here only
const spacesEnabled = SettingsStore.getValue("feature_spaces");
const spacesTweakAllRoomsEnabled = SettingsStore.getValue("feature_spaces.all_rooms");
const spacesTweakSpaceMemberDMsEnabled = SettingsStore.getValue("feature_spaces.space_member_dms");
const spacesTweakSpaceDMBadgesEnabled = SettingsStore.getValue("feature_spaces.space_dm_badges");
const homeSpaceKey = spacesTweakAllRoomsEnabled ? "ALL_ROOMS" : "HOME_SPACE";
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || homeSpaceKey}`;
@ -535,15 +533,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
const roomIds = new Set(childRooms.map(r => r.roomId));
const space = this.matrixClient?.getRoom(spaceId);
if (spacesTweakSpaceMemberDMsEnabled) {
// Add relevant DMs
space?.getMembers().forEach(member => {
if (member.membership !== "join" && member.membership !== "invite") return;
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
roomIds.add(roomId);
});
// Add relevant DMs
space?.getMembers().forEach(member => {
if (member.membership !== "join" && member.membership !== "invite") return;
DMRoomMap.shared().getDMRoomsForUserId(member.userId).forEach(roomId => {
roomIds.add(roomId);
});
}
});
const newPath = new Set(parentPath).add(spaceId);
childSpaces.forEach(childSpace => {
@ -568,14 +564,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
this.spaceFilteredRooms.forEach((roomIds, s) => {
// Update NotificationStates
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
if (roomIds.has(room.roomId)) {
if (s !== HOME_SPACE && spacesTweakSpaceDMBadgesEnabled) return true;
if (!roomIds.has(room.roomId)) return false;
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
return s === HOME_SPACE;
}
return false;
return true;
}));
});
}, 100, { trailing: true, leading: true });
@ -878,8 +873,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
export default class SpaceStore {
public static spacesEnabled = spacesEnabled;
public static spacesTweakAllRoomsEnabled = spacesTweakAllRoomsEnabled;
public static spacesTweakSpaceMemberDMsEnabled = spacesTweakSpaceMemberDMsEnabled;
public static spacesTweakSpaceDMBadgesEnabled = spacesTweakSpaceDMBadgesEnabled;
private static internalInstance = new SpaceStoreClass();

View file

@ -23,7 +23,7 @@ import { NOTIFICATION_STATE_UPDATE, NotificationState } from "./NotificationStat
import { FetchRoomFn } from "./ListNotificationState";
export class SpaceNotificationState extends NotificationState {
private rooms: Room[] = [];
public rooms: Room[] = []; // exposed only for tests
private states: { [spaceId: string]: RoomNotificationState } = {};
constructor(private spaceId: string | symbol, private getRoomFn: FetchRoomFn) {

View file

@ -54,6 +54,7 @@ import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { ELEMENT_CLIENT_ID } from "../../identifiers";
import { getUserLanguage } from "../../languageHandler";
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
// TODO: Destroy all of this code
@ -191,7 +192,8 @@ export class StopGapWidget extends EventEmitter {
}
private runUrlTemplate(opts = { asPopout: false }): string {
const templated = this.mockWidget.getCompleteUrl({
const fromCustomisation = WidgetVariableCustomisations?.provideVariables?.() ?? {};
const defaults: ITemplateParams = {
widgetRoomId: this.roomId,
currentUserId: MatrixClientPeg.get().getUserId(),
userDisplayName: OwnProfileStore.instance.displayName,
@ -199,7 +201,8 @@ export class StopGapWidget extends EventEmitter {
clientId: ELEMENT_CLIENT_ID,
clientTheme: SettingsStore.getValue("theme"),
clientLanguage: getUserLanguage(),
}, opts?.asPopout);
};
const templated = this.mockWidget.getCompleteUrl(Object.assign(defaults, fromCustomisation), opts?.asPopout);
const parsed = new URL(templated);
@ -363,6 +366,9 @@ export class StopGapWidget extends EventEmitter {
}
public async prepare(): Promise<void> {
// Ensure the variables are ready for us to be rendered before continuing
await (WidgetVariableCustomisations?.isReady?.() ?? Promise.resolve());
if (this.scalarToken) return;
const existingMessaging = WidgetMessagingStore.instance.getMessaging(this.mockWidget);
if (existingMessaging) this.messaging = existingMessaging;

View file

@ -19,5 +19,3 @@ limitations under the License.
localStorage.setItem("mx_labs_feature_feature_spaces", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.all_rooms", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.space_member_dms", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.space_dm_badges", "false");

View file

@ -17,6 +17,7 @@ limitations under the License.
import { EventEmitter } from "events";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import "./SpaceStore-setup"; // enable space lab
import "../skinned-sdk"; // Must be first for skinning to work
@ -53,18 +54,22 @@ const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise(r => e.
const testUserId = "@test:user";
const getUserIdForRoomId = jest.fn();
const getDMRoomsForUserId = jest.fn();
// @ts-ignore
DMRoomMap.sharedInstance = { getUserIdForRoomId };
DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId };
const fav1 = "!fav1:server";
const fav2 = "!fav2:server";
const fav3 = "!fav3:server";
const dm1 = "!dm1:server";
const dm1Partner = "@dm1Partner:server";
const dm1Partner = new RoomMember(dm1, "@dm1Partner:server");
dm1Partner.membership = "join";
const dm2 = "!dm2:server";
const dm2Partner = "@dm2Partner:server";
const dm2Partner = new RoomMember(dm2, "@dm2Partner:server");
dm2Partner.membership = "join";
const dm3 = "!dm3:server";
const dm3Partner = "@dm3Partner:server";
const dm3Partner = new RoomMember(dm3, "@dm3Partner:server");
dm3Partner.membership = "join";
const orphan1 = "!orphan1:server";
const orphan2 = "!orphan2:server";
const invite1 = "!invite1:server";
@ -320,11 +325,40 @@ describe("SpaceStore", () => {
getUserIdForRoomId.mockImplementation(roomId => {
return {
[dm1]: dm1Partner,
[dm2]: dm2Partner,
[dm3]: dm3Partner,
[dm1]: dm1Partner.userId,
[dm2]: dm2Partner.userId,
[dm3]: dm3Partner.userId,
}[roomId];
});
getDMRoomsForUserId.mockImplementation(userId => {
switch (userId) {
case dm1Partner.userId:
return [dm1];
case dm2Partner.userId:
return [dm2];
case dm3Partner.userId:
return [dm3];
default:
return [];
}
});
// have dmPartner1 be in space1 with you
const mySpace1Member = new RoomMember(space1, testUserId);
mySpace1Member.membership = "join";
(rooms.find(r => r.roomId === space1).getMembers as jest.Mock).mockReturnValue([
mySpace1Member,
dm1Partner,
]);
// have dmPartner2 be in space2 with you
const mySpace2Member = new RoomMember(space2, testUserId);
mySpace2Member.membership = "join";
(rooms.find(r => r.roomId === space2).getMembers as jest.Mock).mockReturnValue([
mySpace2Member,
dm2Partner,
]);
// dmPartner3 is not in any common spaces with you
await run();
});
@ -375,6 +409,66 @@ describe("SpaceStore", () => {
const space = client.getRoom(space3);
expect(store.getSpaceFilteredRoomIds(space).has(invite2)).toBeTruthy();
});
it("spaces contain dms which you have with members of that space", () => {
expect(store.getSpaceFilteredRoomIds(client.getRoom(space1)).has(dm1)).toBeTruthy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space2)).has(dm1)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space3)).has(dm1)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space1)).has(dm2)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space2)).has(dm2)).toBeTruthy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space3)).has(dm2)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space1)).has(dm3)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space2)).has(dm3)).toBeFalsy();
expect(store.getSpaceFilteredRoomIds(client.getRoom(space3)).has(dm3)).toBeFalsy();
});
it("dms are only added to Notification States for only the Home Space", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// [dm1, dm2, dm3].forEach(d => {
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(d)).toBeTruthy();
// });
[space1, space2, space3].forEach(s => {
[dm1, dm2, dm3].forEach(d => {
expect(store.getNotificationState(s).rooms.map(r => r.roomId).includes(d)).toBeFalsy();
});
});
});
it("orphan rooms are added to Notification States for only the Home Space", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// [orphan1, orphan2].forEach(d => {
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(d)).toBeTruthy();
// });
[space1, space2, space3].forEach(s => {
[orphan1, orphan2].forEach(d => {
expect(store.getNotificationState(s).rooms.map(r => r.roomId).includes(d)).toBeFalsy();
});
});
});
it("favourites are added to Notification States for all spaces containing the room inc Home", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// [fav1, fav2, fav3].forEach(d => {
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(d)).toBeTruthy();
// });
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(fav1)).toBeTruthy();
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(fav2)).toBeFalsy();
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(fav3)).toBeFalsy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(fav1)).toBeTruthy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(fav2)).toBeTruthy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(fav3)).toBeTruthy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(fav1)).toBeFalsy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(fav2)).toBeFalsy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(fav3)).toBeFalsy();
});
it("other rooms are added to Notification States for all spaces containing the room exc Home", () => {
// XXX: All rooms space is forcibly enabled, as part of a future PR test Home space better
// expect(store.getNotificationState(HOME_SPACE).rooms.map(r => r.roomId).includes(room1)).toBeFalsy();
expect(store.getNotificationState(space1).rooms.map(r => r.roomId).includes(room1)).toBeTruthy();
expect(store.getNotificationState(space2).rooms.map(r => r.roomId).includes(room1)).toBeTruthy();
expect(store.getNotificationState(space3).rooms.map(r => r.roomId).includes(room1)).toBeFalsy();
});
});
});

View file

@ -3234,8 +3234,8 @@ eslint-config-google@^0.14.0:
integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==
"eslint-plugin-matrix-org@github:matrix-org/eslint-plugin-matrix-org#main":
version "0.3.3"
resolved "https://codeload.github.com/matrix-org/eslint-plugin-matrix-org/tar.gz/50d6bdf6704dd95016d5f1f824f00cac6eaa64e1"
version "0.3.4"
resolved "https://codeload.github.com/matrix-org/eslint-plugin-matrix-org/tar.gz/45f6937539192e3820edcafc4d6d4d4187e85a6a"
eslint-plugin-react-hooks@^4.2.0:
version "4.2.0"