Merge remote-tracking branch 'origin/experimental' into dbkr/sas

This commit is contained in:
David Baker 2019-01-18 18:33:11 +00:00
commit 970880737e
83 changed files with 2920 additions and 1437 deletions

View file

@ -48,7 +48,6 @@ src/components/views/rooms/LinkPreviewWidget.js
src/components/views/rooms/MemberDeviceInfo.js
src/components/views/rooms/MemberInfo.js
src/components/views/rooms/MemberList.js
src/components/views/rooms/MemberTile.js
src/components/views/rooms/MessageComposer.js
src/components/views/rooms/PinnedEventTile.js
src/components/views/rooms/RoomList.js

View file

@ -5,7 +5,6 @@
@import "./structures/_ContextualMenu.scss";
@import "./structures/_CreateRoom.scss";
@import "./structures/_FilePanel.scss";
@import "./structures/_GroupGridView.scss";
@import "./structures/_GroupView.scss";
@import "./structures/_HomePage.scss";
@import "./structures/_LeftPanel.scss";

View file

@ -30,8 +30,8 @@ limitations under the License.
}
.mx_ContextualMenu {
border-radius: 2px;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.21);
border-radius: 4px;
box-shadow: 4px 4px 12px 0 rgba(118, 131, 156, 0.6);;
background-color: $menu-bg-color;
color: $primary-fg-color;
position: absolute;

View file

@ -1,130 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_GroupGridView {
display: flex;
flex-direction: column;
}
.mx_GroupGridView_rooms {
display: grid;
grid-template-columns: repeat(3, calc(100% / 3));
grid-template-rows: repeat(2, calc(100% / 2));
flex: 1 1 0;
min-width: 0;
}
.mx_GroupGridView_rightPanel {
display: flex;
flex-direction: column;
.mx_GroupGridView_tabs {
flex: 0 0 52px;
border-bottom: 1px solid $primary-hairline-color;
display: flex;
align-items: center;
> div {
justify-content: flex-end;
width: 100%;
margin-right: 10px;
}
}
.mx_RightPanel {
flex: 1 0 auto !important;
}
}
.mx_GroupGridView > .mx_MainSplit {
flex: 1 1 0;
display: flex;
}
.mx_GroupGridView_emptyTile {
display: block;
margin-top: 100px;
text-align: center;
user-select: none;
}
.mx_GroupGridView_tile {
border-right: 1px solid $panel-divider-color;
border-bottom: 1px solid $panel-divider-color;
}
.mx_GroupGridView_activeTile {
position: relative;
}
.mx_GroupGridView_activeTile:before,
.mx_GroupGridView_activeTile:after {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
content: "";
pointer-events: none;
z-index: 3500;
}
.mx_GroupGridView_activeTile:before {
border-radius: 14px;
border: 8px solid $gridview-focus-border-glow-color;
margin: -8px;
}
.mx_GroupGridView_activeTile:after {
border-radius: 8px;
border: 2px solid $gridview-focus-border-color;
margin: -2px;
}
.mx_GroupGridView_tile > .mx_RoomView {
height: 100%;
}
.mx_GroupGridView_rooms > *:nth-child(1) {
grid-column: 1;
grid-row: 1;
}
.mx_GroupGridView_rooms > *:nth-child(2) {
grid-column: 2;
grid-row: 1;
}
.mx_GroupGridView_rooms > *:nth-child(3) {
grid-column: 3;
grid-row: 1;
}
.mx_GroupGridView_rooms > *:nth-child(4) {
grid-column: 1;
grid-row: 2;
}
.mx_GroupGridView_rooms > *:nth-child(5) {
grid-column: 2;
grid-row: 2;
}
.mx_GroupGridView_rooms > *:nth-child(6) {
grid-column: 3;
grid-row: 2;
}

View file

@ -81,8 +81,7 @@ limitations under the License.
Empirically this stops the MessagePanel's width exploding outwards when
gemini is in 'prevented' mode
*/
// disabling this for now as it clips the active room rect on the grid view
// overflow-x: auto;
overflow-x: auto;
/* To fix https://github.com/vector-im/riot-web/issues/3298 where Safari
needed height 100% all the way down to the HomePage. Height does not

View file

@ -33,13 +33,25 @@ limitations under the License.
.mx_RoomSubList {
min-height: 31px;
flex: 0 100000000 auto;
flex: 0 10000 auto;
display: flex;
flex-direction: column;
}
.mx_RoomSubList.resized-sized {
/*
flex-basis to 0 so sublists
are not shrinking/growing relative
to their content (as would be the case with auto),
as this intervenes with sizing an item exactly
when not available space is available
in the flex container
*/
flex: 1 1 0;
}
.mx_RoomSubList_nonEmpty {
min-height: 70px;
min-height: 74px;
.mx_AutoHideScrollbar_offset {
padding-bottom: 4px;
@ -50,17 +62,6 @@ limitations under the License.
flex: none !important;
}
.mx_RoomSubList.resized-all {
flex: 0 1 auto;
}
.mx_RoomSubList.resized-sized {
/* resizer set max-height on resized-sized,
so that limits the height and hence
needs a very small flex-shrink */
flex: 0 10000 auto;
}
.mx_RoomSubList_labelContainer {
display: flex;
flex-direction: row;

View file

@ -95,12 +95,10 @@ limitations under the License.
flex-direction: column;
}
.mx_RoomView_body .mx_RoomView_messagePanel {
order: 2;
}
.mx_RoomView_body .mx_RoomView_messagePanelSpinner {
order: 2;
.mx_RoomView_body {
.mx_RoomView_messagePanel, .mx_RoomView_messagePanelSpinner, .mx_RoomView_messagePanelSearchSpinner{
order: 2;
}
}
.mx_RoomView_body .mx_RoomView_statusArea {
@ -116,6 +114,29 @@ limitations under the License.
overflow-y: auto;
}
.mx_RoomView_messagePanelSearchSpinner {
flex: 1;
background-image: url('../../img/typing-indicator-2x.gif');
background-position: center 367px;
background-size: 25px;
background-repeat: no-repeat;
position: relative;
}
.mx_RoomView_messagePanelSearchSpinner:before {
background-color: $greyed-fg-color;
mask: url('../../img/feather-icons/search-input.svg');
mask-repeat: no-repeat;
mask-position: center;
mask-size: 50px;
content: '';
position: absolute;
top: 286px;
left: 0;
right: 0;
height: 50px;
}
.mx_RoomView_messageListWrapper {
min-height: 100%;
@ -126,8 +147,15 @@ limitations under the License.
justify-content: flex-end;
}
.mx_RoomView_searchResultsPanel .mx_RoomView_messageListWrapper {
justify-content: flex-start;
.mx_RoomView_searchResultsPanel {
.mx_RoomView_messageListWrapper {
justify-content: flex-start;
}
a {
text-decoration: none;
color: inherit;
}
}
.mx_RoomView_empty {

View file

@ -14,8 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_MemberStatusMessageAvatar_hasStatus {
border: 2px solid $accent-color;
border-radius: 40px;
padding-right: 0 !important; /* Override AccessibleButton styling */
.mx_MessageComposer_avatar .mx_BaseAvatar {
padding: 2px;
border: 1px solid transparent;
border-radius: 15px;
}
.mx_MessageComposer_avatar .mx_BaseAvatar_initial {
left: 2px;
}
.mx_MemberStatusMessageAvatar_hasStatus .mx_BaseAvatar {
border-color: $accent-color;
}

View file

@ -14,42 +14,52 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_StatusMessageContextMenu_message {
display: inline-block;
border-radius: 3px 0 0 3px;
.mx_StatusMessageContextMenu {
padding: 10px;
}
.mx_StatusMessageContextMenu_form {
display: flex;
flex-direction: column;
}
input.mx_StatusMessageContextMenu_message {
border-radius: 4px;
border: 1px solid $input-border-color;
font-size: 13px;
padding: 7px 7px 7px 9px;
width: 135px;
background-color: $primary-bg-color !important;
padding: 6.5px 11px;
background-color: $primary-bg-color;
font-weight: normal;
margin: 0 0 10px;
}
.mx_StatusMessageContextMenu_submit {
display: inline-block;
.mx_StatusMessageContextMenu_message::placeholder {
color: $memberstatus-placeholder-color;
}
.mx_StatusMessageContextMenu_submitFaded {
opacity: 0.5;
.mx_StatusMessageContextMenu_actionContainer {
display: flex;
}
.mx_StatusMessageContextMenu_submit img {
vertical-align: middle;
margin-left: 8px;
.mx_StatusMessageContextMenu_submit,
.mx_StatusMessageContextMenu_clear {
@mixin mx_DialogButton;
align-self: start;
font-size: 12px;
padding: 6px 1em;
border: 1px solid transparent;
margin-right: 10px;
}
.mx_StatusMessageContextMenu hr {
border: 0.5px solid $menu-border-color;
}
.mx_StatusMessageContextMenu_clearIcon {
margin: 5px 15px 5px 5px;
vertical-align: middle;
.mx_StatusMessageContextMenu_submit[disabled] {
opacity: 0.49;
}
.mx_StatusMessageContextMenu_clear {
padding: 2px;
color: $warning-color;
background-color: transparent;
border: 1px solid $warning-color;
}
.mx_StatusMessageContextMenu_hasStatus .mx_StatusMessageContextMenu_clear {
color: $warning-color;
.mx_StatusMessageContextMenu_actionContainer .mx_Spinner {
justify-content: start;
}

View file

@ -27,6 +27,7 @@ limitations under the License.
padding: 0;
li {
cursor: pointer;
white-space: nowrap;
padding: 5px 20px;
}

View file

@ -79,6 +79,11 @@
.mx_Markdown_ITALIC {
font-style: italic;
// compensate for Nunito italics being terrible
// https://github.com/google/fonts/issues/1726
transform: skewX(-14deg);
display: inline-block;
}
.mx_Markdown_CODE {

View file

@ -453,6 +453,13 @@ limitations under the License.
display: inline ! important;
}
// compensate for Nunito italics being terrible
// https://github.com/google/fonts/issues/1726
.mx_EventTile_content .markdown-body em {
transform: skewX(-14deg);
display: inline-block;
}
/* end of overrides */
.mx_MatrixChat_useCompactLayout {

View file

@ -53,10 +53,6 @@ limitations under the License.
.mx_MemberList_query,
.mx_GroupMemberList_query,
.mx_GroupRoomList_query {
flex: 0 0 auto;
}
.mx_MemberList .gm-scrollbar-container {
flex: 1 1 0;
}

View file

@ -58,17 +58,13 @@ limitations under the License.
}
.mx_MessageComposer .mx_MessageComposer_avatar {
padding: 0 28px;
padding: 0 27px;
}
.mx_MessageComposer .mx_MessageComposer_avatar .mx_BaseAvatar {
display: block;
}
.mx_MessageComposer .mx_AccessibleButton {
padding: 0 12px 0 0;
}
.mx_MessageComposer_composecontrols {
width: 100%;
}
@ -185,7 +181,7 @@ limitations under the License.
/*display: table-cell;*/
/*vertical-align: middle;*/
/*padding-left: 10px;*/
padding-right: 5px;
padding-right: 12px;
cursor: pointer;
padding-top: 4px;
}

View file

@ -98,6 +98,7 @@ limitations under the License.
font-size: 18px;
margin: 0 7px;
border-bottom: 1px solid transparent;
display: flex;
}
.mx_RoomHeader_nametext {
@ -111,7 +112,6 @@ limitations under the License.
}
.mx_RoomHeader_searchStatus {
display: inline-block;
font-weight: normal;
opacity: 0.6;
}

View file

@ -15,69 +15,52 @@ limitations under the License.
*/
.mx_SearchBar {
padding-top: 5px;
padding-bottom: 5px;
height: 56px;
display: flex;
align-items: center;
}
border-bottom: 1px solid $primary-hairline-color;
.mx_SearchBar_input {
display: inline block;
border-radius: 3px 0px 0px 3px;
border: 1px solid $input-border-color;
font-size: 15px;
padding: 9px;
padding-left: 11px;
width: auto;
flex: 1 1 0;
}
.mx_SearchBar_input {
// border: 1px solid $input-border-color;
// font-size: 15px;
flex: 1 1 0;
margin-left: 22px;
}
.mx_SearchBar_searchButton {
cursor: pointer;
margin-right: 10px;
width: 37px;
height: 37px;
border-radius: 0px 3px 3px 0px;
background-color: $accent-color;
}
.mx_SearchBar_searchButton {
cursor: pointer;
width: 37px;
height: 37px;
background-color: $accent-color;
mask: url('../../img/feather-icons/search-input.svg');
mask-repeat: no-repeat;
mask-position: center;
}
@keyframes pulsate {
0% { opacity: 1.0; }
50% { opacity: 0.1; }
100% { opacity: 1.0; }
}
.mx_SearchBar_button {
border: 0;
margin: 0 0 0 22px;
padding: 5px;
font-size: 15px;
cursor: pointer;
color: $primary-fg-color;
border-bottom: 2px solid $accent-color;
font-weight: 600;
}
.mx_SearchBar_searching img {
animation: pulsate 0.5s ease-out;
animation-iteration-count: infinite;
}
.mx_SearchBar_unselected {
color: $input-darker-fg-color;
border-color: transparent;
}
.mx_SearchBar_button {
display: inline;
border: 0px;
border-radius: 36px;
font-weight: 400;
font-size: 15px;
color: $accent-fg-color;
background-color: $accent-color;
width: auto;
margin: auto;
margin-left: 7px;
padding-top: 6px;
padding-bottom: 4px;
padding-left: 24px;
padding-right: 24px;
cursor: pointer;
}
.mx_SearchBar_unselected {
background-color: $primary-bg-color;
color: $accent-color;
border: $accent-color 1px solid;
}
.mx_SearchBar_cancel {
padding-left: 14px;
padding-right: 14px;
cursor: pointer;
.mx_SearchBar_cancel {
background-color: $warning-color;
mask: url('../../img/cancel.svg');
mask-repeat: no-repeat;
mask-position: center;
mask-size: 14px;
padding: 9px;
margin: 0 12px 0 3px;
cursor: pointer;
}
}

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="14px" viewBox="0 0 22 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>Group 2</title>
<desc>Created with Sketch.</desc>
<g id="Experiments" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g id="multi-room-test-copy-8" transform="translate(-826.000000, -15.000000)" stroke="#929EB4" stroke-width="1.6">
<g id="Group-4" transform="translate(341.000000, 7.000000)">
<g id="Group-2" transform="translate(486.000000, 8.000000)">
<path d="M20,1 L2.30926389e-14,1" id="Line-10"></path>
<path d="M20,7 L3,7" id="Line-10-Copy"></path>
<path d="M20,13 L6,13" id="Line-10-Copy-2"></path>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 995 B

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>Tick</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Custom-Status-Copy" transform="translate(-529.000000, -917.000000)" fill-rule="nonzero">
<g id="Tick" transform="translate(530.000000, 918.000000)">
<circle id="Oval" stroke="#6AAC8C" fill="#75CFA6" cx="9" cy="9" r="9"></circle>
<g id="Glyph" transform="translate(8.949747, 7.949747) rotate(-45.000000) translate(-8.949747, -7.949747) translate(4.449747, 5.449747)" fill="#FFFFFF">
<rect id="Rectangle" x="0" y="0" width="2" height="5"></rect>
<rect id="Rectangle" x="0" y="3" width="9" height="2"></rect>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -162,10 +162,6 @@ $lightbox-bg-color: #454545;
$lightbox-fg-color: #ffffff;
$lightbox-border-color: #ffffff;
/*** GroupGridView ***/
$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5);
$gridview-focus-border-color: rgba(134, 193, 165, 1);
$imagebody-giflabel: rgba(1, 1, 1, 0.7);
$imagebody-giflabel-border: rgba(1, 1, 1, 0.2);
$imagebody-giflabel-color: rgba(0, 0, 0, 1);

View file

@ -68,7 +68,7 @@ $event-selected-color: #f7f7f7;
$primary-hairline-color: #e5e5e5;
// used for the border of input text fields
$input-border-color: #f0f0f0;
$input-border-color: #e7e7e7;
$input-darker-bg-color: rgba(193, 201, 214, 0.29);
$input-darker-fg-color: #9fa9ba;
$input-lighter-bg-color: #f2f5f8;
@ -184,14 +184,13 @@ $lightbox-bg-color: #454545;
$lightbox-fg-color: #ffffff;
$lightbox-border-color: #ffffff;
/*** GroupGridView ***/
$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5);
$gridview-focus-border-color: rgba(134, 193, 165, 1);
// unused?
$progressbar-color: #000;
$room-warning-bg-color: #fff8e3;
$memberstatus-placeholder-color: $roomtile-name-color;
/*** form elements ***/
// .mx_textinput is a container for a text input

View file

@ -175,10 +175,6 @@ $lightbox-bg-color: #454545;
$lightbox-fg-color: #ffffff;
$lightbox-border-color: #ffffff;
/*** GroupGridView ***/
$gridview-focus-border-glow-color: rgba(134, 193, 165, 0.5);
$gridview-focus-border-color: rgba(134, 193, 165, 1);
$imagebody-giflabel: rgba(0, 0, 0, 0.7);
$imagebody-giflabel-border: rgba(0, 0, 0, 0.2);
$imagebody-giflabel-color: rgba(255, 255, 255, 1);
@ -188,6 +184,8 @@ $progressbar-color: #000;
$room-warning-bg-color: #fff8e3;
$memberstatus-placeholder-color: $roomtile-name-color;
// ***** Mixins! *****
@define-mixin mx_DialogButton {

View file

@ -14,10 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import OpenRoomsStore from './stores/OpenRoomsStore';
import RoomViewStore from './stores/RoomViewStore';
/**
* Consumes changes from the OpenRoomsStore and notifies specific things
* Consumes changes from the RoomViewStore and notifies specific things
* about when the active room changes. Unlike listening for RoomViewStore
* changes, you can subscribe to only changes relevant to a particular
* room.
@ -28,15 +28,11 @@ import OpenRoomsStore from './stores/OpenRoomsStore';
class ActiveRoomObserver {
constructor() {
this._listeners = {};
const roomStore = OpenRoomsStore.getActiveRoomStore();
this._activeRoomId = roomStore && roomStore.getRoomId();
this._activeRoomId = RoomViewStore.getRoomId();
// TODO: We could self-destruct when the last listener goes away, or at least
// stop listening.
this._roomStoreToken = OpenRoomsStore.addListener(this._onOpenRoomsStoreUpdate.bind(this));
}
getActiveRoomId() {
return this._activeRoomId;
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
}
addListener(roomId, listener) {
@ -55,23 +51,23 @@ class ActiveRoomObserver {
}
}
_emit(roomId, newActiveRoomId) {
_emit(roomId) {
if (!this._listeners[roomId]) return;
for (const l of this._listeners[roomId]) {
l.call(l, newActiveRoomId);
l.call();
}
}
_onOpenRoomsStoreUpdate() {
const activeRoomStore = OpenRoomsStore.getActiveRoomStore();
const newActiveRoomId = activeRoomStore && activeRoomStore.getRoomId();
_onRoomViewStoreUpdate() {
// emit for the old room ID
if (this._activeRoomId) this._emit(this._activeRoomId, newActiveRoomId);
if (this._activeRoomId) this._emit(this._activeRoomId);
// update our cache
this._activeRoomId = newActiveRoomId;
this._activeRoomId = RoomViewStore.getRoomId();
// and emit for the new one
if (this._activeRoomId) this._emit(this._activeRoomId, this._activeRoomId);
if (this._activeRoomId) this._emit(this._activeRoomId);
}
}

View file

@ -19,7 +19,6 @@ limitations under the License.
export default {
HomePage: "home_page",
RoomView: "room_view",
GroupGridView: "group_grid_view",
UserSettings: "user_settings",
RoomDirectory: "room_directory",
UserView: "user_view",

View file

@ -86,6 +86,18 @@ export const CommandMap = {
hideCompletionAfterSpace: true,
}),
upgraderoom: new Command({
name: 'upgraderoom',
args: '<new_version>',
description: _td('Upgrades a room to a new version'),
runFn: function(roomId, args) {
if (args) {
return success(MatrixClientPeg.get().upgradeRoom(roomId, args));
}
return reject(this.getUsage());
},
}),
nick: new Command({
name: 'nick',
args: '<display_name>',

View file

@ -1,127 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd.
Copyright 2017, 2018 New Vector Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import OpenRoomsStore from '../../stores/OpenRoomsStore';
import dis from '../../dispatcher';
import {_t} from '../../languageHandler';
import RoomView from './RoomView';
import classNames from 'classnames';
import MainSplit from './MainSplit';
import RightPanel from './RightPanel';
import RoomHeaderButtons from '../views/right_panel/RoomHeaderButtons';
export default class RoomGridView extends React.Component {
constructor(props) {
super(props);
this.state = {
roomStores: OpenRoomsStore.getRoomStores(),
activeRoomStore: OpenRoomsStore.getActiveRoomStore(),
};
this.onRoomsChanged = this.onRoomsChanged.bind(this);
}
componentDidUpdate(_, prevState) {
const store = this.state.activeRoomStore;
if (store) {
store.getDispatcher().dispatch({action: 'focus_composer'});
}
}
componentDidMount() {
this.componentDidUpdate();
}
componentWillMount() {
this._unmounted = false;
this._openRoomsStoreRegistration = OpenRoomsStore.addListener(this.onRoomsChanged);
}
componentWillUnmount() {
this._unmounted = true;
if (this._openRoomsStoreRegistration) {
this._openRoomsStoreRegistration.remove();
}
}
onRoomsChanged() {
if (this._unmounted) return;
this.setState({
roomStores: OpenRoomsStore.getRoomStores(),
activeRoomStore: OpenRoomsStore.getActiveRoomStore(),
});
}
_setActive(i) {
const store = OpenRoomsStore.getRoomStoreAt(i);
if (store !== this.state.activeRoomStore) {
dis.dispatch({
action: 'group_grid_set_active',
room_id: store.getRoomId(),
});
}
}
render() {
let roomStores = this.state.roomStores.slice(0, 6);
const emptyCount = 6 - roomStores.length;
if (emptyCount) {
const emptyTiles = Array.from({length: emptyCount}, () => null);
roomStores = roomStores.concat(emptyTiles);
}
const activeRoomId = this.state.activeRoomStore && this.state.activeRoomStore.getRoomId();
let rightPanel;
if (activeRoomId) {
rightPanel = (
<div className="mx_GroupGridView_rightPanel">
<div className="mx_GroupGridView_tabs"><RoomHeaderButtons /></div>
<RightPanel roomId={activeRoomId} />
</div>
);
}
return (<main className="mx_GroupGridView">
<MainSplit panel={rightPanel} collapsedRhs={this.props.collapsedRhs} >
<div className="mx_GroupGridView_rooms">
{ roomStores.map((roomStore, i) => {
if (roomStore) {
const isActive = roomStore === this.state.activeRoomStore;
const tileClasses = classNames({
"mx_GroupGridView_tile": true,
"mx_GroupGridView_activeTile": isActive,
});
return (<section
onClick={() => {this._setActive(i);}}
key={roomStore.getRoomId()}
className={tileClasses}
>
<RoomView
collapsedRhs={this.props.collapsedRhs}
isGrid={true}
roomViewStore={roomStore}
isActive={isActive}
/>
</section>);
} else {
return (<section className={"mx_GroupGridView_emptyTile"} key={`empty-${i}`}>{_t("No room in this tile yet.")}</section>);
}
}) }
</div>
</MainSplit>
</main>);
}
}

View file

@ -31,7 +31,6 @@ import sessionStore from '../../stores/SessionStore';
import MatrixClientPeg from '../../MatrixClientPeg';
import SettingsStore from "../../settings/SettingsStore";
import RoomListStore from "../../stores/RoomListStore";
import OpenRoomsStore from "../../stores/OpenRoomsStore";
import TagOrderActions from '../../actions/TagOrderActions';
import RoomListActions from '../../actions/RoomListActions';
@ -417,7 +416,6 @@ const LoggedInView = React.createClass({
const RoomDirectory = sdk.getComponent('structures.RoomDirectory');
const HomePage = sdk.getComponent('structures.HomePage');
const GroupView = sdk.getComponent('structures.GroupView');
const GroupGridView = sdk.getComponent('structures.GroupGridView');
const MyGroups = sdk.getComponent('structures.MyGroups');
const MatrixToolbar = sdk.getComponent('globals.MatrixToolbar');
const CookieBar = sdk.getComponent('globals.CookieBar');
@ -430,14 +428,7 @@ const LoggedInView = React.createClass({
switch (this.props.page_type) {
case PageTypes.RoomView:
if (!OpenRoomsStore.getActiveRoomStore()) {
console.warn(`LoggedInView: getCurrentRoomStore not set!`);
}
else if (OpenRoomsStore.getActiveRoomStore().getRoomId() !== this.props.currentRoomId) {
console.warn(`LoggedInView: room id in store not the same as in props: ${OpenRoomsStore.getActiveRoomStore().getRoomId()} & ${this.props.currentRoomId}`);
}
page_element = <RoomView
roomViewStore={OpenRoomsStore.getActiveRoomStore()}
ref='roomView'
autoJoin={this.props.autoJoin}
onRegistered={this.props.onRegistered}
@ -451,9 +442,7 @@ const LoggedInView = React.createClass({
ConferenceHandler={this.props.ConferenceHandler}
/>;
break;
case PageTypes.GroupGridView:
page_element = <GroupGridView collapsedRhs={this.props.collapsedRhs} />;
break;
case PageTypes.UserSettings:
page_element = <UserSettings
onClose={this.props.onCloseAllSettings}

View file

@ -71,13 +71,14 @@ export default class MainSplit extends React.Component {
}
componentDidUpdate(prevProps) {
const shouldAllowResizing =
!this.props.collapsedRhs &&
this.props.panel;
const wasExpanded = !this.props.collapsedRhs && prevProps.collapsedRhs;
const wasCollapsed = this.props.collapsedRhs && !prevProps.collapsedRhs;
const wasPanelSet = this.props.panel && !prevProps.panel;
const wasPanelCleared = !this.props.panel && prevProps.panel;
if (shouldAllowResizing && !this.resizer) {
if (wasExpanded || wasPanelSet) {
this._createResizer();
} else if (!shouldAllowResizing && this.resizer) {
} else if (wasCollapsed || wasPanelCleared) {
this.resizer.detach();
this.resizer = null;
}

View file

@ -651,9 +651,6 @@ export default React.createClass({
case 'view_group':
this._viewGroup(payload);
break;
case 'group_grid_view':
this._viewGroupGrid(payload);
break;
case 'view_home_page':
this._viewHome();
break;
@ -865,7 +862,6 @@ export default React.createClass({
// room name and avatar from an invite email)
_viewRoom: function(roomInfo) {
this.focusComposer = true;
console.log("!!! MatrixChat._viewRoom", roomInfo);
const newState = {
currentRoomId: roomInfo.room_id || null,
@ -914,9 +910,6 @@ export default React.createClass({
if (roomInfo.event_id && roomInfo.highlighted) {
presentedId += "/" + roomInfo.event_id;
}
// TODO: only emit this when we're not in grid mode?
this.notifyNewScreen('room/' + presentedId);
newState.ready = true;
this.setState(newState);
@ -933,11 +926,6 @@ export default React.createClass({
this.notifyNewScreen('group/' + groupId);
},
_viewGroupGrid: function(payload) {
this._setPage(PageTypes.GroupGridView);
// this.notifyNewScreen('grid/' + payload.group_id);
},
_viewHome: function() {
// The home page requires the "logged in" view, so we'll set that.
this.setStateForNewView({

View file

@ -165,7 +165,7 @@ export default class RightPanel extends React.Component {
} else if (this.state.phase === RightPanel.Phase.GroupRoomList) {
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) {
panel = <MemberInfo roomId={this.props.roomId} member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
} else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) {
panel = <GroupMemberInfo
groupMember={this.state.member}

View file

@ -34,6 +34,9 @@ import { _t } from '../../languageHandler';
import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils';
const MAX_NAME_LENGTH = 80;
const MAX_TOPIC_LENGTH = 160;
linkifyMatrix(linkify);
module.exports = React.createClass({
@ -390,7 +393,6 @@ module.exports = React.createClass({
const self = this;
let guestRead; let guestJoin; let perms;
for (let i = 0; i < rooms.length; i++) {
const name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room');
guestRead = null;
guestJoin = null;
@ -410,7 +412,15 @@ module.exports = React.createClass({
perms = <div className="mx_RoomDirectory_perms">{guestRead}{guestJoin}</div>;
}
let name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room');
if (name.length > MAX_NAME_LENGTH) {
name = `${name.substring(0, MAX_NAME_LENGTH)}...`;
}
let topic = rooms[i].topic || '';
if (topic.length > MAX_TOPIC_LENGTH) {
topic = `${topic.substring(0, MAX_TOPIC_LENGTH)}...`;
}
topic = linkifyString(sanitizeHtml(topic));
rows.push(

View file

@ -36,6 +36,7 @@ const ContentMessages = require("../../ContentMessages");
const Modal = require("../../Modal");
const sdk = require('../../index');
const CallHandler = require('../../CallHandler');
const dis = require("../../dispatcher");
const Tinter = require("../../Tinter");
const rate_limited_func = require('../../ratelimitedfunc');
const ObjectUtils = require('../../ObjectUtils');
@ -45,6 +46,7 @@ import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
import MainSplit from './MainSplit';
import RightPanel from './RightPanel';
import RoomViewStore from '../../stores/RoomViewStore';
import RoomScrollStateStore from '../../stores/RoomScrollStateStore';
import WidgetEchoStore from '../../stores/WidgetEchoStore';
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
@ -92,8 +94,6 @@ module.exports = React.createClass({
// Servers the RoomView can use to try and assist joins
viaServers: PropTypes.arrayOf(PropTypes.string),
// the store for this room view
roomViewStore: PropTypes.object.isRequired,
},
getInitialState: function() {
@ -155,7 +155,7 @@ module.exports = React.createClass({
},
componentWillMount: function() {
this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction);
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on("Room", this.onRoom);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().on("Room.name", this.onRoomName);
@ -166,7 +166,7 @@ module.exports = React.createClass({
MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus);
this._fetchMediaConfig();
// Start listening for RoomViewStore updates
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate);
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate(true);
WidgetEchoStore.on('update', this._onWidgetEchoStoreUpdate);
@ -197,8 +197,8 @@ module.exports = React.createClass({
if (this.unmounted) {
return;
}
const store = this.props.roomViewStore;
if (!initial && this.state.roomId !== store.getRoomId()) {
if (!initial && this.state.roomId !== RoomViewStore.getRoomId()) {
// RoomView explicitly does not support changing what room
// is being viewed: instead it should just be re-mounted when
// switching rooms. Therefore, if the room ID changes, we
@ -212,21 +212,22 @@ module.exports = React.createClass({
// it was, it means we're about to be unmounted.
return;
}
const newState = {
roomId: store.getRoomId(),
roomAlias: store.getRoomAlias(),
roomLoading: store.isRoomLoading(),
roomLoadError: store.getRoomLoadError(),
joining: store.isJoining(),
initialEventId: store.getInitialEventId(),
isInitialEventHighlighted: store.isInitialEventHighlighted(),
forwardingEvent: store.getForwardingEvent(),
shouldPeek: store.shouldPeek(),
showingPinned: SettingsStore.getValue("PinnedEvents.isOpen", store.getRoomId()),
editingRoomSettings: store.isEditingSettings(),
roomId: RoomViewStore.getRoomId(),
roomAlias: RoomViewStore.getRoomAlias(),
roomLoading: RoomViewStore.isRoomLoading(),
roomLoadError: RoomViewStore.getRoomLoadError(),
joining: RoomViewStore.isJoining(),
initialEventId: RoomViewStore.getInitialEventId(),
isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
forwardingEvent: RoomViewStore.getForwardingEvent(),
shouldPeek: RoomViewStore.shouldPeek(),
showingPinned: SettingsStore.getValue("PinnedEvents.isOpen", RoomViewStore.getRoomId()),
editingRoomSettings: RoomViewStore.isEditingSettings(),
};
if (this.state.editingRoomSettings && !newState.editingRoomSettings) this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'});
if (this.state.editingRoomSettings && !newState.editingRoomSettings) dis.dispatch({action: 'focus_composer'});
// Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307
console.log(
@ -388,7 +389,7 @@ module.exports = React.createClass({
// XXX: EVIL HACK to autofocus inviting on empty rooms.
// We use the setTimeout to avoid racing with focus_composer.
if (this.props.isActive !== false && this.state.room &&
if (this.state.room &&
this.state.room.getJoinedMemberCount() == 1 &&
this.state.room.getLiveTimeline() &&
this.state.room.getLiveTimeline().getEvents() &&
@ -442,7 +443,7 @@ module.exports = React.createClass({
roomView.removeEventListener('dragleave', this.onDragLeaveOrEnd);
roomView.removeEventListener('dragend', this.onDragLeaveOrEnd);
}
this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef);
dis.unregister(this.dispatcherRef);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room", this.onRoom);
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
@ -834,7 +835,7 @@ module.exports = React.createClass({
},
onSearchResultsResize: function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'timeline_resize' }, true);
dis.dispatch({ action: 'timeline_resize' }, true);
},
onSearchResultsFillRequest: function(backwards) {
@ -855,7 +856,7 @@ module.exports = React.createClass({
onInviteButtonClick: function() {
// call AddressPickerDialog
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'view_invite',
roomId: this.state.room.roomId,
});
@ -877,7 +878,7 @@ module.exports = React.createClass({
// Join this room once the user has registered and logged in
const signUrl = this.props.thirdPartyInvite ?
this.props.thirdPartyInvite.inviteSignUrl : undefined;
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'do_after_sync_prepared',
deferred_action: {
action: 'join_room',
@ -887,7 +888,7 @@ module.exports = React.createClass({
// Don't peek whilst registering otherwise getPendingEventList complains
// Do this by indicating our intention to join
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'will_join',
});
@ -898,20 +899,20 @@ module.exports = React.createClass({
if (submitted) {
this.props.onRegistered(credentials);
} else {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'cancel_after_sync_prepared',
});
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'cancel_join',
});
}
},
onDifferentServerClicked: (ev) => {
this.props.roomViewStore.getDispatcher().dispatch({action: 'start_registration'});
dis.dispatch({action: 'start_registration'});
close();
},
onLoginClick: (ev) => {
this.props.roomViewStore.getDispatcher().dispatch({action: 'start_login'});
dis.dispatch({action: 'start_login'});
close();
},
}).close;
@ -921,7 +922,7 @@ module.exports = React.createClass({
Promise.resolve().then(() => {
const signUrl = this.props.thirdPartyInvite ?
this.props.thirdPartyInvite.inviteSignUrl : undefined;
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'join_room',
opts: { inviteSignUrl: signUrl, viaServers: this.props.viaServers },
});
@ -986,10 +987,10 @@ module.exports = React.createClass({
},
uploadFile: async function(file) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'});
dis.dispatch({action: 'focus_composer'});
if (MatrixClientPeg.get().isGuest()) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'});
dis.dispatch({action: 'require_registration'});
return;
}
@ -1013,14 +1014,14 @@ module.exports = React.createClass({
}
// Send message_sent callback, for things like _checkIfAlone because after all a file is still a message.
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'message_sent',
});
},
injectSticker: function(url, info, text) {
if (MatrixClientPeg.get().isGuest()) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'});
dis.dispatch({action: 'require_registration'});
return;
}
@ -1135,11 +1136,6 @@ module.exports = React.createClass({
// XXX: todo: merge overlapping results somehow?
// XXX: why doesn't searching on name work?
if (this.state.searchResults.results === undefined) {
// awaiting results
return [];
}
const ret = [];
if (this.state.searchInProgress) {
@ -1196,7 +1192,7 @@ module.exports = React.createClass({
const roomName = room ? room.name : _t("Unknown room %(roomId)s", { roomId: roomId });
ret.push(<li key={mxEv.getId() + "-room"}>
<h1>{ _t("Room") }: { roomName }</h1>
<h2>{ _t("Room") }: { roomName }</h2>
</li>);
lastRoomId = roomId;
}
@ -1221,7 +1217,7 @@ module.exports = React.createClass({
},
onSettingsClick: function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'open_room_settings' });
dis.dispatch({ action: 'open_room_settings' });
},
onSettingsSaveClick: function() {
@ -1254,31 +1250,31 @@ module.exports = React.createClass({
});
// still editing room settings
} else {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' });
dis.dispatch({ action: 'close_settings' });
}
}).finally(() => {
this.setState({
uploadingRoomSettings: false,
});
this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' });
dis.dispatch({ action: 'close_settings' });
}).done();
},
onCancelClick: function() {
console.log("updateTint from onCancelClick");
this.updateTint();
this.props.roomViewStore.getDispatcher().dispatch({ action: 'close_settings' });
dis.dispatch({ action: 'close_settings' });
if (this.state.forwardingEvent) {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'forward_event',
event: null,
});
}
this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'});
dis.dispatch({action: 'focus_composer'});
},
onLeaveClick: function() {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'leave_room',
room_id: this.state.room.roomId,
});
@ -1286,7 +1282,7 @@ module.exports = React.createClass({
onForgetClick: function() {
MatrixClientPeg.get().forget(this.state.room.roomId).done(function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' });
dis.dispatch({ action: 'view_next_room' });
}, function(err) {
const errCode = err.errcode || _t("unknown error code");
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@ -1303,7 +1299,7 @@ module.exports = React.createClass({
rejecting: true,
});
MatrixClientPeg.get().leave(this.state.roomId).done(function() {
this.props.roomViewStore.getDispatcher().dispatch({ action: 'view_next_room' });
dis.dispatch({ action: 'view_next_room' });
self.setState({
rejecting: false,
});
@ -1329,7 +1325,7 @@ module.exports = React.createClass({
// using /leave rather than /join. In the short term though, we
// just ignore them.
// https://github.com/vector-im/vector-web/issues/1134
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'view_room_directory',
});
},
@ -1348,7 +1344,7 @@ module.exports = React.createClass({
// jump down to the bottom of this room, where new events are arriving
jumpToLiveTimeline: function() {
this.refs.messagePanel.jumpToLiveTimeline();
this.props.roomViewStore.getDispatcher().dispatch({action: 'focus_composer'});
dis.dispatch({action: 'focus_composer'});
},
// jump up to wherever our read marker is
@ -1438,7 +1434,7 @@ module.exports = React.createClass({
},
onFullscreenClick: function() {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
}, true);
@ -1563,7 +1559,6 @@ module.exports = React.createClass({
<RoomHeader ref="header"
room={this.state.room}
oobData={this.props.oobData}
isGrid={this.props.isGrid}
collapsedRhs={this.props.collapsedRhs}
/>
<div className="mx_RoomView_body">
@ -1610,7 +1605,6 @@ module.exports = React.createClass({
<div className="mx_RoomView">
<RoomHeader
ref="header"
isGrid={this.props.isGrid}
room={this.state.room}
collapsedRhs={this.props.collapsedRhs}
/>
@ -1752,9 +1746,7 @@ module.exports = React.createClass({
if (canSpeak) {
messageComposer =
<MessageComposer
roomViewStore={this.props.roomViewStore}
room={this.state.room}
isGrid={this.props.isGrid}
onResize={this.onChildResize}
uploadFile={this.uploadFile}
callState={this.state.callState}
@ -1820,16 +1812,21 @@ module.exports = React.createClass({
let hideMessagePanel = false;
if (this.state.searchResults) {
searchResultsPanel = (
<ScrollPanel ref="searchResultsPanel"
className="mx_RoomView_messagePanel mx_RoomView_searchResultsPanel"
onFillRequest={this.onSearchResultsFillRequest}
onResize={this.onSearchResultsResize}
>
<li className={scrollheader_classes}></li>
{ this.getSearchResultTiles() }
</ScrollPanel>
);
// show searching spinner
if (this.state.searchResults.results === undefined) {
searchResultsPanel = (<div className="mx_RoomView_messagePanel mx_RoomView_messagePanelSearchSpinner" />);
} else {
searchResultsPanel = (
<ScrollPanel ref="searchResultsPanel"
className="mx_RoomView_messagePanel mx_RoomView_searchResultsPanel"
onFillRequest={this.onSearchResultsFillRequest}
onResize={this.onSearchResultsResize}
>
<li className={scrollheader_classes}></li>
{ this.getSearchResultTiles() }
</ScrollPanel>
);
}
hideMessagePanel = true;
}
@ -1881,14 +1878,11 @@ module.exports = React.createClass({
},
);
const rightPanel = this.state.room && !this.props.isGrid ?
<RightPanel roomId={this.state.room.roomId} /> :
undefined;
const rightPanel = this.state.room ? <RightPanel roomId={this.state.room.roomId} /> : undefined;
return (
<main className={"mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "")} ref="roomView">
<RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo}
isGrid={this.props.isGrid}
oobData={this.props.oobData}
editing={this.state.editingRoomSettings}
saving={this.state.uploadingRoomSettings}

View file

@ -82,10 +82,10 @@ const SIMPLE_SETTINGS = [
{ id: "VideoView.flipVideoHorizontally" },
{ id: "TagPanel.disableTagPanel" },
{ id: "enableWidgetScreenshots" },
{ id: "RoomSubList.showEmpty" },
{ id: "pinMentionedRooms" },
{ id: "pinUnreadRooms" },
{ id: "showDeveloperTools" },
{ id: "promptBeforeInviteUnknownUsers" },
];
// These settings must be defined in SettingsStore

View file

@ -40,38 +40,50 @@ export default class MemberStatusMessageAvatar extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
hasStatus: this.hasStatus,
};
}
componentWillMount() {
if (this.props.member.userId !== MatrixClientPeg.get().getUserId()) {
throw new Error("Cannot use MemberStatusMessageAvatar on anyone but the logged in user");
}
}
componentDidMount() {
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
if (this.props.member.user) {
this.setState({message: this.props.member.user._unstable_statusMessage});
} else {
this.setState({message: ""});
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return;
}
}
componentWillUnmount() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents);
const { user } = this.props.member;
if (!user) {
return;
}
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
}
_onRoomStateEvents = (ev, state) => {
if (ev.getStateKey() !== MatrixClientPeg.get().getUserId()) return;
if (ev.getType() !== "im.vector.user_status") return;
// TODO: We should be relying on `this.props.member.user._unstable_statusMessage`
// We don't currently because the js-sdk doesn't emit a specific event for this
// change, and we don't want to race it. This should be improved when we rip out
// the im.vector.user_status stuff and replace it with a complete solution.
this.setState({message: ev.getContent()["status"]});
componentWillUmount() {
const { user } = this.props.member;
if (!user) {
return;
}
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
get hasStatus() {
const { user } = this.props.member;
if (!user) {
return false;
}
return !!user._unstable_statusMessage;
}
_onStatusMessageCommitted = () => {
// The `User` object has observed a status message change.
this.setState({
hasStatus: this.hasStatus,
});
};
_onClick = (e) => {
@ -79,42 +91,43 @@ export default class MemberStatusMessageAvatar extends React.Component {
const elementRect = e.target.getBoundingClientRect();
// The window X and Y offsets are to adjust position when zoomed in to page
const x = (elementRect.left + window.pageXOffset) - (elementRect.width / 2) + 3;
const chevronOffset = 12;
let y = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
y = y - (chevronOffset + 4); // where 4 is 1/4 the height of the chevron
const x = (elementRect.left + window.pageXOffset);
const chevronWidth = 16; // See .mx_ContextualMenu_chevron_bottom
const chevronOffset = (elementRect.width - chevronWidth) / 2;
const chevronMargin = 1; // Add some spacing away from target
const y = elementRect.top + window.pageYOffset - chevronMargin;
ContextualMenu.createMenu(StatusMessageContextMenu, {
chevronOffset: chevronOffset,
chevronFace: 'bottom',
left: x,
top: y,
menuWidth: 190,
menuWidth: 226,
user: this.props.member.user,
});
};
render() {
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return <MemberAvatar member={this.props.member}
width={this.props.width}
height={this.props.height}
resizeMethod={this.props.resizeMethod} />;
}
const avatar = <MemberAvatar
member={this.props.member}
width={this.props.width}
height={this.props.height}
resizeMethod={this.props.resizeMethod}
/>;
const hasStatus = this.props.member.user ? !!this.props.member.user._unstable_statusMessage : false;
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return avatar;
}
const classes = classNames({
"mx_MemberStatusMessageAvatar": true,
"mx_MemberStatusMessageAvatar_hasStatus": hasStatus,
"mx_MemberStatusMessageAvatar_hasStatus": this.state.hasStatus,
});
return <AccessibleButton onClick={this._onClick} className={classes} element="div">
<MemberAvatar member={this.props.member}
width={this.props.width}
height={this.props.height}
resizeMethod={this.props.resizeMethod} />
return <AccessibleButton className={classes}
element="div" onClick={this._onClick}
>
{avatar}
</AccessibleButton>;
}
}

View file

@ -18,69 +18,125 @@ import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index';
import AccessibleButton from '../elements/AccessibleButton';
import classNames from 'classnames';
export default class StatusMessageContextMenu extends React.Component {
static propTypes = {
// js-sdk User object. Not required because it might not exist.
user: PropTypes.object,
// True when waiting for status change to complete.
waiting: false,
};
constructor(props, context) {
super(props, context);
this.state = {
message: props.user ? props.user._unstable_statusMessage : "",
message: this.comittedStatusMessage,
};
}
_onClearClick = async (e) => {
await MatrixClientPeg.get()._unstable_setStatusMessage("");
this.setState({message: ""});
componentWillMount() {
const { user } = this.props;
if (!user) {
return;
}
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
}
componentWillUmount() {
const { user } = this.props;
if (!user) {
return;
}
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
get comittedStatusMessage() {
return this.props.user ? this.props.user._unstable_statusMessage : "";
}
_onStatusMessageCommitted = () => {
// The `User` object has observed a status message change.
this.setState({
message: this.comittedStatusMessage,
waiting: false,
});
};
_onClearClick = (e) => {
MatrixClientPeg.get()._unstable_setStatusMessage("");
this.setState({
waiting: true,
});
};
_onSubmit = (e) => {
e.preventDefault();
MatrixClientPeg.get()._unstable_setStatusMessage(this.state.message);
this.setState({
waiting: true,
});
};
_onStatusChange = (e) => {
this.setState({message: e.target.value});
// The input field's value was changed.
this.setState({
message: e.target.value,
});
};
render() {
const formSubmitClasses = classNames({
"mx_StatusMessageContextMenu_submit": true,
"mx_StatusMessageContextMenu_submitFaded": !this.state.message, // no message == faded
});
const Spinner = sdk.getComponent('views.elements.Spinner');
const form = <form className="mx_StatusMessageContextMenu_form" onSubmit={this._onSubmit} autoComplete="off">
<input type="text" key="message" placeholder={_t("Set a new status...")} autoFocus={true}
className="mx_StatusMessageContextMenu_message"
value={this.state.message} onChange={this._onStatusChange} maxLength="60" />
<AccessibleButton onClick={this._onSubmit} element="div" className={formSubmitClasses}>
<img src="img/icons-checkmark.svg" width="22" height="22" />
</AccessibleButton>
let actionButton;
if (this.comittedStatusMessage) {
if (this.state.message === this.comittedStatusMessage) {
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_clear"
onClick={this._onClearClick}
>
<span>{_t("Clear status")}</span>
</AccessibleButton>;
} else {
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
onClick={this._onSubmit}
>
<span>{_t("Update status")}</span>
</AccessibleButton>;
}
} else {
actionButton = <AccessibleButton className="mx_StatusMessageContextMenu_submit"
disabled={!this.state.message} onClick={this._onSubmit}
>
<span>{_t("Set status")}</span>
</AccessibleButton>;
}
let spinner = null;
if (this.state.waiting) {
spinner = <Spinner w="24" h="24" />;
}
const form = <form className="mx_StatusMessageContextMenu_form"
autoComplete="off" onSubmit={this._onSubmit}
>
<input type="text" className="mx_StatusMessageContextMenu_message"
key="message" placeholder={_t("Set a new status...")}
autoFocus={true} maxLength="60" value={this.state.message}
onChange={this._onStatusChange}
/>
<div className="mx_StatusMessageContextMenu_actionContainer">
{actionButton}
{spinner}
</div>
</form>;
const clearIcon = this.state.message ? "img/cancel-red.svg" : "img/cancel.svg";
const clearButton = <AccessibleButton onClick={this._onClearClick} disabled={!this.state.message}
className="mx_StatusMessageContextMenu_clear">
<img src={clearIcon} alt={_t('Clear status')} width="12" height="12"
className="mx_filterFlipColor mx_StatusMessageContextMenu_clearIcon" />
<span>{_t("Clear status")}</span>
</AccessibleButton>;
const menuClasses = classNames({
"mx_StatusMessageContextMenu": true,
"mx_StatusMessageContextMenu_hasStatus": this.state.message,
});
return <div className={menuClasses}>
return <div className="mx_StatusMessageContextMenu">
{ form }
<hr />
{ clearButton }
</div>;
}
}

View file

@ -21,7 +21,6 @@ import dis from '../../../dispatcher';
import TagOrderActions from '../../../actions/TagOrderActions';
import MatrixClientPeg from '../../../MatrixClientPeg';
import sdk from '../../../index';
import SettingsStore from "../../../settings/SettingsStore";
export default class TagTileContextMenu extends React.Component {
static propTypes = {
@ -35,7 +34,6 @@ export default class TagTileContextMenu extends React.Component {
this._onViewCommunityClick = this._onViewCommunityClick.bind(this);
this._onRemoveClick = this._onRemoveClick.bind(this);
this._onViewAsGridClick = this._onViewAsGridClick.bind(this);
}
_onViewCommunityClick() {
@ -55,28 +53,8 @@ export default class TagTileContextMenu extends React.Component {
this.props.onFinished();
}
_onViewAsGridClick() {
dis.dispatch({
action: 'group_grid_view',
group_id: this.props.tag,
});
this.props.onFinished();
}
render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
let gridViewOption;
if (SettingsStore.isFeatureEnabled("feature_gridview")) {
gridViewOption = (<div className="mx_TagTileContextMenu_item" onClick={this._onViewAsGridClick} >
<TintableSvg
className="mx_TagTileContextMenu_item_icon"
src="img/feather-icons/grid.svg"
width="15"
height="15"
/>
{ _t('View as Grid') }
</div>);
}
return <div>
<div className="mx_TagTileContextMenu_item" onClick={this._onViewCommunityClick} >
<TintableSvg
@ -87,7 +65,6 @@ export default class TagTileContextMenu extends React.Component {
/>
{ _t('View Community') }
</div>
{ gridViewOption }
<hr className="mx_TagTileContextMenu_separator" />
<div className="mx_TagTileContextMenu_item" onClick={this._onRemoveClick} >
<img className="mx_TagTileContextMenu_item_icon" src="img/icon_context_delete.svg" width="15" height="15" />

View file

@ -0,0 +1,81 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {SettingLevel} from "../../../settings/SettingsStore";
import SettingsStore from "../../../settings/SettingsStore";
export default React.createClass({
propTypes: {
unknownProfileUsers: PropTypes.array.isRequired, // [ {userId, errorText}... ]
onInviteAnyways: PropTypes.func.isRequired,
onGiveUp: PropTypes.func.isRequired,
onFinished: PropTypes.func.isRequired,
},
_onInviteClicked: function() {
this.props.onInviteAnyways();
this.props.onFinished(true);
},
_onInviteNeverWarnClicked: function() {
SettingsStore.setValue("promptBeforeInviteUnknownUsers", null, SettingLevel.ACCOUNT, false);
this.props.onInviteAnyways();
this.props.onFinished(true);
},
_onGiveUpClicked: function() {
this.props.onGiveUp();
this.props.onFinished(false);
},
render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const errorList = this.props.unknownProfileUsers
.map(address => <li key={address.userId}>{address.userId}: {address.errorText}</li>);
return (
<BaseDialog className='mx_RetryInvitesDialog'
onFinished={this._onGiveUpClicked}
title={_t('The following users may not exist')}
contentId='mx_Dialog_content'
>
<div id='mx_Dialog_content'>
<p>{_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?")}</p>
<ul>
{ errorList }
</ul>
</div>
<div className="mx_Dialog_buttons">
<button onClick={this._onGiveUpClicked}>
{ _t('Close') }
</button>
<button onClick={this._onInviteNeverWarnClicked}>
{ _t('Invite anyway and never warn me again') }
</button>
<button onClick={this._onInviteClicked} autoFocus="true">
{ _t('Invite anyway') }
</button>
</div>
</BaseDialog>
);
},
});

View file

@ -36,7 +36,7 @@ export default class ChangelogDialog extends React.Component {
for (let i=0; i<REPOS.length; i++) {
const oldVersion = version2[2*i];
const newVersion = version[2*i];
const url = `https://api.github.com/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`;
const url = `https://riot.im/github/repos/${REPOS[i]}/compare/${oldVersion}...${newVersion}`;
request(url, (err, response, body) => {
if (response.statusCode < 200 || response.statusCode >= 300) {
this.setState({ [REPOS[i]]: response.statusText });

View file

@ -78,6 +78,7 @@ export default class HeaderButtons extends React.Component {
// till show_right_panel, just without the fromHeader flag
// as that would hide the right panel again
dis.dispatch(Object.assign({}, payload, {fromHeader: false}));
}
this.setState({
phase: payload.phase,

View file

@ -39,6 +39,7 @@ import Unread from '../../../Unread';
import { findReadReceiptFromUserId } from '../../../utils/Receipt';
import withMatrixClient from '../../../wrappers/withMatrixClient';
import AccessibleButton from '../elements/AccessibleButton';
import RoomViewStore from '../../../stores/RoomViewStore';
import SdkConfig from '../../../SdkConfig';
import MultiInviter from "../../../utils/MultiInviter";
import SettingsStore from "../../../settings/SettingsStore";
@ -49,7 +50,6 @@ module.exports = withMatrixClient(React.createClass({
propTypes: {
matrixClient: PropTypes.object.isRequired,
member: PropTypes.object.isRequired,
roomId: PropTypes.string,
},
getInitialState: function() {
@ -713,7 +713,7 @@ module.exports = withMatrixClient(React.createClass({
}
if (!member || !member.membership || member.membership === 'leave') {
const roomId = member && member.roomId ? member.roomId : this.props.roomId;
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
const onInviteUserButton = async () => {
try {
// We use a MultiInviter to re-use the invite logic, even though

View file

@ -21,10 +21,8 @@ import SettingsStore from "../../../settings/SettingsStore";
const React = require('react');
import PropTypes from 'prop-types';
const MatrixClientPeg = require('../../../MatrixClientPeg');
const sdk = require('../../../index');
const dis = require('../../../dispatcher');
const Modal = require("../../../Modal");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
@ -42,7 +40,46 @@ module.exports = React.createClass({
},
getInitialState: function() {
return {};
return {
statusMessage: this.getStatusMessage(),
};
},
componentDidMount() {
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return;
}
const { user } = this.props.member;
if (!user) {
return;
}
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
},
componentWillUmount() {
const { user } = this.props.member;
if (!user) {
return;
}
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
},
getStatusMessage() {
const { user } = this.props.member;
if (!user) {
return "";
}
return user._unstable_statusMessage;
},
_onStatusMessageCommitted() {
// The `User` object has observed a status message change.
this.setState({
statusMessage: this.getStatusMessage(),
});
},
shouldComponentUpdate: function(nextProps, nextState) {
@ -74,22 +111,23 @@ module.exports = React.createClass({
},
getPowerLabel: function() {
return _t("%(userName)s (power %(powerLevelNumber)s)", {userName: this.props.member.userId, powerLevelNumber: this.props.member.powerLevel});
return _t("%(userName)s (power %(powerLevelNumber)s)", {
userName: this.props.member.userId,
powerLevelNumber: this.props.member.powerLevel,
});
},
render: function() {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const EntityTile = sdk.getComponent('rooms.EntityTile');
const member = this.props.member;
const name = this._getDisplayName();
const active = -1;
const presenceState = member.user ? member.user.presence : null;
let statusMessage = null;
if (member.user && SettingsStore.isFeatureEnabled("feature_custom_status")) {
statusMessage = member.user._unstable_statusMessage;
statusMessage = this.state.statusMessage;
}
const av = (

View file

@ -22,6 +22,7 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import Stickerpicker from './Stickerpicker';
import { makeRoomPermalink } from '../../../matrix-to';
@ -62,7 +63,7 @@ export default class MessageComposer extends React.Component {
isRichTextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'),
},
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
isQuoting: Boolean(this.props.roomViewStore.getQuotingEvent()),
isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
tombstone: this._getRoomTombstone(),
};
}
@ -74,7 +75,7 @@ export default class MessageComposer extends React.Component {
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
MatrixClientPeg.get().on("event", this.onEvent);
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate);
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._waitForOwnMember();
}
@ -123,14 +124,14 @@ export default class MessageComposer extends React.Component {
}
_onRoomViewStoreUpdate() {
const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent());
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
if (this.state.isQuoting === isQuoting) return;
this.setState({ isQuoting });
}
onUploadClick(ev) {
if (MatrixClientPeg.get().isGuest()) {
this.props.roomViewStore.getDispatcher().dispatch({action: 'require_registration'});
dis.dispatch({action: 'require_registration'});
return;
}
@ -164,7 +165,7 @@ export default class MessageComposer extends React.Component {
}
}
const isQuoting = Boolean(this.props.roomViewStore.getQuotingEvent());
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
let replyToWarning = null;
if (isQuoting) {
replyToWarning = <p>{
@ -228,7 +229,7 @@ export default class MessageComposer extends React.Component {
if (!call) {
return;
}
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'hangup',
// hangup the call for this room, which may not be the room in props
// (e.g. conferences which will hangup the 1:1 room instead)
@ -237,7 +238,7 @@ export default class MessageComposer extends React.Component {
}
onCallClick(ev) {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'place_call',
type: ev.shiftKey ? "screensharing" : "video",
room_id: this.props.room.roomId,
@ -245,7 +246,7 @@ export default class MessageComposer extends React.Component {
}
onVoiceCallClick(ev) {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'place_call',
type: "voice",
room_id: this.props.room.roomId,
@ -287,8 +288,7 @@ export default class MessageComposer extends React.Component {
const createEvent = replacementRoom.currentState.getStateEvents('m.room.create', '');
if (createEvent && createEvent.getId()) createEventId = createEvent.getId();
}
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'view_room',
highlighted: true,
event_id: createEventId,
@ -432,10 +432,8 @@ export default class MessageComposer extends React.Component {
controls.push(
<MessageComposerInput
roomViewStore={this.props.roomViewStore}
ref={(c) => this.messageComposerInput = c}
key="controls_input"
isGrid={this.props.isGrid}
onResize={this.props.onResize}
room={this.props.room}
placeholder={placeholderText}
@ -542,6 +540,5 @@ MessageComposer.propTypes = {
uploadAllowed: PropTypes.func.isRequired,
// string representing the current room app drawer state
showApps: PropTypes.bool,
roomViewStore: PropTypes.object.isRequired,
showApps: PropTypes.bool
};

View file

@ -38,6 +38,8 @@ import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import Analytics from '../../../Analytics';
import dis from '../../../dispatcher';
import * as RichText from '../../../RichText';
import * as HtmlUtils from '../../../HtmlUtils';
import Autocomplete from './Autocomplete';
@ -55,6 +57,7 @@ import {
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import {makeUserPermalink} from "../../../matrix-to";
import ReplyPreview from "./ReplyPreview";
import RoomViewStore from '../../../stores/RoomViewStore';
import ReplyThread from "../elements/ReplyThread";
import {ContentHelpers} from 'matrix-js-sdk';
@ -108,6 +111,15 @@ const SLATE_SCHEMA = {
},
};
function onSendMessageFailed(err, room) {
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/riot-web/issues/3148
console.log('MessageComposer got send failure: ' + err.name + '('+err+')');
dis.dispatch({
action: 'message_send_failed',
});
}
function rangeEquals(a: Range, b: Range): boolean {
return (a.anchor.key === b.anchor.key
&& a.anchor.offset === b.anchorOffset
@ -117,18 +129,6 @@ function rangeEquals(a: Range, b: Range): boolean {
&& a.isBackward === b.isBackward);
}
class NoopHistoryManager {
getItem() {}
save() {}
get currentIndex() { return 0; }
set currentIndex(_) {}
get history() { return []; }
set history(_) {}
}
/*
* The textInput part of the MessageComposer
*/
@ -144,7 +144,6 @@ export default class MessageComposerInput extends React.Component {
onFilesPasted: PropTypes.func,
onInputStateChanged: PropTypes.func,
roomViewStore: PropTypes.object.isRequired,
};
client: MatrixClient;
@ -339,31 +338,18 @@ export default class MessageComposerInput extends React.Component {
}
componentWillMount() {
this.dispatcherRef = this.props.roomViewStore.getDispatcher().register(this.onAction);
if (this.props.isGrid) {
this.historyManager = new NoopHistoryManager();
} else {
this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
}
this.dispatcherRef = dis.register(this.onAction);
this.historyManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
}
componentWillUnmount() {
this.props.roomViewStore.getDispatcher().unregister(this.dispatcherRef);
dis.unregister(this.dispatcherRef);
}
_collectEditor = (e) => {
this._editor = e;
}
onSendMessageFailed = (err, room) => {
// XXX: temporary logging to try to diagnose
// https://github.com/vector-im/riot-web/issues/3148
console.log('MessageComposer got send failure: ' + err.name + '('+err+')');
this.props.roomViewStore.getDispatcher().dispatch({
action: 'message_send_failed',
});
}
onAction = (payload) => {
const editorState = this.state.editorState;
@ -1129,7 +1115,7 @@ export default class MessageComposerInput extends React.Component {
return true;
}
const replyingToEv = this.props.roomViewStore.getQuotingEvent();
const replyingToEv = RoomViewStore.getQuotingEvent();
const mustSendHTML = Boolean(replyingToEv);
if (this.state.isRichTextEnabled) {
@ -1217,18 +1203,18 @@ export default class MessageComposerInput extends React.Component {
// Clear reply_to_event as we put the message into the queue
// if the send fails, retry will handle resending.
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'reply_to_event',
event: null,
});
}
this.client.sendMessage(this.props.room.roomId, content).then((res) => {
this.props.roomViewStore.getDispatcher().dispatch({
dis.dispatch({
action: 'message_sent',
});
}).catch((e) => {
this.onSendMessageFailed(e, this.props.room);
onSendMessageFailed(e, this.props.room);
});
this.setState({
@ -1599,7 +1585,7 @@ export default class MessageComposerInput extends React.Component {
return (
<div className="mx_MessageComposer_input_wrapper" onClick={this.focusComposer}>
<div className="mx_MessageComposer_autocomplete_wrapper">
<ReplyPreview roomViewStore={this.props.roomViewStore} />
<ReplyPreview />
<Autocomplete
ref={(e) => this.autocomplete = e}
room={this.props.room}

View file

@ -18,6 +18,7 @@ import React from 'react';
import dis from '../../../dispatcher';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore from "../../../settings/SettingsStore";
function cancelQuoting() {
@ -37,7 +38,7 @@ export default class ReplyPreview extends React.Component {
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
this._roomStoreToken = this.props.roomViewStore.addListener(this._onRoomViewStoreUpdate);
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
this._onRoomViewStoreUpdate();
}
@ -49,7 +50,7 @@ export default class ReplyPreview extends React.Component {
}
_onRoomViewStoreUpdate() {
const event = this.props.roomViewStore.getQuotingEvent();
const event = RoomViewStore.getQuotingEvent();
if (this.state.event !== event) {
this.setState({ event });
}

View file

@ -24,7 +24,6 @@ import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from "../../../Modal";
import RateLimitedFunc from '../../../ratelimitedfunc';
import dis from '../../../dispatcher';
import * as linkify from 'linkifyjs';
import linkifyElement from 'linkifyjs/element';
@ -153,14 +152,6 @@ module.exports = React.createClass({
});
},
onToggleRightPanelClick: function(ev) {
if (this.props.collapsedRhs) {
dis.dispatch({action: "show_right_panel"});
} else {
dis.dispatch({action: "hide_right_panel"});
}
},
_hasUnreadPins: function() {
const currentPinEvent = this.props.room.currentState.getStateEvents("m.room.pinned_events", '');
if (!currentPinEvent) return false;
@ -418,17 +409,6 @@ module.exports = React.createClass({
</div>;
}
let toggleRightPanelButton;
if (this.props.isGrid) {
toggleRightPanelButton =
<AccessibleButton
className="mx_RoomHeader_button"
onClick={this.onToggleRightPanelClick}
title={_t('Toggle right panel')}>
<TintableSvg src="img/feather-icons/toggle-right-panel.svg" width="20" height="20" />
</AccessibleButton>;
}
return (
<div className={"mx_RoomHeader light-panel " + (this.props.editing ? "mx_RoomHeader_editing" : "")}>
<div className="mx_RoomHeader_wrapper">
@ -439,8 +419,7 @@ module.exports = React.createClass({
{ saveButton }
{ cancelButton }
{ rightRow }
{ !this.props.isGrid ? <RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} /> : undefined }
{ toggleRightPanelButton }
<RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} />
</div>
</div>
);

View file

@ -36,7 +36,7 @@ import GroupStore from '../../../stores/GroupStore';
import RoomSubList from '../../structures/RoomSubList';
import ResizeHandle from '../elements/ResizeHandle';
import {Resizer, RoomDistributor, RoomSizer} from '../../../resizer'
import {Resizer, RoomSubListDistributor} from '../../../resizer'
const HIDE_CONFERENCE_CHANS = true;
const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/;
@ -153,7 +153,11 @@ module.exports = React.createClass({
if (typeof newSize === "string") {
newSize = Number.MAX_SAFE_INTEGER;
}
this.subListSizes[id] = newSize;
if (newSize === null) {
delete this.subListSizes[id];
} else {
this.subListSizes[id] = newSize;
}
window.localStorage.setItem("mx_roomlist_sizes", JSON.stringify(this.subListSizes));
// update overflow indicators
this._checkSubListsOverflow();
@ -164,7 +168,7 @@ module.exports = React.createClass({
const cfg = {
onResized: this._onSubListResize,
};
this.resizer = new Resizer(this.resizeContainer, RoomDistributor, cfg, RoomSizer);
this.resizer = new Resizer(this.resizeContainer, RoomSubListDistributor, cfg);
this.resizer.setClassNames({
handle: "mx_ResizeHandle",
vertical: "mx_ResizeHandle_vertical",
@ -724,4 +728,4 @@ module.exports = React.createClass({
</div>
);
},
});
});

View file

@ -29,6 +29,7 @@ import * as RoomNotifs from '../../../RoomNotifs';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import AccessibleButton from '../elements/AccessibleButton';
import ActiveRoomObserver from '../../../ActiveRoomObserver';
import RoomViewStore from '../../../stores/RoomViewStore';
import SettingsStore from "../../../settings/SettingsStore";
module.exports = React.createClass({
@ -61,7 +62,8 @@ module.exports = React.createClass({
roomName: this.props.room.name,
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
notificationCount: this.props.room.getUnreadNotificationCount(),
selected: this.props.room.roomId === ActiveRoomObserver.getActiveRoomId(),
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
statusMessage: this._getStatusMessage(),
});
},
@ -79,6 +81,33 @@ module.exports = React.createClass({
return Boolean(dmRooms);
},
_shouldShowStatusMessage() {
if (!SettingsStore.isFeatureEnabled("feature_custom_status")) {
return false;
}
const isInvite = this.props.room.getMyMembership() === "invite";
const isJoined = this.props.room.getMyMembership() === "join";
const looksLikeDm = this.props.room.getInvitedAndJoinedMemberCount() === 2;
return !isInvite && isJoined && looksLikeDm;
},
_getStatusMessageUser() {
const selfId = MatrixClientPeg.get().getUserId();
const otherMember = this.props.room.currentState.getMembersExcept([selfId])[0];
if (!otherMember) {
return null;
}
return otherMember.user;
},
_getStatusMessage() {
const statusUser = this._getStatusMessageUser();
if (!statusUser) {
return "";
}
return statusUser._unstable_statusMessage;
},
onRoomTimeline: function(ev, room) {
if (room !== this.props.room) return;
this.setState({
@ -112,13 +141,19 @@ module.exports = React.createClass({
this.setState({
notificationCount: this.props.room.getUnreadNotificationCount(),
});
break;
break;
// RoomTiles are one of the few components that may show custom status and
// also remain on screen while in Settings toggling the feature. This ensures
// you can clearly see the status hide and show when toggling the feature.
case 'feature_custom_status_changed':
this.forceUpdate();
break;
}
},
_onActiveRoomChange: function(activeRoomId) {
_onActiveRoomChange: function() {
this.setState({
selected: this.props.room.roomId === activeRoomId,
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
});
},
@ -128,6 +163,16 @@ module.exports = React.createClass({
MatrixClientPeg.get().on("Room.name", this.onRoomName);
ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange);
this.dispatcherRef = dis.register(this.onAction);
if (this._shouldShowStatusMessage()) {
const statusUser = this._getStatusMessageUser();
if (statusUser) {
statusUser.on(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
}
},
componentWillUnmount: function() {
@ -139,6 +184,16 @@ module.exports = React.createClass({
}
ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange);
dis.unregister(this.dispatcherRef);
if (this._shouldShowStatusMessage()) {
const statusUser = this._getStatusMessageUser();
if (statusUser) {
statusUser.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
);
}
}
},
componentWillReceiveProps: function(props) {
@ -166,6 +221,13 @@ module.exports = React.createClass({
return false;
},
_onStatusMessageCommitted() {
// The status message `User` object has observed a message change.
this.setState({
statusMessage: this._getStatusMessage(),
});
},
onClick: function(ev) {
if (this.props.onClick) {
this.props.onClick(this.props.room.roomId, ev);
@ -251,15 +313,9 @@ module.exports = React.createClass({
const mentionBadges = this.props.highlight && this._shouldShowMentionBadge();
const badges = notifBadges || mentionBadges;
const isJoined = this.props.room.getMyMembership() === "join";
const looksLikeDm = this.props.room.getInvitedAndJoinedMemberCount() === 2;
let subtext = null;
if (!isInvite && isJoined && looksLikeDm && SettingsStore.isFeatureEnabled("feature_custom_status")) {
const selfId = MatrixClientPeg.get().getUserId();
const otherMember = this.props.room.currentState.getMembersExcept([selfId])[0];
if (otherMember && otherMember.user && otherMember.user._unstable_statusMessage) {
subtext = otherMember.user._unstable_statusMessage;
}
if (this._shouldShowStatusMessage()) {
subtext = this.state.statusMessage;
}
const classes = classNames({

View file

@ -33,11 +33,11 @@ module.exports = React.createClass({
},
onThisRoomClick: function() {
this.setState({ scope: 'Room' });
this.setState({ scope: 'Room' }, () => this._searchIfQuery());
},
onAllRoomsClick: function() {
this.setState({ scope: 'All' });
this.setState({ scope: 'All' }, () => this._searchIfQuery());
},
onSearchChange: function(e) {
@ -49,6 +49,12 @@ module.exports = React.createClass({
}
},
_searchIfQuery: function() {
if (this.refs.search_term.value) {
this.onSearch();
}
},
onSearch: function() {
this.props.onSearch(this.refs.search_term.value, this.state.scope);
},
@ -60,11 +66,13 @@ module.exports = React.createClass({
return (
<div className="mx_SearchBar">
<input ref="search_term" className="mx_SearchBar_input" type="text" autoFocus={true} placeholder={_t("Search…")} onKeyDown={this.onSearchChange} />
<AccessibleButton className={ searchButtonClasses } onClick={this.onSearch}><img src="img/search-button.svg" width="37" height="37" alt={_t("Search")} /></AccessibleButton>
<AccessibleButton className={ thisRoomClasses } onClick={this.onThisRoomClick}>{_t("This Room")}</AccessibleButton>
<AccessibleButton className={ allRoomsClasses } onClick={this.onAllRoomsClick}>{_t("All Rooms")}</AccessibleButton>
<AccessibleButton className="mx_SearchBar_cancel" onClick={this.props.onCancelClick}><img src="img/cancel.svg" width="18" height="18" /></AccessibleButton>
<div className="mx_SearchBar_input mx_textinput">
<input ref="search_term" type="text" autoFocus={true} placeholder={_t("Search…")} onKeyDown={this.onSearchChange} />
<AccessibleButton className={ searchButtonClasses } onClick={this.onSearch}></AccessibleButton>
</div>
<AccessibleButton className="mx_SearchBar_cancel" onClick={this.props.onCancelClick}></AccessibleButton>
</div>
);
},

View file

@ -186,18 +186,23 @@ export default class KeyBackupPanel extends React.PureComponent {
}
let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
const deviceName = sig.device.getDisplayName() || sig.device.deviceId;
const deviceName = sig.device ? (sig.device.getDisplayName() || sig.device.deviceId) : null;
const validity = sub =>
<span className={sig.valid ? 'mx_KeyBackupPanel_sigValid' : 'mx_KeyBackupPanel_sigInvalid'}>
{sub}
</span>;
const verify = sub =>
<span className={sig.device.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
<span className={sig.device && sig.device.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
{sub}
</span>;
const device = sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>;
let sigStatus;
if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
if (!sig.device) {
sigStatus = _t(
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
{ deviceId: sig.deviceId }, { verify },
);
} else if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from this device",
{}, { validity },
@ -229,7 +234,7 @@ export default class KeyBackupPanel extends React.PureComponent {
}
let verifyButton;
if (!sig.device.isVerified()) {
if (!sig.device || !sig.device.isVerified()) {
verifyButton = <div><br /><AccessibleButton className="mx_UserSettings_button"
onClick={this._verifyDevice} data-sigindex={i}>
{ _t("Verify...") }

View file

@ -17,10 +17,42 @@ limitations under the License.
'use strict';
import MatrixDispatcher from "./matrix-dispatcher";
const flux = require("flux");
class MatrixDispatcher extends flux.Dispatcher {
/**
* @param {Object|function} payload Required. The payload to dispatch.
* If an Object, must contain at least an 'action' key.
* If a function, must have the signature (dispatch) => {...}.
* @param {boolean=} sync Optional. Pass true to dispatch
* synchronously. This is useful for anything triggering
* an operation that the browser requires user interaction
* for.
*/
dispatch(payload, sync) {
// Allow for asynchronous dispatching by accepting payloads that have the
// type `function (dispatch) {...}`
if (typeof payload === 'function') {
payload((action) => {
this.dispatch(action, sync);
});
return;
}
if (sync) {
super.dispatch(payload);
} else {
// Unless the caller explicitly asked for us to dispatch synchronously,
// we always set a timeout to do this: The flux dispatcher complains
// if you dispatch from within a dispatch, so rather than action
// handlers having to worry about not calling anything that might
// then dispatch, we just do dispatches asynchronously.
setTimeout(super.dispatch.bind(this, payload), 0);
}
}
}
if (global.mxDispatcher === undefined) {
global.mxDispatcher = new MatrixDispatcher();
}
module.exports = global.mxDispatcher;

View file

@ -1299,5 +1299,150 @@
"Open Devtools": "Отвори инструментите за разработчици",
"Show developer tools": "Покажи инструментите за разработчици",
"If you would like to create a Matrix account you can <a>register</a> now.": "Ако искате да създадете Matrix акаунт, може да се <a>регистрирате</a> тук.",
"You are currently using Riot anonymously as a guest.": "В момента използвате Riot анонимно, като гост."
"You are currently using Riot anonymously as a guest.": "В момента използвате Riot анонимно, като гост.",
"Unable to load! Check your network connectivity and try again.": "Неуспешно зареждане! Проверете мрежовите настройки и опитайте пак.",
"Failed to invite users to the room:": "Неуспешно поканване на потребители в стаята:",
"There was an error joining the room": "Възникна грешка при влизане в стаята",
"Use a few words, avoid common phrases": "Използвайте няколко думи, избягвайте общи фрази",
"You do not have permission to invite people to this room.": "Нямате привилегии да каните хора в тази стая.",
"User %(user_id)s does not exist": "Потребител %(user_id)s не съществува",
"Unknown server error": "Непозната сървърна грешка",
"No need for symbols, digits, or uppercase letters": "Няма нужда от символи, цифри и главни букви",
"Avoid repeated words and characters": "Избягвайте повтарящи се думи и символи",
"Avoid sequences": "Избягвайте последователности",
"Avoid recent years": "Избягвайте скорошни години",
"Avoid years that are associated with you": "Избягвайте години свързани с вас",
"Avoid dates and years that are associated with you": "Избягвайте дати и години свързани с вас",
"Capitalization doesn't help very much": "Главни букви не помагат много",
"All-uppercase is almost as easy to guess as all-lowercase": "Само главни букви е почти толкова лесно за познаване колкото само малки",
"Reversed words aren't much harder to guess": "Разбъркани думи не са много по-трудни за познаване",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Предвидими замествания (като '@' вместо 'a') не помагат много",
"Add another word or two. Uncommon words are better.": "Добавете една или няколко други думи. Рядко срещаните думи са по-добри.",
"Repeats like \"aaa\" are easy to guess": "Повторения като \"aaa\" са лесни за познаване",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Повторения като \"abcabcabc\" са само малко по-трудни за познаване от \"abc\"",
"Sequences like abc or 6543 are easy to guess": "Последователности като abc и 6543 са лесни за познаване",
"Recent years are easy to guess": "Близките години са лесни за познаване",
"Dates are often easy to guess": "Датите често са лесни за познаване",
"This is a top-10 common password": "Тази парола е в топ 10 на често срещаните пароли",
"This is a top-100 common password": "Тази парола е в топ 100 на често срещаните пароли",
"This is a very common password": "Тази парола е много често срещана",
"This is similar to a commonly used password": "Тази парола е подобна на често срещана такава",
"A word by itself is easy to guess": "Единични думи се отгатват лесно",
"Names and surnames by themselves are easy to guess": "Имена и фамилии сами по себе си са лесни за отгатване",
"Common names and surnames are easy to guess": "Често срещани имена и фамилии са лесни за отгатване",
"Use a longer keyboard pattern with more turns": "Използвайте по-дълга клавиатурна последователност с повече разклонения",
"Backup of encryption keys to server": "Резервно копие на ключовете за шифроване на сървъра",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Покажи напомняне за включване на Защитено Възстановяване на Съобщения в шифровани стаи",
"Messages containing @room": "Съобщения съдържащи @room",
"Encrypted messages in one-to-one chats": "Шифровани съобщения в 1-на-1 чатове",
"Encrypted messages in group chats": "Шифровани съобщения в групови чатове",
"Delete Backup": "Изтрий резервното копие",
"Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Изтриване на резервното копие на ключовете за шифроване от сървъра? Вече няма да може да използвате възстановителния ключ за да разчитате шифрованите съобщения",
"Delete backup": "Изтрий резервното копие",
"Unable to load key backup status": "Неуспешно зареждане на състоянието на резервното копие на ключа",
"This device is uploading keys to this backup": "Това устройство качва ключовете си в това резервно копие",
"This device is <b>not</b> uploading keys to this backup": "Това устройство <b>не</b> качва ключовете си в това резервно копие",
"Backup has a <validity>valid</validity> signature from this device": "Резервното копие има <validity>валиден</validity> подпис за това устройство",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device>x</device>": "Резервното копие има <validity>валиден</validity> подпис от <verify>потвърдено</verify> устройство <device>x</device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Резервното копие има <validity>валиден</validity> подпис от <verify>непотвърдено</verify> устройство <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Резервното копие има <validity>невалиден</validity> подпис от <verify>потвърдено</verify> устройство <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Резервното копие има <validity>невалиден</validity> подпис от <verify>непотвърдено</verify> устройство <device></device>",
"Backup is not signed by any of your devices": "Резервното копие не е подписано от нито едно Ваше устройство",
"Backup version: ": "Версия на резервното копие: ",
"Algorithm: ": "Алгоритъм: ",
"Restore backup": "Възстанови резервно копие",
"No backup is present": "Няма налично резервно копие",
"Start a new backup": "Направи ново резервно копие",
"The following files cannot be uploaded:": "Следните файлове не могат да бъдат качени:",
"Secure Message Recovery": "Защитено Възстановяване на Съобщения",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Ако излезете от профила си или използвате друго устройство, ще загубите защитената история на съобщенията. За да предотвратите това, настройте Защитено Възстановяване на Съобщения.",
"Don't ask again": "Не питай пак",
"Set up": "Настрой",
"Please review and accept all of the homeserver's policies": "Моля прегледайте и приемете всички политики на сървъра",
"Failed to load group members": "Неуспешно зареждане на членовете на групата",
"That doesn't look like a valid email address": "Това не изглежда като валиден имейл адрес",
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "За да избегнете загубата на чат история, трябва да експортирате ключовете на стаята преди да излезете от профила си. Ще трябва да се върнете към по-новата версия на Riot за да направите това",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Преди време сте използвали по-нова версия на Riot на %(host)s. За да използвате тази версия отново с шифроване от край до край, ще е необходимо да излезете от профила си и да влезете отново. ",
"Incompatible Database": "Несъвместима база данни",
"Continue With Encryption Disabled": "Продължи с изключено шифроване",
"Only use lower case letters, numbers and '=_-./'": "Използвайте само малки букви, цифри и '=_-./'",
"Checking...": "Проверяване...",
"Unable to load backup status": "Неуспешно зареждане на състоянието на резервното копие",
"Unable to restore backup": "Неуспешно възстановяване на резервно копие",
"No backup found!": "Не е открито резервно копие!",
"Backup Restored": "Резервното копие е възстановено",
"Failed to decrypt %(failedCount)s sessions!": "Неуспешно разшифроване на %(failedCount)s сесии!",
"Restored %(sessionCount)s session keys": "Възстановени бяха %(sessionCount)s сесийни ключа",
"Enter Recovery Passphrase": "Въведете парола за възстановяване",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Получете достъп до защитената история на съобщенията и настройте защитен чат, чрез въвеждане на паролата за възстановяване.",
"Next": "Напред",
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "Ако сте забравили паролата за възстановяване, можете да <button1>използвате ключа за възстановяване</button1> или да <button2>настройте други варианти за възстановяване</button2>",
"Enter Recovery Key": "Въведете ключ за възстановяване",
"This looks like a valid recovery key!": "Това изглежда като валиден ключ за възстановяване!",
"Not a valid recovery key": "Не е валиден ключ за възстановяване",
"Access your secure message history and set up secure messaging by entering your recovery key.": "Получете достъп до защитената история на съобщенията и настройте защитен чат, чрез въвеждане на ключа за възстановяване.",
"If you've forgotten your recovery passphrase you can <button>set up new recovery options</button>": "Ако сте забравили паролата за възстановяване, може да <button>настройте нов вариант за възстановяване</button>",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Невалидна конфигурация: не може да бъдат намерени име и URL адрес по подразбиране на сървъра",
"Unknown error discovering homeserver": "Непозната грешка при откриването на конфигурацията за сървъра",
"%(count)s Notifications|other": "%(count)s известия",
"%(count)s Notifications|one": "%(count)s известие",
"File is too big. Maximum file size is %(fileSize)s": "Файлът е прекалено голям. Максималният размер е %(fileSize)s",
"Key Backup": "Резервно копие на ключа",
"Invalid homeserver discovery response": "Невалиден отговор по време на откриването на конфигурацията за сървъра",
"Invalid identity server discovery response": "Невалиден отговор по време на откриването на конфигурацията за сървъра за самоличност",
"General failure": "Обща грешка",
"Failed to perform homeserver discovery": "Неуспешно откриване на конфигурацията за сървъра",
"Unknown failure discovering homeserver": "Непозната грешка при откриването на конфигурацията за сървъра",
"Sign in with single sign-on": "Влезте посредством single-sign-on",
"Great! This passphrase looks strong enough.": "Чудесно! Паролата изглежда сигурна.",
"Secure your encrypted message history with a Recovery Passphrase.": "Защитете историята на шифрованите съобщения с парола за възстановяване.",
"You'll need it if you log out or lose access to this device.": "Ще е необходимо, ако излезете от профила си или загубите достъп до това устройство.",
"Enter a passphrase...": "Въведете парола...",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Ако не искате шифрованата история на съобщенията да бъде достъпна на други устройства, <button>откажете това</button>.",
"Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.": "Ако пък не искате да създавате парола за възстановяване, пропуснете тази стъпка и <button>свалете ключ за възстановяване</button>.",
"That matches!": "Това съвпада!",
"That doesn't match.": "Това не съвпада.",
"Go back to set it again.": "Върнете се и го настройте пак.",
"Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Въведете паролата за възстановяване за да потвърдите, че я помните. Ако ще помогне, запазете я в паролите на браузъра си или на друго сигурно място.",
"Repeat your passphrase...": "Повторете паролата...",
"As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Като предпазна мярка, можете да го използвате за възстановяване на шифрованата история на съобщенията, в случай че сте забравили паролата за възстановяване.",
"As a safety net, you can use it to restore your encrypted message history.": "Като предпазна мярка, можете да го използвате за възстановяване на шифрованата история на съобщенията.",
"Make a copy of this Recovery Key and keep it safe.": "Направете копие на ключа за възстановяване и го пазете на сигурно място.",
"Your Recovery Key": "Вашия ключ за възстановяване",
"Copy to clipboard": "Копирай в клипборд",
"Download": "Свали",
"I've made a copy": "Направих копие",
"Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:": "Ключа Ви за възстановяване <b>беше копиран в клипборда</b>, поставете го в:",
"Your Recovery Key is in your <b>Downloads</b> folder.": "Ключът Ви за възстановяване е в папка <b>Изтеглени</b>.",
"<b>Print it</b> and store it somewhere safe": "<b>Принтирайте го</b>и го съхранявайте на безопасно място",
"<b>Save it</b> on a USB key or backup drive": "<b>Запазете го</b> на USB или резервен диск",
"<b>Copy it</b> to your personal cloud storage": "<b>Копирайте го</b> в персонално облачно пространство",
"Got it": "Разбрах",
"Backup created": "Резервното копие бе създадено",
"Your encryption keys are now being backed up to your Homeserver.": "Прави се резервно копие на ключовете Ви за шифроване върху сървъра.",
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Без настроено Защитено Възстановяване на Съобщения, няма да може да възстановите шифрованата история на съобщенията, в случай че излезете от профила си или използвате друго устройство.",
"Set up Secure Message Recovery": "Настрой Защитено Възстановяване на Съобщения",
"Create a Recovery Passphrase": "Създай парола за възстановяване",
"Confirm Recovery Passphrase": "Потвърди парола за възстановяване",
"Recovery Key": "Ключ за възстановяване",
"Keep it safe": "Пазете го в безопасност",
"Backing up...": "Създаване на резервно копие...",
"Create Key Backup": "Създай резервно копие на ключа",
"Unable to create key backup": "Неуспешно създаване на резервно копие на ключа",
"Retry": "Опитай пак",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Без настроено Защитено Възстановяване на Съобщения, ще загубите защитената история на съобщенията когато излезете от профила си.",
"If you don't want to set this up now, you can later in Settings.": "Ако не искате да настройвате това сега, може и по-късно от Настройки.",
"Straight rows of keys are easy to guess": "Клавиши от прави редици са лесни за отгатване",
"Short keyboard patterns are easy to guess": "Къси клавиатурни последователности са лесни за отгатване",
"Custom user status messages": "Собствено статус съобщение",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Резервното копие има <validity>валиден</validity> подпис от <verify>потвърдено</verify> устройство <device></device>",
"Unable to load commit detail: %(msg)s": "Неуспешно зареждане на информация за commit: %(msg)s",
"Set a new status...": "Задаване на нов статус...",
"Clear status": "Изчисти статуса",
"New Recovery Method": "Нов метод за възстановяване",
"A new recovery passphrase and key for Secure Messages has been detected.": "Беше открита нова парола за възстановяване за Защитени Съобщения.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Настройката на Защитени Съобщения на това устройство ще зашифрова наново историята на съобщенията му посредством новия метод за възстановяване.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ако не сте настройвали новия метод за възстановяване, вероятно някой се опитва да проникне в акаунта Ви. Веднага променете паролата на акаунта си и настройте нов метод за възстановяване от Настройки.",
"Set up Secure Messages": "Настрой Защитени Съобщения",
"Go to Settings": "Отиди в Настройки"
}

View file

@ -1355,5 +1355,97 @@
"This looks like a valid recovery key!": "Dies sieht nach einem validen Wiederherstellungsschlüssel aus",
"Not a valid recovery key": "Kein valider Wiederherstellungsschlüssel",
"Key Backup": "Schlüsselsicherung",
"Cannot find homeserver": "Konnte Heimserver nicht finden"
"Cannot find homeserver": "Konnte Heimserver nicht finden",
"There was an error joining the room": "Es gab einen Fehler beim Raum-Beitreten",
"Use a few words, avoid common phrases": "Benutze einige Worte, vermeide gängige Phrasen",
"No need for symbols, digits, or uppercase letters": "Kein Bedarf an Symbolen, Zahlen oder Großbuchstaben",
"Avoid repeated words and characters": "Vermeide wiederholte Worte und Zeichen",
"Avoid sequences": "Vermeide Sätze",
"Avoid recent years": "Vermeide nahe Jahre",
"Avoid years that are associated with you": "Vermeide Jahre, die mit dir zusammenhängen",
"Avoid dates and years that are associated with you": "Vermeide Daten und Jahre, die mit dir in Verbindung stehen",
"Capitalization doesn't help very much": "Großschreibung hilft nicht viel",
"All-uppercase is almost as easy to guess as all-lowercase": "Alles groß zu geschrieben ist fast genauso schnell zu raten, wie alles klein zu schreiben",
"Reversed words aren't much harder to guess": "Umgedrehte Worte sind nicht schwerer zu erraten",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Vorhersagbare Ersetzungen wie '@' anstelle von 'a' helfen nicht viel",
"Add another word or two. Uncommon words are better.": "Füge ein weiteres wort hinzu - oder mehr. Ungewöhnliche Worte sind besser.",
"Repeats like \"aaa\" are easy to guess": "Wiederholungen wie \"aaa\" sind einfach zu erraten",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Wiederholungen wie \"abcabcabc\" sind nur leicht schwerer zu raten als \"abc\"",
"Sequences like abc or 6543 are easy to guess": "Sequenzen wie \"abc\" oder \"6543\" sind leicht zu raten",
"Recent years are easy to guess": "Kürzlich vergangene Jahre sind einfach zu raten",
"Dates are often easy to guess": "Daten sind oft einfach zu erraten",
"This is a top-10 common password": "Dies ist unter den Top 10 der üblichen Passwörter",
"This is a top-100 common password": "Dies ist unter den Top 100 der üblichen Passwörter",
"This is a very common password": "Dies ist ein recht bekanntes Passwort",
"This is similar to a commonly used password": "Dies ist ähnlich zu einem oft genutzten Passwort",
"A word by itself is easy to guess": "Ein Wort alleine ist einfach zu erraten",
"Names and surnames by themselves are easy to guess": "Namen und Familiennamen alleine sind einfach zu erraten",
"Common names and surnames are easy to guess": "Häufige Namen und Familiennamen sind einfach zu erraten",
"You do not have permission to invite people to this room.": "Du hast keine Berechtigung um Personen in diesen Raum einzuladen.",
"User %(user_id)s does not exist": "Benutzer %(user_id)s existiert nicht",
"Unknown server error": "Unbekannter Server-Fehler",
"Failed to invite users to the room:": "Konnte Benutzer nicht in den Raum einladen:",
"Short keyboard patterns are easy to guess": "Kurze Tastaturmuster sind einfach zu erraten",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Zeige eine Erinnerung um die Sichere Nachrichten-Wiederherstellung in verschlüsselten Räumen zu aktivieren",
"Messages containing @room": "Nachrichten die \"@room\" enthalten",
"Encrypted messages in one-to-one chats": "Verschlüsselte Nachrichten in 1:1 Chats",
"Encrypted messages in group chats": "Verschlüsselte Nachrichten in Gruppenchats",
"Use a longer keyboard pattern with more turns": "Nutze ein längeres Tastaturmuster mit mehr Änderungen",
"Straight rows of keys are easy to guess": "Gerade Reihen von Tasten sind einfach zu erraten",
"Custom user status messages": "Angepasste Nutzerstatus-Nachrichten",
"Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Wirklich die gesicherten Verschlüsselungs-Schlüssel vom Server löschen? Du wirst nicht länger in der Lage sein, deinen Wiederherstellungsschlüssel zu verwenden um die verschlüsselte Nachrichtenhistorie zu lesen",
"Unable to load key backup status": "Konnte Status des Schlüsselbackups nicht laden",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Sicherung hat eine <validity>valide</validity> Signatur von einem <verify>verifiziertem</verify> Gerät <device></device>",
"The following files cannot be uploaded:": "Die folgenden Dateien konnten nicht hochgeladen werden:",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Um deine sichere Nachrichtenhistorie zu sehen und sicherzustellen, dass du neue Nachrichten auf zukünftigen Geräten lesen kannst, richte die Sichere Nachrichten-Wiederherstellung ein.",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Wenn du dich abmeldest oder ein anderes Gerät verwendest, wirst du deine sichere Nachrichten-Historie verlieren. Um das zu verhindern, richte die Sichere Nachrichten-Wiederherstellung ein.",
"Secure Message Recovery": "Sichere Nachrichten-Wiederherstellung",
"Don't ask again": "Nicht erneut fragen",
"Set up": "Einrichten",
"Please review and accept all of the homeserver's policies": "Bitte sieh dir die Heimserver-Regularien an und akzeptiere sie",
"Failed to load group members": "Konnte Gruppenmitglieder nicht laden",
"That doesn't look like a valid email address": "Sieht nicht nach einer validen E-Mail-Adresse aus",
"Unable to load commit detail: %(msg)s": "Konnte Commit-Details nicht laden: %(msg)s",
"Only use lower case letters, numbers and '=_-./'": "Nutze nur Kleinbuchstaben, Nummern und '=_-./'",
"Checking...": "Überprüfe...",
"Unable to load backup status": "Konnte Backupstatus nicht laden",
"Failed to decrypt %(failedCount)s sessions!": "Konnte %(failedCount)s Sitzungen nicht entschlüsseln!",
"Restored %(sessionCount)s session keys": "%(sessionCount)s Sitzungsschlüssel wiederhergestellt",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Greife auf deinen sicheren Chatverlauf zu und richte sicheres Schreiben ein indem du deine Wiederherstellungspassphrase eingibst.",
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "Wenn du deinen Wiederherstellungspassphrase vergessen hast, kannst du <button1>deinen Wiederherstellungsschlüssel benutzen</button1> oder <button2>neue Wiederherstellungsoptionen einrichten</button2>",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Du hast kürzlich eine neuere Version von Riot auf %(host)s verwendet. Um diese Version erneut mit Ende-zu-Ende-Verschlüsselung zu nutzen, musst du dich ab- und wieder anmelden. ",
"Access your secure message history and set up secure messaging by entering your recovery key.": "Auf sichere Nachrichtenhistorie zugreifen und sicheren Nachrichtenversand einrichten indem du deinen Wiederherstellungsschlüssel eingibst.",
"If you've forgotten your recovery passphrase you can <button>set up new recovery options</button>": "Wenn du deine Wiederherstellungspassphrase vergessen hast, kannst du <button>neue Wiederherstellungsoptionen einrichten</button>",
"Set a new status...": "Setze einen neuen Status...",
"Clear status": "Status löschen",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Fehlerhafte Konfiguration: Kann keine Standard-Heimserver-URL und Standard-Servernamen bereitstellen",
"Unknown error discovering homeserver": "Unbekannter Fehler beim Aufspüren des Heimservers",
"%(count)s Notifications|other": "%(count)s Benachrichtigungen",
"%(count)s Notifications|one": "%(count)s Benachrichtigung",
"File is too big. Maximum file size is %(fileSize)s": "Datei ist zu groß. Maximale Dateigröße ist %(fileSize)s",
"Invalid homeserver discovery response": "Ungültige Antwort beim Aufspüren des Heimservers",
"Invalid identity server discovery response": "Ungültige Antwort beim Aufspüren des Identitätsservers",
"General failure": "Allgemeiner Fehler",
"Failed to perform homeserver discovery": "Fehler beim Aufspüren des Heimservers",
"Unknown failure discovering homeserver": "Unbekannter Fehler beim Aufspüren des Heimservers",
"Great! This passphrase looks strong enough.": "Gut! Diese Passphrase sieht start genug aus.",
"Secure your encrypted message history with a Recovery Passphrase.": "Sichere deine sichere Nachrichtenhistorie mit einer Wiederherstellungspassphrase.",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Wenn du deine verschlüsselte Nachrichtenhistorie nicht auf anderen Geräten verfügbar haben möchtest, <button>wiederspreche</button>.",
"Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.": "Oder, wenn du keine Wiederherstellungspassphrase erzeugen möchtest, überspringe diesen Schritt und <button>lade einen Wiederherstellungsschlüssel herunter</button>.",
"Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Gebe deine Wiederherstellungspassphrase ein um zu bestätigen, dass du dich daran erinnern kannst. Wenn es hilft, füge sie deinem Passwortmanager hinzu oder speichere sie an einem sicheren Ort.",
"As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Als Sicherheitsnetz kannst du ihn benutzen um deine verschlüsselte Nachrichtenhistorie wiederherzustellen, falls du deine Wiederherstellungspassphrase vergessen hast.",
"As a safety net, you can use it to restore your encrypted message history.": "Als Sicherheitsnetz kannst du ihn benutzen um deine verschlüsselte Nachrichtenhistorie wiederherzustellen.",
"Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:": "Dein Wiederherstellungsschlüssel wurde <b>in deine Zwischenablage kopiert</b>. Füge ihn hier ein:",
"Your Recovery Key is in your <b>Downloads</b> folder.": "Dein Wiederherstellungsschlüssel ist in deinem <b>Downloads</b>-Ordner.",
"Set up Secure Message Recovery": "Richte Sichere Nachrichten-Wiederherstellung ein",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Ohne Sichere Nachrichten-Wiederherstellung einzurichten, wirst du deine sichere Nachrichtenhistorie verlieren, wenn du dich abmeldest.",
"If you don't want to set this up now, you can later in Settings.": "Wenn du dies jetzt nicht einrichten willst, kannst du dies später in den Einstellungen tun.",
"New Recovery Method": "Neue Wiederherstellungsmethode",
"A new recovery passphrase and key for Secure Messages has been detected.": "Eine neue Wiederherstellungspassphrase und ein neuer -schlüssel für sichere Nachrichten wurde entdeckt.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Beim einrichten von Sichere Nachrichten auf diesem Gerät wird die Nachrichtenhistorie mit der neuen Wiederherstellungsmethode erneut verschlüsselt.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Wenn du die neue Wiederherstellungsmethode nicht eingerichtet hast, kann ein Angreifer versuchen Zugang zu deinem Konto zu erlangen. Ändere sofort dein Passwort und setze eine neue Wiederherstellungsmethode.",
"Set up Secure Messages": "Richte sichere Nachrichten ein",
"Go to Settings": "Gehe zu Einstellungen",
"Sign in with single sign-on": "Mit Single Sign-On anmelden",
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Wenn du die Sichere Nachrichten-Wiederherstellung nicht einrichtest, wirst du nicht in der Lage sein deine verschlüsselte Nachrichtenhistorie wiederherzustellen, wenn du dich abmeldest oder ein weiteres Gerät benutzt."
}

View file

@ -132,6 +132,7 @@
"Searches DuckDuckGo for results": "Searches DuckDuckGo for results",
"/ddg is not a command": "/ddg is not a command",
"To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.",
"Upgrades a room to a new version": "Upgrades a room to a new version",
"Changes your display nickname": "Changes your display nickname",
"Changes colour scheme of current room": "Changes colour scheme of current room",
"Sets the room topic": "Sets the room topic",
@ -226,8 +227,10 @@
"Your browser does not support the required cryptography extensions": "Your browser does not support the required cryptography extensions",
"Not a valid Riot keyfile": "Not a valid Riot keyfile",
"Authentication check failed: incorrect password?": "Authentication check failed: incorrect password?",
"Unrecognised address": "Unrecognised address",
"You do not have permission to invite people to this room.": "You do not have permission to invite people to this room.",
"User %(user_id)s does not exist": "User %(user_id)s does not exist",
"User %(user_id)s may or may not exist": "User %(user_id)s may or may not exist",
"Unknown server error": "Unknown server error",
"Use a few words, avoid common phrases": "Use a few words, avoid common phrases",
"No need for symbols, digits, or uppercase letters": "No need for symbols, digits, or uppercase letters",
@ -265,7 +268,6 @@
"Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
"Backup of encryption keys to server": "Backup of encryption keys to server",
"Render simple counters in room header": "Render simple counters in room header",
"Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu",
"Two-way device verification using short text": "Two-way device verification using short text",
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
"Use compact timeline layout": "Use compact timeline layout",
@ -297,7 +299,7 @@
"Pin rooms I'm mentioned in to the top of the room list": "Pin rooms I'm mentioned in to the top of the room list",
"Pin unread rooms to the top of the room list": "Pin unread rooms to the top of the room list",
"Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets",
"Show empty room list headings": "Show empty room list headings",
"Prompt before sending invites to potentially invalid matrix IDs": "Prompt before sending invites to potentially invalid matrix IDs",
"Show developer tools": "Show developer tools",
"Collecting app version information": "Collecting app version information",
"Collecting logs": "Collecting logs",
@ -371,6 +373,7 @@
"This device is <b>not</b> using key backup": "This device is <b>not</b> using key backup",
"Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
"All keys backed up": "All keys backed up",
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
"Backup has a <validity>valid</validity> signature from this device": "Backup has a <validity>valid</validity> signature from this device",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>",
@ -552,7 +555,6 @@
"Forget room": "Forget room",
"Search": "Search",
"Share room": "Share room",
"Toggle right panel": "Toggle right panel",
"Drop here to favourite": "Drop here to favourite",
"Drop here to tag direct chat": "Drop here to tag direct chat",
"Drop here to restore": "Drop here to restore",
@ -654,9 +656,9 @@
"This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.",
"Click here to upgrade to the latest room version and ensure room integrity is protected.": "Click here to upgrade to the latest room version and ensure room integrity is protected.",
"Only room administrators will see this warning": "Only room administrators will see this warning",
"Search…": "Search…",
"This Room": "This Room",
"All Rooms": "All Rooms",
"Search…": "Search…",
"You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled",
"Add some now": "Add some now",
"Stickerpack": "Stickerpack",
@ -900,6 +902,10 @@
"That doesn't look like a valid email address": "That doesn't look like a valid email address",
"You have entered an invalid address.": "You have entered an invalid address.",
"Try using one of the following valid address types: %(validTypesList)s.": "Try using one of the following valid address types: %(validTypesList)s.",
"The following users may not exist": "The following users may not exist",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?",
"Invite anyway and never warn me again": "Invite anyway and never warn me again",
"Invite anyway": "Invite anyway",
"Preparing to send logs": "Preparing to send logs",
"Logs sent": "Logs sent",
"Thank you!": "Thank you!",
@ -1101,9 +1107,10 @@
"Forget": "Forget",
"Low Priority": "Low Priority",
"Direct Chat": "Direct Chat",
"Set a new status...": "Set a new status...",
"Clear status": "Clear status",
"View as Grid": "View as Grid",
"Update status": "Update status",
"Set status": "Set status",
"Set a new status...": "Set a new status...",
"View Community": "View Community",
"Sorry, your browser is <b>not</b> able to run Riot.": "Sorry, your browser is <b>not</b> able to run Riot.",
"Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.",
@ -1114,7 +1121,6 @@
"You must <a>register</a> to use this functionality": "You must <a>register</a> to use this functionality",
"You must join the room to see its files": "You must join the room to see its files",
"There are no visible files in this room": "There are no visible files in this room",
"No room in this tile yet.": "No room in this tile yet.",
"<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n": "<h1>HTML for your community's page</h1>\n<p>\n Use the long description to introduce new members to the community, or distribute\n some important <a href=\"foo\">links</a>\n</p>\n<p>\n You can even use 'img' tags\n</p>\n",
"Add rooms to the community summary": "Add rooms to the community summary",
"Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",

View file

@ -1124,5 +1124,49 @@
"%(senderName)s removed the main address for this room.": "%(senderName)s forigis la ĉefan adreson de la ĉambro.",
"Please <a>contact your service administrator</a> to continue using the service.": "Bonvolu <a>kontakti administranton de la servo</a> por daŭre uzadi la servon.",
"Pin unread rooms to the top of the room list": "Fiksi nelegitajn ĉambrojn supre de la listo",
"Pin rooms I'm mentioned in to the top of the room list": "Fiksi ĉambrojn kun mencioj de mia nomo supre de la listo"
"Pin rooms I'm mentioned in to the top of the room list": "Fiksi ĉambrojn kun mencioj de mia nomo supre de la listo",
"A call is currently being placed!": "Alia voko nun dumas!",
"Unable to load! Check your network connectivity and try again.": "Ne eblas enlegi! Kontrolu vian retan konekton kaj reprovu.",
"Failed to invite users to the room:": "Malsukcesis inviti uzantojn al la ĉambro:",
"Opens the Developer Tools dialog": "Maflermas evoluigistan interagujon",
"This homeserver has hit its Monthly Active User limit.": "Tiu ĉi hejmservilo atingis sian monatan limon de aktivaj uzantoj.",
"This homeserver has exceeded one of its resource limits.": "Tiu ĉi hejmservilo superis je unu el siaj risurcaj limoj.",
"Unable to connect to Homeserver. Retrying...": "Ne povas konektiĝi al hejmservilo. Reprovanta…",
"You do not have permission to invite people to this room.": "Vi ne havas permeson inviti homojn al la ĉambro.",
"User %(user_id)s does not exist": "Uzanto %(user_id)s ne ekzistas",
"Unknown server error": "Nekonata servila eraro",
"Use a few words, avoid common phrases": "Uzu malmultajn vortojn, kaj evitu oftajn frazojn",
"Avoid repeated words and characters": "Evitu ripetadon de vortoj kaj signoj",
"Avoid sequences": "Evitu sinsekvojn",
"Avoid recent years": "Evitu freŝdatajn jarojn",
"Avoid years that are associated with you": "Evitu jarojn, kiuj ligiĝas al vi",
"Avoid dates and years that are associated with you": "Evitu datojn kaj jarojn, kiuj ligiĝas al vi",
"Capitalization doesn't help very much": "Majusklado ne helpas multe",
"All-uppercase is almost as easy to guess as all-lowercase": "Plena majusklado estas preskaŭ same facile konjektebla kiel plena minusklado",
"Reversed words aren't much harder to guess": "Renversitaj vortoj ne estas multe pli malfacile konjekteblaj",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Facile diveneblaj anstataŭigoj, kiel @ anstataŭ a, ne helpas multe",
"Add another word or two. Uncommon words are better.": "Aldonu alian vorton aŭ du. Maloftaj vortoj pli bonas.",
"Repeats like \"aaa\" are easy to guess": "Ripetoj kiel «aaa» estas facile diveneblaj",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetoj kiel «abcabcabc» estas apenaŭ pli bonaj ol nur «abc»",
"Sequences like abc or 6543 are easy to guess": "Sinsekvoj kiel «abc» aŭ «6543» estas facile diveneblaj",
"Recent years are easy to guess": "Freŝdataj jaroj estas facile diveneblaj",
"Dates are often easy to guess": "Datoj estas ofte facile diveneblaj",
"This is a top-10 common password": "Ĉi tiu pasvorto estas inter la 10 plej oftaj",
"This is a top-100 common password": "Ĉi tiu pasvorto estas inter la 100 plej oftaj",
"This is a very common password": "Ĉi tiu pasvorto estas tre ofta",
"This is similar to a commonly used password": "Ĉi tiu pasvorto similas iun tre oftan",
"A word by itself is easy to guess": "Memstara vorto estas facile divenebla",
"Names and surnames by themselves are easy to guess": "Ankaŭ nomoj familiaj kaj individiuaj estas memstare facile diveneblaj",
"Common names and surnames are easy to guess": "Oftaj nomoj familiaj kaj individuaj estas facile diveneblaj",
"There was an error joining the room": "Okazis eraro dum aliĝo al la ĉambro",
"Sorry, your homeserver is too old to participate in this room.": "Pardonu, via hejmservilo estas tro malnova por partoprenado en la ĉambro.",
"Please contact your homeserver administrator.": "Bonvolu kontakti la administranton de via hejmservilo.",
"Increase performance by only loading room members on first view": "Plibonigu efikecon per nur unuafoja enlego de ĉambranoj",
"Backup of encryption keys to server": "Savkopio de ĉifroŝlosiloj al servilo",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Montri memorigilon por ŝalti Sekuran Ricevon de Mesaĝoj en ĉifrataj ĉambroj",
"Show developer tools": "Montri evolugistajn ilojn",
"Messages containing @room": "Mesaĝoj enhavantaj @room",
"Encrypted messages in one-to-one chats": "Ĉifritaj mesaĝoj en duopaj babiloj",
"Encrypted messages in group chats": "Ĉifritaj mesaĝoj en grupaj babiloj",
"Delete Backup": "Forigi savkopion"
}

View file

@ -892,11 +892,11 @@
"%(oneUser)sjoined %(count)s times|other": "%(oneUser)s%(count)s aldiz elkartu da",
"%(oneUser)sjoined %(count)s times|one": "%(oneUser)s elkartu da",
"%(severalUsers)sleft %(count)s times|other": "%(severalUsers)s%(count)s aldiz atera dira",
"%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s atera da",
"%(severalUsers)sleft %(count)s times|one": "%(severalUsers)s atera dira",
"%(oneUser)sleft %(count)s times|other": "%(oneUser)s%(count)s aldiz atera da",
"%(oneUser)sleft %(count)s times|one": "%(oneUser)s atera da",
"%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)s elkartu eta atera dira %(count)s aldiz",
"%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s elkartu eta atera da",
"%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)s elkartu eta atera dira",
"%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)s elkartu eta atera da %(count)s aldiz",
"%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)s elkartu eta atera da",
"%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s atera eta berriz elkartu dira %(count)s aldiz",
@ -1309,7 +1309,7 @@
"Unable to load key backup status": "Ezin izan da babes-kopiaren egoera kargatu",
"This device is uploading keys to this backup": "Gailu honek gakoak babes-kopia honetara igotzen ditu",
"This device is <b>not</b> uploading keys to this backup": "Gailu honek <b>ez</b> ditu gakoak igotzen babes-kopia honetara",
"Backup has a <validity>valid</validity> signature from this device": "Babes-kopiak gailu honen <validity>baliozko</validity> sinadura du",
"Backup has a <validity>valid</validity> signature from this device": "Babes-kopiak gailu honen <validity>baliozko</validity> sinadura bat du",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device>x</device>": "Babes-kopiak <verify>egiaztatutako</verify> <device>x</device> gailuaren <validity>baliozko</validity> sinadura du",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Babes-kopiak <verify>egiaztatu gabeko</verify> <device>gailu baten</device> <validity>baliozko</validity> sinadura du",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Babes-kopiak <verify>egiaztatutako</verify> <device></device> gailuaren <validity>balio gabeko</validity> sinadura du",
@ -1378,5 +1378,75 @@
"Sign in with single sign-on": "Hai saioa urrats batean",
"Failed to perform homeserver discovery": "Huts egin du hasiera-zerbitzarien bilaketak",
"Invalid homeserver discovery response": "Baliogabeko hasiera-zerbitzarien bilaketaren erantzuna",
"Cannot find homeserver": "Ezin izan da hasiera-zerbitzaria aurkitu"
"Cannot find homeserver": "Ezin izan da hasiera-zerbitzaria aurkitu",
"Failed to invite users to the room:": "Huts egin du erabiltzaileak gelara elkartzean:",
"There was an error joining the room": "Errore bat gertatu da gelara elkartzean",
"Use a few words, avoid common phrases": "Erabili hitz gutxi batzuk, ekidin ohiko esaldiak",
"No need for symbols, digits, or uppercase letters": "Ez dira sinboloak, zenbakiak edo letra larriak behar",
"Use a longer keyboard pattern with more turns": "Erabili teklatu-eredu luzeago bat aldaketa gehiagorekin",
"Avoid repeated words and characters": "Ekidin errepikatutako hitzak eta karaktereak",
"Avoid sequences": "Ekidin sekuentziak",
"Avoid recent years": "Ekidin azkenaldiko urteak",
"Avoid years that are associated with you": "Ekidin zurekin zerikusia duten urteak",
"Avoid dates and years that are associated with you": "Ekidin zurekin zerikusia duten datak eta urteak",
"Capitalization doesn't help very much": "Letra larriek eta xeheak ez dute askorik laguntzen",
"All-uppercase is almost as easy to guess as all-lowercase": "Dena letra larriz dena letra xehez bezain erraza da asmatzeko",
"Reversed words aren't much harder to guess": "Alderantzikatutako hitzak ez dira asmatzeko asmoz zailagoak",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Aurreikusi daitezkeen ordezkatzeak, esaterako '@' erabiltzea 'a' adierazteko, ez dute askorik laguntzen",
"Add another word or two. Uncommon words are better.": "Gehitu hitz bat edo bi gehiago. Ezohiko hitzak hobeak dira.",
"Repeats like \"aaa\" are easy to guess": "'aaa' bezalako errepikapenak erraz asmatu daitezke",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "\"abcabcabc\" bezalako errepikapenak ia \"abc\" bezain errazak dira asmatzeko",
"Sequences like abc or 6543 are easy to guess": "abc edo 6543 bezalako sekuentziak errazak dira asmatzeko",
"Recent years are easy to guess": "Azkenaldiko urteak errazak dira asmatzeko",
"Dates are often easy to guess": "Datak maiz errazak dira asmatzeko",
"This is a top-10 common password": "Pasahitz hau 10 erabilienen artean dago",
"This is a top-100 common password": "Pasahitz hau 100 erabilienen artean dago",
"This is a very common password": "Pasahitz hau oso ohikoa da",
"This is similar to a commonly used password": "Pasahitz hau maiz erabilitako beste baten oso antzekoa da",
"A word by itself is easy to guess": "Hitz bat berez asmatzeko oso erreza da",
"Names and surnames by themselves are easy to guess": "Izen eta abizenak berez asmatzeko errazak dira",
"Common names and surnames are easy to guess": "Ohiko izenak eta abizenak asmatzeko errazak dira",
"You do not have permission to invite people to this room.": "Ez duzu jendea gela honetara gonbidatzeko baimenik.",
"User %(user_id)s does not exist": "Ez dago %(user_id)s erabiltzailerik",
"Unknown server error": "Zerbitzari errore ezezaguna",
"The following files cannot be uploaded:": "Honako fitxategi hauek ezin dira igo:",
"Failed to load group members": "Huts egin du taldeko kideak kargatzean",
"File is too big. Maximum file size is %(fileSize)s": "Fitxategia handiegia da. Gehieneko tamaina %(fileSize)s da",
"Great! This passphrase looks strong enough.": "Ongi! Pasaesaldi hau nahiko gogorra ematen du.",
"As a safety net, you can use it to restore your encrypted message history.": "Badaezpada, zure zifratutako mezuen historiala berreskuratzeko erabili dezakezu.",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Erakutsi zifratutako geletan mezuen berreskuratze segurua gaitzeko origarri bat",
"Secure Message Recovery": "Mezuen berreskuratze segurua",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Saioa amaitzen baduzu edo beste gailu bat erabiltzen baduzu, zure mezu seguruen historiala galduko duzu. Hau gertatu ez dadin, ezarri mezuen berreskuratze segurua.",
"Don't ask again": "Ez galdetu berriro",
"Set up": "Ezarri",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Zifratutako mezuen historiala beste gailuetan eskuragarri egotea ez baduzu nahi, <button>desaktibatu</button>.",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Mezuen berreskuratze segurua ezartzen ez baduzu, mezu seguruen historiala galduko duzu saioa amaitzean.",
"If you don't want to set this up now, you can later in Settings.": "Ez baduzu hau orain ezarri nahi, gero ere egin dezakezu ezarpenetan.",
"Messages containing @room": "@room duten mezuak",
"Encrypted messages in one-to-one chats": "Zifratutako mezuak bi pertsonen arteko txatetan",
"Encrypted messages in group chats": "Zifratutako mezuak talde-txatetan",
"That doesn't look like a valid email address": "Horrek ez du baliozko e-mail baten itxurarik",
"Straight rows of keys are easy to guess": "Teklatuko errenkadak asmatzeko errazak dira",
"Short keyboard patterns are easy to guess": "Teklatuko eredu laburrak asmatzeko errazak dira",
"Custom user status messages": "Erabiltzailearen egoera mezu pertsonalizatuak",
"Only use lower case letters, numbers and '=_-./'": "Erabili soilik letra xeheak, zenbakiak eta '=_-./'",
"Checking...": "Egiaztatzen...",
"Set a new status...": "Ezarri egoera berri bat...",
"Clear status": "Garbitu egoera",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Konfigurazio baliogabea: Ezin da lehenetsitako hasiera-zerbitzari bat eta lehenetsitako zerbitzari izen bat zerbitzatu",
"Unknown error discovering homeserver": "Errore ezezaguna hasiera-zerbitzaria bilatzean",
"%(count)s Notifications|other": "%(count)s jakinarazpen",
"%(count)s Notifications|one": "Jakinarazpen %(count)s",
"General failure": "Hutsegite orokorra",
"New Recovery Method": "Berreskuratze metodo berria",
"Set up Secure Messages": "Ezarri mezu seguruak",
"Go to Settings": "Joan ezarpenetara",
"Unknown failure discovering homeserver": "Hutsegite ezezaguna hasiera-zerbitzaria bilatzean",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Babes-kopiak <verify>egiaztatutako</verify> <device>gailu</device> baten <validity>baliozko</validity> sinadura bat du",
"Unable to load commit detail: %(msg)s": "Ezin izan dira xehetasunak kargatu: %(msg)s",
"Invalid identity server discovery response": "Baliogabeko erantzuna identitate zerbitzariaren bilaketan",
"A new recovery passphrase and key for Secure Messages has been detected.": "Mezu seguruentzako berreskuratze pasa-esaldi eta gako berri bat antzeman dira.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Mezu seguruak gailu honetan ezartzeak, gailu honen mezuen historiala birzifratuko du berreskuratze metodo berriarekin.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ez baduzu berreskuratze sistema berria ezarri, erasotzaile bat zure kontua atzitzen saiatzen egon daiteke. Aldatu zure kontuaren pasahitza eta ezarri berreskuratze metodo berria berehala ezarpenetan.",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Zure mezu seguruen historiala ikusteko eta etorkizunean erabiltzen dituzun gailuetan ere mezuak ikusi ahal izango dituzula ziurtatzeko, ezarri mezuen berreskuratze segurua."
}

View file

@ -298,7 +298,7 @@
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Un instant donné de la chronologie na pu être chargé car il na pas pu être trouvé.",
"Turn Markdown off": "Désactiver le formatage Markdown",
"Turn Markdown on": "Activer le formatage Markdown",
"%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s a activé le chiffrement de bout-en-bout (algorithme %(algorithm)s).",
"%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s a activé le chiffrement de bout en bout (algorithme %(algorithm)s).",
"Unable to add email address": "Impossible d'ajouter l'adresse e-mail",
"Unable to remove contact information": "Impossible de supprimer les informations du contact",
"Unable to verify email address.": "Impossible de vérifier ladresse e-mail.",
@ -926,7 +926,7 @@
"Answer": "Répondre",
"Send": "Envoyer",
"Old cryptography data detected": "Anciennes données de chiffrement détectées",
"Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Nous avons détecté des données d'une ancienne version de Riot. Le chiffrement de bout-en-bout n'aura pas fonctionné correctement sur l'ancienne version. Les messages chiffrés échangés récemment dans l'ancienne version ne sont peut-être pas déchiffrables dans cette version. Les échanges de message avec cette version peuvent aussi échouer. Si vous rencontrez des problèmes, déconnectez-vous puis reconnectez-vous. Pour conserver l'historique des messages, exportez puis réimportez vos clés de chiffrement.",
"Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Nous avons détecté des données d'une ancienne version de Riot. Le chiffrement de bout en bout n'aura pas fonctionné correctement sur l'ancienne version. Les messages chiffrés échangés récemment dans l'ancienne version ne sont peut-être pas déchiffrables dans cette version. Les échanges de message avec cette version peuvent aussi échouer. Si vous rencontrez des problèmes, déconnectez-vous puis reconnectez-vous. Pour conserver l'historique des messages, exportez puis réimportez vos clés de chiffrement.",
"Warning": "Attention",
"You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Vous ne pourrez pas annuler cette modification car vous vous destituez. Si vous êtes le dernier utilisateur privilégié de ce salon, il sera impossible de récupérer les privilèges.",
"%(count)s of your messages have not been sent.|one": "Votre message n'a pas été envoyé.",
@ -1070,7 +1070,7 @@
"Monday": "Lundi",
"All messages (noisy)": "Tous les messages (fort)",
"Enable them now": "Les activer maintenant",
"Messages containing my user name": "Message contenant mon nom d'utilisateur",
"Messages containing my user name": "Messages contenant mon nom d'utilisateur",
"Toolbox": "Boîte à outils",
"Collecting logs": "Récupération des journaux",
"more": "plus",
@ -1303,9 +1303,9 @@
"Pin rooms I'm mentioned in to the top of the room list": "Épingler les salons où l'on me mentionne en haut de la liste des salons",
"If you would like to create a Matrix account you can <a>register</a> now.": "Si vous souhaitez créer un compte Matrix, vous pouvez <a>vous inscrire</a> maintenant.",
"You are currently using Riot anonymously as a guest.": "Vous utilisez Riot de façon anonyme en tant qu'invité.",
"Please review and accept all of the homeserver's policies": "Veuillez lire et accepter toutes les polices du serveur d'accueil",
"Please review and accept all of the homeserver's policies": "Veuillez lire et accepter toutes les politiques du serveur d'accueil",
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Pour éviter de perdre l'historique de vos discussions, vous devez exporter vos clés avant de vous déconnecter. Vous devez revenir à une version plus récente de Riot pour pouvoir le faire",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Vous avez utilisé une version plus récente de Riot sur %(host)s. Pour utiliser à nouveau cette version avec le chiffrement de bout à bout, vous devez vous déconnecter et vous reconnecter. ",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Vous avez utilisé une version plus récente de Riot sur %(host)s. Pour utiliser à nouveau cette version avec le chiffrement de bout en bout, vous devez vous déconnecter et vous reconnecter. ",
"Incompatible Database": "Base de données incompatible",
"Continue With Encryption Disabled": "Continuer avec le chiffrement désactivé",
"Sign in with single sign-on": "Se connecter avec l'authentification unique",
@ -1410,5 +1410,58 @@
"Use a longer keyboard pattern with more turns": "Utilisez un schéma plus long et avec plus de variations",
"Great! This passphrase looks strong enough.": "Super ! Cette phrase de passe a l'air assez forte.",
"As a safety net, you can use it to restore your encrypted message history.": "En cas de problème, vous pouvez l'utiliser pour récupérer l'historique de vos messages chiffrés.",
"Failed to load group members": "Échec du chargement des membres du groupe"
"Failed to load group members": "Échec du chargement des membres du groupe",
"Failed to invite users to the room:": "Échec de l'invitation d'utilisateurs dans le salon :",
"There was an error joining the room": "Une erreur est survenue en rejoignant le salon",
"You do not have permission to invite people to this room.": "Vous n'avez pas la permission d'envoyer des invitations dans ce salon.",
"User %(user_id)s does not exist": "L'utilisateur %(user_id)s n'existe pas",
"Unknown server error": "Erreur de serveur inconnue",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Afficher un rappel pour activer la récupération de messages sécurisée dans les salons chiffrés",
"Secure Message Recovery": "Récupération de messages sécurisée",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Si vous vous déconnectez ou si vous utilisez un autre appareil, vous perdrez l'historique de vos messages chiffrés. Pour éviter cela, configurez la récupération de messages sécurisée.",
"Don't ask again": "Ne plus me demander",
"Set up": "Configurer",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Si vous ne souhaitez pas que l'historique de vos messages chiffrés soit disponible sur d'autres appareils, <button>désactivez l'option</button>.",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Si vous ne configurez pas la récupération de messages sécurisée, vous perdrez l'historique de vos messages sécurisés quand vous vous déconnectez.",
"If you don't want to set this up now, you can later in Settings.": "Si vous ne voulez pas le configurer maintenant, vous pouvez le faire plus tard dans les paramètres.",
"Messages containing @room": "Messages contenant @room",
"Encrypted messages in one-to-one chats": "Messages chiffrés dans les discussions directes",
"Encrypted messages in group chats": "Messages chiffrés dans les discussions de groupe",
"That doesn't look like a valid email address": "Cela ne ressemble pas à une adresse e-mail valide",
"Only use lower case letters, numbers and '=_-./'": "Utiliser uniquement des lettres minuscules, des chiffres et les symboles =_-./",
"Checking...": "Vérification…",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Configuration non valide : Impossible de fournir une URL de serveur d'accueil par défaut et un nom de serveur par défaut",
"Unknown error discovering homeserver": "Erreur inconnue lors de la découverte du serveur d'accueil",
"%(count)s Notifications|other": "%(count)s notifications",
"%(count)s Notifications|one": "%(count)s notification",
"Invalid identity server discovery response": "Réponse non valide lors de la découverte du serveur d'identité",
"General failure": "Erreur générale",
"Unknown failure discovering homeserver": "Erreur inconnue lors de la découverte du serveur d'accueil",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "La sauvegarde a une signature <validity>valide</validity> depuis un <device>appareil</device> <verify>vérifié</verify>",
"New Recovery Method": "Nouvelle méthode de récupération",
"A new recovery passphrase and key for Secure Messages has been detected.": "Une nouvelle phrase de passe et une nouvelle clé de récupération pour les messages sécurisés ont été détectées.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "La configuration des messages sécurisés sur cet appareil va rechiffrer l'historique des messages de cet appareil avec la nouvelle méthode de récupération.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Si vous n'avez pas activé de nouvelle méthode de récupération, un attaquant essaye peut-être d'accéder à votre compte. Changez immédiatement le mot de passe de votre compte et configurez une nouvelle méthode de récupération dans les paramètres.",
"Set up Secure Messages": "Configurer les messages sécurisés",
"Go to Settings": "Aller aux paramètres",
"Straight rows of keys are easy to guess": "Les suites de touches sont faciles à deviner",
"Short keyboard patterns are easy to guess": "Les répétitions de motif court sur un clavier sont faciles à deviner",
"Custom user status messages": "Messages de statut de l'utilisateur personnalisés",
"Unable to load commit detail: %(msg)s": "Impossible de charger les détails de l'envoi : %(msg)s",
"Set a new status...": "Configurer un nouveau statut…",
"Clear status": "Effacer le statut",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Pour voir votre historique de messages sécurisé et vous assurer que vous pouvez voir les nouveaux messages sur de futurs appareils, configurez la récupération de messages sécurisée.",
"Unrecognised address": "Adresse non reconnue",
"User %(user_id)s may or may not exist": "L'utilisateur %(user_id)s pourrait exister",
"Always invite users which may not exist": "Toujours inviter les utilisateurs qui pourraient ne pas exister",
"The following users may not exist": "Les utilisateurs suivants pourraient ne pas exister",
"The following users may not exist - would you like to invite them anyways?": "Les utilisateurs suivants pourraient ne pas exister. Souhaitez-vous quand même les inviter ?",
"Invite anyways and never warn me again": "Les inviter quand même et ne plus m'avertir",
"Invite anyways": "Les inviter quand même",
"Prompt before sending invites to potentially invalid matrix IDs": "Demander avant d'envoyer des invitations à des identifiants matrix potentiellement non valides",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Impossible de trouver les profils pour les identifiants Matrix listés ci-dessous. Voulez-vous quand même les inviter ?",
"Invite anyway and never warn me again": "Inviter quand même et ne plus me prévenir",
"Invite anyway": "Inviter quand même",
"Waiting for %(userId)s to accept...": "Attente de l'acceptation de %(userId)s…",
"Waiting for %(userId)s to confirm...": "Attente de la confirmation de %(userId)s…"
}

View file

@ -13,7 +13,7 @@
"Whether or not you're logged in (we don't record your user name)": "चाहे आप लॉग इन हों या ना हों( हम आपका खाता नाम दर्ज नहीं करते )",
"Your language of choice": "आपकी चयन की भाषा",
"Which officially provided instance you are using, if any": "क्या आप कोई अधिकृत संस्करण इस्तेमाल कर रहे हैं? अगर हां, तो कौन सा",
"Your homeserver's URL": "आपके होमसर्वर का यू. आर. एल.",
"Your homeserver's URL": "आपके होमसर्वर का यूआरएल",
"Every page you use in the app": "हर पृष्ठ जिसका आप इस एप में इस्तेमाल करते हैं",
"Your User Agent": "आपका उपभोक्ता प्रतिनिधि",
"Custom Server Options": "कस्टम सर्वर विकल्प",
@ -354,5 +354,170 @@
"Unable to fetch notification target list": "अधिसूचना लक्ष्य सूची लाने में असमर्थ",
"Notification targets": "अधिसूचना के लक्ष्य",
"Advanced notification settings": "उन्नत अधिसूचना सेटिंग्स",
"There are advanced notifications which are not shown here": "उन्नत सूचनाएं हैं जो यहां दिखाई नहीं दी गई हैं"
"There are advanced notifications which are not shown here": "उन्नत सूचनाएं हैं जो यहां दिखाई नहीं दी गई हैं",
"Failed to invite users to the room:": "रूम में उपयोगकर्ताओं को आमंत्रित करने में विफल:",
"There was an error joining the room": "रूम में शामिल होने में एक त्रुटि हुई",
"Use a few words, avoid common phrases": "कम शब्दों का प्रयोग करें, सामान्य वाक्यांशों से बचें",
"No need for symbols, digits, or uppercase letters": "प्रतीकों, अंक, या अपरकेस अक्षरों की कोई ज़रूरत नहीं है",
"Use a longer keyboard pattern with more turns": "अधिक मोड़ के साथ एक लंबा कीबोर्ड पैटर्न का प्रयोग करें",
"Avoid repeated words and characters": "दोहराए गए शब्दों और अक्षरो से बचें",
"Avoid sequences": "अनुक्रम से बचें",
"Avoid recent years": "हाल के वर्षों से बचें",
"Avoid years that are associated with you": "आपके साथ जुड़े वर्षों से बचें",
"Avoid dates and years that are associated with you": "आपके साथ जुड़े तिथियों और वर्षों से बचें",
"Capitalization doesn't help very much": "कैपिटलाइजेशन यहाँ ज्यादा मददगार नहीं हैं",
"All-uppercase is almost as easy to guess as all-lowercase": "सभी अपरकेस सभी लोअरकेस के तरह अनुमान लगाने में आसान हैं",
"Reversed words aren't much harder to guess": "उल्टा शब्द अनुमान लगाने के लिए बहुत कठिन नहीं हैं",
"Predictable substitutions like '@' instead of 'a' don't help very much": "'a' के बजाय '@' जैसी अनुमानित प्रतिस्थापन बहुत मदद नहीं करते हैं",
"Add another word or two. Uncommon words are better.": "एक या एक से ज्यादा शब्द जोड़ें। असामान्य शब्द बेहतर हैं।",
"Repeats like \"aaa\" are easy to guess": "\"Aaa\" जैसे आवृत्ति अनुमान लगाना आसान है",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "\"Abcabcabc\" जैसे आवृत्ति \"abc\" से अनुमान लगाने के लिए थोड़ा कठिन है",
"Sequences like abc or 6543 are easy to guess": "abc या 6543 जैसे अनुक्रम अनुमान लगाना आसान है",
"Recent years are easy to guess": "हाल के वर्षों का अनुमान लगाना आसान है",
"Dates are often easy to guess": "तिथियां अक्सर अनुमान लगाने में आसान होती हैं",
"This is a top-10 common password": "यह एक शीर्ष १० सामान्य पासवर्ड में से एक है",
"This is a top-100 common password": "यह एक शीर्ष १०० सामान्य पासवर्ड में से एक है",
"This is a very common password": "यह एक बहुत ही आम पासवर्ड है",
"This is similar to a commonly used password": "यह आमतौर पर इस्तेमाल किए गए पासवर्ड के समान है",
"You do not have permission to invite people to this room.": "आपको इस कमरे में लोगों को आमंत्रित करने की अनुमति नहीं है।",
"User %(user_id)s does not exist": "उपयोगकर्ता %(user_id)s मौजूद नहीं है",
"Unknown server error": "अज्ञात सर्वर त्रुटि",
"A word by itself is easy to guess": "सिर्फ एक शब्द अनुमान लगाना आसान है",
"Names and surnames by themselves are easy to guess": "खुद के नाम और उपनाम अनुमान लगाना आसान है",
"Common names and surnames are easy to guess": "सामान्य नाम और उपनाम अनुमान लगाना आसान है",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "एन्क्रिप्टेड रूम में सुरक्षित संदेश रिकवरी सक्षम करने के लिए एक अनुस्मारक दिखाएं",
"Messages containing @room": "@Room युक्त संदेश",
"Encrypted messages in one-to-one chats": "एक एक के साथ चैट में एन्क्रिप्टेड संदेश",
"Encrypted messages in group chats": "समूह चैट में एन्क्रिप्टेड संदेश",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "बैकअप के पास <verify>सत्यापित</verify> डिवाइस <device></device> से <validity>वैध</validity> हस्ताक्षर है",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "हो सकता है कि आपने उन्हें रायट के अलावा किसी अन्य ग्राहक में कॉन्फ़िगर किया हो। आप उन्हें रायट में ट्यून नहीं कर सकते लेकिन वे अभी भी आवेदन करते हैं",
"Enable desktop notifications": "डेस्कटॉप अधिसूचनाएं सक्षम करें",
"Show message in desktop notification": "डेस्कटॉप अधिसूचना में संदेश दिखाएं",
"Enable audible notifications in web client": "वेब क्लाइंट में श्रव्य अधिसूचनाएं सक्षम करें",
"Off": "बंद",
"On": "चालू",
"Noisy": "शोरगुल",
"Cannot add any more widgets": "विजेट और जोड़ नहीं सकते हैं",
"The maximum permitted number of widgets have already been added to this room.": "इस रूम में विजेट की अधिकतम अनुमत संख्या पहले से ही जोड़ दी गई है।",
"Add a widget": "विजेट जोड़ें",
"Drop File Here": "यहां फ़ाइल ड्रॉप करें",
"Drop file here to upload": "अपलोड करने के लिए यहां फ़ाइल ड्रॉप करें",
" (unsupported)": " (असमर्थित)",
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.": "<VoiceText>आवाज</voiceText> या <videoText>वीडियो</ videoText> के रूप में शामिल हों।",
"Ongoing conference call%(supportedText)s.": "चल रहे सम्मेलन कॉल %(supportedText)s।",
"This event could not be displayed": "यह घटना प्रदर्शित नहीं की जा सकी",
"%(senderName)s sent an image": "%(senderName)s ने एक छवि भेजी",
"%(senderName)s sent a video": "%(senderName)s ने एक वीडियो भेजा",
"%(senderName)s uploaded a file": "%(senderName)s ने एक फाइल अपलोड की",
"Options": "विकल्प",
"Your key share request has been sent - please check your other devices for key share requests.": "आपका कुंजी शेयर अनुरोध भेजा गया है - कृपया कुंजी शेयर अनुरोधों के लिए अपने अन्य डिवाइस देखें।",
"Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "कुंजी शेयर अनुरोध स्वचालित रूप से अपने अन्य उपकरणों के लिए भेजा जाता है। आप को अस्वीकार कर दिया या अपने अन्य उपकरणों पर कुंजी शेयर अनुरोध को खारिज कर दिया है, तो फिर इस सत्र के लिए कुंजी का अनुरोध करने के लिए यहां क्लिक करें।",
"If your other devices do not have the key for this message you will not be able to decrypt them.": "यदि आपके अन्य उपकरणों में इस संदेश की कुंजी नहीं है तो आप उन्हें डिक्रिप्ट करने में सक्षम नहीं होंगे।",
"Key request sent.": "कुंजी अनुरोध भेजा गया।",
"<requestLink>Re-request encryption keys</requestLink> from your other devices.": "अपने अन्य उपकरणों से <requestLink>एन्क्रिप्शन कुंजी का पुन: अनुरोध</requestLink> करें ।",
"Undecryptable": "डिक्रिप्ट करना संभव नहीं",
"Encrypting": "एन्क्रिप्ट किया जा रहा",
"Encrypted, not sent": "एन्क्रिप्ट हो चूका, भेजा नहीं गया",
"Encrypted by a verified device": "एक सत्यापित डिवाइस द्वारा एन्क्रिप्ट किया गया",
"Encrypted by an unverified device": "एक असत्यापित डिवाइस द्वारा एन्क्रिप्ट किया गया",
"Unencrypted message": "बिना एन्क्रिप्ट वाला संदेश",
"Please select the destination room for this message": "कृपया इस संदेश के लिए गंतव्य रूम का चयन करें",
"Blacklisted": "काली सूची में डाला गया",
"Verified": "सत्यापित",
"Unverified": "असत्यापित",
"device id: ": "डिवाइस आईडी: ",
"Disinvite": "आमंत्रित नहीं करना",
"Kick": "किक",
"Disinvite this user?": "इस उपयोगकर्ता को आमंत्रित नहीं करें?",
"Kick this user?": "इस उपयोगकर्ता को किक करें?",
"Failed to kick": "किक करने में विफल",
"Unban": "अप्रतिबंधित करें",
"Ban": "प्रतिबंध",
"Unban this user?": "इस उपयोगकर्ता को अप्रतिबंधित करें?",
"Ban this user?": "इस उपयोगकर्ता को प्रतिबंधित करें?",
"Failed to ban user": "उपयोगकर्ता को प्रतिबंधित करने में विफल",
"Demote yourself?": "खुद को अवनत करें?",
"You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "आप इस बदलाव को पूर्ववत नहीं कर पाएंगे क्योंकि आप स्वयं को अवनत कर रहे हैं, अगर आप रूम में आखिरी विशेषाधिकार प्राप्त उपयोगकर्ता हैं तो विशेषाधिकार हासिल करना असंभव होगा।",
"Demote": "अवनत",
"Failed to mute user": "उपयोगकर्ता को म्यूट करने में विफल",
"Failed to toggle moderator status": "मॉडरेटर स्थिति टॉगल करने में विफल",
"Failed to change power level": "पावर स्तर बदलने में विफल",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "आप इस परिवर्तन को पूर्ववत नहीं कर पाएंगे क्योंकि आप उपयोगकर्ता को अपने आप से समान शक्ति स्तर रखने के लिए प्रोत्साहित कर रहे हैं।",
"Are you sure?": "क्या आपको यकीन है?",
"No devices with registered encryption keys": "पंजीकृत एन्क्रिप्शन कुंजी के साथ कोई डिवाइस नहीं",
"Devices": "उपकरण",
"Unignore": "अनदेखा न करें",
"Ignore": "अनदेखा करें",
"Jump to read receipt": "पढ़ी हुई रसीद में कूदें",
"Mention": "उल्लेख",
"Invite": "आमंत्रण",
"Share Link to User": "उपयोगकर्ता को लिंक साझा करें",
"User Options": "उपयोगकर्ता विकल्प",
"Direct chats": "प्रत्यक्ष चैट",
"Unmute": "अनम्यूट",
"Mute": "म्यूट",
"Revoke Moderator": "मॉडरेटर को रद्द करें",
"Make Moderator": "मॉडरेटर बनायें",
"Admin Tools": "व्यवस्थापक उपकरण",
"Level:": "स्तर:",
"Close": "बंद",
"and %(count)s others...|other": "और %(count)s अन्य ...",
"and %(count)s others...|one": "और एक अन्य...",
"Invited": "आमंत्रित",
"Filter room members": "रूम के सदस्यों को फ़िल्टर करें",
"%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (शक्ति %(powerLevelNumber)s)",
"bold": "बोल्ड",
"italic": "तिरछा",
"deleted": "हटाए गए",
"underlined": "रेखांकित",
"inline-code": "इनलाइन कोड",
"block-quote": "ब्लॉक उद्धरण",
"bulleted-list": "बुलेटेड सूची",
"numbered-list": "गिने-सूची",
"Attachment": "आसक्ति",
"At this time it is not possible to reply with a file so this will be sent without being a reply.": "इस समय फ़ाइल के साथ जवाब देना संभव नहीं है, इसलिए इसे उत्तर दिए बिना भेजा जाएगा।",
"Are you sure you want to upload the following files?": "क्या आप वाकई निम्नलिखित फाइलें अपलोड करना चाहते हैं?",
"The following files cannot be uploaded:": "निम्नलिखित फाइलें अपलोड नहीं की जा सकती हैं:",
"Upload Files": "फाइल अपलोड करें",
"Encrypted room": "एन्क्रिप्टेड रूम",
"Unencrypted room": "अनएन्क्रिप्टेड रूम",
"Hangup": "फोन रख देना",
"Voice call": "आवाज कॉल",
"Video call": "वीडियो कॉल",
"Upload file": "फाइल अपलोड करें",
"Show Text Formatting Toolbar": "टेक्स्ट स्वरूपण टूलबार दिखाएं",
"Send an encrypted reply…": "एक एन्क्रिप्टेड उत्तर भेजें …",
"Send a reply (unencrypted)…": "एक उत्तर भेजें (अनएन्क्रिप्टेड) …",
"Send an encrypted message…": "एक एन्क्रिप्टेड संदेश भेजें …",
"Send a message (unencrypted)…": "एक संदेश भेजें (अनएन्क्रिप्टेड) …",
"This room has been replaced and is no longer active.": "इस रूम को बदल दिया गया है और अब सक्रिय नहीं है।",
"The conversation continues here.": "वार्तालाप यहां जारी है।",
"You do not have permission to post to this room": "आपको इस रूम में पोस्ट करने की अनुमति नहीं है",
"Turn Markdown on": "मार्कडाउन चालू करें",
"Turn Markdown off": "मार्कडाउन बंद करें",
"Hide Text Formatting Toolbar": "टेक्स्ट स्वरूपण टूलबार छुपाएं",
"Server error": "सर्वर त्रुटि",
"Server unavailable, overloaded, or something else went wrong.": "सर्वर अनुपलब्ध, अधिभारित, या कुछ और गलत हो गया।",
"Command error": "कमांड त्रुटि",
"Unable to reply": "उत्तर देने में असमर्थ",
"At this time it is not possible to reply with an emote.": "इस समय एक भावना के साथ जवाब देना संभव नहीं है।",
"Markdown is disabled": "मार्कडाउन अक्षम है",
"Markdown is enabled": "मार्कडाउन सक्षम है",
"No pinned messages.": "कोई पिन संदेश नहीं।",
"Loading...": "लोड हो रहा है...",
"Pinned Messages": "पिन किए गए संदेश",
"Unpin Message": "संदेश अनपिन करें",
"Jump to message": "संदेश पर कूदें",
"%(duration)ss": "%(duration)s सेकंड",
"%(duration)sm": "%(duration)s मिनट",
"%(duration)sh": "%(duration)s घंटा",
"%(duration)sd": "%(duration)s दिन",
"Online for %(duration)s": "%(duration)s के लिए ऑनलाइन",
"Idle for %(duration)s": "%(duration)s के लिए निष्क्रिय",
"Offline for %(duration)s": "%(duration)s के लिए ऑफ़लाइन",
"Unknown for %(duration)s": "%(duration)s के लिए अज्ञात",
"Online": "ऑनलाइन",
"Idle": "निष्क्रिय",
"Offline": "ऑफलाइन",
"Unknown": "अज्ञात"
}

9
src/i18n/strings/hr.json Normal file
View file

@ -0,0 +1,9 @@
{
"This email address is already in use": "Ova email adresa se već koristi",
"This phone number is already in use": "Ovaj broj telefona se već koristi",
"Failed to verify email address: make sure you clicked the link in the email": "Nismo u mogućnosti verificirati Vašu email adresu. Provjerite dali ste kliknuli link u mailu",
"The platform you're on": "Platforma na kojoj se nalazite",
"The version of Riot.im": "Verzija Riot.im",
"Whether or not you're logged in (we don't record your user name)": "Dali ste prijavljeni ili ne (mi ne spremamo Vaše korisničko ime)",
"Your language of choice": "Izabrani jezik"
}

View file

@ -228,7 +228,7 @@
"Joins room with given alias": "A megadott becenévvel belépett a szobába",
"Jump to first unread message.": "Ugrás az első olvasatlan üzenetre.",
"%(senderName)s kicked %(targetName)s.": "%(senderName)s kizárta: %(targetName)s.",
"Kick": "Kirúg",
"Kick": "Elküld",
"Kicks user with given id": "Az adott azonosítójú felhasználó kirúgása",
"Labs": "Labor",
"Last seen": "Utoljára láttuk",
@ -1410,5 +1410,58 @@
"Common names and surnames are easy to guess": "Elterjedt neveket könnyű kitalálni",
"Great! This passphrase looks strong enough.": "Szuper! Ez a jelmondat elég erősnek látszik.",
"As a safety net, you can use it to restore your encrypted message history.": "Használhatod egy biztonsági hálóként a titkosított üzenetek visszaállításához.",
"Failed to load group members": "A közösség tagságokat nem sikerült betölteni"
"Failed to load group members": "A közösség tagságokat nem sikerült betölteni",
"Failed to invite users to the room:": "Felhasználókat nem sikerült meghívni a szobába:",
"You do not have permission to invite people to this room.": "Nincs jogosultságod embereket meghívni ebbe a szobába.",
"User %(user_id)s does not exist": "%(user_id)s felhasználó nem létezik",
"Unknown server error": "Ismeretlen szerver hiba",
"There was an error joining the room": "A szobába való belépésnél hiba történt",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mutass emlékeztetőt a Biztonságos Üzenet Visszaállítás bekapcsolásához a titkosított szobákban",
"Secure Message Recovery": "Biztonságos Üzenet Visszaállítás",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "A titkosított üzeneteidhez nem férsz hozzá ha kijelentkezel vagy másik eszközt használsz. A Biztonságos Üzenet Visszaállítás beállításával ezt elkerülheted.",
"Don't ask again": "Ne kérdezd többet",
"Set up": "Beállítás",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Ha más eszközön nem szeretnél hozzáférni a titkosított üzeneteidhez akkor <button>akkor agyd ezt ki</button>.",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "A Biztonságos Üzenet Visszaállítás beállítása nélkül kijelentkezés után elveszted a hozzáférést a titkosított üzeneteidhez.",
"If you don't want to set this up now, you can later in Settings.": "Ha most nem akarod beállítani, később a Beállításoknál megteheted.",
"Messages containing @room": "Az üzenetek „@room”-ot tartalmaznak",
"Encrypted messages in one-to-one chats": "Titkosított üzenetek közvetlen csevegésekben",
"Encrypted messages in group chats": "Titkosított üzenetek a csoportos beszélgetésekben",
"That doesn't look like a valid email address": "Ez nem úgy néz ki, mint egy érvényes e-mail cím",
"Only use lower case letters, numbers and '=_-./'": "Csak kisbetűket, számokat és „=_-./” jelet használj",
"Checking...": "Ellenőrzés...",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Hibás konfiguráció: Az alapértelmezett Matrix szerver URL és az alapértelmezett szerver név nem tamogatott",
"Unknown error discovering homeserver": "A mátrix szerver felderítésénél ismeretlen hiba történt",
"%(count)s Notifications|other": "%(count)s értesítés",
"%(count)s Notifications|one": "%(count)s értesítés",
"Invalid identity server discovery response": "Azonosító szerver felderítésére érkezett válasz érvénytelen",
"General failure": "Általános hiba",
"Unknown failure discovering homeserver": "Mátrix szerver felderítésénél ismeretlen hiba történt",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "A mentésnek <verify>ellenőrzött</verify> eszköztől <device></device> származó <validity>érvényes</validity> aláírása van",
"New Recovery Method": "Új Visszaállítási Eljárás",
"A new recovery passphrase and key for Secure Messages has been detected.": "Biztonságos Üzenetekhez való új visszaállítási jelmondatot és kulcsot találtunk.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "A Biztonságos Üzenetek ezen az eszközön való beállításával az új visszaállítási eljárással lesznek újra titkosítva a régi üzenetek.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Ha nem te állítottad be a visszaállítási eljárást akkor lehet, hogy egy támadó próbálja elérni a fiókodat. Változtasd meg a fiókod jelszavát és állítsd be az új visszaállítási eljárást a Beállításokban amint lehet.",
"Set up Secure Messages": "Biztonságos Üzenetek beállítása",
"Go to Settings": "Irány a Beállítások",
"Straight rows of keys are easy to guess": "A billentyű sorokat könnyű kitalálni",
"Short keyboard patterns are easy to guess": "Rövid billentyűzet sormintát könnyű kitalálni",
"Custom user status messages": "Egyedi felhasználói állapot üzenet",
"Set a new status...": "Új állapot beállítása...",
"Clear status": "Állapot törlése",
"Unable to load commit detail: %(msg)s": "Sikertelen betöltés részletek: \n%(msg)s",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Ahhoz, hogy a múltbeli titkosított üzeneteidet és az újakat a leendő eszközeiden láthasd, állítsd be a Biztonságos Üzenet Visszaállítást.",
"Unrecognised address": "Ismeretlen cím",
"User %(user_id)s may or may not exist": "%(user_id)s felhasználó lehet, hogy nem létezik",
"Always invite users which may not exist": "Valószínűleg nem létező felhasználókat is meghívhat",
"The following users may not exist": "Az alábbi felhasználók lehet, hogy nem léteznek",
"The following users may not exist - would you like to invite them anyways?": "Az alábbi felhasználók lehet, hogy nem léteznek - mégis meghívod őket?",
"Invite anyways and never warn me again": "Mindig meghívom és többet nem kérek figyelmeztetést",
"Invite anyways": "Mindig meghív",
"Waiting for %(userId)s to accept...": "Várakozás %(userId)s felhasználóra, hogy elfogadja...",
"Waiting for %(userId)s to confirm...": "Várakozás %(userId)s felhasználóra, hogy megerősítse...",
"Prompt before sending invites to potentially invalid matrix IDs": "Vélhetően hibás matrix ID-kra való meghívó küldés előtt figyelmeztessen",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Az alábbi Matrix ID-koz nem sikerül megtalálni a profilokat - így is meghívod őket?",
"Invite anyway and never warn me again": "Mindenképpen meghív és ne figyelmeztess többet",
"Invite anyway": "Mindenképpen meghív"
}

View file

@ -81,8 +81,8 @@
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s",
"Register": "Registrati",
"Rooms": "Stanze",
"The remote side failed to pick up": "Il destinatario non ha risposto",
"Unable to capture screen": "Impossibile acquisire lo schermo",
"The remote side failed to pick up": "Dall'altro lato non è giunta risposta",
"Unable to capture screen": "Impossibile catturare la schermata",
"Call": "Chiama",
"Answer": "Rispondi",
"Invite to Community": "Invita alla community",
@ -101,13 +101,13 @@
"Your identity server's URL": "L'URL del tuo server identità",
"Analytics": "Statistiche",
"The information being sent to us to help make Riot.im better includes:": "Le informazioni inviate per aiutarci a migliorare Riot.im includono:",
"Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Se questa pagina include informazioni identificabili, come una stanza, utente o ID di gruppo, questi dati sono rimossi prima che vengano inviati al server.",
"Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Se questa pagina include informazioni identificabili, come una stanza, un utente o un ID di un gruppo, tali dati saranno rimossi prima di essere inviati al server.",
"Call Failed": "Chiamata fallita",
"There are unknown devices in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "Ci sono dispositivi sconosciuti in questa stanza: se procedi senza verificarli, qualcuno avrà la possibilità di intercettare la tua chiamata.",
"Review Devices": "Revisiona i dispositivi",
"Review Devices": "Controlla i dispositivi",
"Call Anyway": "Chiama comunque",
"Answer Anyway": "Rispondi comunque",
"Call Timeout": "Scadenza chiamata",
"Call Timeout": "Tempo di attesa della chiamata",
"Existing Call": "Chiamata esistente",
"You are already in a call.": "Partecipi già ad una chiamata.",
"Conference calling is in development and may not be reliable.": "Le chiamate di gruppo sono in sviluppo e potrebbero essere inaffidabili.",
@ -599,7 +599,7 @@
"Communities": "Comunità",
"Home": "Inizio",
"Integrations Error": "Errore di integrazioni",
"Could not connect to the integration server": "Impossibile connettere al server di integrazione",
"Could not connect to the integration server": "Impossibile connettersi al server di integrazione",
"Manage Integrations": "Gestisci integrazioni",
"%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s",
"%(severalUsers)sjoined %(count)s times|other": "%(severalUsers)ssono entrati %(count)s volte",
@ -1196,11 +1196,11 @@
"No Audio Outputs detected": "Nessuna uscita audio rilevata",
"Audio Output": "Uscita audio",
"Try the app first": "Prova prima l'app",
"A conference call could not be started because the intgrations server is not available": "La chiamata di gruppo non può essere iniziata perchè il server di integrazione non è disponibile",
"A conference call could not be started because the intgrations server is not available": "La chiamata di gruppo non può essere avviata perché il server di integrazione non è disponibile",
"Call in Progress": "Chiamata in corso",
"A call is already in progress!": "Una chiamata è già in corso!",
"Permission Required": "Permesso richiesto",
"You do not have permission to start a conference call in this room": "Non hai il permesso di iniziare una chiamata di gruppo in questa stanza",
"You do not have permission to start a conference call in this room": "Non hai il permesso di avviare una chiamata di gruppo in questa stanza",
"Jitsi Conference Calling": "Chiamata di gruppo Jitsi",
"Show empty room list headings": "Mostra le intestazioni dell'elenco delle stanze vuote",
"This event could not be displayed": "Questo evento non può essere mostrato",
@ -1220,7 +1220,7 @@
"The phone number field must not be blank.": "Il campo telefono non deve essere vuoto.",
"The password field must not be blank.": "Il campo passwordl non deve essere vuoto.",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Non è possibile inviare alcun messaggio fino a quando non si esaminano e si accettano <consentLink> i nostri termini e condizioni </ permissionLink>.",
"A call is currently being placed!": "Attualmente è in corso una chiamata!",
"A call is currently being placed!": "Attualmente c'è una chiamata in corso!",
"System Alerts": "Avvisi di sistema",
"This homeserver has hit its Monthly Active User limit. Please <a>contact your service administrator</a> to continue using the service.": "L'homeserver ha raggiunto il suo limite di utenti attivi mensili. <a>Contatta l'amministratore del servizio</a> per continuare ad usarlo.",
"This homeserver has hit its Monthly Active User limit so some users will not be able to log in. Please <a>contact your service administrator</a> to get this limit increased.": "Questo homeserver ha raggiunto il suo limite di utenti attivi mensili, perciò alcuni utenti non potranno accedere. <a>Contatta l'amministratore del servizio</a> per fare aumentare questo limite.",
@ -1297,5 +1297,155 @@
"Add some now": "Aggiungine ora",
"You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Sei un amministratore di questa comunità. Non potrai rientrare senza un invito da parte di un altro amministratore.",
"Open Devtools": "Apri Devtools",
"Show developer tools": "Mostra strumenti sviluppatore"
"Show developer tools": "Mostra strumenti sviluppatore",
"Unable to load! Check your network connectivity and try again.": "Impossibile caricare! Controlla la tua connessione di rete e riprova.",
"Failed to invite users to the room:": "Impossibile invitare gli utenti nella stanza:",
"There was an error joining the room": "Si è verificato un errore entrando nella stanza",
"Use a few words, avoid common phrases": "Usa poche parole, evita frasi comuni",
"No need for symbols, digits, or uppercase letters": "Non sono necessari simboli, numeri o maiuscole",
"Use a longer keyboard pattern with more turns": "Usa una tastiera più lunga con più variazioni",
"Avoid repeated words and characters": "Evita ripetizioni di parole e caratteri",
"Avoid sequences": "Evita sequenze",
"Avoid recent years": "Evita anni recenti",
"Avoid years that are associated with you": "Evita anni che sono associati a te",
"Avoid dates and years that are associated with you": "Evita date e anni che sono associati a te",
"Capitalization doesn't help very much": "Le maiuscole non aiutano molto",
"All-uppercase is almost as easy to guess as all-lowercase": "Tutte maiuscole è altrettanto facile da indovinare come tutte minuscole",
"Reversed words aren't much harder to guess": "Le parole invertite non sono molto più difficili da indovinare",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Sostituzioni prevedibili come '@' al posto di 'a' non aiutano molto",
"Add another word or two. Uncommon words are better.": "Aggiungi ancora una o due parole. Meglio parole non comuni.",
"Repeats like \"aaa\" are easy to guess": "Ripetizioni come \"aaa\" sono facili da indovinare",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Ripetizioni come \"abcabcabc\" sono solo leggermente più difficili da indovinare di \"abc\"",
"Sequences like abc or 6543 are easy to guess": "Sequenze come abc o 6543 sono facili da indovinare",
"Recent years are easy to guess": "Gli anni recenti sono facili da indovinare",
"Dates are often easy to guess": "Le date sono spesso facili da indovinare",
"This is a top-10 common password": "Queste sono le 10 password più comuni",
"This is a top-100 common password": "Queste sono le 100 password più comuni",
"This is a very common password": "Questa è una password molto comune",
"This is similar to a commonly used password": "Questa è simile a una password usata comunemente",
"A word by itself is easy to guess": "Una parola di per sé è facile da indovinare",
"Names and surnames by themselves are easy to guess": "Nomi e cognomi di per sé sono facili da indovinare",
"Common names and surnames are easy to guess": "Nomi e cognomi comuni sono facili da indovinare",
"You do not have permission to invite people to this room.": "Non hai l'autorizzazione di invitare persone in questa stanza.",
"User %(user_id)s does not exist": "L'utente %(user_id)s non esiste",
"Unknown server error": "Errore sconosciuto del server",
"Backup of encryption keys to server": "Backup delle chiavi di cifratura nel server",
"Delete Backup": "Elimina backup",
"Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Eliminare il backup delle tue chiavi di cifratura dal server? Non potrai più usare la chiave di ripristino per leggere la cronologia dei messaggi cifrati",
"Delete backup": "Elimina backup",
"Unable to load key backup status": "Impossibile caricare lo stato del backup delle chiavi",
"This device is uploading keys to this backup": "Questo dispositivo sta inviando le chiavi a questo backup",
"This device is <b>not</b> uploading keys to this backup": "Questo dispositivo <b>non</b> sta inviando le chiavi a questo backup",
"Backup has a <validity>valid</validity> signature from this device": "Il backup ha una firma <validity>valida</validity> da questo dispositivo",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device>x</device>": "Il backup ha una firma <validity>valida</validity> dal dispositivo <verify>verificato</verify> <device>x</device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Il backup ha una firma <validity>valida</validity> dal dispositivo <verify>non verificato</verify> <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Il backup ha una firma <validity>non valida</validity> dal dispositivo <verify>verificato</verify> <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Il backup ha una firma <validity>non valida</validity> dal dispositivo <verify>non verificato</verify> <device></device>",
"Backup is not signed by any of your devices": "Il backup non è firmato da alcun tuo dispositivo",
"Backup version: ": "Versione backup: ",
"Algorithm: ": "Algoritmo: ",
"Restore backup": "Ripristina backup",
"No backup is present": "Nessun backup presente",
"Start a new backup": "Avvia un nuovo backup",
"The following files cannot be uploaded:": "I seguenti file non possono essere inviati:",
"Please review and accept all of the homeserver's policies": "Si prega di rivedere e accettare tutte le politiche dell'homeserver",
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Per evitare di perdere la cronologia della chat, devi esportare le tue chiavi della stanza prima di uscire. Dovrai tornare alla versione più recente di Riot per farlo",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Hai usato in precedenza una versione più recente di Riot su %(host)s. Per usare di nuovo questa versione con cifratura end-to-end, dovrai disconnettere e riaccedere. ",
"Incompatible Database": "Database non compatibile",
"Continue With Encryption Disabled": "Continua con la cifratura disattivata",
"Unable to load backup status": "Impossibile caricare lo stato del backup",
"Unable to restore backup": "Impossibile ripristinare il backup",
"No backup found!": "Nessun backup trovato!",
"Backup Restored": "Backup ripristinato",
"Failed to decrypt %(failedCount)s sessions!": "Decifrazione di %(failedCount)s sessioni fallita!",
"Restored %(sessionCount)s session keys": "Ripristinate le chiavi di %(sessionCount)s sessioni",
"Enter Recovery Passphrase": "Inserisci la password di recupero",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Accedi alla cronologia sicura dei messaggi e imposta la messaggistica sicura inserendo la tua password di recupero.",
"Next": "Prossimo",
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "Se hai dimenticato la password di recupero puoi <button1>usare la tua chiave di recupero</button1> o <button2>impostare nuove opzioni di recupero</button2>",
"Enter Recovery Key": "Inserisci la chiave di recupero",
"This looks like a valid recovery key!": "Sembra essere una chiave di recupero valida!",
"Not a valid recovery key": "Non è una chiave di recupero valida",
"Access your secure message history and set up secure messaging by entering your recovery key.": "Accedi alla cronologia sicura dei messaggi e imposta la messaggistica sicura inserendo la tua chiave di recupero.",
"If you've forgotten your recovery passphrase you can <button>set up new recovery options</button>": "Se hai dimenticato la password di recupero puoi <button>impostare nuove opzioni di recupero</button>",
"Failed to load group members": "Caricamento membri del gruppo fallito",
"You are currently using Riot anonymously as a guest.": "Attualmente stai usando Riot in modo anonimo come ospite.",
"If you would like to create a Matrix account you can <a>register</a> now.": "Se vuoi creare un account Matrix puoi <a>registrarti</a> adesso.",
"File is too big. Maximum file size is %(fileSize)s": "File troppo grande. La dimensione massima è %(fileSize)s",
"Key Backup": "Backup chiave",
"Failed to perform homeserver discovery": "Ricerca dell'homeserver fallita",
"Invalid homeserver discovery response": "Risposta della ricerca homeserver non valida",
"Cannot find homeserver": "Impossibile trovare l'homeserver",
"Sign in with single sign-on": "Accedi con single sign-on",
"Great! This passphrase looks strong enough.": "Ottimo! Questa password sembra abbastanza forte.",
"Secure your encrypted message history with a Recovery Passphrase.": "Proteggi la cronologia dei messaggi cifrati con una password di recupero.",
"You'll need it if you log out or lose access to this device.": "Ti servirà se ti disconnetti o perdi l'accesso a questo dispositivo.",
"Enter a passphrase...": "Inserisci una password...",
"If you don't want encrypted message history to be availble on other devices, <button>opt out</button>.": "Se non vuoi che la cronologia dei messaggi cifrati sia disponibile su altri dispositivi, <button>rifiuta</button>.",
"Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.": "Oppure, se non vuoi creare una password di recupero, salta questo passo e <button>scarica una chiave di recupero</button>.",
"That matches!": "Corrisponde!",
"That doesn't match.": "Non corrisponde.",
"Go back to set it again.": "Torna per reimpostare.",
"Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Digita la tua password di recupero per confermare che la ricordi. Se aiuta, aggiungila al tuo gestore di password o conservarla in un luogo sicuro.",
"Repeat your passphrase...": "Ripeti la password...",
"As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Come rete di sicurezza, puoi usarla per ripristinare la cronologia dei messaggi cifrati se dimentichi la password di recupero.",
"As a safety net, you can use it to restore your encrypted message history.": "Come rete di sicurezza, puoi usarla per ripristinare la cronologia dei messaggi cifrati.",
"Make a copy of this Recovery Key and keep it safe.": "Fai una copia di questa password di recupero e tienila al sicuro.",
"Your Recovery Key": "La tua chiave di recupero",
"Copy to clipboard": "Copia negli appunti",
"Download": "Scarica",
"I've made a copy": "Ho fatto una copia",
"Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:": "La tua chiave di recupero è stata <b>copiata negli appunti</b>, incollala in:",
"Your Recovery Key is in your <b>Downloads</b> folder.": "La tua chiave di recupero è nella cartella <b>Download</b>.",
"<b>Print it</b> and store it somewhere safe": "<b>Stampala</b> e conservala in un luogo sicuro",
"<b>Save it</b> on a USB key or backup drive": "<b>Salvala</b> in una chiave USB o disco di backup",
"<b>Copy it</b> to your personal cloud storage": "<b>Copiala</b> nel tuo archivio cloud personale",
"Got it": "Capito",
"Backup created": "Backup creato",
"Your encryption keys are now being backed up to your Homeserver.": "Le chiavi di cifratura vengono ora salvate sul tuo homeserver.",
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Senza impostare un ripristino sicuro dei messaggi, non potrai ripristinare la cronologia dei messaggi cifrati se ti disconnetti o utilizzi un altro dispositivo.",
"Set up Secure Message Recovery": "Imposta ripristino sicuro dei messaggi",
"Create a Recovery Passphrase": "Crea una password di recupero",
"Confirm Recovery Passphrase": "Conferma la password di recupero",
"Recovery Key": "Chiave di recupero",
"Keep it safe": "Tienila al sicuro",
"Backing up...": "Backup...",
"Create Key Backup": "Crea backup chiave",
"Unable to create key backup": "Impossibile creare backup della chiave",
"Retry": "Riprova",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mostra un promemoria per attivare il ripristino sicuro dei messaggi nelle stanze cifrate",
"Secure Message Recovery": "Ripristino sicuro dei messaggi",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Se ti disconnetti o usi un altro dispositivo, perderai la cronologia sicura dei messaggi. Per evitare che accada, imposta il ripristino sicuro dei messaggi.",
"Don't ask again": "Non chiedere più",
"Set up": "Imposta",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Se non vuoi che la cronologia dei messaggi cifrati sia disponibile su altri dispositivi, <button>rifiuta</button>.",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Se non imposti il ripristino sicuro dei messaggi, perderai la cronologia sicura dei messaggi quando ti disconnetti.",
"If you don't want to set this up now, you can later in Settings.": "Se non vuoi impostarlo ora, è possibile farlo in seguito nelle impostazioni.",
"Messages containing @room": "Messaggi contenenti @room",
"Encrypted messages in one-to-one chats": "Messaggi cifrati in chat uno-ad-uno",
"Encrypted messages in group chats": "Messaggi cifrati in chat di gruppo",
"That doesn't look like a valid email address": "Non sembra essere un indirizzo email valido",
"Only use lower case letters, numbers and '=_-./'": "Usa solo lettere minuscole, numeri e '=_-./'",
"Checking...": "Controllo...",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Configurazione non valida: impossibile fornire un URL di homeserver e un nome server predefiniti",
"Unknown error discovering homeserver": "Errore sconosciuto cercando gli homeserver",
"%(count)s Notifications|other": "%(count)s notifiche",
"%(count)s Notifications|one": "%(count)s notifica",
"Invalid identity server discovery response": "Risposta non valida cercando server di identità",
"General failure": "Guasto generale",
"Unknown failure discovering homeserver": "Errore sconosciuto cercando homeserver",
"Straight rows of keys are easy to guess": "Sequenze di tasti in riga sono facili da indovinare",
"Short keyboard patterns are easy to guess": "Sequenze di tasti brevi sono facili da indovinare",
"Custom user status messages": "Messaggi di stato utente personalizzati",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Il backup ha una firma <validity>valida</validity> dal dispositivo <verify>verificato</verify> <device></device>",
"Unable to load commit detail: %(msg)s": "Caricamento dettagli del commit fallito: %(msg)s",
"Set a new status...": "Imposta un nuovo stato...",
"Clear status": "Elimina stato",
"New Recovery Method": "Nuovo metodo di recupero",
"A new recovery passphrase and key for Secure Messages has been detected.": "Sono state rilevate una nuova password e chiave di recupero per messaggi sicuri.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Impostare i messaggi sicuri su questo dispositivo cripterà di nuovo la cronologia dei messaggi con il nuovo metodo di recupero.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se non hai impostato il nuovo metodo di recupero, un aggressore potrebbe tentare di accedere al tuo account. Cambia la password del tuo account e imposta immediatamente un nuovo metodo di recupero nelle impostazioni.",
"Set up Secure Messages": "Imposta i messaggi sicuri",
"Go to Settings": "Vai alle impostazioni",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Per vedere la tua cronologia di messaggi sicura e assicurarti di poter vedere nuovi messaggi in dispositivi futuri, imposta il Ripristino Sicuro dei Messaggi."
}

View file

@ -883,5 +883,113 @@
"Disinvite": "Atšaukti pakvietimą",
"Disinvite this user?": "Atšaukti pakvietimą šiam naudotojui?",
"Unknown for %(duration)s": "Nežinoma jau %(duration)s",
"(warning: cannot be disabled again!)": "(įspėjimas: nebeįmanoma bus išjungti!)"
"(warning: cannot be disabled again!)": "(įspėjimas: nebeįmanoma bus išjungti!)",
"Unable to load! Check your network connectivity and try again.": "Nepavyko įkelti! Patikrinkite savo tinklo ryšį ir bandykite dar kartą.",
"%(targetName)s joined the room.": "%(targetName)s atėjo į kambarį.",
"User %(user_id)s does not exist": "Naudotojo %(user_id)s nėra",
"Unknown server error": "Nežinoma serverio klaida",
"Avoid sequences": "Venkite sekų",
"Avoid recent years": "Venkite paskiausių metų",
"Avoid years that are associated with you": "Venkite su jumis susijusių metų",
"Avoid dates and years that are associated with you": "Venkite su jumis susijusių metų ir datų",
"Capitalization doesn't help very much": "Rašymas didžiosiomis raidėmis nelabai padeda",
"All-uppercase is almost as easy to guess as all-lowercase": "Visas didžiąsias raides taip pat lengva atspėti kaip ir visas mažąsias",
"Reversed words aren't much harder to guess": "Žodžius atvirkštine tvarka nėra sunkiau atspėti",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Nuspėjami pakaitalai, tokie kaip \"@\" vietoj \"a\", nelabai padeda",
"Add another word or two. Uncommon words are better.": "Pridėkite dar vieną žodį ar du. Geriau nedažnai vartojamus žodžius.",
"Repeats like \"aaa\" are easy to guess": "Tokius pasikartojimus kaip \"aaa\" yra lengva atspėti",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Tokius pasikartojimus kaip \"abcabcabc\" yra tik truputėlį sunkiau atspėti nei \"abc\"",
"Sequences like abc or 6543 are easy to guess": "Tokias sekas kaip \"abc\" ar \"6543\" yra lengva atspėti",
"Recent years are easy to guess": "Paskiausius metus yra lengva atspėti",
"Dates are often easy to guess": "Datas, dažniausiai, yra lengva atspėti",
"This is a top-10 common password": "Tai yra vienas iš 10 dažniausiai naudojamų slaptažodžių",
"This is a top-100 common password": "Tai yra vienas iš 100 dažniausiai naudojamų slaptažodžių",
"This is a very common password": "Tai yra labai dažnai naudojamas slaptažodis",
"This is similar to a commonly used password": "Šis yra panašus į dažnai naudojamą slaptažodį",
"A word by itself is easy to guess": "Patį žodį savaime yra lengva atspėti",
"Names and surnames by themselves are easy to guess": "Pačius vardus ar pavardes yra lengva atspėti",
"Common names and surnames are easy to guess": "Dažnai naudojamus vardus ar pavardes yra lengva atspėti",
"Straight rows of keys are easy to guess": "Klavišų eilę yra lengva atspėti",
"Short keyboard patterns are easy to guess": "Trumpus klaviatūros šablonus yra lengva atspėti",
"Avoid repeated words and characters": "Venkite pasikartojančių žodžių ir simbolių",
"Use a few words, avoid common phrases": "Naudokite kelis žodžius, venkite dažnai naudojamų frazių",
"No need for symbols, digits, or uppercase letters": "Nereikia simbolių, skaitmenų ar didžiųjų raidžių",
"Encrypted messages in group chats": "Šifruotos žinutės grupės pokalbiuose",
"Delete Backup": "Ištrinti atsarginę kopiją",
"Delete backup": "Ištrinti atsarginę kopiją",
"Backup version: ": "Atsarginės kopijos versija: ",
"Algorithm: ": "Algoritmas: ",
"Restore backup": "Atkurti atsarginę kopiją",
"No backup is present": "Nėra jokios atsarginės kopijos",
"Don't ask again": "Daugiau nebeklausti",
"Set up": "Nustatyti",
"Publish this room to the public in %(domain)s's room directory?": "Paskelbti šį kambarį į viešąjį %(domain)s kambarių katalogą?",
"Start authentication": "Pradėti tapatybės nustatymą",
"Failed to load group members": "Nepavyko įkelti grupės dalyvių",
"Integrations Error": "Integracijų klaida",
"Manage Integrations": "Tvarkyti integracijas",
"Matrix Room ID": "Matrix kambario ID",
"That doesn't look like a valid email address": "Tai nepanašu į teisingą el. pašto adresą",
"Preparing to send logs": "Ruošiamasi išsiųsti žurnalus",
"Notes:": "Pastabos:",
"Incompatible Database": "Nesuderinama duomenų bazė",
"Deactivate Account": "Pasyvinti paskyrą",
"I verify that the keys match": "Aš patvirtinu, kad raktai sutampa",
"Incompatible local cache": "Nesuderinamas vietinis podėlis",
"Updating Riot": "Atnaujinama Riot",
"This doesn't appear to be a valid email address": "Tai nepanašu į teisingą el. pašto adresą",
"Unable to add email address": "Nepavyko pridėti el. pašto adreso",
"Unable to verify email address.": "Nepavyko patvirtinti el. pašto adreso.",
"This will allow you to reset your password and receive notifications.": "Tai jums leis atstatyti savo slaptažodį ir gauti pranešimus.",
"Skip": "Praleisti",
"Username not available": "Naudotojo vardas neprieinamas",
"Username invalid: %(errMessage)s": "Neteisingas naudotojo vardas: %(errMessage)s",
"An error occurred: %(error_string)s": "Įvyko klaida: %(error_string)s",
"Checking...": "Tikrinama...",
"Username available": "Naudotojo vardas yra prieinamas",
"To get started, please pick a username!": "Norėdami pradėti, pasirinkite naudotojo vardą!",
"If you already have a Matrix account you can <a>log in</a> instead.": "Jeigu jau turite Matrix paskyrą, tuomet vietoj to, galite <a>prisijungti</a>.",
"Room contains unknown devices": "Kambaryje yra nežinomų įrenginių",
"\"%(RoomName)s\" contains devices that you haven't seen before.": "Kambaryje \"%(RoomName)s\" yra jums anksčiau nematytų įrenginių.",
"Unknown devices": "Nežinomi įrenginiai",
"Unable to restore backup": "Nepavyko atkurti atsarginės kopijos",
"No backup found!": "Nerasta jokios atsarginės kopijos!",
"Backup Restored": "Atsarginė kopija atkurta",
"Failed to decrypt %(failedCount)s sessions!": "Nepavyko iššifruoti %(failedCount)s seansų!",
"Next": "Kitas",
"Private Chat": "Privatus pokalbis",
"Public Chat": "Viešas pokalbis",
"Topic": "Tema",
"There are no visible files in this room": "Šiame kambaryje nėra matomų failų",
"Add a Room": "Pridėti kambarį",
"Add a User": "Pridėti naudotoją",
"Long Description (HTML)": "Ilgasis aprašas (HTML)",
"Description": "Aprašas",
"Community %(groupId)s not found": "Bendruomenė %(groupId)s nerasta",
"Failed to load %(groupId)s": "Nepavyko įkelti%(groupId)s",
"You are currently using Riot anonymously as a guest.": "Šiuo metu naudojate Riot anonimiškai, kaip svečias.",
"Signed Out": "Atsijungta",
"For security, this session has been signed out. Please sign in again.": "Saugumo sumetimais, šis seansas buvo atjungtas. Prisijunkite dar kartą.",
"Your Communities": "Jūsų bendruomenės",
"Create a new community": "Sukurti naują bendruomenę",
"You have no visible notifications": "Jūs neturite matomų pranešimų",
"%(count)s Notifications|one": "%(count)s pranešimas",
"Message not sent due to unknown devices being present": "Žinutė neišsiųsta dėl to, kad yra nežinomų įrenginių",
"File is too big. Maximum file size is %(fileSize)s": "Failas yra per didelis. Didžiausias failo dydis yra %(fileSize)s",
"Submit Debug Logs": "Pateikti derinimo žurnalus",
"Failed to perform homeserver discovery": "Nepavyko atlikti namų serverio aptikimo",
"Unknown failure discovering homeserver": "Nežinoma nesėkmė aptinkant namų serverį",
"Error: Problem communicating with the given homeserver.": "Klaida: Problemos susisiekiant su nurodytu namų serveriu.",
"This server does not support authentication with a phone number.": "Šis serveris nepalaiko tapatybės nustatymo telefono numeriu.",
"An email address is required to register on this homeserver.": "Norint užsiregistruoti šiame namų serveryje, reikalingas el. pašto adresas.",
"A phone number is required to register on this homeserver.": "Norint užsiregistruoti šiame namų serveryje, reikalingas telefono numeris.",
"Great! This passphrase looks strong enough.": "Puiku! Ši slaptafrazė atrodo pakankamai stipri.",
"Your Recovery Key": "Jūsų atkūrimo raktas",
"Copy to clipboard": "Kopijuoti į iškarpinę",
"Download": "Atsisiųsti",
"I've made a copy": "Aš pasidariau kopiją",
"Got it": "Supratau",
"Backup created": "Atsarginė kopija sukurta",
"Recovery Key": "Atkūrimo raktas",
"Retry": "Bandyti dar kartą"
}

View file

@ -1141,7 +1141,7 @@
"Export E2E room keys": "Hent E2E-romnyklar ut",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Det kan henda at du stilte dei inn på ein annan klient enn Riot. Du kan ikkje stilla på dei i Riot men dei gjeld framleis",
"Key share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, click here to request the keys for this session again.": "Nykeldelingsførespurnader vert sende til dei andre einingane dine av seg sjølv. Viss du sa nei til eller avviste førespurnadene på dei andre einingane, klikk her for å beda om nyklane for denne øykta på nytt.",
"Jump to read receipt": "Hopp til lest-lappen",
"Jump to read receipt": "Hopp til lesen-lappen",
"Filter room members": "Filtrer rommedlemer",
"inline-code": "kode-i-tekst",
"block-quote": "blokk-sitat",
@ -1210,7 +1210,7 @@
"Failed to set direct chat tag": "Fekk ikkje til å setja direktesamtale-merke",
"Failed to remove tag %(tagName)s from room": "Fekk ikkje til å fjerna merket %(tagName)s frå rommet",
"Failed to add tag %(tagName)s to room": "Fekk ikkje til å leggja merket %(tagName)s til i rommet",
"Hide read receipts": "Gøym lest-lappar",
"Hide read receipts": "Gøym lesen-lappar",
"For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "Av sikkerheitsmessige grunnar vil det å logga ut sletta alle ende-til-ende-krypteringsnyklar frå nettlesaren. Viss du vil kunna dekryptera samtalehistoria di på framtidige Riot-øykter, ver venleg og hent ut romnyklande dine og tak vare på dei.",
"This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "Dette tillèt deg å henta nyklane for meldingar du har sendt i krypterte rom ut til ei lokal fil. Då kan du henta fila inn til ein annan Matrix-klient i framtida, slik at den klienten òg kan dekryptera meldingane.",
"The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "Å henta filen ut tillèt kven som helst som kan lesa ho å dekryptera alle krypterte meldingar du kan sjå, so du bør passa på å halda ho trygg. For å hjelpa til med dette bør du skriva ei passetning inn i feltet under, som vil brukast til å kryptere den uthenta dataen. Det vil berre vera mogeleg å henta dataen inn med den same passetninga.",

View file

@ -170,7 +170,7 @@
"Conference calls are not supported in this client": "Połączenia konferencyjne nie są obsługiwane w tym kliencie",
"Could not connect to the integration server": "Nie można połączyć się z serwerem integracji",
"Create a new chat or reuse an existing one": "Utwórz nowy czat lub użyj istniejącego",
"Curve25519 identity key": "Curve25519 klucz tożsamości",
"Curve25519 identity key": "Klucz tożsamości Curve25519",
"Custom": "Własny",
"Custom level": "Własny poziom",
"/ddg is not a command": "/ddg nie jest poleceniem",
@ -195,7 +195,7 @@
"Displays action": "Wyświetlane akcje",
"Do you want to load widget from URL:": "Czy chcesz załadować widżet z adresu:",
"Don't send typing notifications": "Nie wysyłaj powiadomienia o pisaniu",
"Download %(text)s": "Pobrano %(text)s",
"Download %(text)s": "Pobierz %(text)s",
"Drop File Here": "Upuść plik tutaj",
"Drop here to tag %(section)s": "Upuść tutaj by oznaczyć %(section)s",
"Ed25519 fingerprint": "Odcisk Ed25519",
@ -279,7 +279,7 @@
"Invalid file%(extra)s": "Nieprawidłowy plik %(extra)s",
"%(senderName)s invited %(targetName)s.": "%(senderName)s zaprosił %(targetName)s.",
"Invite new room members": "Zaproś nowych członków do pokoju",
"Invited": "Zaproszony",
"Invited": "Zaproszeni",
"Invites": "Zaproszenia",
"Invites user with given id to current room": "Zaprasza użytkownika o danym ID do obecnego pokoju",
"'%(alias)s' is not a valid format for an address": "'%(alias)s' nie jest poprawnym formatem adresu",
@ -295,7 +295,7 @@
"Kick": "Wyrzuć",
"Kicks user with given id": "Wyrzuca użytkownika o danym ID",
"Labs": "Laboratoria",
"Last seen": "Ostatnio widziany",
"Last seen": "Ostatnio widziany(-a)",
"Leave room": "Opuść pokój",
"%(targetName)s left the room.": "%(targetName)s opuścił pokój.",
"Level:": "Poziom:",
@ -304,9 +304,9 @@
"Logged in as:": "Zalogowany jako:",
"Logout": "Wyloguj",
"Low priority": "Niski priorytet",
"%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich zaproszenia.",
"%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich dołączenia.",
"%(senderName)s made future room history visible to all room members.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju.",
"%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s uczynił(a) przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich zaproszenia.",
"%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s uczynił(a) przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju, od momentu ich dołączenia.",
"%(senderName)s made future room history visible to all room members.": "%(senderName)s uczynił(a) przyszłą historię pokoju widoczną dla wszyscy członkowie pokoju.",
"%(senderName)s made future room history visible to anyone.": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla kazdego.",
"%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s uczynił przyszłą historię pokoju widoczną dla nieznany (%(visibility)s).",
"Manage Integrations": "Zarządzaj integracjami",
@ -335,7 +335,7 @@
"AM": "AM",
"PM": "PM",
"NOT verified": "NIEzweryfikowany",
"NOTE: Apps are not end-to-end encrypted": "UWAGA: Aplikacje nie są szyfrowane metodą użytkownik-użytkownik",
"NOTE: Apps are not end-to-end encrypted": "UWAGA: Aplikacje nie są szyfrowane metodą end-to-end",
"No devices with registered encryption keys": "Brak urządzeń z zarejestrowanymi kluczami szyfrującymi",
"No display name": "Brak nazwy ekranowej",
"No more results": "Nie ma więcej wyników",
@ -373,7 +373,7 @@
"%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s usunął(-ęła) swoją wyświetlaną nazwę (%(oldDisplayName)s).",
"%(senderName)s removed their profile picture.": "%(senderName)s usunął(-ęła) swoje zdjęcie profilowe.",
"Remove %(threePid)s?": "Usunąć %(threePid)s?",
"%(senderName)s requested a VoIP conference.": "%(senderName)s zażądał grupowego połączenia głosowego VoIP.",
"%(senderName)s requested a VoIP conference.": "%(senderName)s zażądał(a) grupowego połączenia głosowego VoIP.",
"Results from DuckDuckGo": "Wyniki z DuckDuckGo",
"Return to login screen": "Wróć do ekranu logowania",
"Riot does not have permission to send you notifications - please check your browser settings": "Riot nie ma uprawnień, by wysyłać ci powiadomienia - sprawdź ustawienia swojej przeglądarki",
@ -451,7 +451,7 @@
"To reset your password, enter the email address linked to your account": "Aby zresetować swoje hasło, wpisz adres e-mail powiązany z twoim kontem",
"Turn Markdown off": "Wyłącz Markdown",
"Turn Markdown on": "Włącz Markdown",
"%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s włączył szyfrowanie użytkownik-użytkownik (algorithm %(algorithm)s).",
"%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s włączył(a) szyfrowanie end-to-end (algorytm %(algorithm)s).",
"Unable to add email address": "Nie można dodać adresu e-mail",
"Unable to create widget.": "Nie można utworzyć widżetu.",
"Unable to remove contact information": "Nie można usunąć informacji kontaktowych",
@ -715,8 +715,8 @@
"Enable inline URL previews by default": "Włącz domyślny podgląd URL w tekście",
"Enable URL previews for this room (only affects you)": "Włącz podgląd URL dla tego pokoju (dotyczy tylko Ciebie)",
"Enable URL previews by default for participants in this room": "Włącz domyślny podgląd URL dla uczestników w tym pokoju",
"Delete %(count)s devices|other": "Usunięto %(count)s urządzeń",
"Delete %(count)s devices|one": "Usunięto urządzenie",
"Delete %(count)s devices|other": "Usuń %(count)s urządzeń",
"Delete %(count)s devices|one": "Usuń urządzenie",
"Select devices": "Wybierz urządzenia",
"%(senderName)s sent an image": "%(senderName)s wysłał(a) obrazek",
"%(senderName)s sent a video": "%(senderName)s wysłał(a) wideo",
@ -1140,11 +1140,11 @@
"This room is not showing flair for any communities": "Ten pokój nie wyświetla wyróżników dla żadnych społeczności",
"Flair will appear if enabled in room settings": "Wyróżnik pojawi się, jeśli został włączony w ustawieniach pokoju",
"Flair will not appear": "Wyróżnik nie wyświetli się",
"%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sdołączył",
"%(severalUsers)sjoined %(count)s times|one": "%(severalUsers)sdołączyło",
"%(count)s <resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. You can also select individual messages to resend or cancel.|one": "<resendText>Wyślij ponownie wiadomość</resendText> lub <cancelText>anuluj wiadomość</cancelText>.",
"was invited %(count)s times|other": "został zaproszony %(count)s razy",
"was invited %(count)s times|one": "został zaproszony",
"was banned %(count)s times|one": "został zablokowany",
"was invited %(count)s times|other": "został(a) zaproszony(-a) %(count)s razy",
"was invited %(count)s times|one": "został(a) zaproszony(-a)",
"was banned %(count)s times|one": "został(a) zablokowany(-a)",
"was kicked %(count)s times|one": "został wyrzucony",
"Whether or not you're using the Richtext mode of the Rich Text Editor": "Niezależnie od tego, czy używasz trybu Richtext edytora tekstu w formacie RTF",
"Call in Progress": "Łączenie w toku",
@ -1233,5 +1233,94 @@
"Sequences like abc or 6543 are easy to guess": "Sekwencje takie jak abc lub 6543 są łatwe do odgadnięcia",
"A word by itself is easy to guess": "Samo słowo jest łatwe do odgadnięcia",
"Names and surnames by themselves are easy to guess": "Imiona i nazwiska same w sobie są łatwe do odgadnięcia",
"Common names and surnames are easy to guess": "Popularne imiona i nazwiska są łatwe do odgadnięcia"
"Common names and surnames are easy to guess": "Popularne imiona i nazwiska są łatwe do odgadnięcia",
"You do not have permission to invite people to this room.": "Nie masz uprawnień do zapraszania ludzi do tego pokoju.",
"User %(user_id)s does not exist": "Użytkownik %(user_id)s nie istnieje",
"Unknown server error": "Nieznany bład serwera",
"%(oneUser)sleft %(count)s times|one": "%(oneUser)swyszedł(-ła)",
"%(oneUser)sjoined and left %(count)s times|other": "%(oneUser)sdołączył(a) i wyszedł(-ła) %(count)s razy",
"%(oneUser)sjoined and left %(count)s times|one": "%(oneUser)sdołączył(a) i wyszedł(-ła)",
"%(severalUsers)sleft %(count)s times|other": "%(severalUsers)swyszło %(count)s razy",
"%(oneUser)sleft %(count)s times|other": "%(oneUser)sopuścił(a) %(count)s razy",
"%(severalUsers)sjoined and left %(count)s times|one": "%(severalUsers)sdołączyło i wyszli(-ły)",
"%(severalUsers)sjoined and left %(count)s times|other": "%(severalUsers)sdołączyło i wyszli(-ły) %(count)s razy",
"were invited %(count)s times|other": "zostali(-ły) zaproszeni(-one) %(count)s razy",
"were banned %(count)s times|one": "zostali(-ły) zablokowani(-e)",
"were banned %(count)s times|other": "zostali(-ły) zablokowani(-e) %(count)s razy",
"was banned %(count)s times|other": "został(a) zablokowany(-a) %(count)s razy",
"%(oneUser)schanged their avatar %(count)s times|other": "%(oneUser)szmienił(a) swój awatar %(count)s razy",
"%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)szmienił(a) swój awatar",
"%(items)s and %(count)s others|other": "%(items)s i %(count)s innych",
"%(items)s and %(count)s others|one": "%(items)s i jeden inny",
"%(severalUsers)schanged their avatar %(count)s times|one": "%(severalUsers)szmieniło swój awatar",
"%(severalUsers)schanged their avatar %(count)s times|other": "%(severalUsers)szmieniło swój awatar %(count)s razy",
"%(oneUser)schanged their name %(count)s times|one": "%(oneUser)szmienił(a) swoją nazwę",
"%(oneUser)schanged their name %(count)s times|other": "%(oneUser)szmienił(a) swoją nazwę %(count)s razy",
"Failed to invite users to the room:": "Nie udało się zaprosić użytkowników do pokoju:",
"No backup is present": "Brak kopii zapasowej",
"Start a new backup": "Rozpocznij nową kopię zapasową",
"The following files cannot be uploaded:": "Następujące pliki nie mogą zostać wysłane:",
"Add some now": "Dodaj teraz kilka",
"Please review and accept all of the homeserver's policies": "Przeczytaj i zaakceptuj wszystkie zasady dotyczące serwera domowego",
"Failed to remove widget": "Nie udało się usunąć widżetu",
"%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)swyszło i dołączyło ponownie %(count)s razy",
"%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)swyszło i dołączyło ponownie",
"%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie %(count)s razy",
"%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)swyszedł(-ła) i dołączył(a) ponownie",
"%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)sodrzucił(a) ich zaproszenie %(count)s razy",
"%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)sodrzucił(a) ich zaproszenie",
"%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)sodrzuciło ich zaproszenia",
"%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)swycofał(a) zaproszenie %(count)s razy",
"%(oneUser)shad their invitation withdrawn %(count)s times|one": "%(oneUser)swycofał(a) zaproszenie",
"%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)swycofało zaproszenie %(count)s razy",
"%(severalUsers)shad their invitations withdrawn %(count)s times|one": "%(severalUsers)swycofało zaproszenie",
"%(severalUsers)schanged their name %(count)s times|other": "%(severalUsers)szmieniło ich nazwę %(count)s razy",
"%(severalUsers)schanged their name %(count)s times|one": "%(severalUsers)szmieniło ich nazwę",
"Continue With Encryption Disabled": "Kontynuuj Z Wyłączonym Szyfrowaniem",
"Capitalization doesn't help very much": "Kapitalizacja nie pomaga bardzo",
"This is a top-10 common password": "To jest 10 najpopularniejszych haseł",
"This is a top-100 common password": "To jest 100 najpopularniejszych haseł",
"You are currently using Riot anonymously as a guest.": "Używasz obecnie Riot anonimowo jako gość.",
"If you would like to create a Matrix account you can <a>register</a> now.": "Jeśli chcesz utworzyć konto Matrix, możesz <a>zarejestrować się</a> teraz.",
"Enter Recovery Key": "Wprowadź Klucz Odzyskiwania",
"This looks like a valid recovery key!": "To wygląda na prawidłowy klucz odzyskiwania!",
"Not a valid recovery key": "Nieprawidłowy klucz odzyskiwania",
"If you don't want to set this up now, you can later in Settings.": "Jeśli nie chcesz tego teraz ustawiać, możesz to zrobić później w Ustawieniach.",
"Retry": "Ponów",
"Create Key Backup": "Stwórz kopię zapasową klucza",
"Recovery Key": "Przywróć Klucz",
"Backup created": "Stworzono kopię zapasową",
"Unable to create key backup": "Nie można utworzyć kopii zapasowej klucza",
"Backing up...": "Tworzenie kopii zapasowych…",
"Create a Recovery Passphrase": "Utwórz hasło odzyskiwania",
"Confirm Recovery Passphrase": "Potwierdź hasło odzyskiwania",
"Download": "Pobierz",
"Copy to clipboard": "Skopiuj do schowka",
"Your Recovery Key": "Twój Klucz Odzyskiwania",
"Enter a passphrase...": "Wprowadź hasło…",
"Key Backup": "Kopia Zapasowa Klucza",
"File is too big. Maximum file size is %(fileSize)s": "Plik jest zbyt duży. Maksymalny rozmiar pliku to %(fileSize)s",
"%(count)s Notifications|other": "%(count)s Powiadomień",
"%(count)s Notifications|one": "%(count)s Powiadomienie",
"Next": "Następny",
"Backup Restored": "Przywrócono Kopię Zapasową",
"No backup found!": "Nie znaleziono kopii zapasowej!",
"Checking...": "Sprawdzanie…",
"Create a new room with the same name, description and avatar": "Utwórz nowy pokój o tej samej nazwie, opisie i awatarze",
"That doesn't look like a valid email address": "To nie wygląda na poprawny adres e-mail",
"was kicked %(count)s times|other": "został(a) wyrzucony(-a) %(count)s razy",
"were kicked %(count)s times|one": "zostali wyrzuceni",
"were kicked %(count)s times|other": "zostali wyrzuceni %(count)s razy",
"was unbanned %(count)s times|one": "został(a) odbanowany(-a)",
"were unbanned %(count)s times|one": "zostali odbanowani",
"was unbanned %(count)s times|other": "został(a) odbanowany(-a) %(count)s razy",
"were unbanned %(count)s times|other": "zostali odbanowani %(count)s razy",
"Please review and accept the policies of this homeserver:": "Przeczytaj i zaakceptuj zasady tego serwera domowego:",
"Upgrade room to version %(ver)s": "Zaktualizuj pokój do wersji %(ver)s",
"Don't ask again": "Nie pytaj ponownie",
"Messages containing @room": "Wiadomości zawierające @room",
"This is similar to a commonly used password": "Jest to podobne do powszechnie stosowanego hasła",
"<b>Print it</b> and store it somewhere safe": "<b>Wydrukuj</b> przechowuj w bezpiecznym miejscu",
"Your Recovery Key is in your <b>Downloads</b> folder.": "Twój Klucz Odzyskiwania znajduje się w Twoim katalogu <b>Pobrane</b>.",
"That doesn't match.": "To się nie zgadza."
}

View file

@ -462,7 +462,7 @@
"Please check your email to continue registration.": "Por favor, verifique o seu e-mail para continuar o processo de registro.",
"Token incorrect": "Token incorreto",
"Please enter the code it contains:": "Por favor, entre com o código que está na mensagem:",
"powered by Matrix": "rodando a partir do Matrix",
"powered by Matrix": "oferecido por Matrix",
"If you don't specify an email address, you won't be able to reset your password. Are you sure?": "Se não especificar um endereço de e-mail, você não poderá redefinir sua senha. Tem certeza?",
"You are registering with %(SelectedTeamName)s": "Você está se registrando com %(SelectedTeamName)s",
"Default server": "Servidor padrão",
@ -767,8 +767,8 @@
"Addresses": "Endereços",
"Invalid community ID": "ID de comunidade inválido",
"'%(groupId)s' is not a valid community ID": "'%(groupId)s' não é um ID de comunidade válido",
"Flair": "Flair",
"Showing flair for these communities:": "Esta sala mostrará flairs para as seguintes comunidades:",
"Flair": "Insígnia",
"Showing flair for these communities:": "Esta sala mostrará insígnias para as seguintes comunidades:",
"This room is not showing flair for any communities": "Esta sala não está mostrando fairs para nenhuma comunidade",
"New community ID (e.g. +foo:%(localDomain)s)": "Novo ID de comunidade (p.ex: +foo:%(localDomain)s)",
"URL previews are enabled by default for participants in this room.": "Pré-visualizações de links estão ativadas por padrão para participantes desta sala.",
@ -788,7 +788,7 @@
"Failed to withdraw invitation": "Não foi possível retirar o convite",
"Failed to remove user from community": "Não foi possível remover esta pessoa da comunidade",
"Filter community members": "Filtrar participantes da comunidade",
"Flair will appear if enabled in room settings": "Os flairs aparecerão se estiverem ativados nas configurações da sala",
"Flair will appear if enabled in room settings": "As insígnias aparecerão se estiverem ativados nas configurações da sala",
"Flair will not appear": "Os flairs não aparecerão",
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Tem certeza que quer remover a sala '%(roomName)s' do grupo %(groupId)s?",
"Removing a room from the community will also remove it from the community page.": "Remover uma sala da comunidade também a removerá da página da comunidade.",
@ -800,7 +800,7 @@
"Only visible to community members": "Apenas visível para integrantes da comunidade",
"Filter community rooms": "Filtrar salas da comunidade",
"Something went wrong when trying to get your communities.": "Algo deu errado quando estava carregando suas comunidades.",
"Display your community flair in rooms configured to show it.": "Mostrar o flair de sua comunidade em salas configuradas para isso.",
"Display your community flair in rooms configured to show it.": "Mostrar a insígnia de sua comunidade em salas configuradas para isso.",
"You're not currently a member of any communities.": "Atualmente você não é integrante de nenhuma comunidade.",
"NOTE: Apps are not end-to-end encrypted": "Nota: os apps não são criptografados ponta-a-ponta",
"Do you want to load widget from URL:": "Você quer carregar o widget da URL:",
@ -849,7 +849,7 @@
"were unbanned %(count)s times|one": "tiveram seu banimento desfeito",
"was unbanned %(count)s times|other": "teve seu banimento desfeito %(count)s vezes",
"was unbanned %(count)s times|one": "teve seu banimento desfeito",
"were kicked %(count)s times|other": "foram excluídas/os %(count)s vezes",
"were kicked %(count)s times|other": "foram chutados %(count)s vezes",
"were kicked %(count)s times|one": "foram excluídas/os",
"was kicked %(count)s times|other": "foi excluída/o %(count)s vezes",
"was kicked %(count)s times|one": "foi excluída/o",
@ -863,7 +863,7 @@
"%(oneUser)schanged their avatar %(count)s times|one": "%(oneUser)s alterou a sua imagem de perfil",
"%(items)s and %(count)s others|other": "%(items)s e %(count)s outras",
"%(items)s and %(count)s others|one": "%(items)s e uma outra",
"collapse": "colapsar",
"collapse": "recolher",
"expand": "expandir",
"Custom of %(powerLevel)s": "Personalizado de %(powerLevel)s",
"<a>In reply to</a> <pill>": "<a>Em resposta a</a> <pill>",
@ -968,7 +968,7 @@
"If your other devices do not have the key for this message you will not be able to decrypt them.": "Se seus outros dispositivos não têm a chave para esta mensagem, você não poderá decriptá-las.",
"Key request sent.": "Requisição de chave enviada.",
"<requestLink>Re-request encryption keys</requestLink> from your other devices.": "<requestLink>Requisitar novamente chaves de encriptação</requestLink> de seus outros dispositivos.",
"%(user)s is a %(userRole)s": "%(user)s é %(userRole)s",
"%(user)s is a %(userRole)s": "%(user)s é um %(userRole)s",
"Fetching third party location failed": "Falha ao acessar localização de terceiros",
"A new version of Riot is available.": "Uma nova versão do Riot está disponível.",
"I understand the risks and wish to continue": "Entendo os riscos e desejo continuar",
@ -1062,7 +1062,7 @@
"Invite to this room": "Convidar para esta sala",
"Please install <chromeLink>Chrome</chromeLink> or <firefoxLink>Firefox</firefoxLink> for the best experience.": "Por favor Instale <chromeLink>Chrome</chromeLink> Ou <firefoxLink>Firefox</firefoxLink> para uma melhor Experiencia.",
"Failed to get public room list": "Falha ao acessar a lista pública de salas",
"Send logs": "Enviar relatórios de erro",
"Send logs": "Enviar registros",
"All messages": "Todas as mensagens",
"Call invitation": "Convite para chamada",
"Downloading update...": "Baixando atualização...",
@ -1111,8 +1111,337 @@
"Event Content": "Conteúdo do Evento",
"Thank you!": "Obrigado!",
"Quote": "Citar",
"Collapse panel": "Colapsar o painel",
"Collapse panel": "Recolher painel",
"With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Com o seu navegador atual, a aparência e sensação de uso da aplicação podem estar completamente incorretas, e algumas das funcionalidades poderão não funcionar. Se você quiser tentar de qualquer maneira, pode continuar, mas aí vai ter que se virar sozinho(a) com os problemas que porventura encontrar!",
"Checking for an update...": "Verificando se há atualizações...",
"There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui"
"There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui",
"Every page you use in the app": "Toda a página que você usa no aplicativo",
"e.g. <CurrentPageURL>": "ex. <CurrentPageURL>",
"Your User Agent": "Seu Agente de Usuário",
"Your device resolution": "Sua resolução de dispositivo",
"A conference call could not be started because the intgrations server is not available": "Não foi possível iniciar uma chamada em conferência porque o servidor de integrações não está disponível",
"Call in Progress": "Chamada em andamento",
"A call is currently being placed!": "Uma chamada está sendo feita atualmente!",
"A call is already in progress!": "Uma chamada já está em andamento!",
"Permission Required": "Permissão Exigida",
"You do not have permission to start a conference call in this room": "Você não tem permissão para iniciar uma chamada de conferência nesta sala",
"Unable to load! Check your network connectivity and try again.": "Incapaz de carregar! Verifique sua conectividade de rede e tente novamente.",
"Registration Required": "Registro requerido",
"You need to register to do this. Would you like to register now?": "Você precisa se registrar para fazer isso. Você gostaria de se registrar agora?",
"Failed to invite users to the room:": "Não foi possível convidar usuários para a sala:",
"Missing roomId.": "RoomId ausente.",
"Opens the Developer Tools dialog": "Abre a caixa de diálogo Ferramentas do desenvolvedor",
"Forces the current outbound group session in an encrypted room to be discarded": "Força a atual sessão de grupo de saída em uma sala criptografada a ser descartada",
"%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s adicionado %(addedAddresses)s como endereço para esta sala.",
"%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s adicionado %(addedAddresses)s como um endereço para esta sala.",
"%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|other": "%(senderName)s removido %(removedAddresses)s como endereços para esta sala.",
"%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s removido %(removedAddresses)s como um endereço para esta sala.",
"e.g. %(exampleValue)s": "ex. %(exampleValue)s",
"%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s definiu o endereço principal desta sala para %(address)s.",
"%(senderName)s removed the main address for this room.": "%(senderName)s removeu o endereço principal para esta sala.",
"This homeserver has hit its Monthly Active User limit.": "Este homeserver atingiu seu limite de usuário ativo mensal.",
"This homeserver has exceeded one of its resource limits.": "Este homeserver ultrapassou um dos seus limites de recursos.",
"Please <a>contact your service administrator</a> to continue using the service.": "Por favor, <a>entre em contato com o seu administrador de serviços</a> para continuar usando o serviço.",
"Unable to connect to Homeserver. Retrying...": "Não é possível conectar-se ao Homeserver. Tentando novamente ...",
"You do not have permission to invite people to this room.": "Você não tem permissão para convidar pessoas para esta sala.",
"User %(user_id)s does not exist": "Usuário %(user_id)s não existe",
"Unknown server error": "Erro de servidor desconhecido",
"Use a few words, avoid common phrases": "Use algumas palavras, evite frases comuns",
"No need for symbols, digits, or uppercase letters": "Não há necessidade de símbolos, dígitos ou letras maiúsculas",
"Avoid repeated words and characters": "Evite palavras e caracteres repetidos",
"Avoid sequences": "Evite sequências",
"Avoid recent years": "Evite anos recentes",
"Avoid years that are associated with you": "Evite anos associados a você",
"Avoid dates and years that are associated with you": "Evite datas e anos associados a você",
"Capitalization doesn't help very much": "A capitalização não ajuda muito",
"All-uppercase is almost as easy to guess as all-lowercase": "Todas as maiúsculas são quase tão fáceis de adivinhar quanto todas as minúsculas",
"Reversed words aren't much harder to guess": "Palavras invertidas não são muito mais difíceis de adivinhar",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Substituições previsíveis como '@' em vez de 'a' não ajudam muito",
"Add another word or two. Uncommon words are better.": "Adicione outra palavra ou duas. Palavras incomuns são melhores.",
"Repeats like \"aaa\" are easy to guess": "Repetições como \"aaa\" são fáceis de adivinhar",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Repetições como \"abcabcabc\" são apenas um pouco mais difíceis de adivinhar que \"abc\"",
"Sequences like abc or 6543 are easy to guess": "Sequências como abc ou 6543 são fáceis de adivinhar",
"Recent years are easy to guess": "Os últimos anos são fáceis de adivinhar",
"%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s adicionou %(addedAddresses)s e removeu %(removedAddresses)s como endereços para esta sala.",
"Dates are often easy to guess": "As datas costumam ser fáceis de adivinhar",
"This is a top-10 common password": "Esta é uma das top-10 senhas mais comuns",
"This is a top-100 common password": "Esta é uma das top-100 senhas mais comuns",
"This is a very common password": "Isto é uma senha muito comum",
"This is similar to a commonly used password": "Isto é similar a uma senha muito comum",
"A word by itself is easy to guess": "Uma palavra por si só é fácil de adivinhar",
"Names and surnames by themselves are easy to guess": "Nomes e sobrenomes sozinhos são fáceis de adivinhar",
"Common names and surnames are easy to guess": "Nomes e sobrenomes comuns são fáceis de adivinhar",
"Straight rows of keys are easy to guess": "Linhas retas de teclas são fáceis de adivinhar",
"Short keyboard patterns are easy to guess": "Padrões de teclado curtos são fáceis de adivinhar",
"There was an error joining the room": "Houve um erro ao entrar na sala",
"Sorry, your homeserver is too old to participate in this room.": "Desculpe, seu homeserver é muito velho para participar desta sala.",
"Please contact your homeserver administrator.": "Por favor, entre em contato com o administrador do seu homeserver.",
"Custom user status messages": "Mensagens de status de usuário personalizadas",
"Increase performance by only loading room members on first view": "Aumentar o desempenho apenas carregando membros da sala na primeira exibição",
"Backup of encryption keys to server": "Backup de chaves de criptografia para o servidor",
"Always show encryption icons": "Mostrar sempre ícones de criptografia",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Mostrar um lembrete para ativar o Secure Message Recovery em salas criptografadas",
"Send analytics data": "Enviar dados analíticos",
"Enable widget screenshots on supported widgets": "Ativar capturas de tela do widget em widgets suportados",
"Show empty room list headings": "Mostrar cabeçalhos de lista de salas vazias",
"Show developer tools": "Mostrar ferramentas de desenvolvedor",
"Messages containing @room": "Mensagens contendo @room",
"Encrypted messages in one-to-one chats": "Mensagens criptografadas em bate-papos individuais",
"Encrypted messages in group chats": "Mensagens criptografadas em bate-papos de grupo",
"Delete Backup": "Deletar Backup",
"Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Excluir suas chaves de criptografia de backup do servidor? Você não poderá mais usar sua chave de recuperação para ler o histórico de mensagens criptografadas",
"Delete backup": "Deletar backup",
"Unable to load key backup status": "Não é possível carregar o status da chave de backup",
"This device is uploading keys to this backup": "Este dispositivo está carregando chaves para este backup",
"This device is <b>not</b> uploading keys to this backup": "Este dispositivo <b>não</ b> está enviando chaves para este backup",
"Backup has a <validity>valid</validity> signature from this device": "O backup tem uma assinatura <validity>válida</validity> deste dispositivo",
"Pin rooms I'm mentioned in to the top of the room list": "Salas fixadas em que eu fui mencionado no topo da lista de salas",
"Pin unread rooms to the top of the room list": "Salas marcadas não lidas no topo da lista de salas",
"Backup version: ": "Versão do Backup: ",
"Algorithm: ": "Algoritmo: ",
"Restore backup": "Restaurar backup",
"No backup is present": "Não há backup disponível",
"Start a new backup": "Iniciar um novo backup",
"This event could not be displayed": "O evento não pôde ser exibido",
"Encrypting": "Criptografando",
"Encrypted, not sent": "Criptografado, não enviado",
"Use a longer keyboard pattern with more turns": "Use um padrão de teclas em diferentes direções e sentido",
"Share Link to User": "Compartilhar Link com Usuário",
"underlined": "sublinhado",
"inline-code": "código inline",
"numbered-list": "lista ordenada",
"bulleted-list": "lista não-ordenada",
"At this time it is not possible to reply with a file so this will be sent without being a reply.": "No momento, não é possível responder com um arquivo, portanto, isso será enviado sem ser uma resposta.",
"The following files cannot be uploaded:": "Os seguintes arquivos não podem ser enviados:",
"This room has been replaced and is no longer active.": "Esta sala foi substituída e não está mais ativa.",
"The conversation continues here.": "A conversa continua aqui.",
"Unable to reply": "Não é possível responder",
"At this time it is not possible to reply with an emote.": "Neste momento não é possível responder com um emote.",
"Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Visto por %(displayName)s (%(userName)s) em %(dateTime)s",
"Share room": "Compartilhar sala",
"System Alerts": "Alertas do Sistema",
"Joining room...": "Entrando na sala...",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Para visualizar seu histórico de mensagens seguras e garantir a exibição de novas mensagens em dispositivos futuros, configure Recuperação Segura de Mensagens.",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Se você sair ou usar outro dispositivo, perderá seu histórico de mensagens seguras. Para evitar isso, configure a Recuperação Segura de Mensagens.",
"Secure Message Recovery": "Recuperação Segura de Mensagens",
"Don't ask again": "Não pergunte novamente",
"Set up": "Configurar",
"To notify everyone in the room, you must be a": "Para notificar todos na sala, você deve ser um",
"Muted Users": "Usuários silenciados",
"Upgrade room to version %(ver)s": "Atualiza a sala para a versão %(ver)s",
"Open Devtools": "Abrir as Ferramentas de Desenvolvimento",
"Internal room ID: ": "ID da sala interno: ",
"Room version number: ": "Número de versão da sala: ",
"There is a known vulnerability affecting this room.": "Existe uma vulnerabilidade conhecida que afeta esta sala.",
"This room version is vulnerable to malicious modification of room state.": "Esta versão da sala é vulnerável à modificação mal-intencionada do estado da sala.",
"Click here to upgrade to the latest room version and ensure room integrity is protected.": "Clique aqui para atualizar para a versão mais recente do quarto e garantir que a integridade da sala esteja protegida.",
"Only room administrators will see this warning": "Somente administradores de sala verão esse aviso",
"You don't currently have any stickerpacks enabled": "Atualmente, você não tem nenhum stickerpacks ativado",
"Demote": "Reduzir privilégio",
"Demote yourself?": "Reduzir seu próprio privilégio?",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "O backup tem uma assinatura <validity>válida</validity> do dispositivo <verify>verificado</ verify><device></ device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "O backup tem uma assinatura <validity>válida</validity> do dispositivo <verify>não verificado</ verify><device></ device>",
"Backup is not signed by any of your devices": "O backup não está assinado por nenhum dos seus dispositivos",
"deleted": "excluído",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "O backup tem uma assinatura <validity>inválida</validity> do dispositivo <verify>verificado</ verify> <device></ device>",
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "O backup tem uma assinatura <validity>inválida</validity> do dispositivo <verify>não verificado</ verify> <device></ device>",
"block-quote": "bloco de citação",
"You have no historical rooms": "Você não tem salas históricas",
"Add some now": "Adicione alguns agora",
"Stickerpack": "Stickerpack",
"Hide Stickers": "Esconder Stickers",
"Show Stickers": "Mostrar Stickers",
"In encrypted rooms, like this one, URL previews are disabled by default to ensure that your homeserver (where the previews are generated) cannot gather information about links you see in this room.": "Em salas criptografadas, como esta, as visualizações de URL são desabilitadas por padrão para garantir que o seu homeserver (onde as visualizações são geradas) não possa coletar informações sobre os links que você vê nesta sala.",
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "Quando alguém coloca um URL em sua mensagem, uma visualização de URL pode ser exibida para fornecer mais informações sobre esse link, como o título, a descrição e uma imagem do site.",
"This room is a continuation of another conversation.": "Esta sala é uma continuação de outra conversa.",
"Click here to see older messages.": "Clique aqui para ver as mensagens mais antigas.",
"Please review and accept all of the homeserver's policies": "Por favor, revise e aceite todas as políticas do homeserver",
"Please review and accept the policies of this homeserver:": "Por favor, revise e aceite as políticas deste homeserver:",
"Code": "Código",
"The email field must not be blank.": "O campo de email não pode estar em branco.",
"The user name field must not be blank.": "O campo de nome de usuário não deve ficar em branco.",
"The phone number field must not be blank.": "O campo do número de telefone não pode estar em branco.",
"The password field must not be blank.": "O campo da senha não pode ficar em branco.",
"Failed to load group members": "Falha ao carregar membros do grupo",
"Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. This will use a cookie (please see our <PolicyLink>Cookie Policy</PolicyLink>).": "Por favor, ajude a melhorar o Riot.im enviando <UsageDataLink>dados de uso anônimo</ UsageDataLink>. Isso usará um cookie (consulte nossa Política de cookies <PolicyLink> </ PolicyLink>).",
"Please help improve Riot.im by sending <UsageDataLink>anonymous usage data</UsageDataLink>. This will use a cookie.": "Por favor, ajude a melhorar o Riot.im enviando <UsageDataLink>dados de uso anônimo</ UsageDataLink>. Isto irá usar um cookie.",
"Yes, I want to help!": "Sim, quero ajudar!",
"Please <a>contact your service administrator</a> to get this limit increased.": "Por favor, <a>entre em contato com o administrador do serviço</a> para aumentar esse limite.",
"This homeserver has hit its Monthly Active User limit so <b>some users will not be able to log in</b>.": "Este homeserver atingiu seu limite de usuário ativo mensal, então <b>alguns usuários não poderão efetuar login</ b>.",
"This homeserver has exceeded one of its resource limits so <b>some users will not be able to log in</b>.": "Este homeserver excedeu um dos seus limites de recursos, de modo que <b>alguns usuários não poderão efetuar login</ b>.",
"Warning: This widget might use cookies.": "Aviso: Este widget pode usar cookies.",
"Failed to remove widget": "Falha ao remover o widget",
"An error ocurred whilst trying to remove the widget from the room": "Ocorreu um erro ao tentar remover o widget da sala",
"Reload widget": "Recarregar widget",
"Picture": "Figura",
"Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Não é possível carregar o evento que foi respondido, ele não existe ou você não tem permissão para visualizá-lo.",
"That doesn't look like a valid email address": "Isso não parece ser um endereço de e-mail válido",
"Preparing to send logs": "Preparando para enviar registros",
"Logs sent": "Registros enviados",
"Failed to send logs: ": "Falha ao enviar registros: ",
"Submit debug logs": "Submeter registros de depuração",
"Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Os registros de depuração contêm dados de uso do aplicativo, incluindo seu nome de usuário, os IDs ou aliases das salas ou grupos que você visitou e os nomes de usuários de outros usuários. Eles não contêm mensagens.",
"Before submitting logs, you must <a>create a GitHub issue</a> to describe your problem.": "Antes de enviar os registros, você deve <a>criar uma questão no GitHub</a> para descrever seu problema.",
"What GitHub issue are these logs for?": "Para qual questão do GitHub são esses registros?",
"Notes:": "Notas:",
"Unable to load commit detail: %(msg)s": "Não é possível carregar os detalhes do commit: %(msg)s",
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Para evitar perder seu histórico de bate-papo, você deve exportar as chaves do seu quarto antes de fazer logout. Você precisará voltar para a versão mais recente do Riot para fazer isso",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Você já usou uma versão mais recente do Riot em %(host)s. Para usar essa versão novamente com criptografia de ponta a ponta, você precisará sair e voltar novamente. ",
"Incompatible Database": "Banco de dados incompatível",
"Continue With Encryption Disabled": "Continuar com criptografia desativada",
"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>": "Isso tornará sua conta permanentemente inutilizável. Você não poderá efetuar login e ninguém poderá registrar novamente o mesmo ID de usuário. Isso fará com que sua conta deixe todas as salas nas quais está participando e removerá os detalhes da sua conta do seu servidor de identidade. <b>Esta ação é irreversível.</ b>",
"Deactivating your account <b>does not by default cause us to forget messages you have sent.</b> If you would like us to forget your messages, please tick the box below.": "Desativar sua conta <b>não faz com que, por padrão, esqueçamos as mensagens que você enviou.</ B> Se você quiser que esqueçamos suas mensagens, marque a caixa abaixo.",
"Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "A visibilidade da mensagem no Matrix é semelhante ao e-mail. O fato de esquecermos suas mensagens significa que as mensagens que você enviou não serão compartilhadas com usuários novos ou não registrados, mas os usuários registrados que já têm acesso a essas mensagens ainda terão acesso a suas cópias.",
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Por favor, esqueça todas as mensagens que enviei quando minha conta for desativada (<b>Aviso:</ b> isso fará com que futuros usuários vejam uma visão incompleta das conversas)",
"To continue, please enter your password:": "Para continuar, por favor digite sua senha:",
"password": "senha",
"Incompatible local cache": "Cache local incompatível",
"Clear cache and resync": "Limpar cache e ressincronizar",
"Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot agora usa 3-5x menos memória, pois carrega informação sobre outros usuários apenas quando necessário. Por favor, aguarde enquanto ressincronizamos com o servidor!",
"Updating Riot": "Atualizando Riot",
"Failed to upgrade room": "Falha ao atualizar a sala",
"The room upgrade could not be completed": "A atualização da sala não pode ser completada",
"Upgrade this room to version %(version)s": "Atualize essa sala para versão %(version)s",
"Upgrade Room Version": "Atualize a Versão da Sala",
"Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Atualização dessa sala requer fechar a instância atual e criar uma nova sala em seu lugar. Para dar aos usuários a melhor experiência possível, nós vamos:",
"Create a new room with the same name, description and avatar": "Criar uma nova sala com o mesmo nome, descrição e avatar",
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Impedir usuários de conversar na versão antiga da sala e postar uma mensagem aconselhando os usuários a migrarem para a nova sala",
"Put a link back to the old room at the start of the new room so people can see old messages": "Colocar um link para a sala antiga no começo da sala nova de modo que as pessoas possam ver mensagens antigas",
"You've previously used Riot on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, Riot needs to resync your account.": "Você já usou o Riot em %(host)s com o carregamento Lazy de membros ativado. Nesta versão, o carregamento Lazy está desativado. Como o cache local não é compatível entre essas duas configurações, a Riot precisa ressincronizar sua conta.",
"If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Se a outra versão do Riot ainda estiver aberta em outra aba, por favor, feche-a pois usar o Riot no mesmo host com o carregamento Lazy ativado e desativado simultaneamente causará problemas.",
"Update any local room aliases to point to the new room": "Atualize todos os aliases da sala local para apontar para a nova sala",
"Log out and remove encryption keys?": "Sair e remover chaves de criptografia?",
"Clear Storage and Sign Out": "Limpar armazenamento e sair",
"Refresh": "Atualizar",
"We encountered an error trying to restore your previous session.": "Encontramos um erro ao tentar restaurar sua sessão anterior.",
"Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Limpar o armazenamento do seu navegador pode resolver o problema, mas você será deslogado e isso fará que qualquer histórico de bate-papo criptografado fique ilegível.",
"Only use lower case letters, numbers and '=_-./'": "Utilize apenas letras minúsculas, números e '=_-. /'",
"Checking...": "Checando...",
"Share Room": "Compartilhar Sala",
"Link to most recent message": "Link para a mensagem mais recente",
"Share User": "Compartilhar Usuário",
"Share Community": "Compartilhar Comunidade",
"Share Room Message": "Compartilhar Mensagem da Sala",
"Link to selected message": "Link para a mensagem selecionada",
"COPY": "COPIAR",
"Unable to load backup status": "Não é possível carregar o status do backup",
"Unable to restore backup": "Não é possível restaurar o backup",
"No backup found!": "Nenhum backup encontrado!",
"Backup Restored": "Backup restaurado",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Acesse seu histórico de mensagens seguras e configure mensagens seguras digitando sua frase secreta de recuperação.",
"Next": "Próximo",
"If you've forgotten your recovery passphrase you can <button1>use your recovery key</button1> or <button2>set up new recovery options</button2>": "Se você esqueceu sua frase secreata de recuperação, você pode <button1>usar sua chave de recuperação</ button1> ou <button2>configurar novas opções de recuperação</ button2>",
"Enter Recovery Key": "Digite a chave de recuperação",
"This looks like a valid recovery key!": "Isso parece uma chave de recuperação válida!",
"Not a valid recovery key": "Não é uma chave de recuperação válida",
"Access your secure message history and set up secure messaging by entering your recovery key.": "Acesse seu histórico seguro de mensagens e configure mensagens seguras inserindo sua chave de recuperação.",
"If you've forgotten your recovery passphrase you can <button>set up new recovery options</button>": "Se você esqueceu sua senha de recuperação, você pode <button>configurar novas opções de recuperação</ button>",
"Share Message": "Compartilhar Mensagem",
"Popout widget": "Widget Popout",
"Send Logs": "Enviar relatos de problemas",
"Failed to decrypt %(failedCount)s sessions!": "Falha ao descriptografar as sessões de %(failedCount)s!",
"Restored %(sessionCount)s session keys": "Chaves de sessão %(sessionCount)s restauradas",
"Enter Recovery Passphrase": "Digite a frase secreta de recuperação",
"Set a new status...": "Definir um novo status ...",
"Collapse Reply Thread": "Recolher grupo de respostas",
"Clear status": "Limpar status",
"Unable to join community": "Não é possível participar da comunidade",
"You are an administrator of this community. You will not be able to rejoin without an invite from another administrator.": "Você é um administrador dessa comunidade. Você não poderá se reingressar sem um convite de outro administrador.",
"Unable to leave community": "Não é possível sair da comunidade",
"Changes made to your community <bold1>name</bold1> and <bold2>avatar</bold2> might not be seen by other users for up to 30 minutes.": "Alterações feitas à sua comunidade <bold1>nome</ bold1> e <bold2>avatar</ bold2> podem não ser vistas por outros usuários por até 30 minutos.",
"Join this community": "Junte-se a esta comunidade",
"Leave this community": "Deixe esta comunidade",
"Who can join this community?": "Quem pode participar desta comunidade?",
"Everyone": "Todos",
"You are currently using Riot anonymously as a guest.": "Você está usando o Riot anonimamente como convidado.",
"If you would like to create a Matrix account you can <a>register</a> now.": "Se você gostaria de criar uma conta Matrix, você pode <a>registrar-se</a> agora.",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Configuração inválida: Não é possível fornecer uma URL de homeserver padrão e um nome de servidor padrão",
"Can't leave Server Notices room": "Não é possível sair da sala Notificações do servidor",
"This room is used for important messages from the Homeserver, so you cannot leave it.": "Esta sala é usada para mensagens importantes do Homeserver, então você não pode sair dela.",
"Terms and Conditions": "Termos e Condições",
"To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.\n\nPara continuar usando o homeserver %(homeserverDomain)s, você deve rever e concordar com nossos termos e condições.",
"Review terms and conditions": "Revise os termos e condições",
"Unknown error discovering homeserver": "Erro desconhecido ao descobrir o homeserver",
"%(count)s Notifications|other": "%(count)s Notificações",
"%(count)s Notifications|one": "%(count)s Notificação",
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "Você não pode enviar nenhuma mensagem até revisar e concordar com <consentLink>nossos termos e condições</consentLink>.",
"Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.": "Sua mensagem não foi enviada porque este homeserver atingiu seu Limite de usuário ativo mensal. Por favor, <a>entre em contato com o seu administrador de serviços</a> para continuar usando o serviço.",
"Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.": "Sua mensagem não foi enviada porque este homeserver excedeu o limite de recursos. Por favor, <a>entre em contato com o seu administrador de serviços</a> para continuar usando o serviço.",
"File is too big. Maximum file size is %(fileSize)s": "O arquivo é muito grande. Tamanho máximo do arquivo é %(fileSize)s",
"Key Backup": "Chave de Backup",
"Submit Debug Logs": "Submeter logs de depuração",
"If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Se você enviou um bug por meio do GitHub, os logs de depuração podem nos ajudar a rastrear o problema. Os logs de depuração contêm dados de uso do aplicativo, incluindo seu nome de usuário, os IDs ou aliases das salas ou grupos que você visitou e os nomes de usuários de outros usuários. Eles não contêm mensagens.",
"Lazy loading members not supported": "Usuários de carregamento Lazy não são suportados",
"Lazy loading is not supported by your current homeserver.": "O carregamento Lazy não é suportado pelo seu servidor atual.",
"Legal": "Legal",
"No Audio Outputs detected": "Nenhuma saída de áudio detectada",
"Audio Output": "Saída de áudio",
"Invalid homeserver discovery response": "Resposta de descoberta de homeserver inválida",
"Invalid identity server discovery response": "Resposta de descoberta do servidor de identidade inválida",
"General failure": "Falha geral",
"Please <a>contact your service administrator</a> to continue using this service.": "Por favor, <a>entre em contato com o seu administrador de serviços</a> para continuar usando este serviço.",
"Failed to perform homeserver discovery": "Falha ao executar a descoberta do homeserver",
"Unknown failure discovering homeserver": "Falha desconhecida ao descobrir o homeserver",
"Sign in with single sign-on": "Entre com o logon único",
"Try the app first": "Experimente o aplicativo primeiro",
"Unable to query for supported registration methods": "Não é possível consultar os métodos de registro suportados",
"An email address is required to register on this homeserver.": "Um endereço de e-mail é necessário para se registrar neste homeserver.",
"A phone number is required to register on this homeserver.": "Um número de telefone é necessário para se registrar neste homeserver.",
"Great! This passphrase looks strong enough.": "Ótimo! Esta frase secreta parece forte o suficiente.",
"Secure your encrypted message history with a Recovery Passphrase.": "Proteja seu histórico de mensagens criptografadas com uma frase secreta de recuperação.",
"You'll need it if you log out or lose access to this device.": "Você precisará disso se sair ou perder o acesso a este dispositivo.",
"Enter a passphrase...": "Digite uma frase secreta ...",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Se você não quiser que o histórico de mensagens criptografadas esteja disponível em outros dispositivos, <button>desative</ button>.",
"Or, if you don't want to create a Recovery Passphrase, skip this step and <button>download a recovery key</button>.": "Ou, se você não quiser criar uma frase secreta de recuperação, pule esta etapa e <button>faça o download de uma chave de recuperação</ button>.",
"That matches!": "Isto corresponde!",
"That doesn't match.": "Isto não corresponde.",
"Go back to set it again.": "Volte e configure novamente.",
"Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Digite sua frase secreta de recuperação para confirmar que você se lembra dela. Se isso ajudar, adicione-a ao seu gerenciador de senhas ou armazene-a em algum lugar seguro.",
"Repeat your passphrase...": "Repita sua frase se recuperação...",
"As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "Como uma rede de segurança, você pode usá-la para restaurar seu histórico de mensagens criptografadas se esquecer sua frase secreta de recuperação.",
"As a safety net, you can use it to restore your encrypted message history.": "Como uma rede de segurança, você pode usá-la para restaurar seu histórico de mensagens criptografadas.",
"Make a copy of this Recovery Key and keep it safe.": "Faça uma cópia desta chave de recuperação e mantenha-a segura.",
"Your Recovery Key": "Sua chave de recuperação",
"Copy to clipboard": "Copiar para área de transferência",
"Download": "Baixar",
"I've made a copy": "Eu fiz uma cópia",
"Your Recovery Key has been <b>copied to your clipboard</b>, paste it to:": "Sua chave de recuperação foi <b>copiada para sua área de transferência</ b>, cole-a em:",
"Your Recovery Key is in your <b>Downloads</b> folder.": "Sua chave de recuperação está na sua pasta <b>Downloads</ b>.",
"<b>Print it</b> and store it somewhere safe": "<b>Imprima-o</ b> e armazene-o em algum lugar seguro",
"<b>Save it</b> on a USB key or backup drive": "<b>Salve isto</ b> em uma chave USB ou unidade de backup",
"<b>Copy it</b> to your personal cloud storage": "<b>Copie isto</ b> para seu armazenamento em nuvem pessoal",
"Got it": "Consegui",
"Backup created": "Backup criado",
"Your encryption keys are now being backed up to your Homeserver.": "Suas chaves de criptografia agora estão sendo copiadas para o seu Homeserver.",
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Sem configurar o Recuperação Segura de Mensagens, você não poderá restaurar o histórico de mensagens criptografadas se fizer logout ou usar outro dispositivo.",
"Set up Secure Message Recovery": "Configurar Recuperação Segura de Mensagens",
"Create a Recovery Passphrase": "Criar uma frase secreta de recuperação",
"Confirm Recovery Passphrase": "Confirme a frase secreta de recuperação",
"Recovery Key": "Chave de Recuperação",
"Keep it safe": "Mantenha isto seguro",
"Backing up...": "Fazendo backup ...",
"Create Key Backup": "Criar backup de chave",
"Unable to create key backup": "Não é possível criar backup de chave",
"Retry": "Tentar novamente",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Sem configurar a Recuperação Segura de Mensagens, você perderá seu histórico de mensagens seguras quando fizer logout.",
"If you don't want to set this up now, you can later in Settings.": "Se você não quiser configurá-lo agora, poderá fazê-lo posteriormente em Configurações.",
"New Recovery Method": "Novo método de recuperação",
"A new recovery passphrase and key for Secure Messages has been detected.": "Uma nova frase secreta de recuperação e chave para Mensagens Seguras foi detectada.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "A configuração de mensagens seguras neste dispositivo criptografará novamente o histórico de mensagens deste dispositivo com o novo método de recuperação.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se você não definiu o novo método de recuperação, um invasor pode estar tentando acessar sua conta. Altere a senha da sua conta e defina um novo método de recuperação imediatamente em Configurações.",
"Set up Secure Messages": "Configurar mensagens seguras",
"Go to Settings": "Ir para as configurações",
"Unrecognised address": "Endereço não reconhecido",
"User %(user_id)s may or may not exist": "Usuário %(user_id)s pode existir ou não",
"Always invite users which may not exist": "Sempre convidar usuários que talvez não existam",
"The following users may not exist": "Os seguintes usuários podem não existir",
"The following users may not exist - would you like to invite them anyways?": "Os seguintes usuários podem não existir - você gostaria de convidá-los de qualquer maneira?",
"Invite anyways and never warn me again": "Convide mesmo assim e nunca mais me alerte",
"Invite anyways": "Convidar mesmo assim",
"Waiting for %(userId)s to accept...": "Aguardando que %(userId)s aceite...",
"Waiting for %(userId)s to confirm...": "Aguardando que %(userId)s confirme...",
"Prompt before sending invites to potentially invalid matrix IDs": "Avisar antes de enviar convites para IDs da Matrix potencialmente inválidas",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Não é possível encontrar perfis para os IDs da Matrix listados abaixo - você gostaria de convidá-los mesmo assim?",
"Invite anyway and never warn me again": "Convide mesmo assim e nunca mais me avise",
"Invite anyway": "Convide mesmo assim"
}

View file

@ -387,7 +387,7 @@
"To send messages, you must be a": "Aby ste mohli posielať správy, musíte byť",
"To invite users into the room, you must be a": "Aby ste mohli pozývať používateľov do miestnosti, musíte byť",
"To configure the room, you must be a": "Aby ste mohli nastavovať miestnosť, musíte byť",
"To kick users, you must be a": "Aby ste mohli vykazovať používateľov, musíte byť",
"To kick users, you must be a": "Aby ste mohli vykázať používateľov, musíte byť",
"To ban users, you must be a": "Aby ste používateľom mohli zakazovať vstup, musíte byť",
"To remove other users' messages, you must be a": "Aby ste mohli odstraňovať správy, ktoré poslali iní používatelia, musíte byť",
"To send events of type <eventType/>, you must be a": "Aby ste mohli posielať udalosti typu <eventType/>, musíte byť",
@ -1184,14 +1184,14 @@
"Encrypting": "Šifrovanie",
"Encrypted, not sent": "Zašifrované, ale neodoslané",
"Share Link to User": "Zdieľať odkaz na používateľa",
"Share room": "Zdieľaj miestnosť",
"Share room": "Zdieľať miestnosť",
"Share Room": "Zdieľať miestnosť",
"Link to most recent message": "Odkaz na najnovšiu správu",
"Share User": "Zdieľať používateľa",
"Share Community": "Zdieľať komunitu",
"Link to selected message": "Odkaz na vybratú správu",
"COPY": "Kopírovať",
"Share Message": "Zdieľaj správu",
"Share Message": "Zdieľať správu",
"No Audio Outputs detected": "Neboli rozpoznané žiadne zvukové výstupy",
"Audio Output": "Výstup zvuku",
"Try the app first": "Vyskúšať si aplikáciu",
@ -1278,5 +1278,103 @@
"Legal": "Právne",
"Unable to query for supported registration methods": "Nie je možné vyžiadať podporované metódy registrácie",
"An email address is required to register on this homeserver.": "Na registráciu na tomto domovskom servery je vyžadovaná emailová adresa.",
"A phone number is required to register on this homeserver.": "Na registráciu na tomto domovskom servery je vyžadované telefónne číslo."
"A phone number is required to register on this homeserver.": "Na registráciu na tomto domovskom servery je vyžadované telefónne číslo.",
"Unable to load! Check your network connectivity and try again.": "Nie je možné načítať! Skontrolujte prístup na internet a skúste neskôr.",
"Failed to invite users to the room:": "Používateľov sa nepodarilo pozvať do miestnosti:",
"Unrecognised address": "Nerozpoznaná adresa",
"You do not have permission to invite people to this room.": "Nemáte pridelené oprávnenie pozývať ľudí do tejto miestnosti.",
"User %(user_id)s does not exist": "Používateľ %(user_id)s neexistuje",
"User %(user_id)s may or may not exist": "Nie je možné určiť, či používateľ %(user_id)s existuje",
"Unknown server error": "Neznáma chyba servera",
"Use a few words, avoid common phrases": "Použite niekoľko slov, vyhýbajte sa bežným frázam",
"No need for symbols, digits, or uppercase letters": "Nemusí obsahovať len veľké písmená, číslice alebo interpunkčné znaky",
"Use a longer keyboard pattern with more turns": "Zadajte dlhšiu frázu so znakmi rozmiestnenými po celej klávesnici",
"Avoid repeated words and characters": "Neopakujte krátke slová, znaky alebo ich skupiny",
"Avoid sequences": "Nestláčajte klávesy umiestnené v poradí vedľa seba",
"Avoid recent years": "Nepíšte čísla podľa aktuálneho alebo posledných rokov",
"Avoid years that are associated with you": "Nepíšte roky zo života",
"Avoid dates and years that are associated with you": "Nepíšte dôležité dátumy zo života",
"Capitalization doesn't help very much": "Veľkosť písmen nie je veľmi rozhodujúca",
"All-uppercase is almost as easy to guess as all-lowercase": "Všetky veľké písmená je možné uhádnuť rovnako ľahko ako všetky malé písmená",
"Reversed words aren't much harder to guess": "Slová napísané odzadu tiež nie je omnoho náročnejšie uhádnuť",
"Predictable substitutions like '@' instead of 'a' don't help very much": "Predvídateľné nahrádzanie znakov ako „@“ namiesto „a“ veľmi nepomáha",
"Add another word or two. Uncommon words are better.": "Pridajte ešte jedno dve slová. Lepšie sú tie, nie bežne používané.",
"Repeats like \"aaa\" are easy to guess": "Opakovanie znakov ako „aaa“ je možné veľmi ľahko uhádnuť",
"Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Opakovanie skupín znakov napríklad „abcabcabc“ je len o trochu zložitejšie uhádnuť než „abc“",
"Sequences like abc or 6543 are easy to guess": "Sekvencie znakov ako sú „abc“ alebo „6543“ je veľmi ľahko možné uhádnuť",
"Recent years are easy to guess": "Nedávne roky je veľmi ľahké uhádnuť",
"Dates are often easy to guess": "Dátumy je často možné ľahko uhádnuť",
"This is a top-10 common password": "Toto heslo je z 10 najpoužívanejších",
"This is a top-100 common password": "Toto heslo je zo 100 najpoužívanejších",
"This is a very common password": "Toto je veľmi často používané heslo",
"This is similar to a commonly used password": "Toto je veľmi podobné často používanému heslu",
"A word by itself is easy to guess": "Samostatné slovo je ľahké uhádnuť",
"Names and surnames by themselves are easy to guess": "Mená a priezviská je samé o sebe ľahké uhádnuť",
"Common names and surnames are easy to guess": "Bežné mená a priezviská je ľahké uhádnuť",
"Straight rows of keys are easy to guess": "Po sebe nasledujúce rady klávesov je ľahké uhádnuť",
"Short keyboard patterns are easy to guess": "Krátke vzory z klávesov je ľahké uhádnuť",
"There was an error joining the room": "Pri vstupovaní do miestnosti sa vyskytla chyba",
"Custom user status messages": "Vlastné správy o stave používateľa",
"Backup of encryption keys to server": "Záloha šifrovacích kľúčov na server",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "V šifrovaných konverzáciách zobrazovať upozornenie na možnosť aktivovať Bezpečné obnovenie správ",
"Pin rooms I'm mentioned in to the top of the room list": "Pripnúť miestnosti, kde som spomenutý na vrch zoznamu",
"Pin unread rooms to the top of the room list": "Pripnúť miestnosti s neprečítanými správami na vrch zoznamu",
"Always invite users which may not exist": "Vždy pozývať používateľov, ktorí nemusia existovať",
"Show developer tools": "Zobraziť nástroje pre vývojárov",
"Messages containing @room": "Správy obsahujúce @room",
"Encrypted messages in one-to-one chats": "Šifrované správy v priamych konverzáciách",
"Encrypted messages in group chats": "Šifrované správy v skupinových konverzáciách",
"Delete Backup": "Vymazať zálohu",
"Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Chcete naozaj vymazať šifrované kľúče zálohované na servery? Nebudete viac môcť čítať históriu šifrovaných konverzácií pomocou kľúča určeného na obnovu",
"Delete backup": "Vymazať zálohu",
"Unable to load key backup status": "Nie je možné načítať stav zálohy kľúčov",
"This device is uploading keys to this backup": "Z tohoto zariadenia nahrávate kľúče do tejto zálohy",
"This device is <b>not</b> uploading keys to this backup": "Z tohoto zariadenia <b>ne</b>nahrávate kľúče do tejto zálohy",
"Backup has a <validity>valid</validity> signature from this device": "Záloha je podpísaná <validity>platným</validity> kľúčom z tohoto zariadenia",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Záloha je podpísaná <validity>platným</validity> kľúčom z tohoto zariadenia\nZáloha je podpísaná <validity>správnym</validity> kľúčom z <verify>overeného</verify> zariadenia <device></device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Záloha je podpísaná <validity>platným</validity> kľúčom z <verify>neovereného</verify> zariadenia <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Záloha je podpísaná <validity>neplatným</validity> kľúčom z <verify>overeného</verify> zariadenia <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Záloha je podpísaná <validity>neplatným</validity> kľúčom z <verify>neovereného</verify> zariadenia <device></device>",
"Backup is not signed by any of your devices": "Záloha nie je podpísaná žiadnym z vašich zariadení",
"Backup version: ": "Verzia zálohy: ",
"Algorithm: ": "Algoritmus: ",
"Restore backup": "Obnoviť zo zálohy",
"No backup is present": "Nemáte žiadnu zálohu",
"Start a new backup": "Vytvoriť zálohu",
"The following files cannot be uploaded:": "Nie je možné nahrať nasledujúce súbory:",
"Joining room...": "Vstup do miestnosti...",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Aby ste mohli čítať históriu zašifrovaných konverzácií a čítať šifrované správy aj na vašich nových zariadeniach v budúcnosti, nastavte si Bezpečnú obnovu správ.",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Keď sa odhlásite alebo použijete iné zariadenie, stratíte prístup k histórii šifrovaných konverzácií. Predísť tomu môžete, ak si nastavíte Bezpečnú obnovu správ.",
"Secure Message Recovery": "Bezpečná obnova správ",
"Don't ask again": "Viac sa nepýtať",
"Set up": "Nastaviť",
"Open Devtools": "Otvoriť nástroje pre vývojárov",
"Add some now": "Pridajte si nejaké teraz",
"Please review and accept all of the homeserver's policies": "Prosím, prečítajte si a odsúhlaste všetky podmienky tohoto domovského servera",
"Please review and accept the policies of this homeserver:": "Prosím, prečítajte si a odsúhlaste podmienky používania tohoto domovského servera:",
"Failed to load group members": "Nepodarilo sa načítať zoznam členov skupiny",
"That doesn't look like a valid email address": "Toto nevyzerá byť platná emailová adresa",
"The following users may not exist": "Nasledujúci používatelia pravdepodobne neexistujú",
"The following users may not exist - would you like to invite them anyways?": "Nie je možné určiť, či nasledujúci používatelia skutočne existujú - chcete ich napriek tomu pozvať?",
"Invite anyways and never warn me again": "Napriek tomu pozvať a v budúcnosti ma viac neupozorňovať",
"Invite anyways": "Napriek tomu pozvať",
"Unable to load commit detail: %(msg)s": "Nie je možné načítať podrobnosti commit: %(msg)s",
"To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of Riot to do this": "Aby ste po odhlásení neprišli o možnosť čítať históriu šifrovaných konverzácií, mali by ste si ešte pred odhlásením exportovať šifrovacie kľúče miestností. Prosím vráťte sa k novšej verzii Riot a exportujte si kľúče",
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "Už ste použili novšiu verziu Riot na adrese %(host)s. Ak chcete znovu používať túto verziu aj s E2E šifrovaním, musíte sa odhlásiť a potom zas znovu prihlásiť. ",
"Incompatible Database": "Nekompatibilná databáza",
"Continue With Encryption Disabled": "Pokračovať s vypnutým šifrovaním",
"You've previously used Riot on %(host)s with lazy loading of members enabled. In this version lazy loading is disabled. As the local cache is not compatible between these two settings, Riot needs to resync your account.": "Použili ste aj Riot na adrese %(host)s so zapnutou voľbou Načítanie zoznamu členov pri prvom zobrazení. V tejto verzii je Načítanie zoznamu členov pri prvom zobrazení vypnuté. Keď že lokálna vyrovnávacia pamäť nie je vzájomne kompatibilná s takýmito nastaveniami, Riot potrebuje znovu synchronizovať údaje z vašeho účtu.",
"If the other version of Riot is still open in another tab, please close it as using Riot on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Ak máte Riot s iným nastavením otvorený na ďalšej karte, prosím zatvorte ju, pretože použitie Riot s rôznym nastavením na jednom zariadení vám spôsobí len problémy.",
"Incompatible local cache": "Nekompatibilná lokálna vyrovnávacia pamäť",
"Clear cache and resync": "Vymazať vyrovnávaciu pamäť a synchronizovať znovu",
"Only use lower case letters, numbers and '=_-./'": "Len malé písmená, číslice a znaky „=_-./“",
"Checking...": "Kontrola…",
"Unable to load backup status": "Nie je možné načítať stav zálohy",
"Unable to restore backup": "Nie je možné obnoviť zo zálohy",
"No backup found!": "Nebola nájdená žiadna záloha!",
"Backup Restored": "Obnova zo zálohy je hotová",
"Failed to decrypt %(failedCount)s sessions!": "Nepodarilo sa dešifrovať %(failedCount)s relácií!",
"Restored %(sessionCount)s session keys": "Obnovených %(sessionCount)s kľúčov relácií",
"Enter Recovery Passphrase": "Zadajte heslo bezpečného obnovenia",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Vložením vlastného hesla pre bezpečné obnovenie správ, si nastavíte Bezpečnú obnovu správ, aby ste mali neustále prístup k zašifrovaným konverzáciám."
}

View file

@ -1381,5 +1381,53 @@
"Common names and surnames are easy to guess": "Emra dhe mbiemra të rëndomtë janë të kollajtë për tu hamendësuar",
"Great! This passphrase looks strong enough.": "Bukur! Ky frazëkalim duket goxha i fuqishëm.",
"Failed to load group members": "S'u arrit të ngarkoheshin anëtarë grupi",
"As a safety net, you can use it to restore your encrypted message history.": "Si një rrjet sigurie, mund ta përdorni për të rikthyer historikun e mesazheve tuaj të fshehtëzuar."
"As a safety net, you can use it to restore your encrypted message history.": "Si një rrjet sigurie, mund ta përdorni për të rikthyer historikun e mesazheve tuaj të fshehtëzuar.",
"Failed to invite users to the room:": "Su arrit të ftohen përdorues te dhoma:",
"You do not have permission to invite people to this room.": "Skeni leje të ftoni njerëz në këtë dhomë.",
"User %(user_id)s does not exist": "Përdoruesi %(user_id)s nuk ekziston",
"Unknown server error": "Gabim i panjohur shërbyesi",
"There was an error joining the room": "Pati një gabim ardhjeje në dhomë",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "Shfaq një kujtues për aktivizim Rimarrje Mesazhesh të Parrezik në dhoma të fshehtëzuara",
"Secure Message Recovery": "Rimarrje Mesazhesh të Parrezik",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "Nëse dilni nga llogaria apo përdorni një pajisje tjetër, do të humbni historikun e mesazheve të parrezik. Që ta parandaloni këtë, rregulloni Rimarrje Mesazhesh të Parrezik.",
"Don't ask again": "Mos pyet sërish",
"Set up": "Rregulloje",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "Nëse sdoni që historiku i mesazheve të fshehtëzuar të gjendet në pajisje të tjera, <button>zgjidhni lënien jashtë nga kjo</button>.",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Po srregulluat Rimarrje Mesazhesh të Parrezik, do të humbni historikun e mesazheve të parrezik, kur të dilni nga llogaria.",
"If you don't want to set this up now, you can later in Settings.": "Nëse sdoni ta rregulloni tani këtë, mund ta bëni më vonë që nga Rregullimet.",
"Messages containing @room": "Mesazhe që përmbajnë @room",
"Encrypted messages in one-to-one chats": "Mesazhe të fshehtëzuar në fjalosje tek-për-tek",
"Encrypted messages in group chats": "Mesazhe të fshehtëzuar në fjalosje në grup",
"That doesn't look like a valid email address": "Kjo sduket si adresë email e vlefshme",
"Only use lower case letters, numbers and '=_-./'": "Përdorni vetëm shkronja të vogla, numra dhe '=_-./'",
"Checking...": "Po kontrollohet…",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Formësim i pavlefshëm: Smund të jepen një URL parazgjedhje për shërbyesin Home dhe një emër parazgjedhje shërbyesi",
"Unknown error discovering homeserver": "Gabim i panjohur gjatë zbulimit të shërbyesit Home",
"%(count)s Notifications|other": "%(count)s Njoftime",
"%(count)s Notifications|one": "%(count)s Njoftim",
"Invalid identity server discovery response": "Përgjigje e pavlefshme zbulimi identiteti shërbyesi",
"Unknown failure discovering homeserver": "Dështim i panjohur gjatë zbulimi shërbyesi Home",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Kopjeruajtja ka një nënshkrim <validity>të vlefshëm</validity> prej pajisjes së <verify>verifikuar</verify> <device></device>",
"New Recovery Method": "Metodë e Re Rimarrjesh",
"A new recovery passphrase and key for Secure Messages has been detected.": "Janë pikasur një frazëkalim dhe kyç i ri rimarrjesh për Mesazhe të Sigurt.",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Rregullimi i Mesazheve të Sigurt në këtë pajisje do të rifshehtëzojë historikun e mesazheve në këtë pajisje me metodën e re të rimarrjeve.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Nëse metodën e re të rimarrjeve se keni caktuar ju, dikush mund të jetë duke u rrekur të hyjë në llogarinë tuaj. Ndryshoni menjëherë fjalëkalimin e llogarisë tuaj, te Rregullimet, dhe caktoni një metodë të re rimarrjesh.",
"Set up Secure Messages": "Rregulloni Mesazhi të Sigurt",
"Go to Settings": "Kalo te Rregullimet",
"Straight rows of keys are easy to guess": "Rreshta uniformë tastesh janë lehtësisht të hamendësueshëm",
"Short keyboard patterns are easy to guess": "Kombinime të shkurtra tastiere janë lehtësisht të hamendësueshme",
"Custom user status messages": "Mesazhe vetjakë për gjendje përdoruesi",
"Unable to load commit detail: %(msg)s": "Sarrihet të ngarkohen hollësi depozitimi: %(msg)s",
"Set a new status...": "Caktoni një gjendje të re…",
"Clear status": "Pastroji gjendjen",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "Që të shihni historik mesazhesh të sigurta dhe të garantoni se mund ti shihni mesazhet e reja në pajisje të ardhshme, ujdisni Rimarrje Mesazhesh të Sigurt.",
"Unrecognised address": "Adresë jo e pranuar",
"User %(user_id)s may or may not exist": "Përdoruesi %(user_id)s mund të ekzistojë ose jo",
"Waiting for %(userId)s to accept...": "Po pritet që %(userId)s të pranojë…",
"Waiting for %(userId)s to confirm...": "Po pritet që %(userId)s të bëjë ripohimin…",
"Prompt before sending invites to potentially invalid matrix IDs": "Pyet, përpara se të dërgohen ftesa te ID Matrix potencialisht të pavlefshme",
"The following users may not exist": "Përdoruesit vijues mund të mos ekzistojnë",
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Sarrihet të gjenden profile për ID-të Matrix të treguara më poshtë - do të donit të ftohe, sido qoftë?",
"Invite anyway and never warn me again": "Ftoji sido që të jetë dhe mos më sinjalizo më kurrë",
"Invite anyway": "Ftoji sido qoftë"
}

View file

@ -156,7 +156,7 @@
"Add a topic": "添加主题",
"Admin": "管理员",
"Admin Tools": "管理员工具",
"VoIP": "IP 电话",
"VoIP": "VoIP",
"Missing Media Permissions, click here to request.": "没有媒体存储权限,点此获取。",
"No Microphones detected": "未检测到麦克风",
"No Webcams detected": "未检测到摄像头",
@ -1275,5 +1275,54 @@
"%(senderName)s removed %(count)s %(removedAddresses)s as addresses for this room.|one": "%(senderName)s 移除了一个聊天室地址 %(removedAddresses)s。",
"%(senderName)s added %(addedAddresses)s and removed %(removedAddresses)s as addresses for this room.": "%(senderName)s 添加了聊天室地址 %(addedAddresses)s 并移除了地址 %(removedAddresses)s。",
"%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s 将此聊天室的主地址设为了 %(address)s。",
"%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主地址。"
"%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主地址。",
"Unable to load! Check your network connectivity and try again.": "无法加载!请检查您的网络连接并重试。",
"User %(user_id)s does not exist": "用户 %(user_id)s 不存在",
"There was an error joining the room": "加入聊天室时发生错误",
"Custom user status messages": "自定义用户状态信息",
"Backup of encryption keys to server": "将加密密钥备份至服务器",
"Show developer tools": "显示开发者工具",
"Messages containing @room": "含有 @room 的消息",
"Delete Backup": "删除备份",
"Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "是否从服务器中删除您备份的加密密钥?您将无法再次使用您的还原密钥来解密历史加密消息",
"Delete backup": "删除备份",
"Backup version: ": "备份版本: ",
"Algorithm: ": "算法: ",
"Restore backup": "恢复备份",
"Joining room...": "正在加入聊天室…",
"Don't ask again": "不再询问",
"Set up": "设置",
"Open Devtools": "打开开发者工具",
"Secure Message Recovery": "安全消息还原",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "若您退出登录或在其他设备上登录,您将无法查看本客户端上的历史加密消息。为避免这种情况,请设置安全消息还原。",
"Failed to load group members": "聊天室成员加载失败",
"Incompatible local cache": "本地缓存不兼容",
"Clear cache and resync": "清除缓存并重新同步",
"Incompatible Database": "数据库不兼容",
"Continue With Encryption Disabled": "在停用加密的情况下继续",
"Checking...": "正在检查…",
"Updating Riot": "正在更新 Riot",
"Backup Restored": "备份已还原",
"No backup found!": "找不到备份!",
"Unable to restore backup": "无法还原备份",
"Unable to load backup status": "无法获取备份状态",
"Next": "下一个",
"Copy to clipboard": "复制到剪贴板",
"Download": "下载",
"Got it": "知道了",
"Retry": "重试",
"Go to Settings": "打开设置",
"You do not have permission to invite people to this room.": "您没有权限将其他用户邀请至本聊天室。",
"Unknown server error": "未知服务器错误",
"Failed to invite users to the room:": "邀请失败:",
"No need for symbols, digits, or uppercase letters": "不一定要有符号、数字或大写字母",
"Use a longer keyboard pattern with more turns": "使用变化更丰富的字符组合方式",
"Avoid repeated words and characters": "避免重复词语与字符",
"Avoid sequences": "避免递增或递减的序列",
"Avoid recent years": "避免年份",
"Avoid years that are associated with you": "避免与您相关联的年份",
"Avoid dates and years that are associated with you": "避免与您相关联的日期与年份",
"Capitalization doesn't help very much": "大写字母并没有很大的作用",
"All-uppercase is almost as easy to guess as all-lowercase": "全大写的密码通常比全小写的更容易猜测",
"Reversed words aren't much harder to guess": "把单词倒过来不会比原来的难猜很多"
}

View file

@ -1407,5 +1407,53 @@
"Names and surnames by themselves are easy to guess": "姓名與姓氏本身很容易猜測",
"Common names and surnames are easy to guess": "常見的名字與姓氏易於猜測",
"Great! This passphrase looks strong enough.": "很好!這個密碼看起來夠強了。",
"As a safety net, you can use it to restore your encrypted message history.": "做為安全網,您可以使用它來復原您已加密的訊息歷史。"
"As a safety net, you can use it to restore your encrypted message history.": "做為安全網,您可以使用它來復原您已加密的訊息歷史。",
"Failed to invite users to the room:": "邀請使用者到聊天室失敗:",
"There was an error joining the room": "加入聊天室時發生錯誤",
"You do not have permission to invite people to this room.": "您沒有權限邀請夥伴到此聊天室。",
"User %(user_id)s does not exist": "使用者 %(user_id)s 不存在",
"Unknown server error": "未知的伺服器錯誤",
"Failed to load group members": "載入群組成員失敗",
"Show a reminder to enable Secure Message Recovery in encrypted rooms": "顯示在已加密的聊天室中啟用安全訊息復原的提醒",
"Messages containing @room": "包含 @room 的訊息",
"Encrypted messages in one-to-one chats": "在一對一的聊天中的加密訊息",
"Encrypted messages in group chats": "在群組聊天中的已加密訊息",
"Secure Message Recovery": "安全訊息復原",
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "如果您登出或使用其他裝置,您將會遺失您的安全訊息歷史。要避免發生這種事,請設定安全訊息復原。",
"Don't ask again": "不要再次詢問",
"Set up": "設定",
"If you don't want encrypted message history to be available on other devices, <button>opt out</button>.": "如果您不想要在其他裝置上也可以看到已加密的訊息歷史,可以<button>選擇退出</button>。",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "在沒有設定安全訊息復原的情況下,您將會在登出時遺失您的安全訊息歷史。",
"If you don't want to set this up now, you can later in Settings.": "如果您不想立刻進行設定,您稍後可以在設定中進行。",
"That doesn't look like a valid email address": "看起來不像有效的電子郵件地址",
"Invalid configuration: Cannot supply a default homeserver URL and a default server name": "無效的設定:無法提供預設的家伺服器 URL 與預設的伺服器名稱",
"Unknown error discovering homeserver": "探索家伺服器時發生未知的錯誤",
"%(count)s Notifications|other": "%(count)s 個通知",
"%(count)s Notifications|one": "%(count)s 個通知",
"Invalid identity server discovery response": "無效的身份伺服器探索回應",
"General failure": "一般錯誤",
"Unknown failure discovering homeserver": "探索家伺服器時發生未知的失敗",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "備份有從<verify>驗證過的</verify>裝置<device></device>而來的<validity>有效</validity>簽章",
"Only use lower case letters, numbers and '=_-./'": "僅使用小寫字母,數字與 '=_-./'",
"Checking...": "正在檢查……",
"New Recovery Method": "新復原方法",
"A new recovery passphrase and key for Secure Messages has been detected.": "偵測到安全訊息的新復原密碼與金鑰。",
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "在此裝置上設定安全訊息將會以新的復原方法重新加密此裝置的訊息歷史。",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "如果您沒有設定新的復原方法,攻擊者可能會嘗試存取您的帳號。在設定中立刻變更您的密碼並設定新的復原方法。",
"Set up Secure Messages": "設定安全訊息",
"Go to Settings": "到設定",
"Straight rows of keys are easy to guess": "直排按鍵很容易猜到",
"Short keyboard patterns are easy to guess": "短鍵盤重覆很容易猜到",
"Custom user status messages": "自訂使用者狀態訊息",
"Unable to load commit detail: %(msg)s": "無法載入遞交的詳細資訊:%(msg)s",
"Set a new status...": "設定新狀態……",
"Clear status": "清除狀態",
"To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "要檢視您的安全訊息歷史並確保可以在將來的裝置上檢視新訊息,請設定安全訊息復原。",
"Unrecognised address": "無法識別的位置",
"User %(user_id)s may or may not exist": "使用者 %(user_id)s 可能存在也可能不存在",
"Always invite users which may not exist": "總是邀請可能不存在的使用者",
"The following users may not exist": "以下的使用者可能不存在",
"The following users may not exist - would you like to invite them anyways?": "以下的使用者可能不存在,您無論如何都想邀請他們嗎?",
"Invite anyways and never warn me again": "總是邀請而且不要再警告我",
"Invite anyways": "總是邀請"
}

View file

@ -1,53 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
const flux = require("flux");
export default class MatrixDispatcher extends flux.Dispatcher {
/**
* @param {Object|function} payload Required. The payload to dispatch.
* If an Object, must contain at least an 'action' key.
* If a function, must have the signature (dispatch) => {...}.
* @param {boolean=} sync Optional. Pass true to dispatch
* synchronously. This is useful for anything triggering
* an operation that the browser requires user interaction
* for.
*/
dispatch(payload, sync) {
// Allow for asynchronous dispatching by accepting payloads that have the
// type `function (dispatch) {...}`
if (typeof payload === 'function') {
payload((action) => {
this.dispatch(action, sync);
});
return;
}
if (sync) {
super.dispatch(payload);
} else {
// Unless the caller explicitly asked for us to dispatch synchronously,
// we always set a timeout to do this: The flux dispatcher complains
// if you dispatch from within a dispatch, so rather than action
// handlers having to worry about not calling anything that might
// then dispatch, we just do dispatches asynchronously.
setTimeout(super.dispatch.bind(this, payload), 0);
}
}
}

View file

@ -1,82 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
distributors translate a moving cursor into
CSS/DOM changes by calling the sizer
they have two methods:
`resize` receives then new item size
`resizeFromContainerOffset` receives resize handle location
within the container bounding box. For internal use.
This method usually ends up calling `resize` once the start offset is subtracted.
the offset from the container edge of where
the mouse cursor is.
*/
class FixedDistributor {
constructor(sizer, item, id, config) {
this.sizer = sizer;
this.item = item;
this.id = id;
this.beforeOffset = sizer.getItemOffset(this.item);
this.onResized = config && config.onResized;
}
resize(itemSize) {
this.sizer.setItemSize(this.item, itemSize);
if (this.onResized) {
this.onResized(itemSize, this.id, this.item);
}
return itemSize;
}
resizeFromContainerOffset(offset) {
this.resize(offset - this.beforeOffset);
}
}
class CollapseDistributor extends FixedDistributor {
constructor(sizer, item, id, config) {
super(sizer, item, id, config);
this.toggleSize = config && config.toggleSize;
this.onCollapsed = config && config.onCollapsed;
this.isCollapsed = false;
}
resize(newSize) {
const isCollapsedSize = newSize < this.toggleSize;
if (isCollapsedSize && !this.isCollapsed) {
this.isCollapsed = true;
if (this.onCollapsed) {
this.onCollapsed(true, this.item);
}
} else if (!isCollapsedSize && this.isCollapsed) {
if (this.onCollapsed) {
this.onCollapsed(false, this.item);
}
this.isCollapsed = false;
}
if (!isCollapsedSize) {
super.resize(newSize);
}
}
}
module.exports = {
FixedDistributor,
CollapseDistributor,
};

View file

@ -0,0 +1,53 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import FixedDistributor from "./fixed";
import ResizeItem from "../item";
class CollapseItem extends ResizeItem {
notifyCollapsed(collapsed) {
const callback = this.resizer.config.onCollapsed;
if (callback) {
callback(collapsed, this.id, this.domNode);
}
}
}
export default class CollapseDistributor extends FixedDistributor {
static createItem(resizeHandle, resizer, sizer) {
return new CollapseItem(resizeHandle, resizer, sizer);
}
constructor(item, config) {
super(item);
this.toggleSize = config && config.toggleSize;
this.isCollapsed = false;
}
resize(newSize) {
const isCollapsedSize = newSize < this.toggleSize;
if (isCollapsedSize && !this.isCollapsed) {
this.isCollapsed = true;
this.item.notifyCollapsed(true);
} else if (!isCollapsedSize && this.isCollapsed) {
this.item.notifyCollapsed(false);
this.isCollapsed = false;
}
if (!isCollapsedSize) {
super.resize(newSize);
}
}
}

View file

@ -0,0 +1,55 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import ResizeItem from "../item";
import Sizer from "../sizer";
/**
distributors translate a moving cursor into
CSS/DOM changes by calling the sizer
they have two methods:
`resize` receives then new item size
`resizeFromContainerOffset` receives resize handle location
within the container bounding box. For internal use.
This method usually ends up calling `resize` once the start offset is subtracted.
*/
export default class FixedDistributor {
static createItem(resizeHandle, resizer, sizer) {
return new ResizeItem(resizeHandle, resizer, sizer);
}
static createSizer(containerElement, vertical, reverse) {
return new Sizer(containerElement, vertical, reverse);
}
constructor(item) {
this.item = item;
this.beforeOffset = item.offset();
}
resize(size) {
this.item.setSize(size);
}
resizeFromContainerOffset(offset) {
this.resize(offset - this.beforeOffset);
}
start() {}
finish() {}
}

View file

@ -0,0 +1,132 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Sizer from "../sizer";
import ResizeItem from "../item";
class RoomSizer extends Sizer {
setItemSize(item, size) {
item.style.maxHeight = `${Math.round(size)}px`;
item.classList.add("resized-sized");
}
clearItemSize(item) {
item.style.maxHeight = null;
item.classList.remove("resized-sized");
}
}
class RoomSubListItem extends ResizeItem {
isCollapsed() {
return this.domNode.classList.contains("mx_RoomSubList_hidden");
}
maxSize() {
const header = this.domNode.querySelector(".mx_RoomSubList_labelContainer");
const scrollItem = this.domNode.querySelector(".mx_RoomSubList_scroll");
const headerHeight = this.sizer.getItemSize(header);
return headerHeight + (scrollItem ? scrollItem.scrollHeight : 0);
}
minSize() {
const isNotEmpty = this.domNode.classList.contains("mx_RoomSubList_nonEmpty");
return isNotEmpty ? 74 : 31; //size of header + 1? room tile (see room sub list css)
}
isSized() {
return this.domNode.classList.contains("resized-sized");
}
}
export default class RoomSubListDistributor {
static createItem(resizeHandle, resizer, sizer) {
return new RoomSubListItem(resizeHandle, resizer, sizer);
}
static createSizer(containerElement, vertical, reverse) {
return new RoomSizer(containerElement, vertical, reverse);
}
constructor(item) {
this.item = item;
}
_handleSize() {
return 1;
}
resize(size) {
//console.log("*** starting resize session with size", size);
let item = this.item;
while (item) {
const minSize = item.minSize();
if (item.isCollapsed()) {
item = item.previous();
} else if (size <= minSize) {
//console.log(" - resizing", item.id, "to min size", minSize);
item.setSize(minSize);
const remainder = minSize - size;
item = item.previous();
if (item) {
size = item.size() - remainder - this._handleSize();
}
} else {
const maxSize = item.maxSize();
if (size > maxSize) {
// console.log(" - resizing", item.id, "to maxSize", maxSize);
item.setSize(maxSize);
const remainder = size - maxSize;
item = item.previous();
if (item) {
size = item.size() + remainder; // todo: handle size here?
}
} else {
//console.log(" - resizing", item.id, "to size", size);
item.setSize(size);
item = null;
size = 0;
}
}
}
//console.log("*** ending resize session");
}
resizeFromContainerOffset(containerOffset) {
this.resize(containerOffset - this.item.offset());
}
start() {
// set all max-height props to the actual height.
let item = this.item.first();
const sizes = [];
while (item) {
if (!item.isCollapsed()) {
sizes.push(item.size());
} else {
sizes.push(100);
}
item = item.next();
}
item = this.item.first();
sizes.forEach((size) => {
item.setSize(size);
item = item.next();
});
}
finish() {
}
}

View file

@ -14,17 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {Sizer, FlexSizer} from "./sizer";
import {FixedDistributor, CollapseDistributor} from "./distributors";
import {Resizer} from "./resizer";
import {RoomSizer, RoomDistributor} from "./room";
import FixedDistributor from "./distributors/fixed";
import CollapseDistributor from "./distributors/collapse";
import RoomSubListDistributor from "./distributors/roomsublist";
import Resizer from "./resizer";
module.exports = {
Resizer,
Sizer,
FlexSizer,
FixedDistributor,
CollapseDistributor,
RoomSizer,
RoomDistributor,
RoomSubListDistributor,
};

107
src/resizer/item.js Normal file
View file

@ -0,0 +1,107 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export default class ResizeItem {
constructor(handle, resizer, sizer) {
const id = handle.getAttribute("data-id");
const reverse = resizer.isReverseResizeHandle(handle);
const domNode = reverse ? handle.nextElementSibling : handle.previousElementSibling;
this.domNode = domNode;
this.id = id;
this.reverse = reverse;
this.resizer = resizer;
this.sizer = sizer;
}
_copyWith(handle, resizer, sizer) {
const Ctor = this.constructor;
return new Ctor(handle, resizer, sizer);
}
_advance(forwards) {
// opposite direction from fromResizeHandle to get back to handle
let handle = this.reverse ?
this.domNode.previousElementSibling :
this.domNode.nextElementSibling;
const moveNext = forwards !== this.reverse; // xor
// iterate at least once to avoid infinite loop
do {
if (moveNext) {
handle = handle.nextElementSibling;
} else {
handle = handle.previousElementSibling;
}
} while (handle && !this.resizer.isResizeHandle(handle));
if (handle) {
const nextHandle = this._copyWith(handle, this.resizer, this.sizer);
nextHandle.reverse = this.reverse;
return nextHandle;
}
}
next() {
return this._advance(true);
}
previous() {
return this._advance(false);
}
size() {
return this.sizer.getItemSize(this.domNode);
}
offset() {
return this.sizer.getItemOffset(this.domNode);
}
setSize(size) {
this.sizer.setItemSize(this.domNode, size);
const callback = this.resizer.config.onResized;
if (callback) {
callback(size, this.id, this.domNode);
}
}
clearSize() {
this.sizer.clearItemSize(this.domNode);
const callback = this.resizer.config.onResized;
if (callback) {
callback(null, this.id, this.domNode);
}
}
first() {
const firstHandle = Array.from(this.domNode.parentElement.children).find(el => {
return this.resizer.isResizeHandle(el);
});
if (firstHandle) {
return this._copyWith(firstHandle, this.resizer, this.sizer);
}
}
last() {
const lastHandle = Array.from(this.domNode.parentElement.children).reverse().find(el => {
return this.resizer.isResizeHandle(el);
});
if (lastHandle) {
return this._copyWith(lastHandle, this.resizer, this.sizer);
}
}
}

View file

@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {Sizer} from "./sizer";
/*
classNames:
// class on resize-handle
@ -28,12 +26,14 @@ classNames:
resizing: string
*/
export class Resizer {
constructor(container, distributorCtor, distributorCfg, sizerCtor = Sizer) {
export default class Resizer {
// TODO move vertical/horizontal to config option/container class
// as it doesn't make sense to mix them within one container/Resizer
constructor(container, distributorCtor, config) {
this.container = container;
this.distributorCtor = distributorCtor;
this.distributorCfg = distributorCfg;
this.sizerCtor = sizerCtor;
this.config = config;
this.classNames = {
handle: "resizer-handle",
reverse: "resizer-reverse",
@ -79,7 +79,11 @@ export class Resizer {
}
}
_isResizeHandle(el) {
isReverseResizeHandle(el) {
return el && el.classList.contains(this.classNames.reverse);
}
isResizeHandle(el) {
return el && el.classList.contains(this.classNames.handle);
}
@ -99,6 +103,7 @@ export class Resizer {
}
const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle);
distributor.start();
const onMouseMove = (event) => {
const offset = sizer.offsetFromEvent(event);
@ -106,48 +111,33 @@ export class Resizer {
};
const body = document.body;
const onMouseUp = (event) => {
const finishResize = () => {
if (this.classNames.resizing) {
this.container.classList.remove(this.classNames.resizing);
}
body.removeEventListener("mouseup", onMouseUp, false);
distributor.finish();
body.removeEventListener("mouseup", finishResize, false);
document.removeEventListener("mouseleave", finishResize, false);
body.removeEventListener("mousemove", onMouseMove, false);
};
body.addEventListener("mouseup", onMouseUp, false);
body.addEventListener("mouseup", finishResize, false);
document.addEventListener("mouseleave", finishResize, false);
body.addEventListener("mousemove", onMouseMove, false);
}
_createSizerAndDistributor(resizeHandle) {
const vertical = resizeHandle.classList.contains(this.classNames.vertical);
const reverse = resizeHandle.classList.contains(this.classNames.reverse);
// eslint-disable-next-line new-cap
const sizer = new this.sizerCtor(this.container, vertical, reverse);
const items = this._getResizableItems();
const prevItem = resizeHandle.previousElementSibling;
// if reverse, resize the item after the handle instead of before, so + 1
const itemIndex = items.indexOf(prevItem) + (reverse ? 1 : 0);
const item = items[itemIndex];
const id = resizeHandle.getAttribute("data-id");
// eslint-disable-next-line new-cap
const distributor = new this.distributorCtor(
sizer, item, id, this.distributorCfg,
items, this.container);
const reverse = this.isReverseResizeHandle(resizeHandle);
const Distributor = this.distributorCtor;
const sizer = Distributor.createSizer(this.container, vertical, reverse);
const item = Distributor.createItem(resizeHandle, this, sizer);
const distributor = new Distributor(item, this.config);
return {sizer, distributor};
}
_getResizableItems() {
return Array.from(this.container.children).filter(el => {
return !this._isResizeHandle(el) && (
this._isResizeHandle(el.previousElementSibling) ||
this._isResizeHandle(el.nextElementSibling));
});
}
_getResizeHandles() {
return Array.from(this.container.children).filter(el => {
return this._isResizeHandle(el);
return this.isResizeHandle(el);
});
}
}

View file

@ -1,60 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {Sizer} from "./sizer";
import {FixedDistributor} from "./distributors";
class RoomSizer extends Sizer {
setItemSize(item, size) {
const isString = typeof size === "string";
const cl = item.classList;
if (isString) {
if (size === "resized-all") {
cl.add("resized-all");
cl.remove("resized-sized");
item.style.maxHeight = null;
}
} else {
cl.add("resized-sized");
cl.remove("resized-all");
item.style.maxHeight = `${Math.round(size)}px`;
}
}
}
class RoomDistributor extends FixedDistributor {
resize(itemSize) {
const scrollItem = this.item.querySelector(".mx_RoomSubList_scroll");
if (!scrollItem) {
return; //FIXME: happens when starting the page on a community url, taking the safe way out for now
}
const fixedHeight = this.item.offsetHeight - scrollItem.offsetHeight;
if (itemSize > (fixedHeight + scrollItem.scrollHeight)) {
super.resize("resized-all");
} else {
super.resize(itemSize);
}
}
resizeFromContainerOffset(offset) {
return this.resize(offset - this.sizer.getItemOffset(this.item));
}
}
module.exports = {
RoomSizer,
RoomDistributor,
};

View file

@ -18,31 +18,13 @@ limitations under the License.
implements DOM/CSS operations for resizing.
The sizer determines what CSS mechanism is used for sizing items, like flexbox, ...
*/
class Sizer {
export default class Sizer {
constructor(container, vertical, reverse) {
this.container = container;
this.reverse = reverse;
this.vertical = vertical;
}
getItemPercentage(item) {
/*
const flexGrow = window.getComputedStyle(item).flexGrow;
if (flexGrow === "") {
return null;
}
return parseInt(flexGrow) / 1000;
*/
const style = window.getComputedStyle(item);
const sizeStr = this.vertical ? style.height : style.width;
const size = parseInt(sizeStr, 10);
return size / this.getTotalSize();
}
setItemPercentage(item, percent) {
item.style.flexGrow = Math.round(percent * 1000);
}
/**
@param {Element} item the dom element being resized
@return {number} how far the edge of the item is from the edge of the container
@ -82,6 +64,14 @@ class Sizer {
}
}
clearItemSize(item) {
if (this.vertical) {
item.style.height = null;
} else {
item.style.width = null;
}
}
/**
@param {MouseEvent} event the mouse event
@return {number} the distance between the cursor and the edge of the container,
@ -96,12 +86,3 @@ class Sizer {
}
}
}
class FlexSizer extends Sizer {
setItemSize(item, size) {
item.style.flexGrow = `0`;
item.style.flexBasis = `${Math.round(size)}px`;
}
}
module.exports = {Sizer, FlexSizer};

View file

@ -22,6 +22,7 @@ import {
NotificationsEnabledController,
} from "./controllers/NotificationControllers";
import LazyLoadingController from "./controllers/LazyLoadingController";
import CustomStatusController from "./controllers/CustomStatusController";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config'];
@ -88,6 +89,7 @@ export const SETTINGS = {
displayName: _td("Custom user status messages"),
supportedLevels: LEVELS_FEATURE,
default: false,
controller: new CustomStatusController(),
},
"feature_lazyloading": {
isFeature: true,
@ -108,12 +110,6 @@ export const SETTINGS = {
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_gridview": {
isFeature: true,
displayName: _td("Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_sas": {
isFeature: true,
displayName: _td("Two-way device verification using short text"),
@ -330,9 +326,9 @@ export const SETTINGS = {
supportedLevels: ['room-device'],
default: false,
},
"RoomSubList.showEmpty": {
"promptBeforeInviteUnknownUsers": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Show empty room list headings'),
displayName: _td('Prompt before sending invites to potentially invalid matrix IDs'),
default: true,
},
"showDeveloperTools": {

View file

@ -0,0 +1,28 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import SettingController from "./SettingController";
import dis from "../../dispatcher";
export default class CustomStatusController extends SettingController {
onChange(level, roomId, newValue) {
// Dispatch setting change so that some components that are still visible when the
// Settings page is open (such as RoomTiles) can reflect the change.
dis.dispatch({
action: "feature_custom_status_changed",
});
}
}

View file

@ -1,277 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import MatrixDispatcher from '../matrix-dispatcher';
import dis from '../dispatcher';
import {RoomViewStore} from './RoomViewStore';
import GroupStore from './GroupStore';
import {Store} from 'flux/utils';
import MatrixClientPeg from '../MatrixClientPeg';
function matchesRoom(payload, roomStore) {
if (!roomStore) {
return false;
}
if (payload.room_alias) {
return payload.room_alias === roomStore.getRoomAlias();
}
return payload.room_id === roomStore.getRoomId();
}
/**
* A class for keeping track of the RoomViewStores of the rooms shown on the screen.
* Routes the dispatcher actions to the store of currently active room.
*/
class OpenRoomsStore extends Store {
constructor() {
super(dis);
// Initialise state
this._state = {
rooms: [],
currentIndex: null,
group_id: null,
};
this._forwardingEvent = null;
}
getRoomStores() {
return this._state.rooms.map((r) => r.store);
}
getActiveRoomStore() {
const openRoom = this._getActiveOpenRoom();
if (openRoom) {
return openRoom.store;
}
}
getRoomStoreAt(index) {
if (index >= 0 && index < this._state.rooms.length) {
return this._state.rooms[index].store;
}
}
_getActiveOpenRoom() {
const index = this._state.currentIndex;
if (index !== null && index < this._state.rooms.length) {
return this._state.rooms[index];
}
}
_setState(newState) {
this._state = Object.assign(this._state, newState);
this.__emitChange();
}
_hasRoom(payload) {
return this._roomIndex(payload) !== -1;
}
_roomIndex(payload) {
return this._state.rooms.findIndex((r) => matchesRoom(payload, r.store));
}
_cleanupOpenRooms() {
this._state.rooms.forEach((room) => {
room.dispatcher.unregister(room.dispatcherRef);
room.dispatcher.unregister(room.store.getDispatchToken());
});
this._setState({
rooms: [],
group_id: null,
currentIndex: null,
});
}
_createOpenRoom(roomId, roomAlias) {
const dispatcher = new MatrixDispatcher();
// forward all actions coming from the room dispatcher
// to the global one
const dispatcherRef = dispatcher.register((payload) => {
// block a view_room action for the same room because it will switch to
// single room mode in MatrixChat
if (payload.action === 'view_room' && roomId === payload.room_id) {
return;
}
payload.grid_src_room_id = roomId;
payload.grid_src_room_alias = roomAlias;
this.getDispatcher().dispatch(payload);
});
const openRoom = {
store: new RoomViewStore(dispatcher),
dispatcher,
dispatcherRef,
};
dispatcher.dispatch({
action: 'view_room',
room_id: roomId,
room_alias: roomAlias,
}, true);
return openRoom;
}
_setSingleOpenRoom(payload) {
this._setState({
rooms: [this._createOpenRoom(payload.room_id, payload.room_alias)],
currentIndex: 0,
});
}
_setGroupOpenRooms(groupId) {
this._cleanupOpenRooms();
// TODO: register to GroupStore updates
const rooms = GroupStore.getGroupRooms(groupId);
const openRooms = rooms.map((room) => {
return this._createOpenRoom(room.roomId);
});
this._setState({
rooms: openRooms,
group_id: groupId,
currentIndex: 0,
});
}
_forwardAction(payload) {
// don't forward an event to a room dispatcher
// if the event originated from that dispatcher, as this
// would cause the event to be observed twice in that
// dispatcher
if (payload.grid_src_room_id || payload.grid_src_room_alias) {
const srcPayload = {
room_id: payload.grid_src_room_id,
room_alias: payload.grid_src_room_alias,
};
const srcIndex = this._roomIndex(srcPayload);
if (srcIndex === this._state.currentIndex) {
return;
}
}
const currentRoom = this._getActiveOpenRoom();
if (currentRoom) {
currentRoom.dispatcher.dispatch(payload, true);
}
}
async _resolveRoomAlias(payload) {
try {
const result = await MatrixClientPeg.get()
.getRoomIdForAlias(payload.room_alias);
this.getDispatcher().dispatch({
action: 'view_room',
room_id: result.room_id,
event_id: payload.event_id,
highlighted: payload.highlighted,
room_alias: payload.room_alias,
auto_join: payload.auto_join,
oob_data: payload.oob_data,
});
} catch (err) {
this._forwardAction({
action: 'view_room_error',
room_id: null,
room_alias: payload.room_alias,
err: err,
});
}
}
_viewRoom(payload) {
console.log("!!! OpenRoomsStore: view_room", payload);
if (!payload.room_id && payload.room_alias) {
this._resolveRoomAlias(payload);
}
const currentStore = this.getActiveRoomStore();
if (!matchesRoom(payload, currentStore)) {
if (this._hasRoom(payload)) {
const roomIndex = this._roomIndex(payload);
this._setState({currentIndex: roomIndex});
} else {
this._cleanupOpenRooms();
}
}
if (!this.getActiveRoomStore()) {
console.log("OpenRoomsStore: _setSingleOpenRoom");
this._setSingleOpenRoom(payload);
}
console.log("OpenRoomsStore: _forwardAction");
this._forwardAction(payload);
if (this._forwardingEvent) {
this.getDispatcher().dispatch({
action: 'send_event',
room_id: payload.room_id,
event: this._forwardingEvent,
});
this._forwardingEvent = null;
}
}
__onDispatch(payload) {
let proposedIndex;
switch (payload.action) {
// view_room:
// - room_alias: '#somealias:matrix.org'
// - room_id: '!roomid123:matrix.org'
// - event_id: '$213456782:matrix.org'
// - event_offset: 100
// - highlighted: true
case 'view_room':
this._viewRoom(payload);
break;
case 'view_my_groups':
case 'view_group':
this._forwardAction(payload);
this._cleanupOpenRooms();
break;
case 'will_join':
case 'cancel_join':
case 'join_room':
case 'join_room_error':
case 'on_logged_out':
case 'reply_to_event':
case 'open_room_settings':
case 'close_settings':
case 'focus_composer':
this._forwardAction(payload);
break;
case 'forward_event':
this._forwardingEvent = payload.event;
break;
case 'group_grid_set_active':
proposedIndex = this._roomIndex(payload);
if (proposedIndex !== -1) {
this._setState({
currentIndex: proposedIndex,
});
}
break;
case 'group_grid_view':
if (payload.group_id !== this._state.group_id) {
this._setGroupOpenRooms(payload.group_id);
}
break;
}
}
}
let singletonOpenRoomsStore = null;
if (!singletonOpenRoomsStore) {
singletonOpenRoomsStore = new OpenRoomsStore();
}
module.exports = singletonOpenRoomsStore;

View file

@ -14,6 +14,7 @@ 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 dis from '../dispatcher';
import {Store} from 'flux/utils';
import MatrixClientPeg from '../MatrixClientPeg';
import sdk from '../index';
@ -52,12 +53,12 @@ const INITIAL_STATE = {
* with a subset of the js-sdk.
* ```
*/
export class RoomViewStore extends Store {
constructor(dispatcher) {
super(dispatcher);
class RoomViewStore extends Store {
constructor() {
super(dis);
// Initialise state
this._state = Object.assign({}, INITIAL_STATE);
this._state = INITIAL_STATE;
}
_setState(newState) {
@ -84,8 +85,6 @@ export class RoomViewStore extends Store {
});
break;
case 'view_room_error':
// should not go over dispatcher anymore
// but be internal to RoomViewStore
this._viewRoomError(payload);
break;
case 'will_join':
@ -151,11 +150,22 @@ export class RoomViewStore extends Store {
// pull the user out of Room Settings
isEditingSettings: false,
};
if (this._state.forwardingEvent) {
dis.dispatch({
action: 'send_event',
room_id: newState.roomId,
event: this._state.forwardingEvent,
});
}
this._setState(newState);
if (payload.auto_join) {
this._joinRoom(payload);
}
} else if (payload.room_alias) {
// Resolve the alias and then do a second dispatch with the room ID acquired
this._setState({
roomId: null,
initialEventId: null,
@ -165,6 +175,25 @@ export class RoomViewStore extends Store {
roomLoading: true,
roomLoadError: null,
});
MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done(
(result) => {
dis.dispatch({
action: 'view_room',
room_id: result.room_id,
event_id: payload.event_id,
highlighted: payload.highlighted,
room_alias: payload.room_alias,
auto_join: payload.auto_join,
oob_data: payload.oob_data,
});
}, (err) => {
dis.dispatch({
action: 'view_room_error',
room_id: null,
room_alias: payload.room_alias,
err: err,
});
});
}
}
@ -190,7 +219,7 @@ export class RoomViewStore extends Store {
// stream yet, and that's the point at which we'd consider
// the user joined to the room.
}, (err) => {
this.getDispatcher().dispatch({
dis.dispatch({
action: 'join_room_error',
err: err,
});
@ -306,7 +335,8 @@ export class RoomViewStore extends Store {
}
}
const MatrixDispatcher = require("../matrix-dispatcher");
const backwardsCompatInstance = new RoomViewStore(new MatrixDispatcher());
export default backwardsCompatInstance;
let singletonRoomViewStore = null;
if (!singletonRoomViewStore) {
singletonRoomViewStore = new RoomViewStore();
}
module.exports = singletonRoomViewStore;

View file

@ -15,11 +15,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import MatrixClientPeg from '../MatrixClientPeg';
import {getAddressType} from '../UserAddress';
import GroupStore from '../stores/GroupStore';
import Promise from 'bluebird';
import {_t} from "../languageHandler";
import sdk from "../index";
import Modal from "../Modal";
import SettingsStore from "../settings/SettingsStore";
/**
* Invites multiple addresses to a room or group, handling rate limiting from the server
@ -41,7 +45,7 @@ export default class MultiInviter {
this.addrs = [];
this.busy = false;
this.completionStates = {}; // State of each address (invited or error)
this.errorTexts = {}; // Textual error per address
this.errors = {}; // { address: {errorText, errcode} }
this.deferred = null;
}
@ -61,7 +65,10 @@ export default class MultiInviter {
for (const addr of this.addrs) {
if (getAddressType(addr) === null) {
this.completionStates[addr] = 'error';
this.errorTexts[addr] = 'Unrecognised address';
this.errors[addr] = {
errcode: 'M_INVALID',
errorText: _t('Unrecognised address'),
};
}
}
this.deferred = Promise.defer();
@ -85,18 +92,28 @@ export default class MultiInviter {
}
getErrorText(addr) {
return this.errorTexts[addr];
return this.errors[addr] ? this.errors[addr].errorText : null;
}
async _inviteToRoom(roomId, addr) {
async _inviteToRoom(roomId, addr, ignoreProfile) {
const addrType = getAddressType(addr);
if (addrType === 'email') {
return MatrixClientPeg.get().inviteByEmail(roomId, addr);
} else if (addrType === 'mx-user-id') {
const profile = await MatrixClientPeg.get().getProfileInfo(addr);
if (!profile) {
return Promise.reject({errcode: "M_NOT_FOUND", error: "User does not have a profile."});
if (!ignoreProfile && SettingsStore.getValue("promptBeforeInviteUnknownUsers", this.roomId)) {
try {
const profile = await MatrixClientPeg.get().getProfileInfo(addr);
if (!profile) {
// noinspection ExceptionCaughtLocallyJS
throw new Error("User has no profile");
}
} catch (e) {
throw {
errcode: "RIOT.USER_NOT_FOUND",
error: "User does not have a profile or does not exist."
};
}
}
return MatrixClientPeg.get().invite(roomId, addr);
@ -105,14 +122,109 @@ export default class MultiInviter {
}
}
_doInvite(address, ignoreProfile) {
return new Promise((resolve, reject) => {
console.log(`Inviting ${address}`);
_inviteMore(nextIndex) {
let doInvite;
if (this.groupId !== null) {
doInvite = GroupStore.inviteUserToGroup(this.groupId, address);
} else {
doInvite = this._inviteToRoom(this.roomId, address, ignoreProfile);
}
doInvite.then(() => {
if (this._canceled) {
return;
}
this.completionStates[address] = 'invited';
delete this.errors[address];
resolve();
}).catch((err) => {
if (this._canceled) {
return;
}
let errorText;
let fatal = false;
if (err.errcode === 'M_FORBIDDEN') {
fatal = true;
errorText = _t('You do not have permission to invite people to this room.');
} else if (err.errcode === 'M_LIMIT_EXCEEDED') {
// we're being throttled so wait a bit & try again
setTimeout(() => {
this._doInvite(address, ignoreProfile).then(resolve, reject);
}, 5000);
return;
} else if (['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'RIOT.USER_NOT_FOUND'].includes(err.errcode)) {
errorText = _t("User %(user_id)s does not exist", {user_id: address});
} else if (err.errcode === 'M_PROFILE_UNDISCLOSED') {
errorText = _t("User %(user_id)s may or may not exist", {user_id: address});
} else if (err.errcode === 'M_PROFILE_NOT_FOUND' && !ignoreProfile) {
// Invite without the profile check
console.warn(`User ${address} does not have a profile - inviting anyways automatically`);
this._doInvite(address, true).then(resolve, reject);
} else {
errorText = _t('Unknown server error');
}
this.completionStates[address] = 'error';
this.errors[address] = {errorText, errcode: err.errcode};
this.busy = !fatal;
this.fatal = fatal;
if (fatal) {
reject();
} else {
resolve();
}
});
});
}
_inviteMore(nextIndex, ignoreProfile) {
if (this._canceled) {
return;
}
if (nextIndex === this.addrs.length) {
this.busy = false;
if (Object.keys(this.errors).length > 0 && !this.groupId) {
// There were problems inviting some people - see if we can invite them
// without caring if they exist or not.
const unknownProfileErrors = ['M_NOT_FOUND', 'M_USER_NOT_FOUND', 'M_PROFILE_UNDISCLOSED', 'M_PROFILE_NOT_FOUND', 'RIOT.USER_NOT_FOUND'];
const unknownProfileUsers = Object.keys(this.errors).filter(a => unknownProfileErrors.includes(this.errors[a].errcode));
if (unknownProfileUsers.length > 0) {
const inviteUnknowns = () => {
const promises = unknownProfileUsers.map(u => this._doInvite(u, true));
Promise.all(promises).then(() => this.deferred.resolve(this.completionStates));
};
if (!SettingsStore.getValue("promptBeforeInviteUnknownUsers", this.roomId)) {
inviteUnknowns();
return;
}
const AskInviteAnywayDialog = sdk.getComponent("dialogs.AskInviteAnywayDialog");
console.log("Showing failed to invite dialog...");
Modal.createTrackedDialog('Failed to invite the following users to the room', '', AskInviteAnywayDialog, {
unknownProfileUsers: unknownProfileUsers.map(u => {return {userId: u, errorText: this.errors[u].errorText};}),
onInviteAnyways: () => inviteUnknowns(),
onGiveUp: () => {
// Fake all the completion states because we already warned the user
for (const addr of unknownProfileUsers) {
this.completionStates[addr] = 'invited';
}
this.deferred.resolve(this.completionStates);
},
});
return;
}
}
this.deferred.resolve(this.completionStates);
return;
}
@ -134,48 +246,8 @@ export default class MultiInviter {
return;
}
let doInvite;
if (this.groupId !== null) {
doInvite = GroupStore.inviteUserToGroup(this.groupId, addr);
} else {
doInvite = this._inviteToRoom(this.roomId, addr);
}
doInvite.then(() => {
if (this._canceled) { return; }
this.completionStates[addr] = 'invited';
this._inviteMore(nextIndex + 1);
}).catch((err) => {
if (this._canceled) { return; }
let errorText;
let fatal = false;
if (err.errcode === 'M_FORBIDDEN') {
fatal = true;
errorText = _t('You do not have permission to invite people to this room.');
} else if (err.errcode === 'M_LIMIT_EXCEEDED') {
// we're being throttled so wait a bit & try again
setTimeout(() => {
this._inviteMore(nextIndex);
}, 5000);
return;
} else if(err.errcode === "M_NOT_FOUND") {
errorText = _t("User %(user_id)s does not exist", {user_id: addr});
} else {
errorText = _t('Unknown server error');
}
this.completionStates[addr] = 'error';
this.errorTexts[addr] = errorText;
this.busy = !fatal;
this.fatal = fatal;
if (!fatal) {
this._inviteMore(nextIndex + 1);
} else {
this.deferred.resolve(this.completionStates);
}
});
this._doInvite(addr, ignoreProfile).then(() => {
this._inviteMore(nextIndex + 1, ignoreProfile);
}).catch(() => this.deferred.resolve(this.completionStates));
}
}

View file

@ -26,6 +26,7 @@ Once a timer is finished or aborted, it can't be started again
a new one through `clone()` or `cloneIfRun()`.
*/
export default class Timer {
constructor(timeout) {
this._timeout = timeout;
this._onTimeout = this._onTimeout.bind(this);