Merge branch 'v2.6.x-release' into I-17465

This commit is contained in:
André Castro 2023-04-27 19:25:56 -03:00 committed by GitHub
commit 2c52c1a596
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
171 changed files with 1751 additions and 625 deletions

View File

@ -19,8 +19,8 @@ trait UserConnectedToGlobalAudioMsgHdlr {
val header = BbbClientMsgHeader(UserJoinedVoiceConfToClientEvtMsg.NAME, props.meetingProp.intId, vu.intId)
val body = UserJoinedVoiceConfToClientEvtMsgBody(voiceConf = msg.header.voiceConf, intId = vu.intId, voiceUserId = vu.intId,
callingWith = vu.callingWith, callerName = vu.callerName,
callerNum = vu.callerNum, muted = true, talking = false, listenOnly = true)
callingWith = vu.callingWith, callerName = vu.callerName, callerNum = vu.callerNum, color = vu.color,
muted = true, talking = false, listenOnly = true)
val event = UserJoinedVoiceConfToClientEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
@ -36,6 +36,7 @@ trait UserConnectedToGlobalAudioMsgHdlr {
callingWith = "flash",
callerName = user.name,
callerNum = user.name,
color = user.color,
muted = true,
talking = false,
listenOnly = true,

View File

@ -130,7 +130,7 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers {
def sendAllVoiceUsersInMeeting(requesterId: String, voiceUsers: VoiceUsers, meetingId: String): Unit = {
val vu = VoiceUsers.findAll(voiceUsers).map { u =>
VoiceConfUser(intId = u.intId, voiceUserId = u.voiceUserId, callingWith = u.callingWith, callerName = u.callerName,
callerNum = u.callerNum, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
callerNum = u.callerNum, color = u.color, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
}
val event = MsgBuilder.buildGetVoiceUsersMeetingRespMsg(meetingId, requesterId, vu)

View File

@ -14,7 +14,7 @@ trait SyncGetVoiceUsersMsgHdlr {
def buildSyncGetVoiceUsersRespMsg(): BbbCommonEnvCoreMsg = {
val voiceUsers = VoiceUsers.findAll(liveMeeting.voiceUsers).map { u =>
VoiceConfUser(intId = u.intId, voiceUserId = u.voiceUserId, callingWith = u.callingWith, callerName = u.callerName,
callerNum = u.callerNum, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
callerNum = u.callerNum, color = u.color, muted = u.muted, talking = u.talking, listenOnly = u.listenOnly)
}
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)

View File

@ -88,6 +88,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
msg.body.callingWith,
msg.body.callerIdName,
msg.body.callerIdNum,
userColor,
msg.body.muted,
msg.body.talking,
"freeswitch"

View File

@ -10,6 +10,7 @@ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.running.{LiveMeeting, MeetingActor, OutMsgRouter}
import org.bigbluebutton.core.models._
import org.bigbluebutton.core.apps.users.UsersApp
import org.bigbluebutton.core.util.ColorPicker
object VoiceApp extends SystemConfiguration {
@ -164,6 +165,7 @@ object VoiceApp extends SystemConfiguration {
cvu.callingWith,
cvu.callerIdName,
cvu.callerIdNum,
ColorPicker.nextColor(liveMeeting.props.meetingProp.intId),
cvu.muted,
cvu.talking,
cvu.calledInto
@ -213,6 +215,7 @@ object VoiceApp extends SystemConfiguration {
callingWith: String,
callerIdName: String,
callerIdNum: String,
color: String,
muted: Boolean,
talking: Boolean,
callingInto: String
@ -240,6 +243,7 @@ object VoiceApp extends SystemConfiguration {
voiceUserState.voiceUserId,
voiceUserState.callerName,
voiceUserState.callerNum,
voiceUserState.color,
voiceUserState.muted,
voiceUserState.talking,
voiceUserState.callingWith,
@ -267,6 +271,7 @@ object VoiceApp extends SystemConfiguration {
callingWith,
callerIdName,
callerIdNum,
color,
muted,
talking,
listenOnly = isListenOnly,

View File

@ -174,6 +174,7 @@ case class VoiceUserState(
callingWith: String,
callerName: String,
callerNum: String,
color: String,
muted: Boolean,
talking: Boolean,
listenOnly: Boolean,

View File

@ -42,6 +42,7 @@ trait GuestsWaitingApprovedMsgHdlr extends HandlerHelpers with RightsManagementT
"none",
dialInUser.name,
dialInUser.name,
dialInUser.color,
MeetingStatus2x.isMeetingMuted(liveMeeting.status),
false,
"freeswitch"

View File

@ -65,7 +65,7 @@ object FakeUserGenerator {
val voiceUserId = RandomStringGenerator.randomAlphanumericString(8)
val lastFloorTime = System.currentTimeMillis().toString();
VoiceUserState(intId = user.id, voiceUserId = voiceUserId, callingWith, callerName = user.name,
callerNum = user.name, muted, talking, listenOnly, "freeswitch", System.currentTimeMillis(), floor, lastFloorTime)
callerNum = user.name, "#ff6242", muted, talking, listenOnly, "freeswitch", System.currentTimeMillis(), floor, lastFloorTime)
}
def createFakeVoiceOnlyUser(callingWith: String, muted: Boolean, talking: Boolean,
@ -75,7 +75,7 @@ object FakeUserGenerator {
val name = getRandomElement(firstNames, random) + " " + getRandomElement(lastNames, random)
val lastFloorTime = System.currentTimeMillis().toString();
VoiceUserState(intId, voiceUserId = voiceUserId, callingWith, callerName = name,
callerNum = name, muted, talking, listenOnly, "freeswitch", System.currentTimeMillis(), floor, lastFloorTime)
callerNum = name, "#ff6242", muted, talking, listenOnly, "freeswitch", System.currentTimeMillis(), floor, lastFloorTime)
}
def createFakeWebcamStreamFor(userId: String, subscribers: Set[String]): WebcamStream = {

View File

@ -24,7 +24,7 @@ object TestDataGen {
listenOnly: Boolean): VoiceUserState = {
val voiceUserId = RandomStringGenerator.randomAlphanumericString(8)
VoiceUserState(intId = user.id, voiceUserId = voiceUserId, callingWith, callerName = user.name,
callerNum = user.name, muted, talking, listenOnly)
callerNum = user.name, "#ff6242", muted, talking, listenOnly)
}
def createFakeVoiceOnlyUser(callingWith: String, muted: Boolean, talking: Boolean,
@ -32,7 +32,7 @@ object TestDataGen {
val voiceUserId = RandomStringGenerator.randomAlphanumericString(8)
val intId = "v_" + RandomStringGenerator.randomAlphanumericString(16)
VoiceUserState(intId, voiceUserId = voiceUserId, callingWith, callerName = name,
callerNum = name, muted, talking, listenOnly)
callerNum = name, "#ff6242", muted, talking, listenOnly)
}
def createFakeWebcamStreamFor(userId: String, subscribers: Set[String]): WebcamStream = {

View File

@ -373,7 +373,7 @@ object GetVoiceUsersMeetingRespMsg {
case class GetVoiceUsersMeetingRespMsg(header: BbbClientMsgHeader, body: GetVoiceUsersMeetingRespMsgBody) extends BbbCoreMsg
case class GetVoiceUsersMeetingRespMsgBody(users: Vector[VoiceConfUser])
case class VoiceConfUser(intId: String, voiceUserId: String, callingWith: String, callerName: String,
callerNum: String, muted: Boolean, talking: Boolean, listenOnly: Boolean)
callerNum: String, color: String, muted: Boolean, talking: Boolean, listenOnly: Boolean)
/**
* Sent from client to add user to the presenter group of a meeting.

View File

@ -408,7 +408,7 @@ case class UserJoinedVoiceConfEvtMsgBody(voiceConf: String, voiceUserId: String,
object UserJoinedVoiceConfToClientEvtMsg { val NAME = "UserJoinedVoiceConfToClientEvtMsg" }
case class UserJoinedVoiceConfToClientEvtMsg(header: BbbClientMsgHeader, body: UserJoinedVoiceConfToClientEvtMsgBody) extends BbbCoreMsg
case class UserJoinedVoiceConfToClientEvtMsgBody(voiceConf: String, intId: String, voiceUserId: String, callerName: String,
callerNum: String, muted: Boolean,
callerNum: String, color: String, muted: Boolean,
talking: Boolean, callingWith: String, listenOnly: Boolean)
/**

View File

@ -1 +1 @@
BIGBLUEBUTTON_RELEASE=2.6.1
BIGBLUEBUTTON_RELEASE=2.6.5

View File

@ -744,14 +744,18 @@ check_configuration() {
# Look for properties with no values set
#
CONFIG_FILES="$SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties"
ignore_configs_args=()
ignore_configs_args+=(-e "redis.pass")
ignore_configs_args+=(-e "redisPassword")
ignore_configs_args+=(-e "disabledFeatures")
for file in $CONFIG_FILES ; do
if [ ! -f $file ]; then
echo "# Error: File not found: $file"
else
if cat $file | grep -v redis.pass | grep -v redisPassword | grep -v ^# | grep -q "^[^=]*=[ ]*$"; then
if cat $file | grep -v "${ignore_configs_args[@]}" | grep -v ^# | grep -q "^[^=]*=[ ]*$"; then
echo "# The following properties in $file have no value:"
echo "# $(grep '^[^=#]*=[ ]*$' $file | grep -v redis.pass | grep -v redisPassword | sed 's/=//g')"
echo "# $(grep '^[^=#]*=[ ]*$' $file | grep -v "${ignore_configs_args[@]}" | sed 's/=//g')"
fi
fi
done

View File

@ -108,6 +108,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
background-color: rgba(66, 133, 244, 1) !important;
color: #FFF !important;
}
.fade-in {
opacity: 1 !important;
}
.fade-out {
opacity: 0 !important;
}
</style>
<script>
document.addEventListener('gesturestart', function (e) {

View File

@ -758,9 +758,18 @@ class SIPSession {
const setupRemoteMedia = () => {
const mediaElement = document.querySelector(MEDIA_TAG);
const { sdp } = this.currentSession.sessionDescriptionHandler
.peerConnection.remoteDescription;
logger.info({
logCode: 'sip_js_session_setup_remote_media',
extraInfo: {
callerIdName: this.user.callerIdName,
sdp,
},
}, 'Audio call - setup remote media');
this.remoteStream = new MediaStream();
this.currentSession.sessionDescriptionHandler
.peerConnection.getReceivers().forEach((receiver) => {
if (receiver.track) {
@ -792,22 +801,15 @@ class SIPSession {
fsReady,
},
}, 'Audio call - check if ICE is finished and FreeSWITCH is ready');
if (iceCompleted && fsReady) {
if (iceCompleted) {
this.webrtcConnected = true;
setupRemoteMedia();
}
const { sdp } = this.currentSession.sessionDescriptionHandler
.peerConnection.remoteDescription;
logger.info({
logCode: 'sip_js_session_setup_remote_media',
extraInfo: {
callerIdName: this.user.callerIdName,
sdp,
},
}, 'Audio call - setup remote media');
if (fsReady) {
this.callback({ status: this.baseCallStates.started, bridge: this.bridgeName });
resolve();
}
};

View File

@ -8,7 +8,7 @@ export default async function addDialInUser(meetingId, voiceUser) {
const USER_CONFIG = Meteor.settings.public.user;
const ROLE_VIEWER = USER_CONFIG.role_viewer;
const { intId, callerName } = voiceUser;
const { intId, callerName, color } = voiceUser;
const voiceOnlyUser = {
intId,
@ -23,6 +23,7 @@ export default async function addDialInUser(meetingId, voiceUser) {
presenter: false,
locked: false, // TODO
avatar: '',
color,
pin: false,
clientType: 'dial-in-user',
};

View File

@ -70,6 +70,7 @@ export default async function addUser(meetingId, userData) {
intId: userId,
callerName: user.name,
callerNum: '',
color: user.color,
muted: false,
talking: false,
callingWith: '',

View File

@ -40,6 +40,7 @@ export default async function handleGetVoiceUsers({ body }, meetingId) {
callerName: user.callerName,
callerNum: user.callerNum,
muted: user.muted,
color: user.color,
talking: user.talking,
callingWith: user.callingWith,
listenOnly: user.listenOnly,

View File

@ -3,7 +3,6 @@ import Users from '/imports/api/users';
import addDialInUser from '/imports/api/users/server/modifiers/addDialInUser';
import addVoiceUser from '../modifiers/addVoiceUser';
export default async function handleJoinVoiceUser({ body }, meetingId) {
const voiceUser = body;
voiceUser.joined = true;
@ -15,6 +14,7 @@ export default async function handleJoinVoiceUser({ body }, meetingId) {
voiceUserId: String,
callerName: String,
callerNum: String,
color: String,
muted: Boolean,
talking: Boolean,
callingWith: String,

View File

@ -5,7 +5,6 @@ import removeVoiceUser from '../modifiers/removeVoiceUser';
import updateVoiceUser from '../modifiers/updateVoiceUser';
import addVoiceUser from '../modifiers/addVoiceUser';
export default async function handleVoiceUsers({ header, body }) {
const { voiceUsers } = body;
const { meetingId } = header;
@ -38,6 +37,7 @@ export default async function handleVoiceUsers({ header, body }) {
intId: voice.intId,
callerName: voice.callerName,
callerNum: voice.callerNum,
color: voice.color,
muted: voice.muted,
talking: voice.talking,
callingWith: voice.callingWith,

View File

@ -1,7 +1,6 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import VoiceUsers from '/imports/api/voice-users';
import Users from '/imports/api/users';
import flat from 'flat';
export default async function addVoiceUser(meetingId, voiceUser) {
@ -11,6 +10,7 @@ export default async function addVoiceUser(meetingId, voiceUser) {
intId: String,
callerName: String,
callerNum: String,
color: String,
muted: Boolean,
talking: Boolean,
callingWith: String,
@ -27,19 +27,12 @@ export default async function addVoiceUser(meetingId, voiceUser) {
};
const modifier = {
$set: Object.assign(
{ meetingId, spoke: talking },
flat(voiceUser),
),
};
const user = await Users.findOneAsync({ meetingId, userId: intId }, {
fields: {
color: 1,
$set: {
meetingId,
spoke: talking,
...flat(voiceUser),
},
});
if (user) modifier.$set.color = user.color;
};
try {
const { numberAffected } = await VoiceUsers.upsertAsync(selector, modifier);

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import Button from '/imports/ui/components/common/button/component';
const propTypes = {
intl: PropTypes.shape({
formatMessage: PropTypes.func.isRequired,
@ -47,7 +48,8 @@ const PresentationOptionsContainer = ({
buttonType = 'desktop';
}
const isThereCurrentPresentation = hasExternalVideo || hasScreenshare || hasPresentation || hasPinnedSharedNotes;
const isThereCurrentPresentation = hasExternalVideo || hasScreenshare
|| hasPresentation || hasPinnedSharedNotes;
return (
<Button
icon={`${buttonType}${!presentationIsOpen ? '_off' : ''}`}
@ -59,7 +61,12 @@ const PresentationOptionsContainer = ({
hideLabel
circle
size="lg"
onClick={() => setPresentationIsOpen(layoutContextDispatch, !presentationIsOpen)}
onClick={() => {
setPresentationIsOpen(layoutContextDispatch, !presentationIsOpen);
if (!hasExternalVideo && !hasScreenshare && !hasPinnedSharedNotes) {
Session.set('presentationLastState', !presentationIsOpen);
}
}}
id="restore-presentation"
ghost={!presentationIsOpen}
disabled={!isThereCurrentPresentation}

View File

@ -14,6 +14,7 @@ const AUDIO_INPUT = 'audioinput';
const AUDIO_OUTPUT = 'audiooutput';
const DEFAULT_DEVICE = 'default';
const DEVICE_LABEL_MAX_LENGTH = 40;
const SET_SINK_ID_SUPPORTED = 'setSinkId' in HTMLMediaElement.prototype;
const intlMessages = defineMessages({
changeAudioDevice: {
@ -52,6 +53,10 @@ const intlMessages = defineMessages({
id: 'app.audioNotification.deviceChangeFailed',
description: 'Device change failed',
},
defaultOutputDeviceLabel: {
id: 'app.audio.audioSettings.defaultOutputDeviceLabel',
description: 'Default output device label',
},
});
const propTypes = {
@ -263,8 +268,10 @@ class InputStreamLiveSelector extends Component {
},
];
const deviceList = (listLength > 0)
? list.map((device, index) => (
let deviceList = [];
if (listLength > 0) {
deviceList = list.map((device, index) => (
{
key: `${device.deviceId}-${deviceKind}`,
dataTest: `${deviceKind}-${index + 1}`,
@ -273,8 +280,21 @@ class InputStreamLiveSelector extends Component {
iconRight: (device.deviceId === currentDeviceId) ? 'check' : null,
onClick: () => this.onDeviceListClick(device.deviceId, deviceKind, callback),
}
))
: [
));
} else if (deviceKind === AUDIO_OUTPUT && !SET_SINK_ID_SUPPORTED && listLength === 0) {
// If the browser doesn't support setSinkId, show the chosen output device
// as a placeholder Default - like it's done in audio/device-selector
deviceList = [
{
key: `defaultDeviceKey-${deviceKind}`,
label: intl.formatMessage(intlMessages.defaultOutputDeviceLabel),
customStyles: Styled.SelectedLabel,
iconRight: 'check',
disabled: true,
},
];
} else {
deviceList = [
{
key: `noDeviceFoundKey-${deviceKind}-`,
label: listLength < 0
@ -282,6 +302,8 @@ class InputStreamLiveSelector extends Component {
: intl.formatMessage(intlMessages.noDeviceFound),
},
];
}
return listTitle.concat(deviceList);
}

View File

@ -164,6 +164,7 @@ export default class ButtonBase extends React.Component {
'iconRight',
'isVisualEffects',
'panning',
'panSelected',
];
return (

View File

@ -44,6 +44,7 @@ const EmojiButton = styled.button`
overflow: hidden;
z-index: 2;
border: none;
padding: 0;
[dir="rtl"] & {
right: initial;

View File

@ -231,6 +231,10 @@ class VideoPlayer extends Component {
type: ACTIONS.SET_HAS_EXTERNAL_VIDEO,
value: false,
});
layoutContextDispatch({
type: ACTIONS.SET_PRESENTATION_IS_OPEN,
value: Session.get('presentationLastState'),
});
if (hidePresentationOnJoin) {
layoutContextDispatch({

View File

@ -6,6 +6,7 @@ import { INITIAL_INPUT_STATE } from '/imports/ui/components/layout/initState';
import { ACTIONS, CAMERADOCK_POSITION, PANELS } from '../enums';
import Storage from '/imports/ui/services/storage/session';
import { isPresentationEnabled } from '/imports/ui/services/features';
import Draggable from 'react-draggable';
const windowWidth = () => window.document.documentElement.clientWidth;
const windowHeight = () => window.document.documentElement.clientHeight;
@ -645,7 +646,7 @@ const CustomLayout = (props) => {
left: cameraDockBounds.left,
right: cameraDockBounds.right,
tabOrder: 4,
isDraggable: !isMobile && !isTablet,
isDraggable: !isMobile && !isTablet && presentationInput.isOpen,
resizableEdge: {
top: (input.cameraDock.position === CAMERADOCK_POSITION.CONTENT_BOTTOM)
|| (input.cameraDock.position === CAMERADOCK_POSITION.SIDEBAR_CONTENT_BOTTOM

View File

@ -7,6 +7,7 @@ import MediaService from '/imports/ui/components/media/service';
import { LAYOUT_TYPE, ACTIONS } from '../enums';
import { isMobile } from '../utils';
import { updateSettings } from '/imports/ui/components/settings/service';
import { Session } from 'meteor/session';
const HIDE_PRESENTATION = Meteor.settings.public.layout.hidePresentationOnJoin;
@ -76,6 +77,7 @@ class PushLayoutEngine extends React.Component {
const initialPresentation = !getFromUserSettings('bbb_hide_presentation_on_join', HIDE_PRESENTATION || !meetingPresentationIsOpen) || shouldShowScreenshare || shouldShowExternalVideo;
MediaService.setPresentationIsOpen(layoutContextDispatch, initialPresentation);
Session.set('presentationLastState', initialPresentation);
if (selectedLayout === 'custom') {
setTimeout(() => {

View File

@ -35,7 +35,7 @@ function shouldShowScreenshare() {
}
function shouldShowExternalVideo() {
return isExternalVideoEnabled() && getVideoUrl();
return isExternalVideoEnabled() && !!getVideoUrl();
}
function shouldShowSharedNotes() {

View File

@ -116,7 +116,7 @@ class MobileAppModal extends Component {
color="primary"
disabled={url === ''}
label={intl.formatMessage(intlMessages.openApp)}
onClick={() => window.open(`${BBB_TABLET_APP_CONFIG.iosAppUrlScheme}://${meetingName}/${url}`, '_blank')}
onClick={() => window.open(`${BBB_TABLET_APP_CONFIG.iosAppUrlScheme}://${meetingName}/${encodeURIComponent(url)}`, '_blank')}
role="button"
size="lg"
/>

View File

@ -136,6 +136,10 @@ const Notes = ({
type: ACTIONS.SET_NOTES_IS_PINNED,
value: false,
});
layoutContextDispatch({
type: ACTIONS.SET_PRESENTATION_IS_OPEN,
value: Session.get('presentationLastState'),
});
};
}
}, []);

View File

@ -76,7 +76,7 @@ class Presentation extends PureComponent {
tldrawAPI: null,
isPanning: false,
tldrawIsMounting: true,
presentationId: '',
isToolbarVisible: true,
};
this.currentPresentationToastId = null;
@ -92,6 +92,7 @@ class Presentation extends PureComponent {
this.handleResize = this.handleResize.bind(this);
this.setTldrawAPI = this.setTldrawAPI.bind(this);
this.setIsPanning = this.setIsPanning.bind(this);
this.setIsToolbarVisible = this.setIsToolbarVisible.bind(this);
this.handlePanShortcut = this.handlePanShortcut.bind(this);
this.renderPresentationMenu = this.renderPresentationMenu.bind(this);
@ -370,6 +371,12 @@ class Presentation extends PureComponent {
}));
}
setIsToolbarVisible(isVisible) {
this.setState({
isToolbarVisible: isVisible,
});
}
setPresentationRef(ref) {
this.refPresentationContainer = ref;
}
@ -616,7 +623,7 @@ class Presentation extends PureComponent {
fullscreenElementId,
layoutContextDispatch,
} = this.props;
const { tldrawAPI } = this.state;
const { tldrawAPI, isToolbarVisible } = this.state;
return (
<PresentationMenu
@ -625,6 +632,8 @@ class Presentation extends PureComponent {
elementName={intl.formatMessage(intlMessages.presentationLabel)}
elementId={fullscreenElementId}
layoutContextDispatch={layoutContextDispatch}
setIsToolbarVisible={this.setIsToolbarVisible}
isToolbarVisible={isToolbarVisible}
/>
);
}
@ -657,6 +666,7 @@ class Presentation extends PureComponent {
tldrawIsMounting,
isPanning,
tldrawAPI,
isToolbarVisible,
} = this.state;
let viewBoxDimensions;
@ -763,6 +773,7 @@ class Presentation extends PureComponent {
fullscreenRef={this.refPresentationContainer}
presentationId={currentPresentation?.id}
darkTheme={darkTheme}
isToolbarVisible={isToolbarVisible}
/>
{isFullscreen && <PollingContainer />}
</div>

View File

@ -120,6 +120,8 @@ const PresentationMenu = (props) => {
meetingName,
isIphone,
isRTL,
isToolbarVisible,
setIsToolbarVisible,
} = props;
const [state, setState] = useState({
@ -271,29 +273,14 @@ const PresentationMenu = (props) => {
const tools = document.querySelector('#TD-Tools');
if (tools && (props.hasWBAccess || props.amIPresenter)){
const isVisible = tools.style.visibility == 'hidden' ? false : true;
const styles = document.querySelector('#TD-Styles').parentElement;
const option = document.querySelector('#WhiteboardOptionButton');
if (option) {
//When the RTL-LTR changed, the toolbar appears again,
// while the opacity of this button remains the same.
//So we need to reset the opacity here.
option.style.opacity = isVisible ? 'unset' : '0.2';
}
menuItems.push(
{
key: 'list-item-toolvisibility',
dataTest: 'toolVisibility',
label: formattedVisibilityLabel(isVisible),
icon: isVisible ? 'close' : 'pen_tool',
label: formattedVisibilityLabel(isToolbarVisible),
icon: isToolbarVisible ? 'close' : 'pen_tool',
onClick: () => {
tools.style.visibility = isVisible ? 'hidden' : 'visible';
if (styles) {
styles.style.visibility = isVisible ? 'hidden' : 'visible';
}
if (option) {
option.style.opacity = isVisible ? '0.2' : 'unset';
}
setIsToolbarVisible(!isToolbarVisible);
},
},
);

View File

@ -84,7 +84,6 @@ PresentationToolbarContainer.propTypes = {
previousSlide: PropTypes.func.isRequired,
skipToSlide: PropTypes.func.isRequired,
layoutSwapped: PropTypes.bool,
endCurrentPoll: PropTypes.func.isRequired,
};
PresentationToolbarContainer.defaultProps = {

View File

@ -182,6 +182,10 @@ class ScreenshareComponent extends React.Component {
}
this.clearMediaFlowingMonitor();
layoutContextDispatch({
type: ACTIONS.SET_PRESENTATION_IS_OPEN,
value: Session.get('presentationLastState'),
});
}
clearMediaFlowingMonitor() {

View File

@ -73,6 +73,10 @@ const intlMessages = defineMessages({
id: 'app.submenu.application.paginationEnabledLabel',
description: 'enable/disable video pagination',
},
wbToolbarsAutoHideLabel: {
id: 'app.submenu.application.wbToolbarsAutoHideLabel',
description: 'enable/disable auto hiding of whitebord toolbars',
},
layoutOptionLabel: {
id: 'app.submenu.application.layoutOptionLabel',
description: 'layout options',
@ -420,6 +424,29 @@ class ApplicationMenu extends BaseMenu {
{this.renderPaginationToggle()}
{this.renderDarkThemeToggle()}
<Styled.Row>
<Styled.Col aria-hidden="true">
<Styled.FormElement>
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
<Styled.Label>
{intl.formatMessage(intlMessages.wbToolbarsAutoHideLabel)}
</Styled.Label>
</Styled.FormElement>
</Styled.Col>
<Styled.Col>
<Styled.FormElementRight>
{displaySettingsStatus(settings.whiteboardToolbarAutoHide)}
<Toggle
icons={false}
defaultChecked={settings.whiteboardToolbarAutoHide}
onChange={() => this.handleToggle('whiteboardToolbarAutoHide')}
ariaLabel={`${intl.formatMessage(intlMessages.wbToolbarsAutoHideLabel)} - ${displaySettingsStatus(settings.whiteboardToolbarAutoHide, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>
</Styled.Col>
</Styled.Row>
<Styled.Row>
<Styled.Col>
<Styled.FormElement>

View File

@ -130,21 +130,26 @@ class VideoProvider extends Component {
VideoService.onBeforeUnload();
}
static isAbleToAttach(peer) {
static shouldAttachVideoStream(peer, videoElement) {
// Conditions to safely attach a stream to a video element in all browsers:
// 1 - Peer exists
// 2 - It hasn't been attached yet
// 1 - Peer exists, video element exists
// 2 - Target stream differs from videoElement's (diff)
// 3a - If the stream is a remote one, the safest (*ahem* Safari) moment to
// do so is waiting for the server to confirm that media has flown out of it
// towards te remote end (peer.started)
// 3b - If the stream is a local one (webcam sharer) and is started
// 4 - If the stream is local one, check if there area video tracks there are
// video tracks: attach it
if (peer == null || peer.attached) return false;
if (peer.started) return true;
if (peer == null || videoElement == null) return false;
const stream = peer.isPublisher ? peer.getLocalStream() : peer.getRemoteStream();
const diff = stream && (stream.id !== videoElement.srcObject?.id || !videoElement.paused);
if (peer.started && diff) return true;
return peer.isPublisher
&& peer.getLocalStream()
&& peer.getLocalStream().getVideoTracks().length > 0;
&& peer.getLocalStream().getVideoTracks().length > 0
&& diff;
}
constructor(props) {
@ -654,7 +659,6 @@ class VideoProvider extends Component {
this.webRtcPeers[stream] = peer;
peer.stream = stream;
peer.started = false;
peer.attached = false;
peer.didSDPAnswered = false;
peer.inboundIceQueue = [];
peer.isPublisher = true;
@ -698,7 +702,6 @@ class VideoProvider extends Component {
this.webRtcPeers[stream] = peer;
peer.stream = stream;
peer.started = false;
peer.attached = false;
peer.didSDPAnswered = false;
peer.inboundIceQueue = [];
peer.isPublisher = false;
@ -1019,26 +1022,19 @@ class VideoProvider extends Component {
}
attachVideoStream(stream) {
const video = this.getVideoElement(stream);
if (video == null) {
logger.warn({
logCode: 'video_provider_delay_attach_video_stream',
extraInfo: { cameraId: stream },
}, 'Delaying video stream attachment');
return;
}
const videoElement = this.getVideoElement(stream);
const isLocal = VideoService.isLocalStream(stream);
const peer = this.webRtcPeers[stream];
if (peer && peer.attached && video.srcObject) {
return; // Skip if the stream is already attached
}
if (VideoProvider.isAbleToAttach(peer)) {
this.attach(peer, video);
peer.attached = true;
if (VideoProvider.shouldAttachVideoStream(peer, videoElement)) {
const pc = peer.peerConnection;
// Notify current stream state again on attachment since the
// video-list-item component may not have been mounted before the stream
// reached the connected state.
// This is necessary to ensure that the video element is properly
// hidden/shown when the stream is attached.
notifyStreamStateChange(stream, pc.connectionState);
this.attach(peer, videoElement);
if (isLocal) {
if (peer.bbbVideoStream == null) {
@ -1119,7 +1115,7 @@ class VideoProvider extends Component {
const peer = this.webRtcPeers[stream];
this.videoTags[stream] = video;
if (peer && !peer.attached && peer.stream === stream) {
if (peer && peer.stream === stream) {
this.attachVideoStream(stream);
}
}
@ -1170,10 +1166,7 @@ class VideoProvider extends Component {
// Clear camera shared timeout when camera succesfully starts
this.clearRestartTimers(stream);
if (!peer.attached) {
this.attachVideoStream(stream);
}
VideoService.playStart(stream);
} else {

View File

@ -65,8 +65,8 @@ const VideoListItem = (props) => {
// component did mount
useEffect(() => {
onVideoItemMount(videoTag.current);
subscribeToStreamStateChange(cameraId, onStreamStateChange);
onVideoItemMount(videoTag.current);
resizeObserver.observe(videoContainer.current);
videoTag?.current?.addEventListener('loadeddata', onLoadedData);

View File

@ -154,7 +154,13 @@ const WebcamComponent = ({
if (isRTL) {
draggableOffset.left = draggableOffset.left * -1;
}
const isIphone = !!(navigator.userAgent.match(/iPhone/i));
const mobileWidth = `${isDragging ? cameraSize.width : cameraDock.width}pt`;
const mobileHeight = `${isDragging ? cameraSize.height : cameraDock.height}pt`;
const isDesktopWidth = isDragging ? cameraSize.width : cameraDock.width;
const isDesktopHeight = isDragging ? cameraSize.height : cameraDock.height;
const camOpacity = isDragging ? 0.5 : undefined;
return (
<>
{isDragging ? <DropAreaContainer /> : null}
@ -236,9 +242,9 @@ const WebcamComponent = ({
role="region"
draggable={cameraDock.isDraggable && !isFullscreen ? 'true' : undefined}
style={{
width: isDragging ? cameraSize.width : cameraDock.width,
height: isDragging ? cameraSize.height : cameraDock.height,
opacity: isDragging ? 0.5 : undefined,
width: isIphone ? mobileWidth : isDesktopWidth,
height: isIphone ? mobileHeight : isDesktopHeight,
opacity: camOpacity,
background: isCameraSidebar ? colorContentBackground : null,
}}
>

View File

@ -68,8 +68,12 @@ export default function Whiteboard(props) {
hasMultiUserAccess,
tldrawAPI,
setTldrawAPI,
whiteboardToolbarAutoHide,
toggleToolsAnimations,
isIphone,
sidebarNavigationWidth,
animations,
isToolbarVisible,
} = props;
const { pages, pageStates } = initDefaultPages(curPres?.pages.length || 1);
const rDocument = React.useRef({
@ -160,6 +164,14 @@ export default function Whiteboard(props) {
};
}, [tldrawAPI, isToolLocked]);
React.useEffect(() => {
if (whiteboardToolbarAutoHide) {
toggleToolsAnimations('fade-in', 'fade-out', animations ? '3s' : '0s');
} else {
toggleToolsAnimations('fade-out', 'fade-in', animations ? '.3s' : '0s');
}
}, [whiteboardToolbarAutoHide]);
const calculateZoom = (localWidth, localHeight) => {
const calcedZoom = fitToWidth ? (presentationWidth / localWidth) : Math.min(
(presentationWidth) / localWidth,
@ -206,7 +218,9 @@ export default function Whiteboard(props) {
clientY: event.clientY,
});
const canvas = document.getElementById('canvas');
canvas && canvas.dispatchEvent(newEvent);
if (canvas) {
canvas.dispatchEvent(newEvent);
}
}
}
@ -590,6 +604,7 @@ export default function Whiteboard(props) {
const MENU_OFFSET = '48px';
menu.style.position = 'relative';
menu.style.height = presentationMenuHeight;
menu.setAttribute('id', 'TD-Styles-Parent');
if (isRTL) {
menu.style.left = MENU_OFFSET;
} else {
@ -600,6 +615,7 @@ export default function Whiteboard(props) {
.sort((a, b) => (a?.id > b?.id ? -1 : 1))
.forEach((n) => menu.appendChild(n));
}
app.setSetting('language', language);
app?.setSetting('isDarkMode', false);
app?.patchState(
@ -880,6 +896,10 @@ export default function Whiteboard(props) {
setHistory(app.history);
}
if (whiteboardToolbarAutoHide && command && command.id === "change_page") {
toggleToolsAnimations('fade-in', 'fade-out', '0s');
}
if (command?.id?.includes('style')) {
setCurrentStyle({ ...currentStyle, ...command?.after?.appState?.currentStyle });
}
@ -994,7 +1014,7 @@ export default function Whiteboard(props) {
const menuOffset = menuOffsetValues[isRTL][isIphone];
return (
<>
<div key={`animations=-${animations}`}>
<Cursors
tldrawAPI={tldrawAPI}
currentUser={currentUser}
@ -1005,6 +1025,8 @@ export default function Whiteboard(props) {
isPanning={isPanning || panSelected}
isMoving={isMoving}
currentTool={currentTool}
whiteboardToolbarAutoHide={whiteboardToolbarAutoHide}
toggleToolsAnimations={toggleToolsAnimations}
>
{(hasWBAccess || isPresenter) ? editableWB : readOnlyWB}
<Styled.TldrawGlobalStyle
@ -1016,6 +1038,7 @@ export default function Whiteboard(props) {
darkTheme,
menuOffset,
panSelected,
isToolbarVisible,
}}
/>
</Cursors>
@ -1034,7 +1057,7 @@ export default function Whiteboard(props) {
formatMessage={intl?.formatMessage}
/>
)}
</>
</div>
);
}

View File

@ -7,6 +7,7 @@ import {
SizeStyle,
TDShapeType,
} from '@tldraw/tldraw';
import SettingsService from '/imports/ui/services/settings';
import {
getShapes,
getCurrentPres,
@ -18,6 +19,7 @@ import {
changeCurrentSlide,
notifyNotAllowedChange,
notifyShapeNumberExceeded,
toggleToolsAnimations,
} from './service';
import Whiteboard from './component';
import { UsersContext } from '../components-data/users-context/context';
@ -139,6 +141,9 @@ export default withTracker(({
notifyNotAllowedChange,
notifyShapeNumberExceeded,
darkTheme,
whiteboardToolbarAutoHide: SettingsService?.application?.whiteboardToolbarAutoHide,
animations: SettingsService?.application?.animations,
toggleToolsAnimations,
isIphone,
};
})(WhiteboardContainer);

View File

@ -46,11 +46,25 @@ const Cursors = (props) => {
isPanning,
isMoving,
currentTool,
toggleToolsAnimations,
whiteboardToolbarAutoHide,
application,
} = props;
const [panGrabbing, setPanGrabbing] = React.useState(false);
const start = () => setActive(true);
const start = (event) => {
const targetElement = event?.target;
const className = targetElement instanceof SVGElement
? targetElement?.className?.baseVal
: targetElement?.className;
const hasTlPartial = className?.includes('tl-');
if (hasTlPartial) {
event?.preventDefault();
}
if (whiteboardToolbarAutoHide) toggleToolsAnimations('fade-out', 'fade-in', application?.animations ? '.3s' : '0s');
setActive(true);
};
const handleGrabbing = () => setPanGrabbing(true);
const handleReleaseGrab = () => setPanGrabbing(false);
@ -63,6 +77,7 @@ const Cursors = (props) => {
whiteboardId,
});
}
if (whiteboardToolbarAutoHide) toggleToolsAnimations('fade-in', 'fade-out', application?.animations ? '3s' : '0s');
setActive(false);
};
@ -206,6 +221,7 @@ const Cursors = (props) => {
React.useEffect(() => {
const currentCursor = cursorWrapper?.current;
currentCursor?.addEventListener('mouseenter', start);
currentCursor?.addEventListener('touchstart', start);
currentCursor?.addEventListener('mouseleave', end);
currentCursor?.addEventListener('mousedown', handleGrabbing);
currentCursor?.addEventListener('mouseup', handleReleaseGrab);
@ -215,6 +231,7 @@ const Cursors = (props) => {
return () => {
currentCursor?.removeEventListener('mouseenter', start);
currentCursor?.addEventListener('touchstart', start);
currentCursor?.removeEventListener('mouseleave', end);
currentCursor?.removeEventListener('mousedown', handleGrabbing);
currentCursor?.removeEventListener('mouseup', handleReleaseGrab);
@ -222,7 +239,7 @@ const Cursors = (props) => {
currentCursor?.removeEventListener('mousemove', moved);
currentCursor?.removeEventListener('touchmove', moved);
};
}, [cursorWrapper, whiteboardId, currentUser.presenter]);
}, [cursorWrapper, whiteboardId, currentUser.presenter, whiteboardToolbarAutoHide]);
let cursorType = multiUserAccess || currentUser?.presenter ? TOOL_CURSORS[currentTool] || 'none' : 'default';
if (isPanning) {
@ -319,6 +336,7 @@ Cursors.propTypes = {
isPanning: PropTypes.bool.isRequired,
isMoving: PropTypes.bool.isRequired,
currentTool: PropTypes.string,
toggleToolsAnimations: PropTypes.func.isRequired,
};
Cursors.defaultProps = {

View File

@ -367,6 +367,19 @@ const notifyShapeNumberExceeded = (intl, limit) => {
if (intl) notify(intl.formatMessage(intlMessages.shapeNumberExceeded, { 0: limit }), 'warning', 'whiteboard');
};
const toggleToolsAnimations = (activeAnim, anim, time) => {
const tdTools = document.querySelector("#TD-Tools");
const topToolbar = document.getElementById("TD-Styles")?.parentElement;
if (tdTools && topToolbar) {
tdTools.classList.remove(activeAnim);
topToolbar.classList.remove(activeAnim);
topToolbar.style.transition = `opacity ${time} ease-in-out`;
tdTools.style.transition = `opacity ${time} ease-in-out`;
tdTools?.classList?.add(anim);
topToolbar?.classList?.add(anim);
}
}
export {
initDefaultPages,
Annotations,
@ -388,4 +401,5 @@ export {
changeCurrentSlide,
notifyNotAllowedChange,
notifyShapeNumberExceeded,
toggleToolsAnimations,
};

View File

@ -94,6 +94,18 @@ const TldrawGlobalStyle = createGlobalStyle`
cursor: default !important;
}
`}
${({ isToolbarVisible }) => (!isToolbarVisible) && `
#TD-Tools {
visibility: hidden;
}
#TD-Styles-Parent {
visibility: hidden;
}
#WhiteboardOptionButton {
opacity: 0.2;
}
`}
`;
const EditableWBWrapper = styled.div`
@ -120,7 +132,6 @@ const PanTool = styled(Button)`
transform: scale(-1, 1);
}
}
${({ panSelected }) => !panSelected && `
&:hover,
&:focus {

View File

@ -10,7 +10,7 @@ const isMobile = isPhone || isTablet;
const hasMediaDevices = !!navigator.mediaDevices;
const osName = BOWSER_RESULTS.os.name;
const osVersion = BOWSER_RESULTS.os.version;
const isIos = osName === 'iOS';
const isIos = osName === 'iOS' || (isTablet && osName=="macOS");
const isMacos = osName === 'macOS';
const isIphone = !!(userAgent.match(/iPhone/i));

View File

@ -1583,7 +1583,7 @@
"@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
"@types/parse-json": {
@ -2022,7 +2022,7 @@
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
"integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
"dev": true
},
"astral-regex": {
@ -2460,7 +2460,7 @@
"css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
"integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU="
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg=="
},
"css-to-react-native": {
"version": "3.0.0",
@ -3300,7 +3300,7 @@
"exenv": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
"integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
"integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw=="
},
"fast-deep-equal": {
"version": "3.1.3",
@ -4141,7 +4141,7 @@
"language-tags": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
"integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
"integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
"dev": true,
"requires": {
"language-subtag-registry": "~0.3.2"
@ -4303,7 +4303,7 @@
"load-script": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
"integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ="
"integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA=="
},
"locate-path": {
"version": "3.0.0",
@ -5315,7 +5315,7 @@
"normalize-range": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="
},
"npm-run-path": {
"version": "2.0.2",
@ -6120,9 +6120,9 @@
}
},
"react-virtualized": {
"version": "9.22.3",
"resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz",
"integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==",
"version": "9.22.4",
"resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.4.tgz",
"integrity": "sha512-HYOQEK1OWWYKt8C3KnjbEOST224kv5D8USPSdo/huAamDttWzQLTtoi/IvWfqwFOr9cCnwUYzqOTStwPrdkqqQ==",
"requires": {
"@babel/runtime": "^7.7.2",
"clsx": "^1.0.4",
@ -6395,7 +6395,7 @@
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"requires": {
"is-arrayish": "^0.3.1"
},
@ -6507,7 +6507,7 @@
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="
},
"stream-parser": {
"version": "0.3.1",
@ -6520,7 +6520,7 @@
"strictdom": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strictdom/-/strictdom-1.0.1.tgz",
"integrity": "sha1-GJ3pFkn3PUTVm4Qy76aO+dJllGA="
"integrity": "sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg=="
},
"string-argv": {
"version": "0.3.1",
@ -6684,7 +6684,7 @@
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true
},
"strip-eof": {
@ -6839,7 +6839,7 @@
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
},
"to-regex-range": {
"version": "5.0.1",

View File

@ -76,7 +76,7 @@
"react-toastify": "^4.5.2",
"react-toggle": "^4.1.2",
"react-transition-group": "^2.9.0",
"react-virtualized": "^9.22.3",
"react-virtualized": "^9.22.4",
"reconnecting-websocket": "~v4.4.0",
"redis": "^3.1.2",
"sanitize-html": "2.7.1",

View File

@ -35,7 +35,7 @@ public:
helpLink: https://bigbluebutton.org/html5/
delayForUnmountOfSharedNote: 120000
bbbTabletApp:
enabled: false
enabled: true
iosAppStoreUrl: 'https://apps.apple.com/us/app/bigbluebutton-tablet/id1641156756'
iosAppUrlScheme: 'bigbluebutton-tablet'
lockOnJoin: true
@ -176,6 +176,7 @@ public:
guestWaitingAudioAlerts: true
guestWaitingPushAlerts: true
paginationEnabled: true
whiteboardToolbarAutoHide: false
darkTheme: false
# fallbackLocale: if the locale the client is loaded in does not have a
# translation a string, it will use the translation from the locale

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "An Breite anpassen",
"app.presentation.presentationToolbar.fitToPage": "An Seite anpassen",
"app.presentation.presentationToolbar.goToSlide": "Folie {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Werkzeugleisten ausblenden",
"app.presentation.presentationToolbar.showToolsDesc": "Werkzeugleisten anzeigen",
"app.presentation.placeholder": "Es gibt derzeit keine aktive Präsentation",
"app.presentationUploder.title": "Präsentation",
"app.presentationUploder.message": "Es können Office-Dokumente oder PDFs als Präsentation hochgeladen werden. Wir empfehlen PDF für beste Ergebnisse. Bitte sicherstellen, dass die richtige Präsentation mit runden Auswahlfeld auf der linken Seite ausgewählt ist.",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Προσαρμογή κατά πλάτος",
"app.presentation.presentationToolbar.fitToPage": "Προσαρμογή στη σελίδα",
"app.presentation.presentationToolbar.goToSlide": "Διαφάνεια {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Απόκρυψη γραμμών εργαλείων",
"app.presentation.presentationToolbar.showToolsDesc": "Εμφάνιση γραμμών εργαλείων",
"app.presentation.placeholder": "Δεν υπάρχει ενεργή παρουσίαση",
"app.presentationUploder.title": "Παρουσίαση",
"app.presentationUploder.message": "Ως παρουσιαστής έχετε τη δυνατότητα να ανεβάσετε οποιοδήποτε αρχείο Office ή PDF. Συνιστούμε το αρχείο PDF για καλύτερα αποτελέσματα. Βεβαιωθείτε ότι έχετε επιλέξει μια παρουσίαση χρησιμοποιώντας το πλαίσιο ελέγχου κύκλου στην αριστερή πλευρά.",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Εφαρμογή",
"app.submenu.application.animationsLabel": "Γραφικά",
"app.submenu.application.audioFilterLabel": "Φίλτρα ήχου για το μικρόφωνο",
"app.submenu.application.wbToolbarsAutoHideLabel": "Αυτόματη απόκρυψη γραμμών εργαλείων ασπροπίνακα",
"app.submenu.application.darkThemeLabel": "Σκοτεινή κατάσταση",
"app.submenu.application.fontSizeControlLabel": "Μέγεθος γραμματοσειράς",
"app.submenu.application.increaseFontBtnLabel": "Αύξηση μεγέθους γραμμάτων εφαρμογής",

View File

@ -450,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Application",
"app.submenu.application.animationsLabel": "Animations",
"app.submenu.application.audioFilterLabel": "Audio Filters for Microphone",
"app.submenu.application.wbToolbarsAutoHideLabel": "Auto Hide Whiteboard Toolbars",
"app.submenu.application.darkThemeLabel": "Dark mode",
"app.submenu.application.fontSizeControlLabel": "Font size",
"app.submenu.application.increaseFontBtnLabel": "Increase application font size",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Ajustar a lo ancho",
"app.presentation.presentationToolbar.fitToPage": "Ajustar a la página",
"app.presentation.presentationToolbar.goToSlide": "Diapositiva {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Esconder barras de herramientas",
"app.presentation.presentationToolbar.showToolsDesc": "Mostrar barras de herramientas",
"app.presentation.placeholder": "No hay actualmente una presentación activa",
"app.presentationUploder.title": "Presentación",
"app.presentationUploder.message": "Como presentador, tiene la posibilidad de cargar cualquier documento de oficina o archivo PDF. Se recomienda el archivo PDF para obtener los mejores resultados. Asegúrese de seleccionar una presentación usando la casilla de verificación círcular en el lado izquierdo.",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Aplicación",
"app.submenu.application.animationsLabel": "Animaciones",
"app.submenu.application.audioFilterLabel": "Filtros de audio para el micrófono",
"app.submenu.application.wbToolbarsAutoHideLabel": "Ocultar automáticamente las barras de herramientas de la pizarra",
"app.submenu.application.darkThemeLabel": "Modo oscuro",
"app.submenu.application.fontSizeControlLabel": "Tamaño de fuente",
"app.submenu.application.increaseFontBtnLabel": "Incrementar tamaño de fuente",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Ajustar al ancho",
"app.presentation.presentationToolbar.fitToPage": "Ajustar a la página",
"app.presentation.presentationToolbar.goToSlide": "Diapositiva {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Esconder barras de herramientas",
"app.presentation.presentationToolbar.showToolsDesc": "Mostrar barras de herramientas",
"app.presentation.placeholder": "No hay actualmente una presentación activa",
"app.presentationUploder.title": "Presentación",
"app.presentationUploder.message": "Como presentador, tiene la posibilidad de cargar cualquier documento de oficina o archivo PDF. Se recomienda el archivo PDF para obtener los mejores resultados. Asegúrese de seleccionar una presentación usando la casilla de verificación círcular en el lado izquierdo.",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Aplicación",
"app.submenu.application.animationsLabel": "Animaciones",
"app.submenu.application.audioFilterLabel": "Filtros de audio para el micrófono",
"app.submenu.application.wbToolbarsAutoHideLabel": "Ocultar automáticamente las barras de herramientas de la pizarra",
"app.submenu.application.darkThemeLabel": "Modo oscuro",
"app.submenu.application.fontSizeControlLabel": "Tamaño de fuente",
"app.submenu.application.increaseFontBtnLabel": "Aumentar tamaño de fuente de la aplicación",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Kohanda laiusele",
"app.presentation.presentationToolbar.fitToPage": "Kohanda lehe laiusele",
"app.presentation.presentationToolbar.goToSlide": "Slaid {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Peida tööriistaribad",
"app.presentation.presentationToolbar.showToolsDesc": " Näita tööriistaribasid",
"app.presentation.placeholder": "Aktiivne esitlus puudub",
"app.presentationUploder.title": "Esitlus",
"app.presentationUploder.message": "Esitlejana saad üles laadida mis tahes kontoridokumenti või PDF-faili. Parima tulemuse saamiseks soovitame PDF-faili. Veendu, et esitlus oleks vasakul asuva ringikujulise märkekasti abil valitud.",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Rakendus",
"app.submenu.application.animationsLabel": "Animatsioonid",
"app.submenu.application.audioFilterLabel": "Mikrofoni audiofiltrid",
"app.submenu.application.wbToolbarsAutoHideLabel": "Peida tahvli tööriistaribad automaatselt",
"app.submenu.application.darkThemeLabel": "Tume režiim",
"app.submenu.application.fontSizeControlLabel": "Teksti suurus",
"app.submenu.application.increaseFontBtnLabel": "Suurenda rakenduse teksti suurust",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "اندازه متناسب با عرض صفحه",
"app.presentation.presentationToolbar.fitToPage": "اندازه متناسب با صفحه",
"app.presentation.presentationToolbar.goToSlide": "اسلاید {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "مخفی کردن نوار ابزار",
"app.presentation.presentationToolbar.showToolsDesc": "نمایش نوار ابزار",
"app.presentation.placeholder": "در حال حاضر هیچ ارائه فعالی وجود ندارد",
"app.presentationUploder.title": "ارائه",
"app.presentationUploder.message": "به عنوان یک ارائه دهنده شما توانایی بارگذاری انواع پرونده‌های مجموعه آفیس یا پرونده PDF را دارید. ما پرونده PDF را برای بهترین نتیجه توصیه می‌کنیم. لطفا مطمئن شوید که یک ارائه با استفاده از کادر دایره‌ای در سمت چپ انتخاب شده است.",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "برنامه",
"app.submenu.application.animationsLabel": "انیمیشن ها",
"app.submenu.application.audioFilterLabel": "فیلترهای صوتی برای میکروفون",
"app.submenu.application.wbToolbarsAutoHideLabel": "مخفی شدن خودکار نوارابزار تخته سفید",
"app.submenu.application.darkThemeLabel": "حالت تیره",
"app.submenu.application.fontSizeControlLabel": "اندازه قلم",
"app.submenu.application.increaseFontBtnLabel": "افزایش اندازه متن برنامه",

View File

@ -450,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Application",
"app.submenu.application.animationsLabel": "Animations",
"app.submenu.application.audioFilterLabel": "Filtres audios pour microphone",
"app.submenu.application.wbToolbarsAutoHideLabel": "Masquer les barres d'outils du tableau blanc automatiquement",
"app.submenu.application.darkThemeLabel": "Mode sombre",
"app.submenu.application.fontSizeControlLabel": "Taille des caractères",
"app.submenu.application.increaseFontBtnLabel": "Augmenter la taille des caractères",
@ -729,9 +730,9 @@
"app.audio.captions.select.zh-CN": "Chinois",
"app.error.removed": "Vous avez été écarté de la réunion",
"app.error.meeting.ended": "Vous avez été déconnecté de la réunion",
"app.meeting.logout.duplicateUserEjectReason": " Un compte déjà connecté tente de rejoindre la réunion",
"app.meeting.logout.duplicateUserEjectReason": " Un compte utilisateur déjà connecté tente de rejoindre la réunion",
"app.meeting.logout.permissionEjectReason": "Expulsé en raison d'une violation de permission",
"app.meeting.logout.ejectedFromMeeting": "Vous avez été retiré de la réunion",
"app.meeting.logout.ejectedFromMeeting": "Vous avez été exclu de la réunion",
"app.meeting.logout.validateTokenFailedEjectReason": "Le jeton d'autorisation n'a pas pu être validé",
"app.meeting.logout.userInactivityEjectReason": "Utilisateur trop longtemps inactif ",
"app.meeting.logout.maxParticipantsReached": "Le nombre maximum de participants pour cette réunion a été atteint.",
@ -753,7 +754,7 @@
"app.dropdown.list.item.activeLabel": "Actif",
"app.error.400": "Mauvaise requête",
"app.error.401": "Non autorisé",
"app.error.403": "Vous avez été retiré de la réunion",
"app.error.403": "Vous avez été exclu de la réunion",
"app.error.404": "Non trouvé",
"app.error.408": "Échec de l'authentification",
"app.error.409": "Conflit",
@ -774,12 +775,12 @@
"app.guest.noSessionToken": "Aucun jeton de session reçu.",
"app.guest.windowTitle": "Salon d'attente",
"app.guest.missingToken": "L'invité n'a pas de jeton de session",
"app.guest.missingSession": "L'invité manque la séance",
"app.guest.missingSession": "Invité sans session",
"app.guest.missingMeeting": "La conférence n'existe pas.",
"app.guest.meetingEnded": "La conférence est terminée.",
"app.guest.guestWait": "Veuillez attendre qu'un modérateur approuve votre accès à la conférence.",
"app.guest.guestDeny": "L'accès à la conférence a été refusé.",
"app.guest.seatWait": "L'invité attend une place dans la conférence.",
"app.guest.seatWait": "L'invité attend pour accéder à la réunion.",
"app.guest.allow": "Invité approuvé et redirigé vers la réunion",
"app.guest.firstPositionInWaitingQueue": "Vous êtes en premier dans la file !",
"app.guest.positionInWaitingQueue": "Votre position actuelle dans la file d'attente :",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Axustar ao largo",
"app.presentation.presentationToolbar.fitToPage": "Axustar á páxina",
"app.presentation.presentationToolbar.goToSlide": "Diapositiva {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Agochar barras de ferramentas",
"app.presentation.presentationToolbar.showToolsDesc": "Amosar barras de ferramentas",
"app.presentation.placeholder": "Non hai ningunha presentación activa actualmente",
"app.presentationUploder.title": "Presentación",
"app.presentationUploder.message": "Como presentador tes a posibilidade de cargar calquera documento ofimático ou ficheiro PDF. Recomendamos o ficheiro PDF para obter os mellores resultados. Asegúrate de seleccionar unha presentación usando a caixa de verificación circular do lado esquerdo.",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Aplicación",
"app.submenu.application.animationsLabel": "Animacións",
"app.submenu.application.audioFilterLabel": " Filtros de son para o micrófono",
"app.submenu.application.wbToolbarsAutoHideLabel": "Ocultar automaticamente as barras de ferramentas do encerado",
"app.submenu.application.darkThemeLabel": "Modo escuro",
"app.submenu.application.fontSizeControlLabel": "Tamaño da letra",
"app.submenu.application.increaseFontBtnLabel": "Incrementar o tamaño da letra",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Տեղավորել լայնքով",
"app.presentation.presentationToolbar.fitToPage": "Տեղավորել էջի սահմաններում",
"app.presentation.presentationToolbar.goToSlide": "{0} սլայդ",
"app.presentation.presentationToolbar.hideToolsDesc": "Թաքցնել գործիքները",
"app.presentation.presentationToolbar.showToolsDesc": "Ցուցադրել գործիքները",
"app.presentation.placeholder": "Չկա ակտիվ ներկայացում",
"app.presentationUploder.title": "Ներկայացում",
"app.presentationUploder.message": "Որպես ներկայացնող հնարավորություն ունեք վերբեռնել որևէ օֆիսային փաստաթուղթ կամ PDF ֆայլ։ Բարձր արտադրողականության համար ամենահարմարը PDF ֆայլլն է։ Համոզվեք, որ ներկայացումը ընտրված է ձախակողմյան շրջանակի նշիչով։",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Ծրագիր",
"app.submenu.application.animationsLabel": "ԱՆիմացիա",
"app.submenu.application.audioFilterLabel": "Բարձրախոսի ձայնային ֆիլտրեր",
"app.submenu.application.wbToolbarsAutoHideLabel": "Ավտոմատ թաքցնել գրատախտակի գործիքները",
"app.submenu.application.darkThemeLabel": "Մութ ռեժիմ",
"app.submenu.application.fontSizeControlLabel": "Տառաչափ",
"app.submenu.application.increaseFontBtnLabel": "Մեծացնել ծրագրի տառաչափը",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "幅に合わせる",
"app.presentation.presentationToolbar.fitToPage": "ページに合わせる",
"app.presentation.presentationToolbar.goToSlide": "スライド {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "ツールバーを隠す",
"app.presentation.presentationToolbar.showToolsDesc": "ツールバーを表示",
"app.presentation.placeholder": "現在アクティブなプレゼンテーションはありません",
"app.presentationUploder.title": "プレゼンテーション",
"app.presentationUploder.message": "発表者になるとオフィスドキュメントやPDFファイルをアップロードできるようになります。PDFファイルの使用がおすすめです。左側の丸いチェックボックスによってプレゼンファイルが選択されていることを確認してください。",
@ -448,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "アプリケーション",
"app.submenu.application.animationsLabel": "アニメーション効果",
"app.submenu.application.audioFilterLabel": "マイク音声の自動補正",
"app.submenu.application.wbToolbarsAutoHideLabel": "ホワイトボードのツールバーを自動で隠す",
"app.submenu.application.darkThemeLabel": "ダークモード",
"app.submenu.application.fontSizeControlLabel": "フォントサイズ",
"app.submenu.application.increaseFontBtnLabel": "アプリケーションのフォントサイズを大きくする",

View File

@ -2,10 +2,11 @@
"app.home.greeting": "Uw presentatie begint binnenkort ...",
"app.chat.submitLabel": "Bericht verzenden",
"app.chat.loading": "Chatberichten geladen: {0}%",
"app.chat.errorMaxMessageLength": "Het bericht is {0} teken(s) te lang",
"app.chat.errorMaxMessageLength": "Bericht is te lang. De maximale lengte van {0} tekens is overschreden",
"app.chat.disconnected": "De verbinding is verbroken, berichten kunnen niet worden verzonden",
"app.chat.locked": "Chat is vergrendeld, berichten kunnen niet worden verzonden",
"app.chat.inputLabel": "Berichtinvoer voor chat {0}",
"app.chat.emojiButtonLabel": "Emoji-kiezer",
"app.chat.inputPlaceholder": "Bericht {0}",
"app.chat.titlePublic": "Openbare chat",
"app.chat.titlePrivate": "Privéchat met {0}",
@ -21,6 +22,7 @@
"app.chat.offline": "Offline",
"app.chat.pollResult": "Peilingsresultaten",
"app.chat.breakoutDurationUpdated": "Brainstormruimte sluit over {0} minuten.",
"app.chat.breakoutDurationUpdatedModerator": "De tijd voor brainstormruimtes is nu {0} minuten en er is een melding gestuurd.",
"app.chat.emptyLogLabel": "Chatlogboek leeg",
"app.chat.clearPublicChatMessage": "De openbare chatgeschiedenis is gewist door een moderator",
"app.chat.multi.typing": "Meerdere gebruikers zijn aan het typen",
@ -28,6 +30,27 @@
"app.chat.two.typing": "{0} en {1} zijn aan het typen",
"app.chat.copySuccess": "Gekopieerd chat transcript",
"app.chat.copyErr": "Kopiëren chat transcript mislukt",
"app.emojiPicker.search": "Zoek",
"app.emojiPicker.notFound": "Geen emoji gevonden",
"app.emojiPicker.skintext": "Kies je standaard huidskleur",
"app.emojiPicker.clear": "Wissen",
"app.emojiPicker.categories.label": "Emoji categorieën",
"app.emojiPicker.categories.people": "Mensen & lichaam",
"app.emojiPicker.categories.nature": "Dieren & natuur",
"app.emojiPicker.categories.foods": "Eten & drinken",
"app.emojiPicker.categories.places": "Reizen & plaatsen",
"app.emojiPicker.categories.activity": "Activiteit",
"app.emojiPicker.categories.objects": "Objecten",
"app.emojiPicker.categories.symbols": "Symbolen",
"app.emojiPicker.categories.flags": "Vlaggen",
"app.emojiPicker.categories.recent": "Vaak gebruikt",
"app.emojiPicker.categories.search": "Zoekresultaten",
"app.emojiPicker.skintones.1": "Standaard huidtint",
"app.emojiPicker.skintones.2": "Lichte huidtint",
"app.emojiPicker.skintones.3": "Medium-lichte huidtint",
"app.emojiPicker.skintones.4": "Medium huidtint",
"app.emojiPicker.skintones.5": "Medium-donker huidtint",
"app.emojiPicker.skintones.6": "Donkere huidtint",
"app.captions.label": "Bijschriften",
"app.captions.menu.close": "Sluiten",
"app.captions.menu.start": "Starten",
@ -53,12 +76,23 @@
"app.captions.speech.start": "Tekstherkenning gestart",
"app.captions.speech.stop": "Tekstherkenning gestopt",
"app.captions.speech.error": "Spraakherkenning is gestopt omdat de browser niet compatibel is met een stilteperiode",
"app.confirmation.skipConfirm": "Niet meer vragen",
"app.confirmation.virtualBackground.title": "Start nieuwe virtuele achtergrond",
"app.confirmation.virtualBackground.description": "{0} zal als virtuele achtergrond toegevoegd worden. Verder gaan?",
"app.confirmationModal.yesLabel": "Ja",
"app.textInput.sendLabel": "Verstuur",
"app.title.defaultViewLabel": "Standaard presentatiebeeld",
"app.notes.title": "Gedeelde notities",
"app.notes.titlePinned": "Gedeelde notities (vastgezet)",
"app.notes.pinnedNotification": "De gedeelde notities zijn nu vastgezet op het whiteboard.",
"app.notes.label": "Notities",
"app.notes.hide": "Verberg notitie",
"app.notes.locked": "Vergrendeld",
"app.notes.disabled": "Vastgezet op mediazone",
"app.notes.notesDropdown.covertAndUpload": "Notities converteren naar presentatie",
"app.notes.notesDropdown.pinNotes": "Notities vastzetten op whiteboard",
"app.notes.notesDropdown.unpinNotes": "Notities losmaken",
"app.notes.notesDropdown.notesOptions": "Notitie-opties",
"app.pads.hint": "Druk op Esc om de werkbalk van de editor te activeren",
"app.user.activityCheck": "Controle gebruikersactiviteit",
"app.user.activityCheck.label": "Controleer of de gebruiker nog steeds in vergadering is ({0})",
@ -155,8 +189,8 @@
"app.meeting.meetingTimeRemaining": "Resterende vergadertijd: {0}",
"app.meeting.meetingTimeHasEnded": "Tijd verstreken. Vergadering wordt spoedig afgesloten",
"app.meeting.endedByUserMessage": "Deze sessie is beëindigd door {0}",
"app.meeting.endedByNoModeratorMessageSingular": "Deze vergadering is beëindigd omdat er geen moderator meer was na één minuut",
"app.meeting.endedByNoModeratorMessagePlural": "Deze vergadering is beëindigd omdat er geen moderator meer was na {0} minuten",
"app.meeting.endedByNoModeratorMessageSingular": "Deze vergadering is beëindigd omdat er al langer dan één minuut geen moderator meer aanwezig is",
"app.meeting.endedByNoModeratorMessagePlural": "Deze vergadering is beëindigd omdat er al langer dan {0} minuten geen moderator meer aanwezig is",
"app.meeting.endedMessage": "U wordt teruggestuurd naar het startscherm",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Vergadering sluit over één minuut.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Vergadering sluit over {0} minuten.",
@ -170,7 +204,7 @@
"app.presentation.endSlideContent": "Einde van dia-inhoud",
"app.presentation.changedSlideContent": "Presentatie gewijzigd naar dia: {0}",
"app.presentation.emptySlideContent": "Geen inhoud voor huidige dia",
"app.presentation.options.fullscreen": "Volledig scherm",
"app.presentation.options.fullscreen": "Presentatie op volledig scherm",
"app.presentation.options.exitFullscreen": "Volledig scherm afsluiten",
"app.presentation.options.minimize": "Minimaliseer",
"app.presentation.options.snapshot": "Foto van huidige dia",
@ -201,9 +235,24 @@
"app.presentation.presentationToolbar.fitToWidth": "Aanpassen aan breedte",
"app.presentation.presentationToolbar.fitToPage": "Aanpassen aan pagina",
"app.presentation.presentationToolbar.goToSlide": "Dia {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Verberg werkbalken",
"app.presentation.presentationToolbar.showToolsDesc": "Toon werkbalken",
"app.presentation.placeholder": "Er is nu geen actieve presentatie",
"app.presentationUploder.title": "Presentatie",
"app.presentationUploder.message": "Als presentator kunt u elk Office-document of PDF-bestand uploaden. We raden het PDF-bestand aan voor de beste resultaten. Zorg ervoor dat een presentatie is geselecteerd met behulp van het selectievakje aan de rechterkant. ",
"app.presentationUploder.message": "Als presentator kunt u elk Office-document of PDF-bestand uploaden. We raden het PDF-bestand aan voor de beste resultaten. Zorg ervoor dat een presentatie is geselecteerd met behulp van het selectievakje aan de linkerkant. ",
"app.presentationUploader.exportHint": "Het selecteren van \"Stuur naar chat\" geeft gebruikers een link om de annotaties via de chat te downloaden.",
"app.presentationUploader.exportToastHeader": "Naar chat sturen ({0} item)",
"app.presentationUploader.exportToastHeaderPlural": "Naar chat sturen ({0} items)",
"app.presentationUploader.exporting": "Naar chat sturen",
"app.presentationUploader.sending": "Sturen...",
"app.presentationUploader.collecting": "Dia {0} van {1} uitpakken...",
"app.presentationUploader.processing": "Dia {0} van {1} annoteren...",
"app.presentationUploader.sent": "Stuur",
"app.presentationUploader.exportingTimeout": "De export duurt te lang...",
"app.presentationUploader.export": "Stuur naar chat",
"app.presentationUploader.export.linkAvailable": "Link om {0} te downloaden via de chat.",
"app.presentationUploader.export.notAccessibleWarning": "kan toegankelijkheidsproblemen bevatten",
"app.presentationUploader.currentPresentationLabel": "Huidige presentatie",
"app.presentationUploder.extraHint": "BELANGRIJK: elk bestand mag niet groter zijn dan {0} MB en {1} pagina's.",
"app.presentationUploder.uploadLabel": "Upload",
"app.presentationUploder.confirmLabel": "Bevestigen",
@ -214,11 +263,14 @@
"app.presentationUploder.dropzoneImagesLabel": "Sleep afbeeldingen hierheen om te uploaden",
"app.presentationUploder.browseFilesLabel": "of blader naar bestanden",
"app.presentationUploder.browseImagesLabel": "of bladeren / vastleggen voor afbeeldingen",
"app.presentationUploder.externalUploadTitle": "Voeg inhoud toe van een andere applicatie",
"app.presentationUploder.externalUploadLabel": "Blader door bestanden",
"app.presentationUploder.fileToUpload": "Wordt geüpload ...",
"app.presentationUploder.currentBadge": "Huidig",
"app.presentationUploder.rejectedError": "De geselecteerde bestanden zijn geweigerd. Controleer bestandstype(s).",
"app.presentationUploder.connectionClosedError": "Onderbroken wegens slechte verbinding. Probeer opnieuw.",
"app.presentationUploder.upload.progress": "Uploaden ({0}%)",
"app.presentationUploder.conversion.204": "Geen inhoud om op te nemen",
"app.presentationUploder.upload.413": "Bestand is te groot. De maximale grootte van {0} MB is overschreden",
"app.presentationUploder.genericError": "Oeps! Er is iets misgegaan ...",
"app.presentationUploder.upload.408": "Verzoek time-out voor uploadtoken.",
@ -230,14 +282,14 @@
"app.presentationUploder.conversion.generatedSlides": "Dia's gegenereerd ...",
"app.presentationUploder.conversion.generatingSvg": "SVG-afbeeldingen genereren ...",
"app.presentationUploder.conversion.pageCountExceeded": "Het maximale aantal pagina's van {0} is overschreden",
"app.presentationUploder.conversion.invalidMimeType": "Ongeldig formaat gevonden (extensie={0}, inhoudstype={1})",
"app.presentationUploder.conversion.conversionTimeout": "Dia {0} kon niet verwerkt worden binnen {1} pogingen.",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Kan Office-document niet verwerken. Upload in plaats daarvan een PDF.",
"app.presentationUploder.conversion.officeDocConversionFailed": "Kan Office-document niet verwerken. Upload in plaats daarvan een PDF.",
"app.presentationUploder.conversion.pdfHasBigPage": "We konden het PDF-bestand niet converteren. Probeer het te optimaliseren. Maximale paginagrootte {0}",
"app.presentationUploder.conversion.timeout": "Oeps, de conversie heeft te lang geduurd",
"app.presentationUploder.conversion.pageCountFailed": "Bepalen van het aantal pagina's is mislukt.",
"app.presentationUploder.conversion.unsupportedDocument": "De bestands-extensie wordt niet ondersteund",
"app.presentationUploder.isDownloadableLabel": "Het downloaden van presentaties is niet toegestaan - klik om toe te staan dat de presentatie wordt gedownload",
"app.presentationUploder.isNotDownloadableLabel": "Downloaden van presentaties is toegestaan - klik om te voorkomen dat de presentatie wordt gedownload",
"app.presentationUploder.removePresentationLabel": "Presentatie verwijderen",
"app.presentationUploder.setAsCurrentPresentation": "Presentatie instellen als huidige",
"app.presentationUploder.tableHeading.filename": "Bestandsnaam",
@ -251,6 +303,10 @@
"app.presentationUploder.clearErrors": "Fouten wissen",
"app.presentationUploder.clearErrorsDesc": "Wist mislukte uploads van presentaties",
"app.presentationUploder.uploadViewTitle": "Upload uw presentatie",
"app.poll.questionAndoptions.label" : "Te tonen vraagtekst.\nA. Peilingsoptie *\nB. Peilingsoptie (optioneel)\nC. Peilingsoptie (optioneel)\nD. Peilingsoptie (optioneel)\nE. Peilingsoptie (optioneel)",
"app.poll.customInput.label": "Aangepaste invoer",
"app.poll.customInputInstructions.label": "Aangepaste invoer is ingeschakeld - schrijf peilingsvragen en optie(s) in het opgegeven formaat of sleep en zet een tekstbestand neer in hetzelfde formaat.",
"app.poll.maxOptionsWarning.label": "Slechts de eerste 5 opties kunnen gebruikt worden!",
"app.poll.pollPaneTitle": "Peiling",
"app.poll.enableMultipleResponseLabel": "Meerdere antwoorden per respondent toestaan?",
"app.poll.quickPollTitle": "Snelle peiling",
@ -270,7 +326,7 @@
"app.poll.clickHereToSelect": "Klik hier om te selecteren",
"app.poll.question.label" : "Noteer je vraag....",
"app.poll.optionalQuestion.label" : "Noteer je vraag (optioneel)....",
"app.poll.userResponse.label" : "Reactie van de gebruiker",
"app.poll.userResponse.label" : "Getypt antwoord",
"app.poll.responseTypes.label" : "Reactietypes",
"app.poll.optionDelete.label" : "Verwijder",
"app.poll.responseChoices.label" : "Reactiekeuzes",
@ -329,7 +385,7 @@
"app.muteWarning.disableMessage": "Waarschuwingen dempen uitgeschakeld tot het dempen weer wordt opgeheven",
"app.muteWarning.tooltip": "Klik om waarschuwing te sluiten en uit te schakelen tot de volgende keer dat dempen wordt uitgeschakeld",
"app.navBar.settingsDropdown.optionsLabel": "Opties",
"app.navBar.settingsDropdown.fullscreenLabel": "Volledig scherm maken",
"app.navBar.settingsDropdown.fullscreenLabel": "Applicatie op volledig scherm",
"app.navBar.settingsDropdown.settingsLabel": "Instellingen",
"app.navBar.settingsDropdown.aboutLabel": "Over",
"app.navBar.settingsDropdown.leaveSessionLabel": "Verlaat de vergadering",
@ -342,6 +398,7 @@
"app.navBar.settingsDropdown.hotkeysLabel": "Sneltoetsen",
"app.navBar.settingsDropdown.hotkeysDesc": "Lijst met beschikbare sneltoetsen",
"app.navBar.settingsDropdown.helpLabel": "Help",
"app.navBar.settingsDropdown.openAppLabel": "Open in BigBlueButton tablet app",
"app.navBar.settingsDropdown.helpDesc": "Koppelt gebruiker aan videotutorials (opent nieuw tabblad)",
"app.navBar.settingsDropdown.endMeetingDesc": "Beëindigt de huidige vergadering",
"app.navBar.settingsDropdown.endMeetingLabel": "Vergadering beëindigen",
@ -359,7 +416,7 @@
"app.endMeeting.description": "Deze actie beëindigt de sessie voor {0} actieve gebruiker(s). Weet u zeker dat u deze sessie wilt beëindigen?",
"app.endMeeting.noUserDescription": "Weet u zeker dat u deze sessie wil beëindigen?",
"app.endMeeting.contentWarning": "Chatberichten, gedeelde notities, whiteboard-inhoud en gedeelde documenten voor deze sessie zullen niet meer rechtstreeks toegankelijk zijn",
"app.endMeeting.yesLabel": "Ja",
"app.endMeeting.yesLabel": "Beëindig sessie voor alle gebruikers",
"app.endMeeting.noLabel": "Nee",
"app.about.title": "Over",
"app.about.version": "Client build:",
@ -369,6 +426,15 @@
"app.about.confirmDesc": "OK",
"app.about.dismissLabel": "Annuleren",
"app.about.dismissDesc": "Sluiten over klantinformatie",
"app.mobileAppModal.title": "Open BigBlueButton tablet app",
"app.mobileAppModal.description": "Heb je de BigBlueButton Tablet app geïnstalleerd op je toestel?",
"app.mobileAppModal.openApp": "Ja, open de app nu",
"app.mobileAppModal.obtainUrlMsg": "VergaderingsURL ophalen",
"app.mobileAppModal.obtainUrlErrorMsg": "Fout bij het ophalen van de vergaderingsURL",
"app.mobileAppModal.openStore": "Nee, open de App Store om te downloaden",
"app.mobileAppModal.dismissLabel": "Annuleer",
"app.mobileAppModal.dismissDesc": "Sluit",
"app.mobileAppModal.userConnectedWithSameId": "Gebruiker {0} connecteerde net met de zelfde ID als jij.",
"app.actionsBar.changeStatusLabel": "Status wijzigen",
"app.actionsBar.muteLabel": "Dempen",
"app.actionsBar.unmuteLabel": "Dempen opheffen",
@ -379,10 +445,13 @@
"app.actionsBar.actionsDropdown.restorePresentationDesc": "Knop om de presentatie te herstellen nadat deze is geminimaliseerd",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Presentatie minimaliseren",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Knop gebruikt om de presentatie te minimaliseren",
"app.actionsBar.actionsDropdown.layoutModal": "Layout instellingen modaal",
"app.screenshare.screenShareLabel" : "Screen share",
"app.submenu.application.applicationSectionTitle": "Applicatie",
"app.submenu.application.animationsLabel": "Animaties",
"app.submenu.application.audioFilterLabel": "Audiofilters voor microfoon",
"app.submenu.application.wbToolbarsAutoHideLabel": "Automatisch whiteboard-werkbalken verbergen",
"app.submenu.application.darkThemeLabel": "Donkere modus",
"app.submenu.application.fontSizeControlLabel": "Lettergrootte",
"app.submenu.application.increaseFontBtnLabel": "Toepassing lettertype vergroten",
"app.submenu.application.decreaseFontBtnLabel": "Toepassing lettertype verkleinen",
@ -392,6 +461,69 @@
"app.submenu.application.noLocaleOptionLabel": "Geen actieve landinstellingen",
"app.submenu.application.paginationEnabledLabel": "Video gepagineerd",
"app.submenu.application.layoutOptionLabel": "Lay-out type",
"app.submenu.application.pushLayoutLabel": "Stuur layout",
"app.submenu.application.localeDropdown.af": "Afrikaans",
"app.submenu.application.localeDropdown.ar": "Arabisch",
"app.submenu.application.localeDropdown.az": "Azerbaijaans",
"app.submenu.application.localeDropdown.bg-BG": "Bulgaars",
"app.submenu.application.localeDropdown.bn": "Bengaals",
"app.submenu.application.localeDropdown.ca": "Catalaans",
"app.submenu.application.localeDropdown.cs-CZ": "Chechisch",
"app.submenu.application.localeDropdown.da": "Deens",
"app.submenu.application.localeDropdown.de": "Duits",
"app.submenu.application.localeDropdown.dv": "Dhivehi",
"app.submenu.application.localeDropdown.el-GR": "Grieks (Griekenland)",
"app.submenu.application.localeDropdown.en": "Engels",
"app.submenu.application.localeDropdown.eo": "Esperanto",
"app.submenu.application.localeDropdown.es": "Spaans",
"app.submenu.application.localeDropdown.es-419": "Spaans (Latijns Amerika)",
"app.submenu.application.localeDropdown.es-ES": "Spaans (Spanje)",
"app.submenu.application.localeDropdown.es-MX": "Spaans (Mexico)",
"app.submenu.application.localeDropdown.et": "Ests",
"app.submenu.application.localeDropdown.eu": "Basqisch",
"app.submenu.application.localeDropdown.fa-IR": "Persisch",
"app.submenu.application.localeDropdown.fi": "Fins",
"app.submenu.application.localeDropdown.fr": "Frans",
"app.submenu.application.localeDropdown.gl": "Galicisch",
"app.submenu.application.localeDropdown.he": "Hebreeuws",
"app.submenu.application.localeDropdown.hi-IN": "Hindi",
"app.submenu.application.localeDropdown.hr": "Croatisch",
"app.submenu.application.localeDropdown.hu-HU": "Hongaars",
"app.submenu.application.localeDropdown.hy": "Armeens",
"app.submenu.application.localeDropdown.id": "Indonesisch",
"app.submenu.application.localeDropdown.it-IT": "Italiaans",
"app.submenu.application.localeDropdown.ja": "Japans",
"app.submenu.application.localeDropdown.ka": "Georgisch",
"app.submenu.application.localeDropdown.km": "Khmer",
"app.submenu.application.localeDropdown.kn": "Kannada",
"app.submenu.application.localeDropdown.ko-KR": "Koreaans (Korea)",
"app.submenu.application.localeDropdown.lo-LA": "Lao",
"app.submenu.application.localeDropdown.lt-LT": "Lithouws",
"app.submenu.application.localeDropdown.lv": "Lets",
"app.submenu.application.localeDropdown.ml": "Malayalam",
"app.submenu.application.localeDropdown.mn-MN": "Mongools",
"app.submenu.application.localeDropdown.nb-NO": "Noors (Bokmal)",
"app.submenu.application.localeDropdown.nl": "Nederlands",
"app.submenu.application.localeDropdown.oc": "Occitaans",
"app.submenu.application.localeDropdown.pl-PL": "Pools",
"app.submenu.application.localeDropdown.pt": "Portuguees",
"app.submenu.application.localeDropdown.pt-BR": "Portugees (Brazilië)",
"app.submenu.application.localeDropdown.ro-RO": "Roemeens",
"app.submenu.application.localeDropdown.ru": "Russisch",
"app.submenu.application.localeDropdown.sk-SK": "Slovaaks (Slovakije)",
"app.submenu.application.localeDropdown.sl": "Sloveens",
"app.submenu.application.localeDropdown.sr": "Servisch",
"app.submenu.application.localeDropdown.sv-SE": "Zweeds",
"app.submenu.application.localeDropdown.ta": "Tamil",
"app.submenu.application.localeDropdown.te": "Telugu",
"app.submenu.application.localeDropdown.th": "Thais",
"app.submenu.application.localeDropdown.tr": "Turks",
"app.submenu.application.localeDropdown.tr-TR": "Turks (Turkije)",
"app.submenu.application.localeDropdown.uk-UA": "Oekraïns",
"app.submenu.application.localeDropdown.vi": "Vietnamees",
"app.submenu.application.localeDropdown.vi-VN": "Vietnamees (Vietnam)",
"app.submenu.application.localeDropdown.zh-CN": "Chinees vereenvoudigd (China)",
"app.submenu.application.localeDropdown.zh-TW": "Chinees traditioneel (Taiwan)",
"app.submenu.notification.SectionTitle": "Notificaties",
"app.submenu.notification.Desc": "Bepaal hoe en over wat u wordt gewaarschuwd.",
"app.submenu.notification.audioAlertLabel": "Hoorbare Waarschuwingen",
@ -420,7 +552,7 @@
"app.settings.main.save.label.description": "Slaat de wijzigingen op en sluit het instellingenmenu",
"app.settings.dataSavingTab.label": "Gegevensbesparing",
"app.settings.dataSavingTab.webcam": "Webcams inschakelen",
"app.settings.dataSavingTab.screenShare": "Desktop delen inschakelen",
"app.settings.dataSavingTab.screenShare": "Scherm delen inschakelen",
"app.settings.dataSavingTab.description": "Om uw bandbreedte te besparen, kunt u aanpassen wat momenteel wordt weergegeven.",
"app.settings.save-notification.label": "Instellingen zijn opgeslagen",
"app.statusNotifier.lowerHands": "Handen omlaag",
@ -437,10 +569,9 @@
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0} waren aan het spreken",
"app.talkingIndicator.wasTalking" : "{0} is gestopt met spreken",
"app.actionsBar.actionsDropdown.actionsLabel": "Acties",
"app.actionsBar.actionsDropdown.presentationLabel": "Presentaties beheren",
"app.actionsBar.actionsDropdown.presentationLabel": "Upload/beheer presentaties",
"app.actionsBar.actionsDropdown.initPollLabel": "Een peiling initiëren",
"app.actionsBar.actionsDropdown.desktopShareLabel": "Deel uw scherm",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "Schermdeling vergrendeld",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "Stop met het delen van uw scherm",
"app.actionsBar.actionsDropdown.presentationDesc": "Upload uw presentatie",
"app.actionsBar.actionsDropdown.initPollDesc": "Een peiling initiëren",
@ -457,6 +588,7 @@
"app.actionsBar.actionsDropdown.takePresenterDesc": "Wijs uzelf toe als de nieuwe presentator",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "Selecteer willekeurige gebruiker",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "Kiest willekeurig een gebruiker uit de beschikbare kijkers",
"app.actionsBar.actionsDropdown.propagateLayoutLabel": "Layout versturen",
"app.actionsBar.emojiMenu.statusTriggerLabel": "Status instellen",
"app.actionsBar.emojiMenu.awayLabel": "Afwezig",
"app.actionsBar.emojiMenu.awayDesc": "Wijzig uw status in afwezig",
@ -496,6 +628,7 @@
"app.audioNotification.audioFailedError1012": "Verbinding gesloten (ICE-fout 1012)",
"app.audioNotification.audioFailedMessage": "Uw audioverbinding kon geen verbinding maken",
"app.audioNotification.mediaFailedMessage": "getUserMicMedia is mislukt omdat alleen beveiligde oorsprong is toegestaan",
"app.audioNotification.deviceChangeFailed": "Wisselen van audiotoestel mislukt. Controleer of het gekozen toestel behoorlijk is ingesteld en beschikbaar",
"app.audioNotification.closeLabel": "Sluiten",
"app.audioNotificaion.reconnectingAsListenOnly": "Microfoon is vergrendeld voor kijkers, u bent verbonden als alleen luisteren",
"app.breakoutJoinConfirmation.title": "Deelnemen aan brainstormruimte",
@ -509,6 +642,7 @@
"app.breakout.dropdown.manageDuration": "Wijzig duur",
"app.breakout.dropdown.destroyAll": "Beëindig brainstormruimte",
"app.breakout.dropdown.options": "Opties brainstormruimtes",
"app.breakout.dropdown.manageUsers": "Gebruikers beheren",
"app.calculatingBreakoutTimeRemaining": "Resterende tijd berekenen ...",
"app.audioModal.ariaTitle": "Deelnemen aan audio modaal",
"app.audioModal.microphoneLabel": "Microfoon",
@ -555,6 +689,7 @@
"app.audio.changeAudioDevice": "Wijzig audio-apparaat",
"app.audio.enterSessionLabel": "Neem deel aan sessie",
"app.audio.playSoundLabel": "Geluid afspelen",
"app.audio.stopAudioFeedback": "Stop audio feedback",
"app.audio.backLabel": "Terug",
"app.audio.loading": "Laden",
"app.audio.microphones": "Microfoons",
@ -567,10 +702,32 @@
"app.audio.audioSettings.testSpeakerLabel": "Test je luidspreker",
"app.audio.audioSettings.microphoneStreamLabel": "Het volume van uw audiostream",
"app.audio.audioSettings.retryLabel": "Opnieuw proberen",
"app.audio.audioSettings.fallbackInputLabel": "Audio input {0}",
"app.audio.audioSettings.fallbackOutputLabel": "Audio output {0}",
"app.audio.audioSettings.defaultOutputDeviceLabel": "Standaard",
"app.audio.audioSettings.findingDevicesLabel": "Toestellen zoeken...",
"app.audio.listenOnly.backLabel": "Terug",
"app.audio.listenOnly.closeLabel": "Sluiten",
"app.audio.permissionsOverlay.title": "Toegang tot uw microfoon toestaan",
"app.audio.permissionsOverlay.hint": "We moeten uw toestemming hebben om uw media-apparaten te gebruiken om u aan de spraakconferentie te laten deelnemen :)",
"app.audio.captions.button.start": "Start ondertitels",
"app.audio.captions.button.stop": "Stop ondertitels",
"app.audio.captions.button.language": "Taal",
"app.audio.captions.button.transcription": "Transcriptie",
"app.audio.captions.button.transcriptionSettings": "Transcriptieinstellingen",
"app.audio.captions.speech.title": "Automatische transcriptie",
"app.audio.captions.speech.disabled": "Uitgeschakeld",
"app.audio.captions.speech.unsupported": "Je browser ondersteunt geen spraakherkenning. Er zal geen transcriptie van je audio gebeuren",
"app.audio.captions.select.de-DE": "Duits",
"app.audio.captions.select.en-US": "Engels",
"app.audio.captions.select.es-ES": "Spaans",
"app.audio.captions.select.fr-FR": "Frans",
"app.audio.captions.select.hi-ID": "Hindi",
"app.audio.captions.select.it-IT": "Italiaans",
"app.audio.captions.select.ja-JP": "Japans",
"app.audio.captions.select.pt-BR": "Portuguees",
"app.audio.captions.select.ru-RU": "Russisch",
"app.audio.captions.select.zh-CN": "Chinees",
"app.error.removed": "U bent verwijderd uit de conferentie",
"app.error.meeting.ended": "U bent uitgelogd van de conferentie",
"app.meeting.logout.duplicateUserEjectReason": "Dubbele gebruiker die aan de vergadering probeert deel te nemen",
@ -578,6 +735,7 @@
"app.meeting.logout.ejectedFromMeeting": "U bent uit de vergadering verwijderd",
"app.meeting.logout.validateTokenFailedEjectReason": "Kan autorisatietoken niet valideren",
"app.meeting.logout.userInactivityEjectReason": "Gebruiker te lang inactief",
"app.meeting.logout.maxParticipantsReached": "Het maximaal aantal deelnemers voor deze vergadering is bereikt",
"app.meeting-ended.rating.legendLabel": "Feedbackbeoordeling",
"app.meeting-ended.rating.starLabel": "Star",
"app.modal.close": "Sluiten",
@ -599,8 +757,11 @@
"app.error.403": "U bent verwijderd uit de vergadering",
"app.error.404": "Niet gevonden",
"app.error.408": "Authenticatie mislukt",
"app.error.409": "Conflict",
"app.error.410": "Vergadering is beëindigd",
"app.error.500": "Oeps, er is iets misgegaan",
"app.error.503": "Je verbinding is verbroken",
"app.error.disconnected.rejoin": "Je kunt de pagina verversen om opnieuw deel te nemen.",
"app.error.userLoggedOut": "De gebruiker heeft een ongeldig sessie-token door af te melden",
"app.error.ejectedUser": "De gebruiker heeft een ongeldig sessie-token door verbanning",
"app.error.joinedAnotherWindow": "Deze sessie lijkt geopend in een andere browser",
@ -609,7 +770,6 @@
"app.error.fallback.presentation.title": "Er is een fout opgetreden",
"app.error.fallback.presentation.description": "Het is vastgelegd. Probeer de pagina opnieuw te laden.",
"app.error.fallback.presentation.reloadButton": "Herladen",
"app.guest.waiting": "Wachten op goedkeuring om deel te nemen",
"app.guest.errorSeeConsole": "Fout: meer details in de console",
"app.guest.noModeratorResponse": "Geen antwoord van de moderator",
"app.guest.noSessionToken": "Geen sessie-teken ontvangen.",
@ -644,14 +804,18 @@
"app.userList.guest.privateMessageLabel": "Bericht",
"app.userList.guest.acceptLabel": "Accepteer",
"app.userList.guest.denyLabel": "Weiger",
"app.userList.guest.feedbackMessage": "Toegepaste actie:",
"app.user-info.title": "Woordenboek zoekopdracht",
"app.toast.breakoutRoomEnded": "De brainstormruimte is beëindigd. Neem opnieuw deel aan de audio.",
"app.toast.chat.public": "Nieuw openbaar chatbericht",
"app.toast.chat.private": "Nieuw privéchatbericht",
"app.toast.chat.system": "Systeem",
"app.toast.chat.poll": "Peilingsresultaten",
"app.toast.chat.pollClick": "Peilingsresultaten gepubliceerd. Klik hier om te bekijken.",
"app.toast.clearedEmoji.label": "Emoji-status gewist",
"app.toast.setEmoji.label": "Emoji-status ingesteld op {0}",
"app.toast.meetingMuteOn.label": "Alle gebruikers zijn gedempt",
"app.toast.meetingMuteOnViewers.label": "Alle gebruikers zijn gedempt",
"app.toast.meetingMuteOff.label": "Vergadering dempen uitgeschakeld",
"app.toast.setEmoji.raiseHand": "Je hebt je hand opgestoken",
"app.toast.setEmoji.lowerHand": "Je hand is omlaag gedaan",
@ -667,6 +831,7 @@
"app.shortcut-help.title": "Sneltoetsen",
"app.shortcut-help.accessKeyNotAvailable": "Toegangssleutels niet beschikbaar",
"app.shortcut-help.comboLabel": "Combo",
"app.shortcut-help.alternativeLabel": "Alternatief",
"app.shortcut-help.functionLabel": "Functie",
"app.shortcut-help.closeLabel": "Sluiten",
"app.shortcut-help.closeDesc": "Sluit modal voor sneltoetsen",
@ -688,6 +853,38 @@
"app.shortcut-help.toggleFullscreenKey": "Entertoets",
"app.shortcut-help.nextSlideKey": "Pijl rechts",
"app.shortcut-help.previousSlideKey": "Pijl links",
"app.shortcut-help.select": "Selecteer tool",
"app.shortcut-help.pencil": "Potlood",
"app.shortcut-help.eraser": "Gum",
"app.shortcut-help.rectangle": "Rechthoek",
"app.shortcut-help.elipse": "Elips",
"app.shortcut-help.triangle": "Driehoek",
"app.shortcut-help.line": "Lijn",
"app.shortcut-help.arrow": "Pijl",
"app.shortcut-help.text": "Tekst tool",
"app.shortcut-help.note": "Post-it",
"app.shortcut-help.general": "Algemeen",
"app.shortcut-help.presentation": "Presentatie",
"app.shortcut-help.whiteboard": "Whiteboard",
"app.shortcut-help.zoomIn": "Inzoomen",
"app.shortcut-help.zoomOut": "Uitzoomen",
"app.shortcut-help.zoomFit": "Zoom opnieuw instellen",
"app.shortcut-help.zoomSelect": "Zoom naar selectie",
"app.shortcut-help.flipH": "Horizontaal draaien",
"app.shortcut-help.flipV": "Verticaal draaien",
"app.shortcut-help.lock": "Op slot / los",
"app.shortcut-help.moveToFront": "Vooraan",
"app.shortcut-help.moveToBack": "Achteraan",
"app.shortcut-help.moveForward": "Naar voor",
"app.shortcut-help.moveBackward": "Naar achter",
"app.shortcut-help.undo": "Ongedaan maken",
"app.shortcut-help.redo": "Opnieuw",
"app.shortcut-help.cut": "Knip",
"app.shortcut-help.copy": "Kopiëren",
"app.shortcut-help.paste": "Plakken",
"app.shortcut-help.selectAll": "Selecteer alles",
"app.shortcut-help.delete": "Verwijder",
"app.shortcut-help.duplicate": "Dupliceer",
"app.lock-viewers.title": "Vergrendel kijkers",
"app.lock-viewers.description": "Met deze opties kunt u ervoor zorgen dat kijkers geen specifieke functies gebruiken.",
"app.lock-viewers.featuresLable": "Kenmerk",
@ -724,6 +921,7 @@
"app.connection-status.no": "Nee",
"app.connection-status.notification": "Slechte verbinding gedetecteerd",
"app.connection-status.offline": "offline",
"app.connection-status.clientNotRespondingWarning": "Cliënt antwoord niet",
"app.connection-status.audioUploadRate": "Audio upload snelheid",
"app.connection-status.audioDownloadRate": "Audio downloadsnelheid",
"app.connection-status.videoUploadRate": "Video uploadsnelheid",
@ -737,13 +935,19 @@
"app.connection-status.next": "Volgende pagina",
"app.connection-status.prev": "Vorige pagina",
"app.learning-dashboard.label": "Learning Analytics dashboard",
"app.learning-dashboard.description": "Open een startpagina met gebruikersactiviteiten",
"app.learning-dashboard.description": "Dashboard met gebruikersactiviteiten",
"app.learning-dashboard.clickHereToOpen": "Open het Learning Analytics dashboard",
"app.recording.startTitle": "Opname starten",
"app.recording.stopTitle": "Opname onderbreken",
"app.recording.resumeTitle": "Opname hervatten",
"app.recording.startDescription": "U kunt later opnieuw op de opname knop klikken om deze te pauzeren.",
"app.recording.stopDescription": "Weet u zeker dat u de opname wilt pauzeren? U kunt later doorgaan door de opnieuw op de opnameknop te klikken.",
"app.recording.notify.title": "Opname gestart",
"app.recording.notify.description": "Er zal een opname beschikbaar komen gebaseerd op de rest van deze sessie",
"app.recording.notify.continue": "Ga verder",
"app.recording.notify.leave": "Verlaat sessie",
"app.recording.notify.continueLabel" : "Accepteer opname en ga verder",
"app.recording.notify.leaveLabel" : "Aanvaard de opname niet en verlaat de vergadering",
"app.videoPreview.cameraLabel": "Camera",
"app.videoPreview.profileLabel": "Kwaliteit",
"app.videoPreview.quality.low": "Laag",
@ -760,13 +964,20 @@
"app.videoPreview.webcamOptionLabel": "Kies webcam",
"app.videoPreview.webcamPreviewLabel": "Webcamvoorbeeld",
"app.videoPreview.webcamSettingsTitle": "Webcaminstellingen",
"app.videoPreview.webcamEffectsTitle": "Visuele effecten webcam",
"app.videoPreview.webcamVirtualBackgroundLabel": "Virtuele achtergrondinstellingen",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Dit toestel ondersteunt geen virtuele achtergronden",
"app.videoPreview.webcamNotFoundLabel": "Webcam niet gevonden",
"app.videoPreview.profileNotFoundLabel": "Geen ondersteund cameraprofiel",
"app.videoPreview.brightness": "Helderheid",
"app.videoPreview.wholeImageBrightnessLabel": "Hele afbeelding",
"app.videoPreview.wholeImageBrightnessDesc": "Past helderheid aan van stream en achtergrondafbeelding",
"app.videoPreview.sliderDesc": "Vergroot of verklein het helderheidsniveau",
"app.video.joinVideo": "Webcam delen",
"app.video.connecting": "Het delen van de webcam begint ...",
"app.video.leaveVideo": "Stop met delen webcam",
"app.video.videoSettings": "Video-instellingen",
"app.video.visualEffects": "Visuele effecten",
"app.video.advancedVideo": "Open geavanceerde instellingen",
"app.video.iceCandidateError": "Fout bij het toevoegen van ICE-kandidaat",
"app.video.iceConnectionStateError": "Verbindingsfout (ICE-fout 1107)",
@ -782,6 +993,7 @@
"app.video.notReadableError": "Kon geen webcamvideo ophalen. Zorg ervoor dat andere programma's de webcam niet gebruiken",
"app.video.timeoutError": "Browser reageerde niet op tijd.",
"app.video.genericError": "Er is een onbekende fout opgetreden met het toestel (Fout {0})",
"app.video.inactiveError": "Je webcam is onverwacht gestopt. Bekijk de rechten in je browser",
"app.video.mediaTimedOutError": "Je webcam-stream is onderbroken. Probeer die opnieuw te delen",
"app.video.mediaFlowTimeout1020": "Media konden de server niet bereiken (fout 1020)",
"app.video.suggestWebcamLock": "Vergrendel-instelling afdwingen voor webcams van kijkers?",
@ -804,8 +1016,17 @@
"app.video.virtualBackground.board": "Bord",
"app.video.virtualBackground.coffeeshop": "Koffieshop",
"app.video.virtualBackground.background": "Achtergrond",
"app.video.virtualBackground.backgroundWithIndex": "Achtergrond {0}",
"app.video.virtualBackground.custom": "Upload van je computer",
"app.video.virtualBackground.remove": "Verwijder toegevoegde afbeelding",
"app.video.virtualBackground.genericError": "Toepassen van het camera-effect mislukt. Probeer opnieuw.",
"app.video.virtualBackground.camBgAriaDesc": "Webcam virtuele achtergrond instellen op {0}",
"app.video.virtualBackground.maximumFileSizeExceeded": "Maximale bestandsgrootte overschreden. ({0}MB)",
"app.video.virtualBackground.typeNotAllowed": "Bestandstype niet toegestaan.",
"app.video.virtualBackground.errorOnRead": "Er ging wat fout bij het lezen van de bestanden.",
"app.video.virtualBackground.uploaded": "Geüpload",
"app.video.virtualBackground.uploading": "Uploaden...",
"app.video.virtualBackground.button.customDesc": "Voegt een nieuwe virtuele achtergrondsafbeelding toe",
"app.video.camCapReached": "Je kunt niet meer camera's delen",
"app.video.meetingCamCapReached": "Maximaal aantal simultane camera's in de vergadering bereikt",
"app.video.dropZoneLabel": "Zet hier neer",
@ -826,6 +1047,8 @@
"app.whiteboard.annotations.poll": "Peiling resultaten zijn gepubliceerd",
"app.whiteboard.annotations.pollResult": "Peilingresultaten",
"app.whiteboard.annotations.noResponses": "Geen antwoorden",
"app.whiteboard.annotations.notAllowed": "Je mag dit niet wijzigen",
"app.whiteboard.annotations.numberExceeded": "Het aantal annotaties dat de limiet overschrijdt {{0}}",
"app.whiteboard.toolbar.tools": "Gereedschappen",
"app.whiteboard.toolbar.tools.hand": "Hand",
"app.whiteboard.toolbar.tools.pencil": "Potlood",
@ -852,6 +1075,7 @@
"app.whiteboard.toolbar.color.silver": "Zilver",
"app.whiteboard.toolbar.undo": "Annotatie ongedaan maken",
"app.whiteboard.toolbar.clear": "Alle annotaties wissen",
"app.whiteboard.toolbar.clearConfirmation": "Weet je zeker dat je alle annotaties wil verwijderen?",
"app.whiteboard.toolbar.multiUserOn": "Whiteboard voor meerdere gebruikers inschakelen",
"app.whiteboard.toolbar.multiUserOff": "Whiteboard voor meerdere gebruikers uitschakelen",
"app.whiteboard.toolbar.palmRejectionOn": "Schakel palmafwijzing in",
@ -871,13 +1095,13 @@
"app.videoDock.webcamUnfocusDesc": "Ongericht de geselecteerde webcam",
"app.videoDock.webcamPinLabel": "Zet vast",
"app.videoDock.webcamPinDesc": "Zet de geselecteerde webcam vast",
"app.videoDock.webcamFullscreenLabel": "Webcam volledig scherm",
"app.videoDock.webcamSqueezedButtonLabel": "Webcamopties",
"app.videoDock.webcamUnpinLabel": "Maak los",
"app.videoDock.webcamUnpinLabelDisabled": "Enkel moderatoren kunnen gebruikers losmaken",
"app.videoDock.webcamUnpinDesc": "Maak de geselecteerde webcam los",
"app.videoDock.autoplayBlockedDesc": "We hebben uw toestemming nodig om u de webcams van andere gebruikers te laten zien.",
"app.videoDock.autoplayAllowLabel": "Bekijk webcams",
"app.invitation.title": "Brainstormruimte uitnodiging",
"app.invitation.confirm": "Uitnodigen",
"app.createBreakoutRoom.title": "Brainstormruimtes",
"app.createBreakoutRoom.ariaTitle": "Brainstormruimtes verbergen",
"app.createBreakoutRoom.breakoutRoomLabel": "Brainstormruimtes {0}",
@ -909,6 +1133,8 @@
"app.createBreakoutRoom.addRoomTime": "Tijd voor brainstormruimte verhogen tot",
"app.createBreakoutRoom.addParticipantLabel": "+ Deelnemer toevoegen",
"app.createBreakoutRoom.freeJoin": "Gebruikers toestaan een brainstormruimte te kiezen om deel te nemen",
"app.createBreakoutRoom.captureNotes": "Maak een opname van de gedeelde notities wanneer de brainstormruimte eindigt",
"app.createBreakoutRoom.captureSlides": "Maak een opname van het whiteboard wanneer de brainstormruimte eindigt",
"app.createBreakoutRoom.leastOneWarnBreakout": "U moet ten minste één gebruiker in een brainstormruimte plaatsen.",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "Minimale duur voor een brainstormruimte is {0} minuten.",
"app.createBreakoutRoom.modalDesc": "Tip: u kunt de naam van een gebruiker slepen en neerzetten om deze aan een specifieke brainstormruimte toe te wijzen.",
@ -921,6 +1147,14 @@
"app.createBreakoutRoom.setTimeCancel": "Annuleren",
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "De tijdsduur voor de brainstormruimte kan niet langer zijn dan de overgebleven tijd voor de vergadering.",
"app.createBreakoutRoom.roomNameInputDesc": "Naam voor brainstormruimte aanpassen",
"app.createBreakoutRoom.movedUserLabel": "{0} verplaatst naar kamer {1}",
"app.updateBreakoutRoom.modalDesc": "Om een gebruiker aan te passen of uit te nodigen kun je hem slepen naar de gewenste kamer.",
"app.updateBreakoutRoom.cancelLabel": "Annuleer",
"app.updateBreakoutRoom.title": "Brainstormruimte aanpassen",
"app.updateBreakoutRoom.confirm": "Toepassen",
"app.updateBreakoutRoom.userChangeRoomNotification": "Je bent verplaatst naar kamer {0}.",
"app.smartMediaShare.externalVideo": "Externe video's",
"app.update.resetRoom": "Gebruikerskamer opnieuw instellen",
"app.externalVideo.start": "Deel een nieuwe video",
"app.externalVideo.title": "Deel een externe video",
"app.externalVideo.input": "Externe video-URL",
@ -946,6 +1180,15 @@
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(deze wordt uitgeschakeld als u het webcamgedeelte sleept of het formaat ervan wijzigt)",
"app.debugWindow.form.chatLoggerLabel": "Test chat logniveau",
"app.debugWindow.form.button.apply": "Toepassen",
"app.layout.modal.title": "Layouts",
"app.layout.modal.confirm": "Bevestig",
"app.layout.modal.cancel": "Annuleer",
"app.layout.modal.layoutLabel": "Selecteer je layout",
"app.layout.modal.keepPushingLayoutLabel": "Stuur layout naar iedereen",
"app.layout.modal.pushLayoutLabel": "Stuur naar iedereen",
"app.layout.modal.layoutToastLabel": "Layout instellingen gewijzigd",
"app.layout.modal.layoutSingular": "Layout",
"app.layout.modal.layoutBtnDesc": "Zet layout als geselecteerde optie",
"app.layout.style.custom": "Aangepast",
"app.layout.style.smart": "Slimme lay-out",
"app.layout.style.presentationFocus": "Focus op presentatie",
@ -995,6 +1238,7 @@
"playback.player.thumbnails.wrapper.aria": "Miniaturenzone",
"playback.player.webcams.wrapper.aria": "Webcam-zone",
"app.learningDashboard.dashboardTitle": "Learning Analytics dashboard",
"app.learningDashboard.bigbluebuttonTitle": "BigBlueButton",
"app.learningDashboard.downloadSessionDataLabel": "Download sessie-gegevens",
"app.learningDashboard.lastUpdatedLabel": "Laatste update op",
"app.learningDashboard.sessionDataDownloadedLabel": "Gedownload!",
@ -1019,6 +1263,12 @@
"app.learningDashboard.userDetails.response": "Reactie",
"app.learningDashboard.userDetails.mostCommonAnswer": "Meest voorkomend antwoord",
"app.learningDashboard.userDetails.anonymousAnswer": "Anonieme peiling",
"app.learningDashboard.userDetails.talkTime": "Spreektijd",
"app.learningDashboard.userDetails.messages": "Berichten",
"app.learningDashboard.userDetails.emojis": "Emojis",
"app.learningDashboard.userDetails.raiseHands": "Handen opsteken",
"app.learningDashboard.userDetails.pollVotes": "Stemmen van de peiling",
"app.learningDashboard.userDetails.onlineIndicator": "{0} online-tijd",
"app.learningDashboard.usersTable.title": "Overzicht",
"app.learningDashboard.usersTable.colOnline": "Online-tijd",
"app.learningDashboard.usersTable.colTalk": "Spreektijd",
@ -1042,8 +1292,13 @@
"app.learningDashboard.pollsTable.anonymousRowName": "Anoniem",
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "Er zijn geen peilingen gemaakt",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "Als er een peiling naar de gebruikers verstuurd is, dan zullen de resultaten in deze lijst verschijnen.",
"app.learningDashboard.pollsTable.answerTotal": "Totaal",
"app.learningDashboard.pollsTable.userLabel": "Gebruiker",
"app.learningDashboard.statusTimelineTable.title": "Tijdlijn",
"app.learningDashboard.statusTimelineTable.thumbnail": "Presentatie-icoontje",
"app.learningDashboard.statusTimelineTable.presentation": "Presentatie",
"app.learningDashboard.statusTimelineTable.pageNumber": "Pagina",
"app.learningDashboard.statusTimelineTable.setAt": "Zet op",
"app.learningDashboard.errors.invalidToken": "Ongeldig sessietoken",
"app.learningDashboard.errors.dataUnavailable": "Gegevens niet meer beschikbaar",
"mobileApp.portals.list.empty.addFirstPortal.label": "Voeg je eerste portaal toe met bovenstaande knop,",
@ -1057,6 +1312,4 @@
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Vereiste velden",
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Naam reeds in gebruik",
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Fout bij het laden van de pagina - controleer de URL en de netwerkverbinding"
}

View File

@ -2,10 +2,12 @@
"app.home.greeting": "A sessão vai iniciar em breve ...",
"app.chat.submitLabel": "Enviar mensagem",
"app.chat.loading": "Mensagens carregadas: {0}%",
"app.chat.errorMaxMessageLength": "Mensagem maior do que {0} caracter(es)",
"app.chat.disconnected": "Está desligado, pelo que mensagens não podem ser enviadas",
"app.chat.locked": "Chat bloqueado, pelo que mensagens não podem ser enviadas",
"app.chat.errorMaxMessageLength": "A mensagem é muito longa, excedeu o máximo de {0} caracteres",
"app.chat.disconnected": "Está desligado e por isso não pode enviar mensagens.",
"app.chat.locked": "O chat está bloqueado! Não pode enviar mensagens.",
"app.chat.inputLabel": "Entrada de mensagem para o chat {0}",
"app.chat.emojiButtonLabel": "Seletor de emojis",
"app.chat.inputPlaceholder": "Mensagem {0}",
"app.chat.titlePublic": "Chat Público",
"app.chat.titlePrivate": "Chat Privado com {0}",
"app.chat.partnerDisconnected": "{0} saiu da sessão",
@ -17,15 +19,38 @@
"app.chat.dropdown.copy": "Copiar",
"app.chat.dropdown.save": "Guardar",
"app.chat.label": "Chat",
"app.chat.offline": "Offline",
"app.chat.offline": "Desligado",
"app.chat.pollResult": "Resultados da sondagem",
"app.chat.breakoutDurationUpdated": "O intervalo agora é de {0} minutos",
"app.chat.breakoutDurationUpdatedModerator": "O tempo de intervalo agora é de {0} minutos e uma notificação foi enviada.",
"app.chat.emptyLogLabel": "Registo do chat está vazio",
"app.chat.clearPublicChatMessage": "O histórico do chat público foi apagado por um moderador",
"app.chat.multi.typing": "Múltiplos utilizadores estão a escrever",
"app.chat.multi.typing": "Vários utilizadores estão a escrever",
"app.chat.one.typing": "{0} está a escrever",
"app.chat.two.typing": "{0} e {1} estão a escrever",
"app.chat.copySuccess": "Transcrição do chat copiado",
"app.chat.copySuccess": "Transcrição do chat copiada",
"app.chat.copyErr": "A transcrição da cópia do chat falhou",
"app.emojiPicker.search": "Procurar",
"app.emojiPicker.notFound": "Nenhum emoji encontrado",
"app.emojiPicker.skintext": "Escolha o seu tom de pele padrão",
"app.emojiPicker.clear": "Limpar",
"app.emojiPicker.categories.label": "Categorias de emojis",
"app.emojiPicker.categories.people": "Pessoas e Corpo",
"app.emojiPicker.categories.nature": "Animais e Natureza",
"app.emojiPicker.categories.foods": "Comida e bebida",
"app.emojiPicker.categories.places": "Viagens e lugares",
"app.emojiPicker.categories.activity": "Atividade",
"app.emojiPicker.categories.objects": "Objetos",
"app.emojiPicker.categories.symbols": "Símbolos",
"app.emojiPicker.categories.flags": "Bandeiras",
"app.emojiPicker.categories.recent": "Usado frequentemente",
"app.emojiPicker.categories.search": "Resultados de Procura",
"app.emojiPicker.skintones.1": "Tom de pele padrão",
"app.emojiPicker.skintones.2": "Tom de pele claro",
"app.emojiPicker.skintones.3": "Tom de pele médio-claro",
"app.emojiPicker.skintones.4": "Tom de pele médio",
"app.emojiPicker.skintones.5": "Tom de pele médio-escuro",
"app.emojiPicker.skintones.6": "Tom de pele escuro",
"app.captions.label": "Legendas",
"app.captions.menu.close": "Fechar",
"app.captions.menu.start": "Iniciar",
@ -41,8 +66,34 @@
"app.captions.menu.backgroundColor": "Cor de fundo",
"app.captions.menu.previewLabel": "Pré-visualizar",
"app.captions.menu.cancelLabel": "Cancelar",
"app.captions.hide": "Ocultar legendas",
"app.captions.ownership": "Assumir",
"app.captions.ownershipTooltip": "Será atribuído como proprietário de {0} legendas",
"app.captions.dictationStart": "Iniciar ditar",
"app.captions.dictationStop": "Parar ditar",
"app.captions.dictationOnDesc": "Ativar o reconhecimento de fala",
"app.captions.dictationOffDesc": "Desativar o reconhecimento de fala",
"app.captions.speech.start": "Reconhecimento de fala iniciado",
"app.captions.speech.stop": "Reconhecimento de fala parado",
"app.captions.speech.error": "O reconhecimento de fala parou devido à incompatibilidade do navegador ou algum tempo de silêncio ",
"app.confirmation.skipConfirm": "Não perguntar novamente",
"app.confirmation.virtualBackground.title": "Iniciar novo plano de fundo virtual",
"app.confirmation.virtualBackground.description": "{0} será adicionado como plano de fundo virtual. Continuar?",
"app.confirmationModal.yesLabel": "Sim",
"app.textInput.sendLabel": "Enviar",
"app.title.defaultViewLabel": "Vista de apresentação padrão",
"app.notes.title": "Notas partilhadas",
"app.notes.titlePinned": "Notas partilhadas (fixadas)",
"app.notes.pinnedNotification": "As notas partilhadas agora estão fixadas no quadro branco.",
"app.notes.label": "Notas",
"app.notes.hide": "Ocultar notas",
"app.notes.locked": "Bloqueado",
"app.notes.disabled": "Fixado na área de multimédia",
"app.notes.notesDropdown.covertAndUpload": "Converter notas em apresentação",
"app.notes.notesDropdown.pinNotes": "Fixar notas no quadro branco",
"app.notes.notesDropdown.unpinNotes": "Desafixar notas",
"app.notes.notesDropdown.notesOptions": "Opções de notas",
"app.pads.hint": "Pressione Esc para focar a barra de ferramentas do pad",
"app.user.activityCheck": "Verificar atividade do utilizador",
"app.user.activityCheck.label": "Verificar se o utilizador ainda está na sessão ({0})",
"app.user.activityCheck.check": "Verificar",
@ -53,13 +104,13 @@
"app.userList.notesListItem.unreadContent": "Novos conteúdos disponíveis na secção de anotações partilhadas",
"app.userList.captionsTitle": "Legendas",
"app.userList.presenter": "Apresentador",
"app.userList.you": "Eu",
"app.userList.you": "Você",
"app.userList.locked": "Bloqueado",
"app.userList.byModerator": "pelo (Moderador)",
"app.userList.label": "Lista de utilizadores",
"app.userList.toggleCompactView.label": "Alternar para o modo de exibição compacto",
"app.userList.toggleCompactView.label": "Mudar para o modo de exibição compacto",
"app.userList.moderator": "Moderador",
"app.userList.mobile": "Móvel",
"app.userList.mobile": "Telemóvel",
"app.userList.guest": "Convidado",
"app.userList.sharingWebcam": "Webcam",
"app.userList.menuTitleContext": "Opções disponíveis",
@ -89,8 +140,8 @@
"app.userList.userOptions.muteAllDesc": "Silenciar todos os utilizadores na sessão",
"app.userList.userOptions.clearAllLabel": "Limpar todos os ícones de estado",
"app.userList.userOptions.clearAllDesc": "Limpa o ícone de estado de todos os utilizadores",
"app.userList.userOptions.muteAllExceptPresenterLabel": "Silenciar todos os utilizadores exceto o apresentador",
"app.userList.userOptions.muteAllExceptPresenterDesc": "Silencia todos os utilizadores na sessão, exceto o apresentador",
"app.userList.userOptions.muteAllExceptPresenterLabel": "Silenciar todos os utilizadores excepto o apresentador",
"app.userList.userOptions.muteAllExceptPresenterDesc": "Silenciar todos os utilizadores na sessão, excepto o apresentador",
"app.userList.userOptions.unmuteAllLabel": "Desligar o modo silêncio da sessão",
"app.userList.userOptions.unmuteAllDesc": "Desliga o modo de silêncio da sessão",
"app.userList.userOptions.lockViewersLabel": "Bloquear participantes",
@ -101,22 +152,27 @@
"app.userList.userOptions.disableMic": "Os microfones dos espetadores estão desativados",
"app.userList.userOptions.disablePrivChat": "O chat privado está desativado",
"app.userList.userOptions.disablePubChat": "O chat público está desativado",
"app.userList.userOptions.disableNotes": "As notas partilhadas agora estão bloqueadas",
"app.userList.userOptions.hideUserList": "A lista de utilizadores está agora oculta para participantes",
"app.userList.userOptions.webcamsOnlyForModerator": "Apenas moderadores podem ver as webcams dos participantes (devido às configurações de bloqueio)",
"app.userList.userOptions.webcamsOnlyForModerator": "Apenas os moderadores podem ver as webcams dos participantes (devido às configurações de bloqueio)",
"app.userList.content.participants.options.clearedStatus": "Foram limpos todos os estados de utilizador",
"app.userList.userOptions.enableCam": "Webcams de participantes estão ativas",
"app.userList.userOptions.enableMic": "Microfones de participantes estão ativos",
"app.userList.userOptions.enablePrivChat": "Chat privado está ativo",
"app.userList.userOptions.enablePubChat": "Chat público está ativo",
"app.userList.userOptions.showUserList": "Lista de utilizadores é agora exibida a participantes",
"app.userList.userOptions.enableNotes": "As notas partilhadas agora estão habilitadas",
"app.userList.userOptions.showUserList": "Lista de utilizadores é agora mostrada a participantes",
"app.userList.userOptions.enableOnlyModeratorWebcam": "Pode ativar a sua webcam agora, e todos o poderão ver",
"app.userList.userOptions.savedNames.title": "Lista de utilizadores na sessão {0} em {1}",
"app.userList.userOptions.sortedFirstName.heading": "Ordenado por primeiro nome:",
"app.userList.userOptions.sortedLastName.heading": "Ordenado por último nome:",
"app.media.label": "Media",
"app.userList.userOptions.hideViewersCursor": "Os cursores do visualizador estão bloqueados",
"app.userList.userOptions.showViewersCursor": "Os cursores do visualizador estão desbloqueados",
"app.media.label": "Multimédia",
"app.media.autoplayAlertDesc": "Permitir acesso",
"app.media.screenshare.start": "A partilha do ecrã iniciou",
"app.media.screenshare.end": "A partilha do ecrã terminou",
"app.media.screenshare.endDueToDataSaving": "A partilha de ecrã foi interrompida devido à poupança de dados",
"app.media.screenshare.unavailable": "Partilha de ecrã indisponível",
"app.media.screenshare.notSupported": "A partilha de ecrã não é suportada neste browser.",
"app.media.screenshare.autoplayBlockedDesc": "Necessitamos da sua permissão para lhe mostrar o ecrã do apresentador",
@ -133,8 +189,8 @@
"app.meeting.meetingTimeRemaining": "Tempo restante da sessão: {0}",
"app.meeting.meetingTimeHasEnded": "Tempo limite atingido. A sessão vai fechar dentro de momentos",
"app.meeting.endedByUserMessage": "Esta sessão foi encerrada por {0}",
"app.meeting.endedByNoModeratorMessageSingular": "A reunião terminou devido à ausência de um moderador ao fim de um minuto",
"app.meeting.endedByNoModeratorMessagePlural": "A reunião terminou devido à ausência de um moderador após {0} minutos",
"app.meeting.endedByNoModeratorMessageSingular": "A reunião terminou porque nenhum moderador esteve presente por um minuto",
"app.meeting.endedByNoModeratorMessagePlural": "A reunião terminou porque nenhum moderador esteve presente por {0} minutos",
"app.meeting.endedMessage": "Vai ser redirecionado para o ecrã inicial",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Sessão vai terminar em um minuto.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Sessão vai terminar em {0} minutos.",
@ -146,7 +202,15 @@
"app.presentation.slideContent": "Conteúdo de slide",
"app.presentation.startSlideContent": "Início do conteúdo de slide",
"app.presentation.endSlideContent": "Fim do conteúdo de slide",
"app.presentation.changedSlideContent": "Apresentação alterada para slide: {0}",
"app.presentation.emptySlideContent": "Sem conteúdo para o slide atual",
"app.presentation.options.fullscreen": "Apresentação em ecrã cheio",
"app.presentation.options.exitFullscreen": "Sair de ecrã cheio",
"app.presentation.options.minimize": "Minimizar",
"app.presentation.options.snapshot": "Instantâneo do slide atual",
"app.presentation.options.downloading": "A descarregar ...",
"app.presentation.options.downloaded": "A apresentação atual foi descarregada",
"app.presentation.options.downloadFailed": "Não foi possível descarregar a apresentação atual",
"app.presentation.presentationToolbar.noNextSlideDesc": "Fim da apresentação",
"app.presentation.presentationToolbar.noPrevSlideDesc": "Início da apresentação",
"app.presentation.presentationToolbar.selectLabel": "Selecionar slide",
@ -166,13 +230,30 @@
"app.presentation.presentationToolbar.zoomInDesc": "Aproximar a apresentação",
"app.presentation.presentationToolbar.zoomOutLabel": "Afastar",
"app.presentation.presentationToolbar.zoomOutDesc": "Afastar a apresentação",
"app.presentation.presentationToolbar.zoomReset": "Repor Zoom",
"app.presentation.presentationToolbar.zoomReset": "Repor zoom",
"app.presentation.presentationToolbar.zoomIndicator": "Percentagem de zoom atual",
"app.presentation.presentationToolbar.fitToWidth": "Ajustar à largura",
"app.presentation.presentationToolbar.fitToPage": "Ajustar à página",
"app.presentation.presentationToolbar.goToSlide": "Slide {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Ocultar Barras de Ferramentas",
"app.presentation.presentationToolbar.showToolsDesc": "Mostrar Barras de Ferramentas",
"app.presentation.placeholder": "Não há nenhuma apresentação ativa no momento",
"app.presentationUploder.title": "Apresentação",
"app.presentationUploder.message": "Como um apresentador, possui acesso à funcionalidade de carregar qualquer documento do Office ou ficheiro PDF. Recomendamos PDF para melhores resultados. Por favor, certifique-se que uma apresentação está escolhida, usado a checkbox circular do lado direito.",
"app.presentationUploder.message": "Como apresentador, pode fazer o carregamento de qualquer documento do Office ou ficheiro PDF. Recomendamos ficheiro PDF para melhores resultados. Certifique-se de que uma apresentação seja selecionada usando a caixa de seleção do círculo no lado esquerdo.",
"app.presentationUploader.exportHint": "Selecionar \"Enviar para chat\" fornecerá aos utilizadores um link para descarregamento com anotações no chat público.",
"app.presentationUploader.exportToastHeader": "A enviar para o chat ({0} item)",
"app.presentationUploader.exportToastHeaderPlural": "A enviar para o chat ({0} item)",
"app.presentationUploader.exporting": "A enviar para o chat ",
"app.presentationUploader.sending": "A enviar ...",
"app.presentationUploader.collecting": "A extrair slide {0} de {1}...",
"app.presentationUploader.processing": "A anotar slide {0} de {1}...",
"app.presentationUploader.sent": "Enviado",
"app.presentationUploader.exportingTimeout": "A exportação está a demorar muito...",
"app.presentationUploader.export": "Enviar para o chat",
"app.presentationUploader.export.linkAvailable": "Link para descarregar {0} disponível no chat público.",
"app.presentationUploader.export.notAccessibleWarning": "pode não ser compatível com acessibilidade",
"app.presentationUploader.currentPresentationLabel": "Apresentação atual",
"app.presentationUploder.extraHint": "IMPORTANTE: cada ficheiro não pode exceder {0} MB e {1} páginas.",
"app.presentationUploder.uploadLabel": "Carregar",
"app.presentationUploder.confirmLabel": "Confirmar",
"app.presentationUploder.confirmDesc": "Guardar as alterações e iniciar a apresentação",
@ -182,10 +263,14 @@
"app.presentationUploder.dropzoneImagesLabel": "Arraste imagens para aqui, para as carregar",
"app.presentationUploder.browseFilesLabel": "ou procure ficheiros",
"app.presentationUploder.browseImagesLabel": "ou procure/capture imagens",
"app.presentationUploder.externalUploadTitle": "Adicionar conteúdo de aplicação externa",
"app.presentationUploder.externalUploadLabel": "Procurar ficheiros",
"app.presentationUploder.fileToUpload": "Para carregar...",
"app.presentationUploder.currentBadge": "Atual",
"app.presentationUploder.rejectedError": "O(s) ficheiro(s) selecionados foram rejeitados. Verifique por favor os tipos de ficheiro.",
"app.presentationUploder.connectionClosedError": "Interrompido por fraca conectividade. Por favor, tente novamente.",
"app.presentationUploder.upload.progress": "A carregar ({0}%)",
"app.presentationUploder.conversion.204": "Nenhum conteúdo para capturar",
"app.presentationUploder.upload.413": "O ficheiro é demasiado grande, excedeu o máximo de {0} MB",
"app.presentationUploder.genericError": "Oops, aconteceu algo errado...",
"app.presentationUploder.upload.408": "Timeout no pedido de token de carregamento.",
@ -197,14 +282,14 @@
"app.presentationUploder.conversion.generatedSlides": "Slides gerados ...",
"app.presentationUploder.conversion.generatingSvg": "A gerar imagens SVG ...",
"app.presentationUploder.conversion.pageCountExceeded": "Número de páginas excedeu o máximo de {0}",
"app.presentationUploder.conversion.invalidMimeType": "Formato inválido detectado (extensão={0}, tipo de conteúdo={1})",
"app.presentationUploder.conversion.conversionTimeout": "O slide {0} não pôde ser processado em {1} tentativas.",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Não foi possível processar este documento do Office. Por favor tente enviar em formato PDF.",
"app.presentationUploder.conversion.officeDocConversionFailed": "Não foi possível processar este documento do Office. Por favor tente enviar em formato PDF.",
"app.presentationUploder.conversion.pdfHasBigPage": "Não foi possível converter o ficheiro PDF, por favor tente optimizá-lo. Tamanho máximo de página {0}",
"app.presentationUploder.conversion.timeout": "Ops, a conversão demorou muito",
"app.presentationUploder.conversion.pageCountFailed": "Não foi possível determinar o número de páginas.",
"app.presentationUploder.conversion.unsupportedDocument": "Extensão de ficheiro não suportada",
"app.presentationUploder.isDownloadableLabel": "O download da apresentação não é permitido - clique para permitir",
"app.presentationUploder.isNotDownloadableLabel": "O download da apresentação é permitido - clique para impedir",
"app.presentationUploder.removePresentationLabel": "Eliminar apresentação",
"app.presentationUploder.setAsCurrentPresentation": "Definir apresentação como atual",
"app.presentationUploder.tableHeading.filename": "Nome do ficheiro",
@ -218,7 +303,12 @@
"app.presentationUploder.clearErrors": "Limpar erros",
"app.presentationUploder.clearErrorsDesc": "Limpar ficheiros de apresentação que falharam o carregamento",
"app.presentationUploder.uploadViewTitle": "Carregar apresentação",
"app.poll.questionAndoptions.label" : "Texto da pergunta a ser mostrado.\nA. Opção de sondagem*\nB. Opção de sondagem (opcional)\nC. Opção de sondagem (opcional)\nD. Opção de sondagem (opcional)\nE. Opção de sonagem (opcional)",
"app.poll.customInput.label": "Entrada personalizada",
"app.poll.customInputInstructions.label": "A entrada personalizada está habilitada - escreva a pergunta da sondagem e e as opções em determinado formato ou arraste e solte um ficheiro de texto no mesmo formato.",
"app.poll.maxOptionsWarning.label": "Apenas as primeiras 5 opções podem ser usadas!",
"app.poll.pollPaneTitle": "Sondagem",
"app.poll.enableMultipleResponseLabel": "Permitir várias respostas por utilizador?",
"app.poll.quickPollTitle": "Sondagem rápida",
"app.poll.hidePollDesc": "Ocultar menu de sondagem",
"app.poll.quickPollInstruction": "Selecione uma opção abaixo para iniciar a sua sondagem.",
@ -236,7 +326,7 @@
"app.poll.clickHereToSelect": "Clique aqui para selecionar",
"app.poll.question.label" : "Escreva a sua pergunta...",
"app.poll.optionalQuestion.label" : "Escreva a sua pergunta (opcional)...",
"app.poll.userResponse.label" : "Resposta do utilizador",
"app.poll.userResponse.label" : "Resposta digitada",
"app.poll.responseTypes.label" : "Tipos de resposta",
"app.poll.optionDelete.label" : "Apagar",
"app.poll.responseChoices.label" : "Opções de resposta",
@ -295,19 +385,20 @@
"app.muteWarning.disableMessage": "Alertas de silêncio desactivados até desactivar o silêncio",
"app.muteWarning.tooltip": "Clique para fechar e desativar o aviso até a próxima ativação do som",
"app.navBar.settingsDropdown.optionsLabel": "Opções",
"app.navBar.settingsDropdown.fullscreenLabel": "Alternar para ecrã inteiro",
"app.navBar.settingsDropdown.fullscreenLabel": "Aplicativo em ecrã cheio",
"app.navBar.settingsDropdown.settingsLabel": "Abrir configurações",
"app.navBar.settingsDropdown.aboutLabel": "Sobre",
"app.navBar.settingsDropdown.leaveSessionLabel": "Sair da sessão",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Sair do modo de ecrã inteiro",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Sair de ecrã cheio",
"app.navBar.settingsDropdown.fullscreenDesc": "Alternar o menu de configurações para ecrã inteiro",
"app.navBar.settingsDropdown.settingsDesc": "Alterar as configurações gerais",
"app.navBar.settingsDropdown.aboutDesc": "Mostrar informações sobre o cliente",
"app.navBar.settingsDropdown.aboutDesc": "Mostrar informações sobre o navegador",
"app.navBar.settingsDropdown.leaveSessionDesc": "Sair da sessão",
"app.navBar.settingsDropdown.exitFullscreenDesc": "Sair do modo de écrã inteiro",
"app.navBar.settingsDropdown.exitFullscreenDesc": "Sair do modo de ecrã inteiro",
"app.navBar.settingsDropdown.hotkeysLabel": "Atalhos do teclado",
"app.navBar.settingsDropdown.hotkeysDesc": "Lista de atalhos de teclado disponíveis",
"app.navBar.settingsDropdown.helpLabel": "Ajuda",
"app.navBar.settingsDropdown.openAppLabel": "Abrir na aplicação BigBlueButton Tablet",
"app.navBar.settingsDropdown.helpDesc": "Links para tutoriais vídeo (abre num novo separador)",
"app.navBar.settingsDropdown.endMeetingDesc": "Termina a sessão atual",
"app.navBar.settingsDropdown.endMeetingLabel": "Terminar sessão",
@ -325,15 +416,25 @@
"app.endMeeting.description": "Esta acção vai terminar a sessão para {0} utilizador(es). Tem a certeza que deseja terminar a sessão?",
"app.endMeeting.noUserDescription": "Tem certeza que deseja encerrar esta sessão?",
"app.endMeeting.contentWarning": "Mensagens de chat, notas partilhadas, conteúdo de quadro branco e documentos partilhados para esta sessão deixarão de ser directamente acessíveis",
"app.endMeeting.yesLabel": "Sim",
"app.endMeeting.yesLabel": "Encerrar sessão para todos os utilizadores",
"app.endMeeting.noLabel": "Não",
"app.about.title": "Sobre",
"app.about.version": "Build do cliente:",
"app.about.version": "Versão do navegador:",
"app.about.version_label": "Versão BigBlueButton:",
"app.about.copyright": "Direitos de autor:",
"app.about.confirmLabel": "OK",
"app.about.confirmDesc": "OK",
"app.about.dismissLabel": "Cancelar",
"app.about.dismissDesc": "Fechar informações sobre o cliente",
"app.about.dismissDesc": "Fechar informações sobre o navegador",
"app.mobileAppModal.title": "Abrir app BigBlueButton Tablet",
"app.mobileAppModal.description": "Tem a app BigBlueButton Tablet instalada no seu dispositivo?",
"app.mobileAppModal.openApp": "Sim, abra a app agora",
"app.mobileAppModal.obtainUrlMsg": "A obter o URL da reunião",
"app.mobileAppModal.obtainUrlErrorMsg": "Erro ao tentar obter o URL da reunião",
"app.mobileAppModal.openStore": "Não, abra a App Store para descarregar",
"app.mobileAppModal.dismissLabel": "Cancelar",
"app.mobileAppModal.dismissDesc": "Fechar",
"app.mobileAppModal.userConnectedWithSameId": "O utilizador {0} acabou de se conectar usando o seu ID.",
"app.actionsBar.changeStatusLabel": "Alterar estado",
"app.actionsBar.muteLabel": "Silenciar",
"app.actionsBar.unmuteLabel": "Falar",
@ -344,10 +445,13 @@
"app.actionsBar.actionsDropdown.restorePresentationDesc": "Botão para restaurar apresentação minimizada",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Minimizar apresentação",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Botão para minimizar apresentação",
"app.actionsBar.actionsDropdown.layoutModal": "Modo de configurações de layout",
"app.screenshare.screenShareLabel" : "Partilhar ecrã",
"app.submenu.application.applicationSectionTitle": "Aplicação",
"app.submenu.application.animationsLabel": "Animações",
"app.submenu.application.audioFilterLabel": "Filtros de áudio para o microfone",
"app.submenu.application.wbToolbarsAutoHideLabel": "Ocultar automaticamente as barras de ferramentas do quadro branco",
"app.submenu.application.darkThemeLabel": "Modo escuro",
"app.submenu.application.fontSizeControlLabel": "Tamanho da fonte",
"app.submenu.application.increaseFontBtnLabel": "Aumentar o tamanho da fonte da aplicação",
"app.submenu.application.decreaseFontBtnLabel": "Diminuir o tamanho da fonte da aplicação",
@ -357,6 +461,69 @@
"app.submenu.application.noLocaleOptionLabel": "Não existem esquemas de idiomas disponíveis",
"app.submenu.application.paginationEnabledLabel": "Paginação de vídeo",
"app.submenu.application.layoutOptionLabel": "Tipo de layout",
"app.submenu.application.pushLayoutLabel": "Propagar layout",
"app.submenu.application.localeDropdown.af": "Afrikaans",
"app.submenu.application.localeDropdown.ar": "Arabic",
"app.submenu.application.localeDropdown.az": "Azerbaijani",
"app.submenu.application.localeDropdown.bg-BG": "Bulgarian",
"app.submenu.application.localeDropdown.bn": "Bengali",
"app.submenu.application.localeDropdown.ca": "Catalan",
"app.submenu.application.localeDropdown.cs-CZ": "Czech",
"app.submenu.application.localeDropdown.da": "Danish",
"app.submenu.application.localeDropdown.de": "German",
"app.submenu.application.localeDropdown.dv": "Dhivehi",
"app.submenu.application.localeDropdown.el-GR": "Greek (Greece)",
"app.submenu.application.localeDropdown.en": "Inglês",
"app.submenu.application.localeDropdown.eo": "Esperanto",
"app.submenu.application.localeDropdown.es": "Espanhol",
"app.submenu.application.localeDropdown.es-419": "Espanhol (América Latina)",
"app.submenu.application.localeDropdown.es-ES": "Espanhol (Espanha)",
"app.submenu.application.localeDropdown.es-MX": "Espanhol (México)",
"app.submenu.application.localeDropdown.et": "Estonian",
"app.submenu.application.localeDropdown.eu": "Basque",
"app.submenu.application.localeDropdown.fa-IR": "Persian",
"app.submenu.application.localeDropdown.fi": "Finnish",
"app.submenu.application.localeDropdown.fr": "French",
"app.submenu.application.localeDropdown.gl": "Galician",
"app.submenu.application.localeDropdown.he": "Hebrew",
"app.submenu.application.localeDropdown.hi-IN": "Hindi",
"app.submenu.application.localeDropdown.hr": "Croatian",
"app.submenu.application.localeDropdown.hu-HU": "Hungarian",
"app.submenu.application.localeDropdown.hy": "Armenian",
"app.submenu.application.localeDropdown.id": "Indonesian",
"app.submenu.application.localeDropdown.it-IT": "Italian",
"app.submenu.application.localeDropdown.ja": "Japanese",
"app.submenu.application.localeDropdown.ka": "Georgian",
"app.submenu.application.localeDropdown.km": "Khmer",
"app.submenu.application.localeDropdown.kn": "Kannada",
"app.submenu.application.localeDropdown.ko-KR": "Korean (Korea)",
"app.submenu.application.localeDropdown.lo-LA": "Lao",
"app.submenu.application.localeDropdown.lt-LT": "Lithuanian",
"app.submenu.application.localeDropdown.lv": "Latvian",
"app.submenu.application.localeDropdown.ml": "Malayalam",
"app.submenu.application.localeDropdown.mn-MN": "Mongolian",
"app.submenu.application.localeDropdown.nb-NO": "Norwegian (bokmal)",
"app.submenu.application.localeDropdown.nl": "Dutch",
"app.submenu.application.localeDropdown.oc": "Occitan",
"app.submenu.application.localeDropdown.pl-PL": "Polish",
"app.submenu.application.localeDropdown.pt": "Português",
"app.submenu.application.localeDropdown.pt-BR": "Português (Brasil)",
"app.submenu.application.localeDropdown.ro-RO": "Romanian",
"app.submenu.application.localeDropdown.ru": "Russian",
"app.submenu.application.localeDropdown.sk-SK": "Slovak (Slovakia)",
"app.submenu.application.localeDropdown.sl": "Slovenian",
"app.submenu.application.localeDropdown.sr": "Serbian",
"app.submenu.application.localeDropdown.sv-SE": "Swedish",
"app.submenu.application.localeDropdown.ta": "Tamil",
"app.submenu.application.localeDropdown.te": "Telugu",
"app.submenu.application.localeDropdown.th": "Thai",
"app.submenu.application.localeDropdown.tr": "Turkish",
"app.submenu.application.localeDropdown.tr-TR": "Turkish (Turkey)",
"app.submenu.application.localeDropdown.uk-UA": "Ukrainian",
"app.submenu.application.localeDropdown.vi": "Vietnamese",
"app.submenu.application.localeDropdown.vi-VN": "Vietnamese (Vietnam)",
"app.submenu.application.localeDropdown.zh-CN": "Chinese Simplified (China)",
"app.submenu.application.localeDropdown.zh-TW": "Chinese Traditional (Taiwan)",
"app.submenu.notification.SectionTitle": "Notificações",
"app.submenu.notification.Desc": "Defina as notificações pretendidas.",
"app.submenu.notification.audioAlertLabel": "Alertas de audio",
@ -385,10 +552,11 @@
"app.settings.main.save.label.description": "Guardar as alterações e fechar o menu de configurações",
"app.settings.dataSavingTab.label": "Economia de dados",
"app.settings.dataSavingTab.webcam": "Permitir webcams",
"app.settings.dataSavingTab.screenShare": "Permitir partilha de ecrã",
"app.settings.dataSavingTab.screenShare": "Ativar partilha de área de trabalho de outros participantes",
"app.settings.dataSavingTab.description": "Para otimizar o volume de transferência de dados, ajuste o que está a ser exibido atualmente.",
"app.settings.save-notification.label": "As configurações foram guardadas",
"app.statusNotifier.lowerHands": "Mãos baixadas",
"app.statusNotifier.lowerHandDescOneUser": "Baixar a mão de {0}",
"app.statusNotifier.raisedHandsTitle": "Mãos levantadas",
"app.statusNotifier.raisedHandDesc": "{0} levantaram as mãos",
"app.statusNotifier.raisedHandDescOneUser": "{0} levantou a mão",
@ -401,10 +569,9 @@
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ estavam a falar",
"app.talkingIndicator.wasTalking" : "{0} parou de falar",
"app.actionsBar.actionsDropdown.actionsLabel": "Ações",
"app.actionsBar.actionsDropdown.presentationLabel": "Gerir apresentações",
"app.actionsBar.actionsDropdown.presentationLabel": "Carregar/Gerir apresentações",
"app.actionsBar.actionsDropdown.initPollLabel": "Iniciar uma sondagem",
"app.actionsBar.actionsDropdown.desktopShareLabel": "Partilhar o seu ecrã",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "Partilha de ecrã bloqueada",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "Parar partilha de ecrã",
"app.actionsBar.actionsDropdown.presentationDesc": "Carregar a sua apresentação",
"app.actionsBar.actionsDropdown.initPollDesc": "Iniciar uma sondagem",
@ -421,6 +588,7 @@
"app.actionsBar.actionsDropdown.takePresenterDesc": "Atribuir a si o papel de apresentador",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "Selecionar um utilizador aleatoriamente",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "Escolhe aleatoriamente um utilizador da lista",
"app.actionsBar.actionsDropdown.propagateLayoutLabel": "Propagar layout",
"app.actionsBar.emojiMenu.statusTriggerLabel": "Definir estado",
"app.actionsBar.emojiMenu.awayLabel": "Ausente",
"app.actionsBar.emojiMenu.awayDesc": "Mudar o seu estado para ausente",
@ -460,6 +628,7 @@
"app.audioNotification.audioFailedError1012": "Ligação terminada (erro ICE 1012)",
"app.audioNotification.audioFailedMessage": "A ligação de áudio falhou",
"app.audioNotification.mediaFailedMessage": "getUserMicMedia falhou pois só são permitidas origens seguras",
"app.audioNotification.deviceChangeFailed": "Audio device change failed. Check if the chosen device is properly set up and available",
"app.audioNotification.closeLabel": "Fechar",
"app.audioNotificaion.reconnectingAsListenOnly": "O microfone foi bloqueado para os participantes, vai entrar no modo ouvir apenas",
"app.breakoutJoinConfirmation.title": "Entrar na sessão de grupo",
@ -470,8 +639,12 @@
"app.breakoutJoinConfirmation.freeJoinMessage": "Selecione uma sessão de grupo para entrar",
"app.breakoutTimeRemainingMessage": "Tempo restante da sessão de grupo: {0}",
"app.breakoutWillCloseMessage": "O tempo terminou. A sessão de grupo vai fechar dentro de momentos",
"app.breakout.dropdown.manageDuration": "Change duration",
"app.breakout.dropdown.destroyAll": "End breakout rooms",
"app.breakout.dropdown.options": "Breakout Options",
"app.breakout.dropdown.manageUsers": "Manage users",
"app.calculatingBreakoutTimeRemaining": "A calcular o tempo remanescente ...",
"app.audioModal.ariaTitle": "Modal de ativar áudio",
"app.audioModal.ariaTitle": "Ativar áudio",
"app.audioModal.microphoneLabel": "Microfone",
"app.audioModal.listenOnlyLabel": "Ouvir apenas",
"app.audioModal.microphoneDesc": "Entrar na áudio-conferência com microfone",
@ -489,23 +662,23 @@
"app.audioModal.no.arialabel" : "Eco não é audível",
"app.audioModal.echoTestTitle": "Este é um teste de eco privado. Diga algumas palavras. Ouviu o áudio?",
"app.audioModal.settingsTitle": "Alterar as configurações de áudio",
"app.audioModal.helpTitle": "Houve um problema com seus dispositivos de media",
"app.audioModal.helpTitle": "Houve um problema com seus dispositivos de multimédia",
"app.audioModal.helpText": "Autorizou o acesso ao microfone? Note que uma caixa de dialogo deve aparecer quando tenta ativar o áudio, pedindo permissão para aceder aos seus dispositivos de media. Por favor aceite para poder entrar na conferência de áudio. Se não consegue, tente mudar as suas permissões de microfone nas configurações do seu navegador.",
"app.audioModal.help.noSSL": "Esta página não está certificada com SSL. Para obter acesso ao microfone a página deve ser servida por SSL. Por favor, contacte o administrador do sistema.",
"app.audioModal.help.macNotAllowed": "Parece que as Preferências de Sistema do seu Mac estão a bloquear o acesso ao seu microfone. Abra as Preferências de Sistema > Segurança e Privacidade > Privacidade > Microfone e verifique que o browser que está a usar está activo.",
"app.audioModal.help.macNotAllowed": "Parece que as Preferências de Sistema do seu Mac estão a bloquear o acesso ao seu microfone. Abra as Preferências de Sistema > Segurança e Privacidade > Privacidade > Microfone e verifique que o browser que está a usar está ativo.",
"app.audioModal.audioDialTitle": "Entrar usando o telefone",
"app.audioDial.audioDialDescription": "Ligue para o",
"app.audioDial.audioDialConfrenceText": "e introduza o número PIN da conferência:",
"app.audioModal.autoplayBlockedDesc": "Necessitamos da sua permissão para reproduzir audio",
"app.audioModal.playAudio": "Reproduzir audio",
"app.audioModal.playAudio.arialabel" : "Reproduzir audio",
"app.audioModal.autoplayBlockedDesc": "Precisamos da sua permissão para reproduzir áudio",
"app.audioModal.playAudio": "Reproduzir áudio",
"app.audioModal.playAudio.arialabel" : "Reproduzir áudio",
"app.audioDial.tipIndicator": "Dica",
"app.audioDial.tipMessage": "Prima a tecla '0' no seu telefone para alternar entre o modo silencio",
"app.audioModal.connecting": "A estabelecer ligação áudio",
"app.audioManager.joinedAudio": "Entrou na conferência de áudio",
"app.audioManager.joinedEcho": "Iniciou o teste de áudio",
"app.audioManager.leftAudio": "Saiu da conferência de áudio",
"app.audioManager.reconnectingAudio": "A tentar restablecer ligação audio",
"app.audioManager.reconnectingAudio": "A tentar restablecer ligação áudio",
"app.audioManager.genericError": "Erro: Ocorreu um erro, tente novamente",
"app.audioManager.connectionError": "Erro: Erro de ligação",
"app.audioManager.requestTimeout": "Erro: Tempo limite do pedido foi ultrapassado",
@ -516,6 +689,7 @@
"app.audio.changeAudioDevice": "Alterar dispositivo de áudio",
"app.audio.enterSessionLabel": "Entrar na sessão",
"app.audio.playSoundLabel": "Reproduzir som",
"app.audio.stopAudioFeedback": "Stop audio feedback",
"app.audio.backLabel": "Voltar",
"app.audio.loading": "A carregar",
"app.audio.microphones": "Microfones",
@ -525,33 +699,57 @@
"app.audio.audioSettings.descriptionLabel": "Por favor, note que aparecerá uma caixa de diálogo no seu navegador, a solicitar autorização para partilhar o seu microfone.",
"app.audio.audioSettings.microphoneSourceLabel": "Selecionar microfone",
"app.audio.audioSettings.speakerSourceLabel": "Selecionar altifalante",
"app.audio.audioSettings.testSpeakerLabel": "Test your speaker",
"app.audio.audioSettings.microphoneStreamLabel": "Volume da transmissão de áudio",
"app.audio.audioSettings.retryLabel": "Tentar novamente",
"app.audio.audioSettings.fallbackInputLabel": "Audio input {0}",
"app.audio.audioSettings.fallbackOutputLabel": "Audio output {0}",
"app.audio.audioSettings.defaultOutputDeviceLabel": "Default",
"app.audio.audioSettings.findingDevicesLabel": "Finding devices...",
"app.audio.listenOnly.backLabel": "Voltar",
"app.audio.listenOnly.closeLabel": "Fechar",
"app.audio.permissionsOverlay.title": "Permitir que o BigBlueButton aceda ao seu microfone",
"app.audio.permissionsOverlay.title": "Permitir que o sistema aceda ao seu microfone",
"app.audio.permissionsOverlay.hint": "É necessário que permita o acesso aos seus dispositivos de media para permitir a entrada na sessão de áudio :)",
"app.audio.captions.button.start": "Start closed captions",
"app.audio.captions.button.stop": "Stop closed captions",
"app.audio.captions.button.language": "Language",
"app.audio.captions.button.transcription": "Transcription",
"app.audio.captions.button.transcriptionSettings": "Transcription settings",
"app.audio.captions.speech.title": "Automatic transcription",
"app.audio.captions.speech.disabled": "Disabled",
"app.audio.captions.speech.unsupported": "Your browser doesn't support speech recognition. Your audio won't be transcribed",
"app.audio.captions.select.de-DE": "German",
"app.audio.captions.select.en-US": "English",
"app.audio.captions.select.es-ES": "Spanish",
"app.audio.captions.select.fr-FR": "French",
"app.audio.captions.select.hi-ID": "Hindi",
"app.audio.captions.select.it-IT": "Italian",
"app.audio.captions.select.ja-JP": "Japanese",
"app.audio.captions.select.pt-BR": "Portuguese",
"app.audio.captions.select.ru-RU": "Russian",
"app.audio.captions.select.zh-CN": "Chinese",
"app.error.removed": "Foi removido da sessão",
"app.error.meeting.ended": "Saiu da sessão",
"app.meeting.logout.duplicateUserEjectReason": "Utilizador duplicado a tentar entrar na sessão",
"app.meeting.logout.permissionEjectReason": "Ejetado por violação de permissão",
"app.meeting.logout.permissionEjectReason": "Expulso por violação de permissão",
"app.meeting.logout.ejectedFromMeeting": "Foi removido da sessão",
"app.meeting.logout.validateTokenFailedEjectReason": "A validação do token de autorização falhou",
"app.meeting.logout.userInactivityEjectReason": "Utilizador inativo por demasiado tempo",
"app.meeting.logout.userInactivityEjectReason": "Utilizador inativo há demasiado tempo",
"app.meeting.logout.maxParticipantsReached": "Foi atingido o número mázximo de participantes permitido para esta reunião",
"app.meeting-ended.rating.legendLabel": "Avaliação",
"app.meeting-ended.rating.starLabel": "Estrelas",
"app.modal.close": "Fechar",
"app.modal.close.description": "Ignora alterações e fecha a janela modal",
"app.modal.confirm": "Terminado",
"app.modal.close.description": "Ignora alterações e fecha a janela",
"app.modal.confirm": "Feito",
"app.modal.newTab": "(abre novo separador)",
"app.modal.confirm.description": "Guarda as alterações e fecha a janela modal",
"app.modal.randomUser.noViewers.description": "Não existem utilizadores por onde escolher",
"app.modal.confirm.description": "Guarda as alterações e fecha a janela",
"app.modal.randomUser.noViewers.description": "Não existem utilizadores para escolher aleatoriamente",
"app.modal.randomUser.selected.description": "Foi escolhido aleatoriamente",
"app.modal.randomUser.title": "Utilizador escolhido aleatoriamente",
"app.modal.randomUser.who": "Quem será escolhido?",
"app.modal.randomUser.alone": "Existe apenas um participante",
"app.modal.randomUser.reselect.label": "Escolher novamente",
"app.modal.randomUser.ariaLabel.title": "Janela de escolha aleatória de Utilizador",
"app.modal.randomUser.ariaLabel.title": "Janela de escolha aleatória de utilizador",
"app.dropdown.close": "Fechar",
"app.dropdown.list.item.activeLabel": "Activo",
"app.error.400": "400 Pedido incorreto",
@ -559,16 +757,19 @@
"app.error.403": "Foi removido da sessão",
"app.error.404": "Não encontrado",
"app.error.408": "Falha de autenticação",
"app.error.409": "Conflito",
"app.error.410": "A sessão terminou",
"app.error.500": "Ops, ocorreu um erro",
"app.error.503": "Você foi desligado",
"app.error.disconnected.rejoin": "Pode atualizar a página para entrar novamente.",
"app.error.userLoggedOut": "O participante tem um token de sessão inválido porque se desconectou",
"app.error.ejectedUser": "O participante tem um token de sessão inválido porque foi bloqueado",
"app.error.joinedAnotherWindow": "Esta sessão parece estar aberta em outra janela do seu navegador.",
"app.error.userBanned": "O participante foi bloqueado",
"app.error.leaveLabel": "Faça login novamente",
"app.error.fallback.presentation.title": "Ocorreu um erro",
"app.error.fallback.presentation.description": "Foi logado. Por favor tente recarregar a página",
"app.error.fallback.presentation.reloadButton": "Recarregar",
"app.guest.waiting": "À espera de aprovação para entrar",
"app.guest.errorSeeConsole": "Erro: mais detalhes na consola de erros.",
"app.guest.noModeratorResponse": "Sem resposta do moderador.",
"app.guest.noSessionToken": "Token de sessão não recebido.",
@ -581,6 +782,10 @@
"app.guest.guestDeny": "Convidado teve sua entrada negada.",
"app.guest.seatWait": "Convidado aguardando uma vaga na reunião.",
"app.guest.allow": "Convidado aprovado e sendo redirecionado para a sessão.",
"app.guest.firstPositionInWaitingQueue": "Você é o primeiro da fila!",
"app.guest.positionInWaitingQueue": "A sua posição atual na fila de espera:",
"app.guest.guestInvalid": "Utilizador convidado é inválido",
"app.guest.meetingForciblyEnded": "Não pode ingressar em uma reunião que já foi terminada",
"app.userList.guest.waitingUsers": "Utilizadores à espera",
"app.userList.guest.waitingUsersTitle": "Gestão de utilizadores",
"app.userList.guest.optionTitle": "Rever utilizadores pendentes",
@ -589,23 +794,33 @@
"app.userList.guest.allowEveryone": "Autorizar todos",
"app.userList.guest.denyEveryone": "Recusar todos",
"app.userList.guest.pendingUsers": "{0} Utilizadores pendentes",
"app.userList.guest.pendingGuestUsers": "{0} Utilizadores Convidados pendentes",
"app.userList.guest.noPendingUsers": "Atualmente não há utilizadores pendentes...",
"app.userList.guest.pendingGuestUsers": "{0} Utilizadores convidados pendentes",
"app.userList.guest.pendingGuestAlert": "Entrou na sessão e está à espera da sua aprovação",
"app.userList.guest.rememberChoice": "Lembrar escolha",
"app.userList.guest.emptyMessage": "Actualmente sem mensagem",
"app.userList.guest.inputPlaceholder": "Mensagem para a sala de espera",
"app.userList.guest.privateInputPlaceholder": "Mensagem para {0}",
"app.userList.guest.privateMessageLabel": "Mensagem",
"app.userList.guest.acceptLabel": "Aceitar",
"app.userList.guest.denyLabel": "Negar",
"app.userList.guest.feedbackMessage": "Ação executada",
"app.user-info.title": "Pesquisa de diretório",
"app.toast.breakoutRoomEnded": "A sessão de grupo terminou. Por favor ative o áudio.",
"app.toast.chat.public": "Nova mensagem de Chat público",
"app.toast.chat.private": "Nova mensagem de Chat privado",
"app.toast.chat.system": "Sistema",
"app.toast.chat.poll": "Resultados da sondagem",
"app.toast.chat.pollClick": "Os resultados da sondagem foram publicados. Clique aqui para ver.",
"app.toast.clearedEmoji.label": "Estado emoji limpo",
"app.toast.setEmoji.label": "Estado emoji definido para {0}",
"app.toast.meetingMuteOn.label": "Todos os utilizadores foram silenciados",
"app.toast.meetingMuteOnViewers.label": "Todos os participantes foram silenciados",
"app.toast.meetingMuteOff.label": "Esta sessão não se encontra agora silenciada",
"app.toast.setEmoji.raiseHand": "Levantou a sua mão",
"app.toast.setEmoji.lowerHand": "A sua mão foi baixada",
"app.toast.promotedLabel": "Foi promovido a moderador",
"app.toast.demotedLabel": "Foi despromovido a participante",
"app.notification.recordingStart": "Esta reunião está a ser gravada",
"app.notification.recordingStop": "Esta sessão não está a ser gravada",
"app.notification.recordingPaused": "Esta sessão já não está a ser gravada",
@ -616,6 +831,7 @@
"app.shortcut-help.title": "Atalhos do teclado",
"app.shortcut-help.accessKeyNotAvailable": "Teclas de acesso não disponíveis",
"app.shortcut-help.comboLabel": "Combo",
"app.shortcut-help.alternativeLabel": "Alt",
"app.shortcut-help.functionLabel": "Função",
"app.shortcut-help.closeLabel": "Fechar",
"app.shortcut-help.closeDesc": "Fecha a modal de atalhos do teclado",
@ -633,6 +849,42 @@
"app.shortcut-help.toggleFullscreen": "Alternar tela cheia (Apresentador)",
"app.shortcut-help.nextSlideDesc": "Slide seguinte (apresentador)",
"app.shortcut-help.previousSlideDesc": "Slide anterior (apresentador)",
"app.shortcut-help.togglePanKey": "Barra de espaços",
"app.shortcut-help.toggleFullscreenKey": "Enter",
"app.shortcut-help.nextSlideKey": "Seta para a direita",
"app.shortcut-help.previousSlideKey": "Seta para a esquerda",
"app.shortcut-help.select": "Selecionar ferramenta",
"app.shortcut-help.pencil": "Lápis",
"app.shortcut-help.eraser": "Apagador",
"app.shortcut-help.rectangle": "Retângulo",
"app.shortcut-help.elipse": "Circunferência",
"app.shortcut-help.triangle": "Triângulo",
"app.shortcut-help.line": "Linha",
"app.shortcut-help.arrow": "Seta",
"app.shortcut-help.text": "Ferramenta de texto",
"app.shortcut-help.note": "Nota adesiva",
"app.shortcut-help.general": "Geral",
"app.shortcut-help.presentation": "Apresentação",
"app.shortcut-help.whiteboard": "Quadro",
"app.shortcut-help.zoomIn": "Ampliar visualização",
"app.shortcut-help.zoomOut": "Diminuir ampliação",
"app.shortcut-help.zoomFit": "Tamanho normal",
"app.shortcut-help.zoomSelect": "Ver a seleção",
"app.shortcut-help.flipH": "Virar horizontalmente",
"app.shortcut-help.flipV": "Virar verticalmente",
"app.shortcut-help.lock": "Bloquear / Desbloquear",
"app.shortcut-help.moveToFront": "Mover para a frente",
"app.shortcut-help.moveToBack": "Mover para trás",
"app.shortcut-help.moveForward": "Mover para cima",
"app.shortcut-help.moveBackward": "Mover para baixo",
"app.shortcut-help.undo": "Desfazer",
"app.shortcut-help.redo": "Voltar a fazer",
"app.shortcut-help.cut": "Cortar",
"app.shortcut-help.copy": "Copiar",
"app.shortcut-help.paste": "Colar",
"app.shortcut-help.selectAll": "Selecionar tudo",
"app.shortcut-help.delete": "Apagar",
"app.shortcut-help.duplicate": "Duplicar",
"app.lock-viewers.title": "Bloquear participantes",
"app.lock-viewers.description": "Esta opção permite-lhe restringir determinados utilizadores de aceder a funcionalidades específicas.",
"app.lock-viewers.featuresLable": "Funcionalidade",
@ -648,6 +900,7 @@
"app.lock-viewers.button.apply": "Aplicar",
"app.lock-viewers.button.cancel": "Cancelar",
"app.lock-viewers.locked": "Bloqueado",
"app.lock-viewers.hideViewersCursor": "Ver os cursores dos outros participantes",
"app.guest-policy.ariaTitle": "Janela de configurações da política de convidado",
"app.guest-policy.title": "Política de convidado",
"app.guest-policy.description": "Alterar configuração da política de convidados da sessão",
@ -660,23 +913,41 @@
"app.connection-status.description": "Ver o estado da ligação do utilizador",
"app.connection-status.empty": "Atualmente não foram comunicados problemas de ligação",
"app.connection-status.more": "mais",
"app.connection-status.copy": "Copiar estatísticas",
"app.connection-status.copied": "Copiado!",
"app.connection-status.jitter": "Jitter",
"app.connection-status.label": "Estado de ligação",
"app.connection-status.settings": "Ajustar as suas preferências",
"app.connection-status.no": "Não",
"app.connection-status.notification": "Foi detectada uma falha na ligação",
"app.connection-status.offline": "desconectado",
"app.connection-status.clientNotRespondingWarning": "Navegador não está a responder",
"app.connection-status.audioUploadRate": "Taxa de envio de áudio",
"app.connection-status.audioDownloadRate": "Taxa de recepção de áudio",
"app.connection-status.videoUploadRate": "Taxa de envio de vídeo",
"app.connection-status.videoDownloadRate": "Taxa de recepção de vídeo",
"app.connection-status.lostPackets": "Pacotes perdidos",
"app.connection-status.usingTurn": "Usando TURN",
"app.connection-status.yes": "Sim",
"app.connection-status.connectionStats": "Estatísticas da ligação",
"app.connection-status.myLogs": "Meus registos",
"app.connection-status.sessionLogs": "Registos da sessão",
"app.connection-status.next": "Próxima página",
"app.connection-status.prev": "Página anterior",
"app.learning-dashboard.label": "Estatísticas do Painel de Aprendizagem",
"app.learning-dashboard.description": "Abrir painel com a atividade dos utilizadores",
"app.learning-dashboard.description": "Painel com as actividades dos utilizadores",
"app.learning-dashboard.clickHereToOpen": "Abrir as Estatísticas do Painel de Aprendizagem",
"app.recording.startTitle": "Iniciar gravação",
"app.recording.stopTitle": "Pausar gravação",
"app.recording.resumeTitle": "Retomar gravação",
"app.recording.startDescription": "Pode clicar no botão gravar novamente para pausar a gravação.",
"app.recording.stopDescription": "Pretende pausar a gravação? Poderá recomeçar novamente mais tarde clicando no botão de gravação.",
"app.recording.notify.title": "A gravação começou",
"app.recording.notify.description": "Ficará disponível a gravação a partir deste momento",
"app.recording.notify.continue": "Continuar",
"app.recording.notify.leave": "Sair da sessão",
"app.recording.notify.continueLabel" : "Aceitar a gravação e continuar",
"app.recording.notify.leaveLabel" : "Não aceitar a gravação e sair da sessão",
"app.videoPreview.cameraLabel": "Webcam",
"app.videoPreview.profileLabel": "Qualidade",
"app.videoPreview.quality.low": "Baixa",
@ -693,13 +964,20 @@
"app.videoPreview.webcamOptionLabel": "Escolher webcam",
"app.videoPreview.webcamPreviewLabel": "Pré-visualização da webcam",
"app.videoPreview.webcamSettingsTitle": "Configurações da webcam",
"app.videoPreview.webcamEffectsTitle": "Efeitos visuais da webcam",
"app.videoPreview.webcamVirtualBackgroundLabel": "Configurações do fundo virtual",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Este dispositivo não suporta fundos virtuais",
"app.videoPreview.webcamNotFoundLabel": "Webcam não encontrada",
"app.videoPreview.profileNotFoundLabel": "Não existe perfil de webcam suportado",
"app.videoPreview.brightness": "Brilho",
"app.videoPreview.wholeImageBrightnessLabel": "Imagem inteira",
"app.videoPreview.wholeImageBrightnessDesc": "Aplica brilho à imagem da webcam e ao de fundo",
"app.videoPreview.sliderDesc": "Aumentar ou diminuir os níveis de brilho",
"app.video.joinVideo": "Partilhar webcam",
"app.video.connecting": "A iniciar a partilha da webcam...",
"app.video.leaveVideo": "Parar partilha de webcam",
"app.video.videoSettings": "Definições de vídeo",
"app.video.visualEffects": "Efeitos visuais",
"app.video.advancedVideo": "Abrir opções avançadas",
"app.video.iceCandidateError": "Error ao adicionar candidato ICE",
"app.video.iceConnectionStateError": "Falha na ligação (erro ICE 1107)",
@ -715,6 +993,7 @@
"app.video.notReadableError": "Não foi possível aceder à webcam. Por favor, certifique-se que a webcam não está a ser usada por nenhum outro programa",
"app.video.timeoutError": "O navegador não respondeu a tempo.",
"app.video.genericError": "Ocorreu um erro desconhecido com o dispositivo (Erro {0})",
"app.video.inactiveError": "A sua webcam parou inesperadamente. Reveja as permissões do seu navegador",
"app.video.mediaTimedOutError": "A transmissão da sua webcam foi interrompida. Tente partilhá-la novamente",
"app.video.mediaFlowTimeout1020": "O ficheiro de media não chegou ao servidor (erro 1020)",
"app.video.suggestWebcamLock": "Forçar a definição de bloqueio das webcams dos utilizadores?",
@ -737,8 +1016,19 @@
"app.video.virtualBackground.board": "Quadro",
"app.video.virtualBackground.coffeeshop": "Café",
"app.video.virtualBackground.background": "Fundo",
"app.video.virtualBackground.backgroundWithIndex": "Fundo {0}",
"app.video.virtualBackground.custom": "Carregar do seu computador",
"app.video.virtualBackground.remove": "Remover imagem adicionada",
"app.video.virtualBackground.genericError": "Falha ao aplicar efeito de webcam. Tente novamente.",
"app.video.virtualBackground.camBgAriaDesc": "Define fundo virtual de webcam para {0}",
"app.video.virtualBackground.maximumFileSizeExceeded": "Tamanho do ficheiro excedido. ({0}MB)",
"app.video.virtualBackground.typeNotAllowed": "Tipo de ficheiro não permitido",
"app.video.virtualBackground.errorOnRead": "Alguma coisa correu mal ao abrir o ficheiro",
"app.video.virtualBackground.uploaded": "Carregado",
"app.video.virtualBackground.uploading": "A carregar...",
"app.video.virtualBackground.button.customDesc": "Adiciona uma nova imagem de fundo virtual",
"app.video.camCapReached": "Não pode partilhar mais câmaras",
"app.video.meetingCamCapReached": "A reunião atingiu o limite de câmaras simultâneas",
"app.video.dropZoneLabel": "Largar aqui",
"app.fullscreenButton.label": "Passar {0} a ecrã inteiro",
"app.fullscreenUndoButton.label": "Reverter {0} de ecrã inteiro",
@ -757,6 +1047,8 @@
"app.whiteboard.annotations.poll": "Os resultados da sondagem foram publicados",
"app.whiteboard.annotations.pollResult": "Resultados da sondagem",
"app.whiteboard.annotations.noResponses": "Sem respostas",
"app.whiteboard.annotations.notAllowed": "Não está autorizado a fazer esta alteração",
"app.whiteboard.annotations.numberExceeded": "O número de anotações excedeu o limite ({0})",
"app.whiteboard.toolbar.tools": "Ferramentas",
"app.whiteboard.toolbar.tools.hand": "Pan",
"app.whiteboard.toolbar.tools.pencil": "Lápis",
@ -783,6 +1075,7 @@
"app.whiteboard.toolbar.color.silver": "Prata",
"app.whiteboard.toolbar.undo": "Anular Anotação",
"app.whiteboard.toolbar.clear": "Limpar todas as anotações",
"app.whiteboard.toolbar.clearConfirmation": "Tem a certeza de que deseja apagar todas as anotações?",
"app.whiteboard.toolbar.multiUserOn": "Iniciar o modo multiutilizador",
"app.whiteboard.toolbar.multiUserOff": "Terminar modo multiutilizador",
"app.whiteboard.toolbar.palmRejectionOn": "Ligar a rejeição da palma da mão",
@ -802,13 +1095,13 @@
"app.videoDock.webcamUnfocusDesc": "Desfocar a webcam selecionada",
"app.videoDock.webcamPinLabel": "Fixar",
"app.videoDock.webcamPinDesc": "Fixar a webcam selecionada",
"app.videoDock.webcamFullscreenLabel": "Webcam em ecrã inteiro",
"app.videoDock.webcamSqueezedButtonLabel": "Opçções da webcam",
"app.videoDock.webcamUnpinLabel": "Soltar",
"app.videoDock.webcamUnpinLabelDisabled": "Apenas moderadores podem soltar utilizadores",
"app.videoDock.webcamUnpinDesc": "Soltar a webcam escolhida",
"app.videoDock.autoplayBlockedDesc": "Necessitamos da sua permissão para exibir a webcam de outros utilizadores",
"app.videoDock.autoplayAllowLabel": "Ver webcams",
"app.invitation.title": "Convite para sala de grupo",
"app.invitation.confirm": "Convidar",
"app.createBreakoutRoom.title": "Salas de Grupo",
"app.createBreakoutRoom.ariaTitle": "Esconder Salas de Grupo",
"app.createBreakoutRoom.breakoutRoomLabel": "Salas de Grupo {0}",
@ -828,7 +1121,11 @@
"app.createBreakoutRoom.durationInMinutes": "Duração (minutos)",
"app.createBreakoutRoom.randomlyAssign": "Atribuir aleatóriamente",
"app.createBreakoutRoom.randomlyAssignDesc": "Atribui os utilizadores aleatoriamente a salas de grupo",
"app.createBreakoutRoom.resetAssignments": "Redefinir atribuições",
"app.createBreakoutRoom.resetAssignmentsDesc": "Redefinir todas as atribuições de sala do utilizador",
"app.createBreakoutRoom.endAllBreakouts": "Terminar todas as salas de grupo",
"app.createBreakoutRoom.chatTitleMsgAllRooms": "todas as salas",
"app.createBreakoutRoom.msgToBreakoutsSent": "A mensagem foi enviada para {0} salas temáticas",
"app.createBreakoutRoom.roomName": "{0} (Sala - {1})",
"app.createBreakoutRoom.doneLabel": "Terminado",
"app.createBreakoutRoom.nextLabel": "Próximo",
@ -836,6 +1133,8 @@
"app.createBreakoutRoom.addRoomTime": "Aumentar o tempo da sala de grupo para",
"app.createBreakoutRoom.addParticipantLabel": "+ Adicionar participante",
"app.createBreakoutRoom.freeJoin": "Permitir que os utilizadores escolham uma sala de grupo para entrar",
"app.createBreakoutRoom.captureNotes": "Guarde notas partilhadas quando as salas temáticas terminarem",
"app.createBreakoutRoom.captureSlides": "Captureos quadros quando as salas temáticas terminarem",
"app.createBreakoutRoom.leastOneWarnBreakout": "É necessário atribuir pelo menos um utilizador a uma sala de grupo",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "A duração mínima de uma sala de apoio é de {0} minutos.",
"app.createBreakoutRoom.modalDesc": "Dica: Pode arrastar um utilizador para uma sala de grupo.",
@ -843,7 +1142,19 @@
"app.createBreakoutRoom.numberOfRoomsError": "O número de salas é inválido",
"app.createBreakoutRoom.duplicatedRoomNameError": "O nome da sala não pode ser duplicado.",
"app.createBreakoutRoom.emptyRoomNameError": "O nome da sala não pode estar vazio.",
"app.createBreakoutRoom.setTimeInMinutes": "Definir duração para (minutos)",
"app.createBreakoutRoom.setTimeLabel": "Aplicar",
"app.createBreakoutRoom.setTimeCancel": "Cancelar",
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "A duração das salas temáticas não pode exceder o tempo restante da reunião.",
"app.createBreakoutRoom.roomNameInputDesc": "Atualiza o nome da sala de apoio",
"app.createBreakoutRoom.movedUserLabel": "Movido {0} para a sala {1}",
"app.updateBreakoutRoom.modalDesc": "Para atualizar ou convidar um utilizador, basta arrastá-lo para a sala desejada.",
"app.updateBreakoutRoom.cancelLabel": "Cancelar",
"app.updateBreakoutRoom.title": "Actualizar salas temáticas",
"app.updateBreakoutRoom.confirm": "Aplicar",
"app.updateBreakoutRoom.userChangeRoomNotification": "Você foi transferido para a sala {0}.",
"app.smartMediaShare.externalVideo": "Vídeo(s) externo(s)",
"app.update.resetRoom": "Redefinir sala do utilizador",
"app.externalVideo.start": "Partilhar novo vídeo",
"app.externalVideo.title": "Partilhar um vídeo externo",
"app.externalVideo.input": "URL do vídeo externo",
@ -854,6 +1165,8 @@
"app.externalVideo.refreshLabel": "Atualizar reprodutor de vídeo",
"app.externalVideo.fullscreenLabel": "Reprodutor de vídeo",
"app.externalVideo.noteLabel": "Nota: A partilha de vídeo externos não vai aparecer em gravações de sessão. URLs do YouTube, Vimeo, Instructure Media, Twitch, Dailymotion e outros tipos de URL de ficheiros multimedia (ex. https://example.com/xy.mp4) são suportados.",
"app.externalVideo.subtitlesOn": "Desligar",
"app.externalVideo.subtitlesOff": "Ligar (se disponível)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Partilhar um vídeo externo",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Parar a partilha de vídeo externo",
"app.iOSWarning.label": "Por favor atualize para iOS 12.2 ou posterior",
@ -861,12 +1174,21 @@
"app.legacy.upgradeBrowser": "Aparentemente está a usar uma versão antiga dum navegador suportado. Por favor atualize o seu navegador.",
"app.legacy.criosBrowser": "No iOS por favor use o Safari para obter suporte completo a esta aplicação",
"app.debugWindow.windowTitle": "Depurar",
"app.debugWindow.form.userAgentLabel": "User Agent",
"app.debugWindow.form.userAgentLabel": "Agente de utilizador",
"app.debugWindow.form.button.copy": "Copiar",
"app.debugWindow.form.enableAutoarrangeLayoutLabel": "Activar a disposição automática",
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(será desactivado se arrastar ou redimensionar a área das webcams)",
"app.debugWindow.form.chatLoggerLabel": "Testar níveis do registador de chat",
"app.debugWindow.form.button.apply": "Aplicar",
"app.layout.modal.title": "Layouts",
"app.layout.modal.confirm": "Confirmar",
"app.layout.modal.cancel": "Cancelar",
"app.layout.modal.layoutLabel": "Selecione o seu layout",
"app.layout.modal.keepPushingLayoutLabel": "Propagar layout para todos",
"app.layout.modal.pushLayoutLabel": "Propagar para todos",
"app.layout.modal.layoutToastLabel": "Definições do layout alteradas",
"app.layout.modal.layoutSingular": "Layout",
"app.layout.modal.layoutBtnDesc": "Define o layout como opção selecionada",
"app.layout.style.custom": "Personalizado",
"app.layout.style.smart": "Layout inteligente",
"app.layout.style.presentationFocus": "Foco na apresentação",
@ -883,9 +1205,21 @@
"playback.button.search.aria": "Procurar",
"playback.button.section.aria": "Secção lateral",
"playback.button.swap.aria": "Trocar conteúdo",
"playback.button.theme.aria": "Alterar tema",
"playback.error.wrapper.aria": "Área de erro",
"playback.loader.wrapper.aria": "Área de carregamento",
"playback.player.wrapper.aria": "Área do reprodutor",
"playback.player.about.modal.shortcuts.title": "Atalhos",
"playback.player.about.modal.shortcuts.alt": "Alt",
"playback.player.about.modal.shortcuts.shift": "Shift",
"playback.player.about.modal.shortcuts.fullscreen": "Alterar ecrã inteiro",
"playback.player.about.modal.shortcuts.play": "Play/Pausa",
"playback.player.about.modal.shortcuts.section": "Alterar secção lateral",
"playback.player.about.modal.shortcuts.seek.backward": "Procurar para trás",
"playback.player.about.modal.shortcuts.seek.forward": "Seek forwards",
"playback.player.about.modal.shortcuts.skip.next": "Próximo slide",
"playback.player.about.modal.shortcuts.skip.previous": "Slide anterior",
"playback.player.about.modal.shortcuts.swap": "Trocar conteúdo",
"playback.player.chat.message.poll.name": "Resultado da sondagem",
"playback.player.chat.message.poll.question": "Pergunta",
"playback.player.chat.message.poll.options": "Opções",
@ -894,6 +1228,7 @@
"playback.player.chat.message.poll.option.abstention": "Abstenção",
"playback.player.chat.message.poll.option.true": "Verdadeiro",
"playback.player.chat.message.poll.option.false": "Falso",
"playback.player.chat.message.video.name": "Vídeo externo",
"playback.player.chat.wrapper.aria": "Área do chat",
"playback.player.notes.wrapper.aria": "Área das anotações",
"playback.player.presentation.wrapper.aria": "Área da apresentação",
@ -901,15 +1236,39 @@
"playback.player.search.modal.title": "Procurar",
"playback.player.search.modal.subtitle": "Encontre o conteúdo dos slides da apresentação",
"playback.player.thumbnails.wrapper.aria": "Área das miniaturas",
"playback.player.webcams.wrapper.aria": "Área de webcams",
"app.learningDashboard.dashboardTitle": "Estatísticas do Painel de Aprendizagem",
"app.learningDashboard.bigbluebuttonTitle": "BigBlueButton",
"app.learningDashboard.downloadSessionDataLabel": "Download Session Data",
"app.learningDashboard.lastUpdatedLabel": "Última atualização em",
"app.learningDashboard.sessionDataDownloadedLabel": "Descarregado!",
"app.learningDashboard.shareButton": "Partilhar com outros",
"app.learningDashboard.shareLinkCopied": "Ligação copiada!",
"app.learningDashboard.user": "Utilizador",
"app.learningDashboard.indicators.meetingStatusEnded": "Terminou",
"app.learningDashboard.indicators.meetingStatusActive": "Activo",
"app.learningDashboard.indicators.usersOnline": "Utilizadores activos",
"app.learningDashboard.indicators.usersTotal": "Número total de utilizadores",
"app.learningDashboard.indicators.polls": "Sondagens",
"app.learningDashboard.indicators.timeline": "Linha do tempo",
"app.learningDashboard.indicators.activityScore": "Pontuação de atividade",
"app.learningDashboard.indicators.duration": "Duração",
"app.learningDashboard.userDetails.startTime": "Hora de início",
"app.learningDashboard.userDetails.endTime": "Hora de fim",
"app.learningDashboard.userDetails.joined": "Participaram",
"app.learningDashboard.userDetails.category": "Categoria",
"app.learningDashboard.userDetails.average": "Média",
"app.learningDashboard.userDetails.activityPoints": "Pontos de actividade",
"app.learningDashboard.userDetails.poll": "Sondagem",
"app.learningDashboard.userDetails.response": "Resposta",
"app.learningDashboard.userDetails.mostCommonAnswer": "Resposta mais frequente",
"app.learningDashboard.userDetails.anonymousAnswer": "Sondagem anónima",
"app.learningDashboard.userDetails.talkTime": "Tempo a falar",
"app.learningDashboard.userDetails.messages": "Mensagens",
"app.learningDashboard.userDetails.emojis": "Emojis",
"app.learningDashboard.userDetails.raiseHands": "Levantar mãos",
"app.learningDashboard.userDetails.pollVotes": "Votos",
"app.learningDashboard.userDetails.onlineIndicator": "{0} tempo online",
"app.learningDashboard.usersTable.title": "Visão geral",
"app.learningDashboard.usersTable.colOnline": "Tempo online",
"app.learningDashboard.usersTable.colTalk": "Tempo de fala",
@ -922,10 +1281,35 @@
"app.learningDashboard.usersTable.userStatusOnline": "Online",
"app.learningDashboard.usersTable.userStatusOffline": "Offline",
"app.learningDashboard.usersTable.noUsers": "Ainda sem utilizadores",
"app.learningDashboard.usersTable.name": "Nome",
"app.learningDashboard.usersTable.moderator": "Moderador",
"app.learningDashboard.usersTable.pollVotes": "Votos da sondagem",
"app.learningDashboard.usersTable.join": "Entrar",
"app.learningDashboard.usersTable.left": "Sair",
"app.learningDashboard.usersTable.notAvailable": "N/D",
"app.learningDashboard.pollsTable.title": "Sondagens",
"app.learningDashboard.pollsTable.anonymousAnswer": "Sondagem Anónima (respostas na última linha)",
"app.learningDashboard.pollsTable.anonymousRowName": "Anónimo",
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "Não foram criadas sondagens",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "Assim que uma sondagem for enviada aos utulizadores, os resultados aparecerão nesta lista.",
"app.learningDashboard.pollsTable.answerTotal": "Total",
"app.learningDashboard.pollsTable.userLabel": "Utilizador",
"app.learningDashboard.statusTimelineTable.title": "Linha do tempo",
"app.learningDashboard.statusTimelineTable.thumbnail": "Miniatura da apresentação",
"app.learningDashboard.statusTimelineTable.presentation": "Apresentação",
"app.learningDashboard.statusTimelineTable.pageNumber": "Página",
"app.learningDashboard.statusTimelineTable.setAt": "Definido em",
"app.learningDashboard.errors.invalidToken": "Token de sessão inválido",
"app.learningDashboard.errors.dataUnavailable": "Dados actualmente indisponíveis"
"app.learningDashboard.errors.dataUnavailable": "Dados actualmente indisponíveis",
"mobileApp.portals.list.empty.addFirstPortal.label": "Adicione o seu primeiro portal utilizando o botão abaixo",
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "ou use o nosso servidor de demonstração",
"mobileApp.portals.list.add.button.label": "Adicionar portal",
"mobileApp.portals.fields.name.label": "Nome do portal",
"mobileApp.portals.fields.name.placeholder": "Demonstração do BigBlueButton",
"mobileApp.portals.fields.url.label": "URL do servidor",
"mobileApp.portals.addPortalPopup.confirm.button.label": "Gravar",
"mobileApp.portals.drawerNavigation.button.label": "Portais",
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Campos obrigatórios",
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Nome já está em utilização",
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Erro ao tentar carregar a página - verifique o URL e a ligação de rede"
}

View File

@ -450,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Uygulama",
"app.submenu.application.animationsLabel": "Canlandırmalar",
"app.submenu.application.audioFilterLabel": "Mikrofon için ses süzgeçleri",
"app.submenu.application.wbToolbarsAutoHideLabel": "Beyaz tahta araç çubukları otomatik gizlensin",
"app.submenu.application.darkThemeLabel": "Koyu kip",
"app.submenu.application.fontSizeControlLabel": "Yazı boyutu",
"app.submenu.application.increaseFontBtnLabel": "Uygulamanın yazı boyutunu büyüt",

View File

@ -235,6 +235,8 @@
"app.presentation.presentationToolbar.fitToWidth": "Умістити за шириною",
"app.presentation.presentationToolbar.fitToPage": "Умістити на сторінку",
"app.presentation.presentationToolbar.goToSlide": "Слайд {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Приховати панель інструментів",
"app.presentation.presentationToolbar.showToolsDesc": "Показати панель інструментів",
"app.presentation.placeholder": "Немає активної презентації",
"app.presentationUploder.title": "Презентація",
"app.presentationUploder.message": "У ролі доповідача у вас є можливість завантажити будь який офісний документ або PDF файл. Ми рекомендуємо PDF файли для кращої сумісності. Переконайтесь, що презентація помічена як обрана для показу на дошці ліворуч від імені файлу.",

View File

@ -444,6 +444,14 @@ exports.zoomOutButton = 'button[data-test="zoomOutBtn"]';
exports.wbPan = 'button[data-test="panButton"]';
exports.wbEraser = 'button[id="TD-PrimaryTools-Eraser"]';
exports.wbArrowShape = 'button[id="TD-PrimaryTools-ArrowTopRight"]';
exports.wbDelete = 'span[id="TD-Delete"]';
exports.wbUndo = 'button[id="TD-TopPanel-Undo"]';
exports.wbRedo = 'button[id="TD-TopPanel-Redo"]';
exports.wbStyles = 'button[id="TD-Styles"]';
exports.wbColorRed = 'button[id="TD-Styles-Color-Swatch-red"]';
exports.wbFillDrawing = 'button[id="TD-Styles-Fill"]';
exports.wbDashDotted = 'div[id="TD-Styles-Dash-dotted"]';
exports.wbSizeLarge = 'div[id="TD-Styles-Dash-large"]';
// About modal
exports.showAboutModalButton = 'li[data-test="aboutModal"]';

View File

@ -54,6 +54,8 @@ exports.downloadPresentationWithAnnotations = 'disabledFeatures=downloadPresenta
exports.importPresentationWithAnnotationsFromBreakoutRooms = 'disabledFeatures=importPresentationWithAnnotationsFromBreakoutRooms';
exports.importSharedNotesFromBreakoutRooms = 'disabledFeatures=importSharedNotesFromBreakoutRooms';
exports.layouts = 'disabledFeatures=layouts';
exports.presentation = 'disabledFeatures=presentation';
exports.customVirtualBackground = 'disabledFeatures=customVirtualBackgrounds';
// Shortcuts
exports.shortcuts = 'userdata-bbb_shortcuts=[$]';

View File

@ -305,6 +305,18 @@ class CustomParameters extends MultiUsers {
await this.modPage.waitAndClick(e.createBreakoutRooms);
await this.modPage.wasRemoved(e.captureBreakoutSharedNotes);
}
async presentation() {
await this.modPage.wasRemoved(e.whiteboard);
await this.modPage.wasRemoved(e.minimizePresentation);
await this.modPage.wasRemoved(e.restorePresentation);
}
async customVirtualBackground() {
await this.modPage.waitAndClick (e.joinVideo);
await this.modPage.waitForSelector(e.webcamSettingsModal);
await this.modPage.wasRemoved(e.inputBackgroundButton);
}
}
exports.CustomParameters = CustomParameters;

View File

@ -293,5 +293,17 @@ test.describe.parallel('CustomParameters', () => {
await customParam.initModPage(page, true, { customParameter: c.importSharedNotesFromBreakoutRooms });
await customParam.importSharedNotesFromBreakoutRooms();
});
test('Presentation', async ({ browser, context, page }) => {
const customParam = new CustomParameters(browser, context);
await customParam.initModPage(page, true, { customParameter: c.presentation });
await customParam.presentation();
});
test('Custom Virtual Background', async ({ browser, context, page }) => {
const customParam = new CustomParameters(browser, context);
await customParam.initModPage(page, true, { customParameter: c.customVirtualBackground });
await customParam.customVirtualBackground();
});
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

@ -6,7 +6,7 @@ const { checkSvgIndex, getSlideOuterHtml, uploadSinglePresentation, uploadMultip
const { ELEMENT_WAIT_LONGER_TIME, ELEMENT_WAIT_EXTRA_LONG_TIME, UPLOAD_PDF_WAIT_TIME } = require('../core/constants');
const { sleep } = require('../core/helpers');
const { getSettings } = require('../core/settings');
const { waitAndClearDefaultPresentationNotification } = require('../notifications/util');
const { waitAndClearDefaultPresentationNotification, waitAndClearNotification } = require('../notifications/util');
class Presentation extends MultiUsers {
constructor(browser, context) {
@ -133,9 +133,9 @@ class Presentation extends MultiUsers {
await this.modPage.waitAndClick(e.confirmManagePresentation);
await this.modPage.wasRemoved(e.whiteboard);
await this.modPage.hasElementDisabled(e.minimizePresentation);
await this.modPage.wasRemoved(e.minimizePresentation);
await this.userPage.wasRemoved(e.whiteboard);
await this.userPage.hasElementDisabled(e.minimizePresentation);
await this.userPage.wasRemoved(e.minimizePresentation);
}
async uploadAndRemoveAllPresentations() {
@ -155,9 +155,9 @@ class Presentation extends MultiUsers {
await this.modPage.waitAndClick(e.confirmManagePresentation);
await this.modPage.wasRemoved(e.whiteboard);
await this.modPage.hasElementDisabled(e.minimizePresentation);
await this.modPage.wasRemoved(e.minimizePresentation);
await this.userPage.wasRemoved(e.whiteboard);
await this.userPage.hasElementDisabled(e.minimizePresentation);
await this.userPage.wasRemoved(e.minimizePresentation);
// Check removed presentations inside the Manage Presentations
await this.modPage.waitAndClick(e.actions);
@ -175,7 +175,6 @@ class Presentation extends MultiUsers {
}
async removePreviousPresentationFromPreviousPresenter() {
await waitAndClearDefaultPresentationNotification(this.modPage);
await uploadSinglePresentation(this.modPage, e.uploadPresentationFileName);
const modSlides1 = await getSlideOuterHtml(this.modPage);
@ -222,6 +221,7 @@ class Presentation extends MultiUsers {
async presentationSnapshot(testInfo) {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await waitAndClearNotification(this.modPage);
await this.modPage.waitAndClick(e.whiteboardOptionsButton);
const presentationSnapshotLocator = this.modPage.getLocator(e.presentationSnapshot);
await this.modPage.handleDownload(presentationSnapshotLocator, testInfo);

View File

@ -8,19 +8,19 @@ test.describe.parallel('Shared Notes', () => {
await sharedNotes.openSharedNotes();
});
test('Type in shared notes', async ({ browser, page, context }) => {
// https://docs.bigbluebutton.org/2.5/release-tests.html#using-shared-notes-panel
// https://docs.bigbluebutton.org/2.6/release-tests.html#using-shared-notes-panel
const sharedNotes = new SharedNotes(browser, context);
await sharedNotes.initModPage(page);
await sharedNotes.typeInSharedNotes();
});
test('Formate text in shared notes', async ({ browser, page, context }) => {
// https://docs.bigbluebutton.org/2.5/release-tests.html#using-shared-notes-formatting-tools
// https://docs.bigbluebutton.org/2.6/release-tests.html#using-shared-notes-formatting-tools
const sharedNotes = new SharedNotes(browser, context);
await sharedNotes.initModPage(page);
await sharedNotes.formatTextInSharedNotes();
});
test('Export shared notes', async ({ browser, page, context }, testInfo) => {
// https://docs.bigbluebutton.org/2.5/release-tests.html#exporting-shared-notes
// https://docs.bigbluebutton.org/2.6/release-tests.html#exporting-shared-notes
const sharedNotes = new SharedNotes(browser, context);
await sharedNotes.initModPage(page);
await sharedNotes.exportSharedNotes(testInfo);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -8,7 +8,7 @@ async function startSharedNotes(test) {
}
function getNotesLocator(test) {
return test.page.frameLocator(e.etherpadFrame)
return test.page.frameLocator(e.etherpadFrame).last()
.frameLocator(e.etherpadOuter)
.frameLocator(e.etherpadInner)
.locator(e.etherpadEditable);

View File

@ -0,0 +1,120 @@
const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
class ChangeStyles extends MultiUsers {
constructor(browser, context) {
super(browser, context);
}
async changingColor() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbShapesButton);
await this.modPage.waitAndClick(e.wbEllipseShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbStyles);
await this.modPage.waitAndClick(e.wbColorRed);
await this.modPage.waitAndClick(e.wbStyles);
await expect(modWbLocator).toHaveScreenshot('moderator-change-color.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-change-color.png', screenshotOptions);
}
async fillDrawing() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbShapesButton);
await this.modPage.waitAndClick(e.wbEllipseShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbStyles);
await this.modPage.waitAndClick(e.wbFillDrawing);
await this.modPage.press('Escape');
await expect(modWbLocator).toHaveScreenshot('moderator-fill-drawing.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-fill-drawing.png', screenshotOptions);
}
async dashDrawing() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbShapesButton);
await this.modPage.waitAndClick(e.wbEllipseShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbStyles);
await this.modPage.waitAndClick(e.wbDashDotted);
await this.modPage.waitAndClick(e.wbStyles);
await expect(this.modPage.page).toHaveScreenshot('moderator-dash-drawing.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-dash-drawing.png', screenshotOptions);
}
async sizeDrawing() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbShapesButton);
await this.modPage.waitAndClick(e.wbEllipseShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbStyles);
await this.modPage.waitAndClick(e.wbSizeLarge);
await this.modPage.waitAndClick(e.wbStyles);
await expect(this.modPage.page).toHaveScreenshot('moderator-size-drawing.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-size-drawing.png', screenshotOptions);
}
}
exports.ChangeStyles = ChangeStyles;

View File

@ -0,0 +1,36 @@
const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
class DeleteDrawing extends MultiUsers {
constructor(browser, page) {
super(browser, page);
}
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbArrowShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbDelete);
await expect(modWbLocator).toHaveScreenshot('moderator-delete-drawing.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-delete-drawing.png', screenshotOptions);
}
}
exports.DeleteDrawing = DeleteDrawing;

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawArrow extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawArrow extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbArrowShape);
@ -26,9 +24,9 @@ class DrawArrow extends MultiUsers {
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-arrow.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-arrow.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-arrow.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-arrow.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawEllipse extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawEllipse extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbShapesButton);
@ -27,9 +25,10 @@ class DrawEllipse extends MultiUsers {
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-ellipse.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-ellipse.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-ellipse.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-ellipse.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawLine extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawLine extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbShapesButton);
@ -27,9 +25,10 @@ class DrawLine extends MultiUsers {
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-line.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-line.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-line.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-line.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawPencil extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawPencil extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbPencilShape);
@ -29,9 +27,10 @@ class DrawPencil extends MultiUsers {
await this.modPage.page.mouse.move(wbBox.x + 0.8 * wbBox.width, wbBox.y + 0.4 * wbBox.height, moveOptions);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-pencil.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-pencil.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-pencil.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-pencil.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawRectangle extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawRectangle extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbShapesButton);
@ -27,9 +25,9 @@ class DrawRectangle extends MultiUsers {
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-rectangle.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-rectangle.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-rectangle.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-rectangle.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawStickyNote extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawStickyNote extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbStickyNoteShape);
@ -30,10 +28,11 @@ class DrawStickyNote extends MultiUsers {
await this.modPage.page.mouse.click(wbBox.x + 0.6 * wbBox.width, wbBox.y + 0.6 * wbBox.height);
await this.modPage.hasText(e.wbTypedStickyNote, 'AB');
await this.modPage2.hasText(e.wbTypedStickyNote, 'AB');
await this.userPage.hasText(e.wbTypedStickyNote, 'AB');
await expect(this.modPage.page).toHaveScreenshot('moderator1-sticky.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-sticky.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-sticky.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-sticky.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawText extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawText extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbTextShape);
@ -29,8 +27,9 @@ class DrawText extends MultiUsers {
await this.modPage.press('B');
await this.modPage.page.mouse.click(wbBox.x + 0.6 * wbBox.width, wbBox.y + 0.6 * wbBox.height);
await expect(this.modPage.page).toHaveScreenshot('moderator1-text.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-text.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-text.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-text.png', screenshotOptions);
}
}

View File

@ -2,7 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
class DrawTriangle extends MultiUsers {
constructor(browser, context) {
@ -12,11 +11,10 @@ class DrawTriangle extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbShapesButton);
@ -27,9 +25,10 @@ class DrawTriangle extends MultiUsers {
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-triangle.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-triangle.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-triangle.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-triangle.png', screenshotOptions);
}
}

View File

@ -2,11 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
const defaultZoomLevel = '100%';
const zoomedInZoomLevel = '125%';
const maxZoomLevel = '400%';
class Eraser extends MultiUsers {
constructor(browser, context) {
@ -16,11 +11,10 @@ class Eraser extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
await this.modPage.waitAndClick(e.wbShapesButton);
@ -36,12 +30,13 @@ class Eraser extends MultiUsers {
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await expect(this.modPage.page).toHaveScreenshot('moderator1-eraser1.png', screenshotOptions);
await expect(this.modPage.page).toHaveScreenshot('moderator2-eraser1.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(modWbLocator).toHaveScreenshot('moderator-eraser1.png', screenshotOptions);
await expect(userWbLocator).toHaveScreenshot('viewer-eraser1.png', screenshotOptions);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-eraser2.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-eraser2.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-eraser2.png', screenshotOptions);
await expect(userWbLocator).toHaveScreenshot('viewer-eraser2.png', screenshotOptions);
}
}

View File

@ -2,11 +2,6 @@ const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
const { constructClipObj } = require('../core/util');
const defaultZoomLevel = '100%';
const zoomedInZoomLevel = '125%';
const maxZoomLevel = '400%';
class Pan extends MultiUsers {
constructor(browser, context) {
@ -16,11 +11,10 @@ class Pan extends MultiUsers {
async test() {
await this.modPage.waitForSelector(e.resetZoomButton, ELEMENT_WAIT_LONGER_TIME);
const wbBox = await this.modPage.getElementBoundingBox(e.whiteboard);
const clipObj = constructClipObj(wbBox);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixels: 1000,
clip: clipObj,
};
for(let i = 100; i < 200; i += 25) {
@ -31,9 +25,11 @@ class Pan extends MultiUsers {
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await expect(this.modPage.page).toHaveScreenshot('moderator1-pan.png', screenshotOptions);
await expect(this.modPage2.page).toHaveScreenshot('moderator2-pan.png', screenshotOptions);
await expect(modWbLocator).toHaveScreenshot('moderator-pan.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-pan.png', screenshotOptions);
}
}

View File

@ -0,0 +1,37 @@
const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
class RealTimeText extends MultiUsers {
constructor(browser, context) {
super(browser, context);
}
async realTimeTextTyping() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbTextShape);
await this.modPage.page.mouse.click(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.press('A');
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(modWbLocator).toHaveScreenshot('moderator-realtime-text.png', screenshotOptions);
await expect(userWbLocator).toHaveScreenshot('viewer-realtime-text.png', screenshotOptions);
await this.modPage.press('A');
await this.modPage.page.mouse.click(wbBox.x + 0.6 * wbBox.width, wbBox.y + 0.6 * wbBox.height);
await expect(modWbLocator).toHaveScreenshot('moderator-realtime-text-2.png', screenshotOptions);
await expect(userWbLocator).toHaveScreenshot('viewer-realtime-text-2.png', screenshotOptions);
await expect(modWbLocator).toHaveText('AA');
}
}
exports.RealTimeText = RealTimeText;

View File

@ -0,0 +1,37 @@
const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
class RedoDrawing extends MultiUsers {
constructor(browser, page) {
super(browser, page);
}
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbArrowShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbUndo);
await this.modPage.waitAndClick(e.wbRedo);
await expect(modWbLocator).toHaveScreenshot('moderator-redo-drawing.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-redo-drawing.png', screenshotOptions);
}
}
exports.RedoDrawing = RedoDrawing;

View File

@ -0,0 +1,36 @@
const { expect } = require('@playwright/test');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { MultiUsers } = require('../user/multiusers');
class UndoDrawing extends MultiUsers {
constructor(browser, page) {
super(browser, page);
}
async test() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const modWbLocator = this.modPage.getLocator(e.whiteboard);
const wbBox = await modWbLocator.boundingBox();
const screenshotOptions = {
maxDiffPixelRatio: 0.05,
};
await this.modPage.waitAndClick(e.wbArrowShape);
await this.modPage.page.mouse.move(wbBox.x + 0.3 * wbBox.width, wbBox.y + 0.3 * wbBox.height);
await this.modPage.page.mouse.down();
await this.modPage.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.modPage.page.mouse.up();
await this.modPage.waitAndClick(e.wbUndo);
await expect(modWbLocator).toHaveScreenshot('moderator-undo-drawing.png', screenshotOptions);
const userWbLocator = this.userPage.getLocator(e.whiteboard);
await expect(userWbLocator).toHaveScreenshot('viewer-undo-drawing.png', screenshotOptions);
}
}
exports.UndoDrawing = UndoDrawing;

View File

@ -14,6 +14,11 @@ const { DrawArrow } = require('./drawArrow');
const { MultiUsers } = require('../user/multiusers');
const { encodeCustomParams } = require('../customparameters/util');
const { PARAMETER_HIDE_PRESENTATION_TOAST } = require('../core/constants');
const { DeleteDrawing } = require('./deleteDrawing');
const { UndoDrawing } = require('./undoDraw');
const { RedoDrawing } = require('./redoDraw');
const { ChangeStyles } = require('./changeStyles');
const { RealTimeText } = require('./realTimeText');
const hidePresentationToast = encodeCustomParams(PARAMETER_HIDE_PRESENTATION_TOAST);
@ -40,77 +45,133 @@ test.describe.parallel('Whiteboard tools - visual regression', () => {
test('Draw rectangle', async ({ browser, context, page }) => {
const drawRectangle = new DrawRectangle(browser, context);
await drawRectangle.initModPage(page, true, { customMeetingId: 'draw_rectangle_meeting', customParameter: hidePresentationToast });
await drawRectangle.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawRectangle.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawRectangle.test();
});
test('Draw ellipse', async ({ browser, context, page }) => {
const drawEllipse = new DrawEllipse(browser, context);
await drawEllipse.initModPage(page, true, { customMeetingId: 'draw_ellipse_meeting', customParameter: hidePresentationToast });
await drawEllipse.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawEllipse.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawEllipse.test();
});
test('Draw triangle', async ({ browser, context, page }) => {
const drawTriangle = new DrawTriangle(browser, context);
await drawTriangle.initModPage(page, true, { customMeetingId: 'draw_triangle_meeting', customParameter: hidePresentationToast });
await drawTriangle.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawTriangle.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawTriangle.test();
});
test('Draw line', async ({ browser, context, page }) => {
const drawLine = new DrawLine(browser, context);
await drawLine.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await drawLine.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawLine.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawLine.test();
});
test('Draw with pencil', async ({ browser, context, page }) => {
const drawPencil = new DrawPencil(browser, context);
await drawPencil.initModPage(page, true, { customMeetingId: 'draw_pencil_meeting', customParameter: hidePresentationToast });
await drawPencil.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawPencil.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawPencil.test();
});
test('Type text', async ({ browser, context, page }) => {
const drawText = new DrawText(browser, context);
await drawText.initModPage(page, true, { customMeetingId: 'draw_text_meeting', customParameter: hidePresentationToast });
await drawText.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawText.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawText.test();
});
test('Create sticky note', async ({ browser, context, page }) => {
const drawStickyNote = new DrawStickyNote(browser, context);
await drawStickyNote.initModPage(page, true, { customMeetingId: 'draw_sticky_meeting', customParameter: hidePresentationToast });
await drawStickyNote.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawStickyNote.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawStickyNote.test();
});
test('Zoom', async ({ browser, context, page }) => {
const zoom = new Zoom(browser, context);
await zoom.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await zoom.initModPage2(true, context, { customParameter: hidePresentationToast });
await zoom.initUserPage(true, context, { customParameter: hidePresentationToast });
await zoom.test();
});
test('Pan', async ({ browser, context, page }) => {
const pan = new Pan(browser, context);
await pan.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await pan.initModPage2(true, context, { customParameter: hidePresentationToast });
await pan.initUserPage(true, context, { customParameter: hidePresentationToast });
await pan.test();
});
test('Eraser', async ({ browser, context, page }) => {
const eraser = new Eraser(browser, context);
await eraser.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await eraser.initModPage2(true, context, { customParameter: hidePresentationToast });
await eraser.initUserPage(true, context, { customParameter: hidePresentationToast });
await eraser.test();
});
test('Draw arrow', async ({ browser, context, page }) => {
const drawArrow = new DrawArrow(browser, context);
await drawArrow.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await drawArrow.initModPage2(true, context, { customParameter: hidePresentationToast });
await drawArrow.initUserPage(true, context, { customParameter: hidePresentationToast });
await drawArrow.test();
});
test('Delete drawing', async ({ browser, context, page }) => {
const deleteDrawing = new DeleteDrawing(browser, context);
await deleteDrawing.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await deleteDrawing.initUserPage(true, context, { customParameter: hidePresentationToast });
await deleteDrawing.test();
});
test('Undo drawing', async ({ browser, context, page }) => {
const undoDrawing = new UndoDrawing(browser, context);
await undoDrawing.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await undoDrawing.initUserPage(true, context, { customParameter: hidePresentationToast });
await undoDrawing.test();
});
test('Redo drawing', async ({ browser, context, page }) => {
const redoDrawing = new RedoDrawing(browser, context);
await redoDrawing.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await redoDrawing.initUserPage(true, context, { customParameter: hidePresentationToast });
await redoDrawing.test();
});
test('Change color', async ({ browser, context, page }) => {
const changeColor = new ChangeStyles(browser, context);
await changeColor.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await changeColor.initUserPage(true, context, { customParameter: hidePresentationToast });
await changeColor.changingColor();
});
test('Fill drawing', async ({ browser, context, page }) => {
const fillDrawing = new ChangeStyles(browser, context);
await fillDrawing.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await fillDrawing.initUserPage(true, context, { customParameter: hidePresentationToast });
await fillDrawing.fillDrawing();
});
test('Dash drawing', async ({ browser, context, page }) => {
const dashDrawing = new ChangeStyles(browser, context);
await dashDrawing.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await dashDrawing.initUserPage(true, context, { customParameter: hidePresentationToast });
await dashDrawing.dashDrawing();
});
test('Size drawing', async ({ browser, context, page }) => {
const sizeDrawing = new ChangeStyles(browser, context);
await sizeDrawing.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await sizeDrawing.initUserPage(true, context, { customParameter: hidePresentationToast });
await sizeDrawing.sizeDrawing();
});
test('Real time text typing', async ({ browser, context, page }) => {
const realTimeText = new RealTimeText(browser, context);
await realTimeText.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: hidePresentationToast });
await realTimeText.initUserPage(true, context, { customParameter: hidePresentationToast });
await realTimeText.realTimeTextTyping();
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

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