Merge remote-tracking branch 'upstream/v2.7.x-release' into issue-13844

This commit is contained in:
Ramón Souza 2023-05-17 15:44:39 -03:00
commit 18720e1536
162 changed files with 2428 additions and 1478 deletions

View File

@ -21,7 +21,8 @@ trait PresentationConversionCompletedSysPubMsgHdlr {
pod <- PresentationPodsApp.getPresentationPod(state, msg.body.podId)
pres <- pod.getPresentation(msg.body.presentation.id)
} yield {
val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres, temporaryPresentationId)
val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres, temporaryPresentationId,
msg.body.presentation.isInitialPresentation)
PresentationSender.broadcastPresentationConversionCompletedEvtMsg(
bus,

View File

@ -58,7 +58,7 @@ object PresentationPodsApp {
}
PresentationVO(p.id, "", p.name, p.current,
pages.toVector, p.downloadable, p.removable)
pages.toVector, p.downloadable, p.removable, false)
}
PresentationPodVO(pod.id, pod.currentPresenter, presentationVOs.toVector)
@ -73,7 +73,8 @@ object PresentationPodsApp {
state.update(podManager)
}
def translatePresentationToPresentationVO(pres: PresentationInPod, temporaryPresentationId: String): PresentationVO = {
def translatePresentationToPresentationVO(pres: PresentationInPod, temporaryPresentationId: String,
isInitialPresentation: Boolean): PresentationVO = {
val pages = pres.pages.values.map { page =>
PageVO(
id = page.id,
@ -88,7 +89,8 @@ object PresentationPodsApp {
heightRatio = page.heightRatio
)
}
PresentationVO(pres.id, temporaryPresentationId, pres.name, pres.current, pages.toVector, pres.downloadable, pres.removable)
PresentationVO(pres.id, temporaryPresentationId, pres.name, pres.current, pages.toVector, pres.downloadable, pres.removable,
isInitialPresentation)
}
def setCurrentPresentationInPod(state: MeetingState2x, podId: String, nextCurrentPresId: String): Option[PresentationPod] = {

View File

@ -146,8 +146,8 @@ object RegisteredUsers {
u
}
def updateUserJoin(users: RegisteredUsers, user: RegisteredUser): RegisteredUser = {
val u = user.copy(joined = true)
def updateUserJoin(users: RegisteredUsers, user: RegisteredUser, joined: Boolean): RegisteredUser = {
val u = user.copy(joined = joined)
users.save(u)
u
}

View File

@ -21,7 +21,7 @@ trait HandlerHelpers extends SystemConfiguration {
regUser: RegisteredUser
): Unit = {
if (!regUser.joined) {
RegisteredUsers.updateUserJoin(liveMeeting.registeredUsers, regUser)
RegisteredUsers.updateUserJoin(liveMeeting.registeredUsers, regUser, joined = true)
}
}

View File

@ -869,9 +869,12 @@ class MeetingActor(
leftUsers foreach { leftUser =>
for {
u <- Users2x.remove(liveMeeting.users2x, leftUser.intId)
ru <- RegisteredUsers.findWithUserId(leftUser.intId, liveMeeting.registeredUsers)
} yield {
log.info("Removing user from meeting. meetingId=" + props.meetingProp.intId + " userId=" + u.intId + " user=" + u)
RegisteredUsers.updateUserJoin(liveMeeting.registeredUsers, ru, joined = false)
captionApp2x.handleUserLeavingMsg(leftUser.intId, liveMeeting, msgBus)
// send a user left event for the clients to update

View File

@ -1,17 +1,19 @@
package org.bigbluebutton.core.util
import java.security.SecureRandom
object RandomStringGenerator {
// From: http://www.bindschaedler.com/2012/04/07/elegant-random-string-generation-in-scala/
// Random generator
val random = new scala.util.Random
val random = new SecureRandom()
// Generate a random string of length n from the given alphabet
def randomString(alphabet: String)(n: Int): String =
Stream.continually(random.nextInt(alphabet.size)).map(alphabet).take(n).mkString
LazyList.continually(random.nextInt(alphabet.length)).map(alphabet).take(n).mkString
// Generate a random alphabnumeric string of length n
def randomAlphanumericString(n: Int) =
def randomAlphanumericString(n: Int): String =
randomString("abcdefghijklmnopqrstuvwxyz0123456789")(n)
}

View File

@ -1,7 +1,8 @@
package org.bigbluebutton.common2.domain
case class PresentationVO(id: String, temporaryPresentationId: String, name: String, current: Boolean = false,
pages: Vector[PageVO], downloadable: Boolean, removable: Boolean)
pages: Vector[PageVO], downloadable: Boolean, removable: Boolean,
isInitialPresentation: Boolean)
case class PageVO(id: String, num: Int, thumbUri: String = "",
txtUri: String, svgUri: String, current: Boolean = false, xOffset: Double = 0,

View File

@ -535,11 +535,18 @@ public class ParamsProcessorUtil {
listOfDisabledFeatures.add("learningDashboard");
}
int learningDashboardCleanupMins = 0;
// Learning Dashboard not allowed for Breakout Rooms
if(!isBreakout) {
learningDashboardCleanupMins = learningDashboardCleanupDelayInMinutes;
if(isBreakout) {
listOfDisabledFeatures.add("learningDashboard");
}
//Set Learning Dashboard configs
String learningDashboardAccessToken = "";
int learningDashboardCleanupMins = 0;
if(listOfDisabledFeatures.contains("learningDashboard") == false) {
learningDashboardAccessToken = RandomStringUtils.randomAlphanumeric(12).toLowerCase();
learningDashboardCleanupMins = learningDashboardCleanupDelayInMinutes;
if (!StringUtils.isEmpty(params.get(ApiParams.LEARNING_DASHBOARD_CLEANUP_DELAY_IN_MINUTES))) {
try {
learningDashboardCleanupMins = Integer.parseInt(params
@ -552,12 +559,6 @@ public class ParamsProcessorUtil {
}
}
//Generate token to access Activity Report
String learningDashboardAccessToken = "";
if(listOfDisabledFeatures.contains("learningDashboard") == false) {
learningDashboardAccessToken = RandomStringUtils.randomAlphanumeric(12).toLowerCase();
}
Boolean notifyRecordingIsOn = defaultNotifyRecordingIsOn;
if (!StringUtils.isEmpty(params.get(ApiParams.NOTIFY_RECORDING_IS_ON))) {
notifyRecordingIsOn = Boolean.parseBoolean(params.get(ApiParams.NOTIFY_RECORDING_IS_ON));

View File

@ -202,7 +202,7 @@ public class Meeting {
}
public Integer countUniqueExtIds() {
List<String> uniqueExtIds = new ArrayList<String>();
List<String> uniqueExtIds = new ArrayList<>();
for (User user : users.values()) {
if(!uniqueExtIds.contains(user.getExternalUserId())) {
uniqueExtIds.add(user.getExternalUserId());

View File

@ -41,6 +41,7 @@ public final class UploadedPresentation {
private String authzToken;
private boolean conversionStarted = false;
private boolean isInitialPresentation;
public UploadedPresentation(String podId,
String meetingId,
@ -51,7 +52,8 @@ public final class UploadedPresentation {
Boolean current,
String authzToken,
Boolean uploadFailed,
ArrayList<String> uploadFailReason) {
ArrayList<String> uploadFailReason,
Boolean isInitialPresentation) {
this.podId = podId;
this.meetingId = meetingId;
this.id = id;
@ -63,6 +65,21 @@ public final class UploadedPresentation {
this.authzToken = authzToken;
this.uploadFailed = uploadFailed;
this.uploadFailReason = uploadFailReason;
this.isInitialPresentation = isInitialPresentation;
}
public UploadedPresentation(String podId,
String meetingId,
String id,
String temporaryPresentationId,
String name,
String baseUrl,
Boolean current,
String authzToken,
Boolean uploadFailed,
ArrayList<String> uploadFailReason) {
this(podId, meetingId, id, temporaryPresentationId, name, baseUrl,
current, authzToken, uploadFailed, uploadFailReason, false);
}
public UploadedPresentation(String podId,
@ -75,7 +92,21 @@ public final class UploadedPresentation {
Boolean uploadFailed,
ArrayList<String> uploadFailReason) {
this(podId, meetingId, id, "", name, baseUrl,
current, authzToken, uploadFailed, uploadFailReason);
current, authzToken, uploadFailed, uploadFailReason, false);
}
public UploadedPresentation(String podId,
String meetingId,
String id,
String name,
String baseUrl,
Boolean current,
String authzToken,
Boolean uploadFailed,
ArrayList<String> uploadFailReason,
Boolean isInitialPresentation) {
this(podId, meetingId, id, "", name, baseUrl,
current, authzToken, uploadFailed, uploadFailReason, isInitialPresentation);
}
public File getUploadedFile() {
@ -177,4 +208,8 @@ public final class UploadedPresentation {
public ArrayList<String> getUploadFailReason() {
return uploadFailReason;
}
public boolean getIsInitialPresentation() {
return isInitialPresentation;
}
}

View File

@ -113,7 +113,7 @@ public class SlidesGenerationProgressNotifier {
pres.getId(), pres.getTemporaryPresentationId(), pres.getId(),
pres.getName(), "notUsedYet", "notUsedYet",
pres.isDownloadable(), pres.isRemovable(), ConversionMessageConstants.CONVERSION_COMPLETED_KEY,
pres.getNumberOfPages(), generateBasePresUrl(pres), pres.isCurrent());
pres.getNumberOfPages(), generateBasePresUrl(pres), pres.isCurrent(), pres.getIsInitialPresentation());
messagingService.sendDocConversionMsg(progress);
}

View File

@ -15,11 +15,12 @@ public class DocPageCompletedProgress implements IDocConversionMsg {
public final Integer numPages;
public final String presBaseUrl;
public final Boolean current;
public final Boolean isInitialPresentation;
public DocPageCompletedProgress(String podId, String meetingId, String presId, String temporaryPresentationId, String presInstance,
String filename, String uploaderId, String authzToken,
Boolean downloadable, Boolean removable, String key,
Integer numPages, String presBaseUrl, Boolean current) {
Integer numPages, String presBaseUrl, Boolean current, Boolean isInitialPresentation) {
this.podId = podId;
this.meetingId = meetingId;
this.presId = presId;
@ -34,5 +35,6 @@ public class DocPageCompletedProgress implements IDocConversionMsg {
this.numPages = numPages;
this.presBaseUrl = presBaseUrl;
this.current = current;
this.isInitialPresentation = isInitialPresentation;
}
}

View File

@ -148,7 +148,8 @@ object MsgBuilder {
val pages = generatePresentationPages(msg.presId, msg.numPages.intValue(), msg.presBaseUrl)
val presentation = PresentationVO(msg.presId, msg.temporaryPresentationId, msg.filename,
current = msg.current.booleanValue(), pages.values.toVector, msg.downloadable.booleanValue(), msg.removable.booleanValue())
current = msg.current.booleanValue(), pages.values.toVector, msg.downloadable.booleanValue(), msg.removable.booleanValue(),
isInitialPresentation = msg.isInitialPresentation)
val body = PresentationConversionCompletedSysPubMsgBody(podId = msg.podId, messageKey = msg.key,
code = msg.key, presentation)

View File

@ -1,11 +1,10 @@
package org.bigbluebutton.api2.util
import java.io.{ File, FileOutputStream, FileWriter, IOException }
import java.io.{ File, FileInputStream, FileOutputStream, FileWriter, IOException, InputStreamReader }
import java.nio.channels.Channels
import java.nio.charset.StandardCharsets
import java.util
import java.nio.file.{ Files, Paths }
import com.google.gson.Gson
import org.bigbluebutton.api.domain.RecordingMetadata
import org.bigbluebutton.api2.{ BbbWebApiGWApp, RecordingServiceGW }
@ -15,11 +14,9 @@ import scala.xml.{ Elem, PrettyPrinter, XML }
import scala.collection.JavaConverters._
import scala.collection.mutable.{ Buffer, ListBuffer, Map }
import scala.collection.Iterable
import java.io.IOException
import java.nio.charset.Charset
import java.nio.file.Files
import java.nio.file.Paths
import com.google.gson.internal.LinkedTreeMap
import scala.util.Try
@ -31,9 +28,13 @@ class RecMetaXmlHelper(gw: BbbWebApiGWApp) extends RecordingServiceGW with LogHe
val CAPTIONS_FILE = "captions.json"
def loadMetadataXml(path: String): Option[Elem] = {
var stream: FileInputStream = null
var reader: InputStreamReader = null
try {
//val xml = XML.loadFile(path)
val xml = XML.load(new java.io.InputStreamReader(new java.io.FileInputStream(path), StandardCharsets.UTF_8.name()))
stream = new FileInputStream(path)
reader = new InputStreamReader(stream, StandardCharsets.UTF_8.name())
val xml = XML.load(reader)
Some(xml)
} catch {
case ioe: IOException =>
@ -43,6 +44,9 @@ class RecMetaXmlHelper(gw: BbbWebApiGWApp) extends RecordingServiceGW with LogHe
logger.info("Exception while loading {}", path)
logger.info("Exception details: {}", ex.getMessage)
None
} finally {
if (reader != null) reader.close()
if (stream != null) stream.close()
}
}
@ -52,7 +56,7 @@ class RecMetaXmlHelper(gw: BbbWebApiGWApp) extends RecordingServiceGW with LogHe
val Encoding = StandardCharsets.UTF_8.name()
val pp = new PrettyPrinter(80, 2)
val fos = new FileOutputStream(xml.getAbsolutePath)
val writer = Channels.newWriter(fos.getChannel(), Encoding)
val writer = Channels.newWriter(fos.getChannel, Encoding)
try {
writer.write("<?xml version='1.0' encoding='" + Encoding + "'?>\n")
@ -64,6 +68,7 @@ class RecMetaXmlHelper(gw: BbbWebApiGWApp) extends RecordingServiceGW with LogHe
logger.info("Exception details: {}", ex.fillInStackTrace())
} finally {
writer.close()
fos.close()
}
} catch {
case ioe: IOException =>
@ -72,6 +77,7 @@ class RecMetaXmlHelper(gw: BbbWebApiGWApp) extends RecordingServiceGW with LogHe
logger.info("Exception while saving {}", xml.getAbsolutePath)
logger.info("Exception details: {}", ex.fillInStackTrace())
}
result
}

View File

@ -89,17 +89,19 @@ async function collectAnnotationsFromRedis() {
await client.publish(config.redis.channels.publish, statusUpdate.build(pageNumber));
}
} else {
const imageName = 'slide1';
if (fs.existsSync(`${presFile}.png`)) {
// PNG file available
fs.copyFileSync(`${presFile}.png`, path.join(dropbox, 'slide1.png'));
fs.copyFileSync(`${presFile}.png`, path.join(dropbox, `${imageName}.png`));
} else if (fs.existsSync(`${presFile}.jpeg`)) {
// JPEG file available
fs.copyFileSync(`${presFile}.jpeg`, path.join(dropbox, 'slide1.jpeg'));
await client.publish(config.redis.channels.publish, statusUpdate.build());
fs.copyFileSync(`${presFile}.jpeg`, path.join(dropbox, `${imageName}.jpeg`));
} else if (fs.existsSync(`${presFile}.jpg`)) {
// JPG file available: copy changing extension to JPEG
fs.copyFileSync(`${presFile}.jpg`, path.join(dropbox, `${imageName}.jpeg`));
} else {
await client.publish(config.redis.channels.publish, statusUpdate.build());
client.disconnect();
return logger.error(`No PDF, PNG or JPEG file available for job ${jobId}`);
return logger.error(`No PDF, PNG, JPG or JPEG file available for job ${jobId}`);
}
await client.publish(config.redis.channels.publish, statusUpdate.build());

View File

@ -1 +1,2 @@
BIGBLUEBUTTON_RELEASE=2.7.0-alpha.1

View File

@ -94,9 +94,11 @@ remove_raw_of_recordings_without_marks
#
remove_raw_of_published_recordings(){
#TYPES=$(cd /usr/local/bigbluebutton/core/scripts/process; ls *.rb | sed s/.rb//g)
TYPES=$(cd /usr/local/bigbluebutton/core/scripts/process; ls *.rb | sed s/.rb//g)
logger "Removing raw directory of old recordings:"
TYPES="presentation"
if [ "$TYPES" == "" ]; then
TYPES="presentation"
fi
cd /var/bigbluebutton/recording/raw/
old_meetings=$(find . -name events.xml -mtime +$published_days | cut -d"/" -f2 )
for meeting in $old_meetings

View File

@ -5,19 +5,19 @@
meteor-base@1.5.1
mobile-experience@1.1.0
mongo@1.16.4
mongo@1.16.6
reactive-var@1.0.12
standard-minifier-css@1.8.3
standard-minifier-css@1.9.2
standard-minifier-js@2.8.1
es5-shim@4.8.0
ecmascript@0.16.5
ecmascript@0.16.7
shell-server@0.5.0
static-html@1.3.2
react-meteor-data
session@1.2.1
tracker@1.3.0
tracker@1.3.2
check@1.3.2
rocketchat:streamer

View File

@ -1 +1 @@
METEOR@2.10.0
METEOR@2.12

View File

@ -1,6 +1,6 @@
allow-deny@1.1.1
autoupdate@1.8.0
babel-compiler@7.10.2
babel-compiler@7.10.4
babel-runtime@1.5.1
base64@1.0.12
binary-heap@1.0.11
@ -8,16 +8,16 @@ blaze-tools@1.1.3
boilerplate-generator@1.7.1
caching-compiler@1.2.2
caching-html-compiler@1.2.1
callback-hook@1.5.0
callback-hook@1.5.1
check@1.3.2
ddp@1.4.1
ddp-client@2.6.1
ddp-common@1.4.0
ddp-server@2.6.0
ddp-server@2.6.1
diff-sequence@1.1.2
dynamic-import@0.7.2
ecmascript@0.16.5
ecmascript-runtime@0.8.0
dynamic-import@0.7.3
ecmascript@0.16.7
ecmascript-runtime@0.8.1
ecmascript-runtime-client@0.12.1
ecmascript-runtime-server@0.11.0
ejson@1.1.3
@ -32,29 +32,29 @@ id-map@1.1.1
inter-process-messaging@0.1.1
launch-screen@1.3.0
lmieulet:meteor-coverage@4.1.0
logging@1.3.1
meteor@1.11.0
logging@1.3.2
meteor@1.11.2
meteor-base@1.5.1
meteortesting:browser-tests@1.3.5
meteortesting:mocha@2.0.3
meteortesting:mocha-core@8.1.2
minifier-css@1.6.2
minifier-css@1.6.4
minifier-js@2.7.5
minimongo@1.9.1
minimongo@1.9.3
mobile-experience@1.1.0
mobile-status-bar@1.1.0
modern-browsers@0.1.9
modules@0.19.0
modules-runtime@0.13.1
mongo@1.16.4
mongo@1.16.6
mongo-decimal@0.1.3
mongo-dev-server@1.1.0
mongo-id@1.0.8
npm-mongo@4.12.1
npm-mongo@4.16.0
ordered-dict@1.1.0
promise@0.12.2
random@1.2.1
react-fast-refresh@0.2.5
react-fast-refresh@0.2.7
react-meteor-data@2.5.1
reactive-dict@1.3.1
reactive-var@1.0.12
@ -64,15 +64,15 @@ rocketchat:streamer@1.1.0
routepolicy@1.1.1
session@1.2.1
shell-server@0.5.0
socket-stream-client@0.5.0
socket-stream-client@0.5.1
spacebars-compiler@1.3.1
standard-minifier-css@1.8.3
standard-minifier-css@1.9.2
standard-minifier-js@2.8.1
static-html@1.3.2
templating-tools@1.2.2
tracker@1.3.0
typescript@4.7.4
underscore@1.0.11
tracker@1.3.2
typescript@4.9.4
underscore@1.0.13
url@1.3.2
webapp@1.13.3
webapp@1.13.5
webapp-hashing@1.1.1

View File

@ -1,105 +0,0 @@
# Localization with Transifex
We use Transifex for crowdsourcing for BigBlueButton Internationalization(i18n). The following steps are not a part of the typical installation and are only required for bringing the language strings in github up to date. There are two ways to pull the translation files; using the transifex.sh script or the transifex client.
## Using transifex.sh
The transifex.sh script aims to make retrieving translation files on the Transifex servers as simple as possible. In order to use the script, you must provide your Transifex credentials which have the appropriate authorization. The script can be used in the following ways.
~~~
$ ./transifex.sh all
~~~
Using the all argument will tell the script to download all available translation files.
~~~
$ ./transifex.sh fr de pt-BR
~~~
If you only need a specific set of translations, the script can be run with the required locales as argument.
## Setup & Configure Transifex Client
This is an alternative method to using the transifex.sh and is essentially the manual process for retrieving translation files from the Transifex servers.
### 1. Install Transifex Client ###
To installation the Transifex client we use pip, a package management system designed to manage and install Python packages.
~~~
$ sudo apt-get install python-pip
~~~
Next we use Pip to install the Transifex client.
~~~
$ sudo pip install transifex-client
~~~
The following command is used to upgrade the client to the most current version.
~~~
$ pip install --upgrade transifex-client
~~~
### 2. Transifex Project Initialization ###
The `tx init` command is used to initialize a project. Run from the root directory of the application.
~~~
$ tx init
Creating .tx folder. . .
Transifex instance [https://www.transifex.com]:
~~~
Press Enter (will be prompted for your Transifex username and password)
~~~
Creating skeleton...
Creating config file...
Done.
~~~
This will create a Transifex project file in the current directory containing the projects configuration file.
### 3. Transifex Client configuration ###
#### .tx/config ####
The Transifex client uses a per project configuration file. This is located in .tx/config of your project's root directory and is generated on running the `tx init` command. It should be updated with the following configuration:
~~~
[main]
host = https://www.transifex.com
[bigbluebutton-html5.enjson]
file_filter = private/locales/<lang>.json
source_file = private/locales/en_US.json
source_lang = en_US
type = KEYVALUEJSON
~~~
### 4. Set a Project Remote ###
`tx set` allows you to configure and edit Transifex project files on your local computer.
The following command is used to initialize a local project for the remote project specified by the URL.
`$ tx set --auto-remote https://www.transifex.com/projects/p/bigbluebutton-html5/resources/enjson/`
Next we can pull language files located on the Transifex server.
### 5. Pull: Download Transifex Translations ###
To pull all translation files from the Transifex server, the following command is used.
`$ tx pull -a bigbluebutton-html5.enjson`
In the event that there are a lot of translations, instead of pulling all, we can specify which translations we want to acquire.
`$ tx pull -r bigbluebutton-html5.enjson -l pt_BR`
Alternatively, simply download a ZIP archive of all languages in the project from the Transifex project page and unarchive it in the `private/locales/` directory.

View File

@ -19,7 +19,7 @@
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import logger from '/imports/startup/client/logger';
import '/imports/ui/services/mobile-app';
import Base from '/imports/startup/client/base';
@ -45,7 +45,7 @@ import('/imports/api/audio/client/bridge/bridge-whitelist').catch(() => {
const { disableWebsocketFallback } = Meteor.settings.public.app;
if (disableWebsocketFallback) {
Meteor.connection._stream._sockjsProtocolsWhitelist = function () { return ['websocket']; }
Meteor.connection._stream._sockjsProtocolsWhitelist = function () { return ['websocket']; };
Meteor.disconnect();
Meteor.reconnect();
@ -77,10 +77,12 @@ Meteor.startup(() => {
}, message);
});
const root = createRoot(document.getElementById('app'));
// TODO make this a Promise
render(
root.render(
<ContextProviders>
<React.Fragment>
<>
<JoinHandler>
<AuthenticatedHandler>
<Subscriptions>
@ -93,8 +95,7 @@ Meteor.startup(() => {
<UsersAdapter />
<ChatAdapter />
<GroupChatAdapter />
</React.Fragment>
</>
</ContextProviders>,
document.getElementById('app'),
);
});

View File

@ -1,4 +1,5 @@
import { GroupChatMsg } from '/imports/api/group-chat-msg';
import GroupChat from '/imports/api/group-chat';
import Logger from '/imports/startup/server/logger';
import flat from 'flat';
import { parseMessage } from './addGroupChatMsg';
@ -24,7 +25,14 @@ export default async function addBulkGroupChatMsgs(msgs) {
senderRole: sender.role,
};
})
.map((el) => flat(el, { safe: true }));
.map((el) => flat(el, { safe: true }))
.map((msg)=>{
const groupChat = GroupChat.findOne({ meetingId: msg.meetingId, chatId: msg.chatId });
return {
...msg,
participants: [...groupChat.users],
};
});
try {
const { insertedCount } = await GroupChatMsg.rawCollection().insertMany(mappedMsgs);

View File

@ -3,6 +3,7 @@ import Logger from '/imports/startup/server/logger';
import { GroupChatMsg } from '/imports/api/group-chat-msg';
import { BREAK_LINE } from '/imports/utils/lineEndings';
import changeHasMessages from '/imports/api/users-persistent-data/server/modifiers/changeHasMessages';
import GroupChat from '/imports/api/group-chat';
export function parseMessage(message) {
let parsedMessage = message || '';
@ -34,6 +35,8 @@ export default async function addGroupChatMsg(meetingId, chatId, msg) {
...restMsg
} = msg;
const groupChat = GroupChat.findOne({ meetingId, chatId });
const msgDocument = {
...restMsg,
sender: sender.id,
@ -41,6 +44,7 @@ export default async function addGroupChatMsg(meetingId, chatId, msg) {
senderRole: sender.role,
meetingId,
chatId,
participants: [...groupChat.users],
message: parseMessage(msg.message),
};

View File

@ -6,8 +6,7 @@ import GroupChat from '/imports/api/group-chat';
import Logger from '/imports/startup/server/logger';
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
async function groupChatMsg(chatCount) {
check(chatCount, Number);
async function groupChatMsg() {
const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
@ -36,10 +35,10 @@ async function groupChatMsg(chatCount) {
timestamp: { $gte: User.authTokenValidatedTime },
$or: [
{ meetingId, chatId: { $eq: PUBLIC_GROUP_CHAT_ID } },
{ meetingId, chatId: { $in: chatsIds } },
{ meetingId, participants: { $in: [userId] } },
],
};
return GroupChatMsg.find(selector);
return GroupChatMsg.find(selector, { fields: { participants: 0 } });
}
function publish(...args) {

View File

@ -51,6 +51,7 @@ export default async function addPresentation(meetingId, podId, presentation) {
],
downloadable: Boolean,
removable: Boolean,
isInitialPresentation: Boolean,
});
const selector = {

View File

@ -272,8 +272,9 @@ export default class KurentoScreenshareBridge {
this.broker.onstart = this.handleViewerStart.bind(this);
this.broker.onerror = this.handleBrokerFailure.bind(this);
this.broker.onended = this.handleEnded.bind(this);
if (!this.reconnecting) {
this.broker.onended = this.handleEnded.bind(this);
}
return this.broker.view().finally(this.scheduleReconnect.bind(this));
}

View File

@ -38,7 +38,10 @@ export default async function handleValidateAuthToken({ body }, meetingId) {
check(reasonCode, String);
const pendingAuths = pendingAuthenticationsStore.take(meetingId, userId, authToken);
Logger.info(`PendingAuths length [${pendingAuths.length}]`);
const printablePendingAuthStore = pendingAuths.map((a) => {
return { meetingId: a.meetingId, userId: a.userId, authToken: a.authToken }
})
Logger.info(`PendingAuths length [${pendingAuths.length}]: ${JSON.stringify(printablePendingAuthStore)}`);
if (pendingAuths.length === 0) return;
if (!valid) {
@ -58,11 +61,12 @@ export default async function handleValidateAuthToken({ body }, meetingId) {
// Schedule socket disconnection for this user
// giving some time for client receiving the reason of disconnection
Logger.info(`Scheduling socket disconnection for user ${userId} ${connectionId} due to invalid auth token`);
new Promise((resolve) => {
setTimeout(() => {
Meteor.setTimeout(() => {
methodInvocationObject.connection.close();
Logger.info(`Closed connection ${connectionId} due to invalid auth token.`);
resolve();
resolve();
}, 2000);
});
} catch (e) {

View File

@ -12,11 +12,11 @@ async function validateAuthToken(meetingId, requesterUserId, requesterToken, ext
const userValidation = await new Promise(async (res, rej) => {
const observeFunc = (obj) => {
if (obj.validationStatus === ValidationStates.VALIDATED) {
clearTimeout(setTimeoutRef);
Meteor.clearTimeout(setTimeoutRef);
return res(obj);
}
if (obj.validationStatus === ValidationStates.INVALID) {
clearTimeout(setTimeoutRef);
Meteor.clearTimeout(setTimeoutRef);
return res(obj);
}
};
@ -27,7 +27,7 @@ async function validateAuthToken(meetingId, requesterUserId, requesterToken, ext
changed: observeFunc,
});
setTimeoutRef = setTimeout(() => {
setTimeoutRef = Meteor.setTimeout(() => {
authTokenValidationObserver.stop();
rej();
}, AUTH_TIMEOUT);
@ -68,7 +68,7 @@ async function validateAuthToken(meetingId, requesterUserId, requesterToken, ext
const errMsg = `Exception while invoking method validateAuthToken ${err}`;
Logger.error(errMsg);
rej(errMsg);
clearTimeout(setTimeoutRef);
Meteor.clearTimeout(setTimeoutRef);
authTokenValidationObserver.stop();
}
});

View File

@ -209,7 +209,7 @@ const QuickPollDropdown = (props) => {
setTimeout(() => {
handleClickQuickPoll(layoutContextDispatch);
if (singlePollType === 'R-' || singlePollType === 'TF') {
if (singlePollType === 'R-' || singlePollType === 'TF' || singlePollType === 'YN') {
startPoll(singlePollType, currentSlide.id, answers, pollQuestion, multiResponse);
} else {
startPoll(

View File

@ -70,10 +70,6 @@ const intlMessages = defineMessages({
id: 'app.actionsBar.label',
description: 'Aria-label for ActionsBar Section',
},
iOSWarning: {
id: 'app.iOSWarning.label',
description: 'message indicating to upgrade ios version',
},
clearedEmoji: {
id: 'app.toast.clearedEmoji.label',
description: 'message for cleared emoji status',
@ -153,7 +149,6 @@ class App extends Component {
const {
notify,
intl,
validIOSVersion,
layoutContextDispatch,
isRTL,
} = this.props;
@ -186,12 +181,6 @@ class App extends Component {
body.classList.add(`os-${osName.split(' ').shift().toLowerCase()}`);
if (!validIOSVersion()) {
notify(
intl.formatMessage(intlMessages.iOSWarning), 'error', 'warning',
);
}
this.handleWindowResize();
window.addEventListener('resize', this.handleWindowResize, false);
window.addEventListener('localeChanged', () => {
@ -576,7 +565,7 @@ class App extends Component {
? <ExternalVideoContainer isLayoutSwapped={!presentationIsOpen} isPresenter={isPresenter} />
: null
}
{shouldShowSharedNotes
{shouldShowSharedNotes
? (
<NotesContainer
area="media"

View File

@ -28,7 +28,6 @@ const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
import {
getFontSize,
getBreakoutRooms,
validIOSVersion,
} from './service';
import App from './component';
@ -94,7 +93,7 @@ const AppContainer = (props) => {
const { focusedId } = cameraDock;
if(
layoutContextDispatch
layoutContextDispatch
&& (typeof meetingLayout != "undefined")
&& (layoutType.current != meetingLayout)
) {
@ -142,7 +141,7 @@ const AppContainer = (props) => {
useEffect(() => {
MediaService.buildLayoutWhenPresentationAreaIsDisabled(layoutContextDispatch)});
return currentUserId
? (
<App
@ -286,7 +285,6 @@ export default withTracker(() => {
customStyleUrl,
UserInfo,
notify,
validIOSVersion,
isPhone: deviceInfo.isPhone,
isRTL: document.documentElement.getAttribute('dir') === 'rtl',
currentUserEmoji: currentUserEmoji(currentUser),

View File

@ -20,15 +20,6 @@ function meetingIsBreakout() {
return (meeting && meeting.meetingProp.isBreakout);
}
const validIOSVersion = () => {
const { isIos, isIosVersionSupported } = deviceInfo;
if (isIos) {
return isIosVersionSupported();
}
return true;
};
const setDarkTheme = (value) => {
if (value && !DarkReader.isEnabled()) {
DarkReader.enable(
@ -56,7 +47,6 @@ export {
getFontSize,
meetingIsBreakout,
getBreakoutRooms,
validIOSVersion,
setDarkTheme,
isDarkThemeEnabled,
};

View File

@ -8,6 +8,8 @@ const CaptionsWrapper = styled.div`
bottom: 100px;
left: 20%;
z-index: 5;
pointer-events: none;
user-select:none;
`;
const ActionsBar = styled.section`

View File

@ -153,7 +153,7 @@ class MessageForm extends PureComponent {
}
handleSendMessage(escapeHtml(msg));
this.setState({ message: '', hasErrors: false });
this.setState({ message: '', error: '', hasErrors: false });
}
setMessageHint() {

View File

@ -262,7 +262,7 @@ class MessageForm extends PureComponent {
const callback = this.typingIndicator ? stopUserTyping : null;
handleSendMessage(escapeHtml(msg));
this.setState({ message: '', hasErrors: false, showEmojiPicker: false }, callback);
this.setState({ message: '', error: '', hasErrors: false, showEmojiPicker: false }, callback);
}
handleEmojiSelect(emojiObject) {

View File

@ -27,8 +27,7 @@ export default withTracker(({ idChatOpen }) => {
};
if (idChatOpen !== PUBLIC_CHAT_KEY) {
selector.isTypingTo = Auth.userID;
selector.userId = idChatOpen;
selector.isTypingTo = idChatOpen;
}
const currentUser = Users.findOne({

View File

@ -129,7 +129,7 @@ class BBBMenu extends React.Component {
style={customStyles}
onClick={(event) => {
onClick();
const close = !key.includes('setstatus') && !key.includes('back');
const close = !key?.includes('setstatus') && !key?.includes('back');
// prevent menu close for sub menu actions
if (close) this.handleClose(event);
event.stopPropagation();

View File

@ -7,6 +7,7 @@ import { ACTIONS, CAMERADOCK_POSITION, PANELS } from '../enums';
import Storage from '/imports/ui/services/storage/session';
import { defaultsDeep } from '/imports/utils/array-utils';
import { isPresentationEnabled } from '/imports/ui/services/features';
import Draggable from 'react-draggable';
const windowWidth = () => window.document.documentElement.clientWidth;
const windowHeight = () => window.document.documentElement.clientHeight;
@ -169,6 +170,9 @@ const CustomLayout = (props) => {
width: input.screenShare.width,
height: input.screenShare.height,
},
sharedNotes: {
isPinned: sharedNotesInput.isPinned,
},
}, INITIAL_INPUT_STATE),
});
} else {
@ -205,6 +209,9 @@ const CustomLayout = (props) => {
width: input.screenShare.width,
height: input.screenShare.height,
},
sharedNotes: {
isPinned: sharedNotesInput.isPinned,
},
}, INITIAL_INPUT_STATE),
});
}
@ -646,7 +653,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

@ -102,6 +102,9 @@ const SmartLayout = (props) => {
width: screenShareInput.width,
height: screenShareInput.height,
},
sharedNotes: {
isPinned: sharedNotesInput.isPinned,
},
}, INITIAL_INPUT_STATE),
});
} else {
@ -138,6 +141,9 @@ const SmartLayout = (props) => {
width: screenShareInput.width,
height: screenShareInput.height,
},
sharedNotes: {
isPinned: sharedNotesInput.isPinned,
},
}, INITIAL_INPUT_STATE),
});
}

View File

@ -121,7 +121,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

@ -141,6 +141,13 @@ const Notes = ({
value: Session.get('presentationLastState'),
});
};
}else{
if(shouldShowSharedNotesOnPresentationArea) {
layoutContextDispatch({
type: ACTIONS.SET_NOTES_IS_PINNED,
value: true,
});
}
}
}, []);

View File

@ -9,6 +9,8 @@ import UserService from '/imports/ui/components/user-list/service';
export default injectIntl(withTracker(({ intl }) => {
NotificationsCollection.find({}).observe({
added: (obj) => {
NotificationsCollection.remove(obj);
if (obj.messageId === 'app.userList.guest.pendingGuestAlert') {
return WaitingUsersAlertService.alert(obj, intl);
}

View File

@ -77,6 +77,7 @@ class Presentation extends PureComponent {
isPanning: false,
tldrawIsMounting: true,
isToolbarVisible: true,
hadPresentation: false,
};
this.currentPresentationToastId = null;
@ -136,9 +137,15 @@ class Presentation extends PureComponent {
window.addEventListener('resize', this.onResize, false);
const {
currentSlide, slidePosition, numPages, layoutContextDispatch,
currentSlide, slidePosition, numPages, layoutContextDispatch, currentPresentationId,
} = this.props;
if (currentPresentationId) {
this.setState({
hadPresentation: true
});
}
if (currentSlide) {
layoutContextDispatch({
type: ACTIONS.SET_PRESENTATION_NUM_CURRENT_SLIDE,
@ -154,7 +161,7 @@ class Presentation extends PureComponent {
layoutContextDispatch({
type: ACTIONS.SET_PRESENTATION_SLIDES_LENGTH,
value: numPages,
})
});
}
}
@ -174,10 +181,11 @@ class Presentation extends PureComponent {
intl,
multiUser,
numPages,
currentPresentationId,
} = this.props;
const {
presentationWidth, presentationHeight, zoom, isPanning, fitToWidth,
presentationWidth, presentationHeight, zoom, isPanning, fitToWidth, presentationId, hadPresentation,
} = this.state;
const {
numCameras: prevNumCameras,
@ -197,7 +205,7 @@ class Presentation extends PureComponent {
layoutContextDispatch({
type: ACTIONS.SET_PRESENTATION_SLIDES_LENGTH,
value: numPages,
})
});
}
if (
@ -256,18 +264,28 @@ class Presentation extends PureComponent {
},
});
}
const presentationChanged = presentationId !== currentPresentationId;
if (!presentationIsOpen && restoreOnUpdate && currentSlide) {
const isInitialPresentation = currentPresentation.isInitialPresentation;
if (!presentationIsOpen && restoreOnUpdate && (currentSlide || presentationChanged)) {
const slideChanged = currentSlide.id !== prevProps.currentSlide.id;
const positionChanged = slidePosition
.viewBoxHeight !== prevProps.slidePosition.viewBoxHeight
|| slidePosition.viewBoxWidth !== prevProps.slidePosition.viewBoxWidth;
const pollPublished = publishedPoll && !prevProps.publishedPoll;
if (slideChanged || positionChanged || pollPublished) {
if (slideChanged || positionChanged || pollPublished || (presentationChanged && (hadPresentation || !isInitialPresentation))) {
setPresentationIsOpen(layoutContextDispatch, !presentationIsOpen);
}
}
if (presentationChanged) {
this.setState({
presentationId: currentPresentationId,
hadPresentation: true
});
}
if ((presentationBounds !== prevPresentationBounds)
|| (!presentationWidth && !presentationHeight)) this.onResize();
} else if (slidePosition) {
@ -736,7 +754,7 @@ class Presentation extends PureComponent {
textAlign: 'center',
display: !presentationIsOpen ? 'none' : 'block',
}}
id={"presentationInnerWrapper"}
id="presentationInnerWrapper"
>
<Styled.VisuallyHidden id="currentSlideText">{slideContent}</Styled.VisuallyHidden>
{!tldrawIsMounting && currentSlide && this.renderPresentationMenu()}

View File

@ -116,7 +116,7 @@ export default lockContextContainer(
});
}
}
const currentPresentation = PresentationService.getCurrentPresentation(podId);
return {
currentSlide,
slidePosition,
@ -127,7 +127,8 @@ export default lockContextContainer(
) && presentationIsOpen,
presentationIsDownloadable,
mountPresentation: !!currentSlide,
currentPresentation: PresentationService.getCurrentPresentation(podId),
currentPresentation,
currentPresentationId: currentPresentation?.id,
numPages,
notify,
zoomSlide: PresentationToolbarService.zoomSlide,

View File

@ -423,6 +423,9 @@ class PresentationToolbar extends PureComponent {
? intl.formatMessage(intlMessages.fitToPage)
: intl.formatMessage(intlMessages.fitToWidth)}
hideLabel
{...{
fitToWidth,
}}
/>
</Styled.PresentationZoomControls>
</Styled.PresentationToolbarWrapper>

View File

@ -194,16 +194,16 @@ const FitToWidthButton = styled(Button)`
box-shadow: none !important;
border: 0;
${({ fitToWidth }) => fitToWidth && `
& > span {
border: solid ${borderSizeLarge} ${colorGrayDark};
}
`}
&:focus {
background-color: ${colorOffWhite};
border: 0;
}
${({ panning }) => panning && `
> span {
background-color: #DCE4EC;
}
`}
`;
const MultiUserTool = styled.span`

View File

@ -36,6 +36,7 @@ const propTypes = {
conversion: PropTypes.shape,
upload: PropTypes.shape,
})).isRequired,
currentPresentation: PropTypes.string.isRequired,
isOpen: PropTypes.bool.isRequired,
handleFiledrop: PropTypes.func.isRequired,
selectedToBeNextCurrent: PropTypes.string,
@ -53,7 +54,7 @@ const defaultProps = {
};
const intlMessages = defineMessages({
current: {
currentBadge: {
id: 'app.presentationUploder.currentBadge',
},
title: {
@ -357,7 +358,7 @@ class PresentationUploader extends Component {
}
componentDidUpdate(prevProps) {
const { isOpen, presentations: propPresentations, intl } = this.props;
const { isOpen, presentations: propPresentations, currentPresentation, intl } = this.props;
const { presentations } = this.state;
const { presentations: prevPropPresentations } = prevProps;
@ -432,7 +433,7 @@ class PresentationUploader extends Component {
unregisterTitleView();
}
// Updates presentation list when chat modal opens to avoid missing presentations
// Updates presentation list when modal opens to avoid missing presentations
if (isOpen && !prevProps.isOpen) {
registerTitleView(intl.formatMessage(intlMessages.uploadViewTitle));
const focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
@ -458,6 +459,10 @@ class PresentationUploader extends Component {
});
}
if (currentPresentation && currentPresentation !== prevProps.currentPresentation) {
this.handleCurrentChange(currentPresentation);
}
if (presentations.length > 0) {
const selected = propPresentations.filter((p) => p.isCurrent);
if (selected.length > 0) Session.set('selectedToBeNextCurrent', selected[0].id);
@ -547,7 +552,7 @@ class PresentationUploader extends Component {
handleCurrentChange(id) {
const { presentations, disableActions } = this.state;
if (disableActions) return;
if (disableActions || presentations?.length === 0) return;
const currentIndex = presentations.findIndex((p) => p.isCurrent);
const newCurrentIndex = presentations.findIndex((p) => p.id === id);
@ -883,31 +888,18 @@ class PresentationUploader extends Component {
renderToastExportItem(item) {
const { status } = item.exportation;
const loading = (status === EXPORT_STATUSES.RUNNING
|| status === EXPORT_STATUSES.COLLECTING
|| status === EXPORT_STATUSES.PROCESSING);
const loading = [EXPORT_STATUSES.RUNNING, EXPORT_STATUSES.COLLECTING,
EXPORT_STATUSES.PROCESSING].includes(status);
const done = status === EXPORT_STATUSES.EXPORTED;
let icon;
const statusIconMap = {
[EXPORT_STATUSES.RUNNING]: 'blank',
[EXPORT_STATUSES.COLLECTING]: 'blank',
[EXPORT_STATUSES.PROCESSING]: 'blank',
[EXPORT_STATUSES.EXPORTED]: 'check',
[EXPORT_STATUSES.TIMEOUT]: 'warning',
};
switch (status) {
case EXPORT_STATUSES.RUNNING:
icon = 'blank';
break;
case EXPORT_STATUSES.COLLECTING:
icon = 'blank';
break;
case EXPORT_STATUSES.PROCESSING:
icon = 'blank';
break;
case EXPORT_STATUSES.EXPORTED:
icon = 'check';
break;
case EXPORT_STATUSES.TIMEOUT:
icon = 'warning';
break;
default:
break;
}
const icon = statusIconMap[status] || '';
return (
<Styled.UploadRow
@ -1039,7 +1031,7 @@ class PresentationUploader extends Component {
? (
<Styled.TableItemCurrent>
<Styled.CurrentLabel>
{intl.formatMessage(intlMessages.current)}
{intl.formatMessage(intlMessages.currentBadge)}
</Styled.CurrentLabel>
</Styled.TableItemCurrent>
)

View File

@ -26,7 +26,8 @@ const PresentationUploaderContainer = (props) => {
};
export default withTracker(() => {
const currentPresentations = Service.getPresentations();
const presentations = Service.getPresentations();
const currentPresentation = presentations.find((p) => p.isCurrent)?.id || '';
const {
dispatchDisableDownloadable,
dispatchEnableDownloadable,
@ -36,7 +37,8 @@ export default withTracker(() => {
const isOpen = isPresentationEnabled() && (Session.get('showUploadPresentationView') || false);
return {
presentations: currentPresentations,
presentations,
currentPresentation,
fileUploadConstraintsHint: PRESENTATION_CONFIG.fileUploadConstraintsHint,
fileSizeMax: PRESENTATION_CONFIG.mirroredFromBBBCore.uploadSizeMax,
filePagesMax: PRESENTATION_CONFIG.mirroredFromBBBCore.uploadPagesMax,

View File

@ -385,7 +385,7 @@ const exportPresentationToChat = (presentationId, observer) => {
const cursor = Presentations.find({ id: presentationId });
const checkStatus = (exportation) => {
const shouldStop = lastStatus.status === 'RUNNING' && exportation.status === 'EXPORTED';
const shouldStop = ['RUNNING', 'PROCESSING'].includes(lastStatus.status) && exportation.status === 'EXPORTED';
if (shouldStop) {
observer(exportation, true);

View File

@ -56,9 +56,7 @@ const getCurrentSlide = (podId) => {
});
};
const getSlidesLength = (podId) => {
return getCurrentPresentation(podId)?.pages?.length || 0;
}
const getSlidesLength = (podId) => getCurrentPresentation(podId)?.pages?.length || 0;
const getSlidePosition = (podId, presentationId, slideId) => SlidePositions.findOne({
podId,
@ -87,7 +85,7 @@ const parseCurrentSlideContent = (yesValue, noValue, abstentionValue, trueValue,
content,
} = currentSlide;
const questionRegex = /.*?\?/gm;
const questionRegex = /^.+\?\s*$/gm;
const question = safeMatch(questionRegex, content, '');
if (question?.length > 0) {

View File

@ -152,7 +152,7 @@ class Settings extends Component {
const { intl } = this.props;
if (textOnly) {
return status ? intl.formatMessage(intlMessages.on)
: intl.formatMessage(intlMessages.off)
: intl.formatMessage(intlMessages.off);
}
return (
<Styled.ToggleLabel aria-hidden>

View File

@ -117,6 +117,9 @@ const intlMessages = defineMessages({
id: 'app.layout.style.customPush',
description: 'label for custom layout style (push to all)',
},
disableLabel: {
id: 'app.videoDock.webcamDisableLabel',
}
});
class ApplicationMenu extends BaseMenu {
@ -447,6 +450,28 @@ class ApplicationMenu extends BaseMenu {
</Styled.Col>
</Styled.Row>
<Styled.Row>
<Styled.Col aria-hidden="true">
<Styled.FormElement>
<Styled.Label>
{intl.formatMessage(intlMessages.disableLabel)}
</Styled.Label>
</Styled.FormElement>
</Styled.Col>
<Styled.Col>
<Styled.FormElementRight>
{displaySettingsStatus(settings.disableCam)}
<Toggle
icons={false}
defaultChecked={settings.selfViewDisable}
onChange={() => this.handleToggle('selfViewDisable')}
ariaLabel={`${intl.formatMessage(intlMessages.disableLabel)} - ${displaySettingsStatus(settings.selfViewDisable, false)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>
</Styled.Col>
</Styled.Row>
<Styled.Row>
<Styled.Col>
<Styled.FormElement>

View File

@ -131,22 +131,11 @@ export default withTracker(() => {
let groupChatMessageHandler = {};
if (isChatEnabled() && ready) {
const chatsCount = GroupChat.find({
$or: [
{
meetingId,
access: PUBLIC_CHAT_TYPE,
chatId: { $ne: PUBLIC_GROUP_CHAT_ID },
},
{ meetingId, users: { $all: [requesterUserId] } },
],
}).count();
const subHandler = {
...subscriptionErrorHandler,
};
groupChatMessageHandler = Meteor.subscribe('group-chat-msg', chatsCount, subHandler);
groupChatMessageHandler = Meteor.subscribe('group-chat-msg', subHandler);
}
// TODO: Refactor all the late subscribers

View File

@ -337,14 +337,14 @@ const getActiveChats = ({ groupChatsMessages, groupChats, users }) => {
} else if (b.unreadCounter > a.unreadCounter) {
return 1;
} else {
if (a.name.toLowerCase() < b.name.toLowerCase()) {
return -1;
}
if (a.name.toLowerCase() > b.name.toLowerCase()) {
return 1;
}
return 0;
if (a.name.toLowerCase() < b.name.toLowerCase()) {
return -1;
}
if (a.name.toLowerCase() > b.name.toLowerCase()) {
return 1;
}
return 0;
}
});
return sortByChatIdAndUnread;
};
@ -641,15 +641,15 @@ const requestUserInformation = (userId) => {
};
const sortUsersByFirstName = (a, b) => {
const aUser = { name: a.firstName ? a.firstName : '' };
const bUser = { name: b.firstName ? b.firstName : '' };
const aUser = { sortName: a.firstName ? a.firstName : '' };
const bUser = { sortName: b.firstName ? b.firstName : '' };
return sortUsersByName(aUser, bUser);
};
const sortUsersByLastName = (a, b) => {
const aUser = { name: a.lastName ? a.lastName : '' };
const bUser = { name: b.lastName ? b.lastName : '' };
const aUser = { sortName: a.lastName ? a.lastName : '' };
const bUser = { sortName: b.lastName ? b.lastName : '' };
return sortUsersByName(aUser, bUser);
};

View File

@ -7,8 +7,10 @@ import Service from '/imports/ui/components/user-list/service';
import Auth from '/imports/ui/services/auth';
import { withTracker } from 'meteor/react-meteor-data';
import Storage from '/imports/ui/services/storage/session';
import { Session } from 'meteor/session';
const CLOSED_CHAT_LIST_KEY = 'closedChatList';
const STARTED_CHAT_LIST_KEY = 'startedChatList';
const UserMessagesContainer = () => {
const usingChatContext = useContext(ChatContext);
@ -28,5 +30,6 @@ export default withTracker(() => {
// We need to rerender this component whenever this
// Storage variable changes.
Storage.getItem(CLOSED_CHAT_LIST_KEY);
Session.get(STARTED_CHAT_LIST_KEY);
return {};
})(UserMessagesContainer);

View File

@ -1,6 +1,6 @@
import logger from '/imports/startup/client/logger';
const MIME_TYPES_ALLOWED = ['image/png', 'image/jpeg'];
const MIME_TYPES_ALLOWED = ['image/png', 'image/jpeg', 'image/webp'];
const MAX_FILE_SIZE = 5000; // KBytes
const withObjectStore = ({

View File

@ -4,7 +4,6 @@ import ButtonEmoji from '/imports/ui/components/common/button/button-emoji/Butto
import VideoService from '../service';
import { defineMessages, injectIntl } from 'react-intl';
import Styled from './styles';
import { validIOSVersion } from '/imports/ui/components/app/service';
import deviceInfo from '/imports/utils/deviceInfo';
import { debounce } from 'radash';
import BBBMenu from '/imports/ui/components/common/menu/component';
@ -52,10 +51,6 @@ const intlMessages = defineMessages({
id: 'app.video.clientDisconnected',
description: 'Meteor disconnected label',
},
iOSWarning: {
id: 'app.iOSWarning.label',
description: 'message indicating to upgrade ios version',
},
});
const JOIN_VIDEO_DELAY_MILLISECONDS = 500;
@ -89,10 +84,6 @@ const JoinVideoButton = ({
const [isVideoPreviewModalOpen, setVideoPreviewModalIsOpen] = useState(false);
const handleOnClick = debounce({ delay: JOIN_VIDEO_DELAY_MILLISECONDS }, () => {
if (!validIOSVersion()) {
return VideoService.notify(intl.formatMessage(intlMessages.iOSWarning));
}
switch (status) {
case 'videoConnecting':
VideoService.stopVideo();

View File

@ -5,6 +5,7 @@ import VideoService from '/imports/ui/components/video-provider/service';
import { layoutSelect, layoutSelectOutput, layoutDispatch } from '../../layout/context';
import { UsersContext } from '/imports/ui/components/components-data/users-context/context';
import Auth from '/imports/ui/services/auth';
import Users from '/imports/api/users';
const VideoListContainer = ({ children, ...props }) => {
const layoutType = layoutSelect((i) => i.layoutType);
@ -41,7 +42,17 @@ const VideoListContainer = ({ children, ...props }) => {
);
};
export default withTracker((props) => ({
numberOfPages: VideoService.getNumberOfPages(),
...props,
}))(VideoListContainer);
export default withTracker((props) => {
const { streams } = props;
return {
...props,
numberOfPages: VideoService.getNumberOfPages(),
streams: streams.filter((stream) => Users.findOne({ userId: stream.userId },
{
fields: {
userId: 1,
},
})),
};
})(VideoListContainer);

View File

@ -1,5 +1,6 @@
/* eslint-disable no-nested-ternary */
import React, { useEffect, useRef, useState } from 'react';
import { injectIntl } from 'react-intl';
import { injectIntl, defineMessages, useIntl } from 'react-intl';
import PropTypes from 'prop-types';
import UserActions from '/imports/ui/components/video-provider/video-list/video-list-item/user-actions/component';
import UserStatus from '/imports/ui/components/video-provider/video-list/video-list-item/user-status/component';
@ -15,6 +16,13 @@ import Settings from '/imports/ui/services/settings';
import VideoService from '/imports/ui/components/video-provider/service';
import Styled from './styles';
import { withDragAndDrop } from './drag-and-drop/component';
import Auth from '/imports/ui/services/auth';
const intlMessages = defineMessages({
disableDesc: {
id: 'app.videoDock.webcamDisableDesc',
},
});
const VIDEO_CONTAINER_WIDTH_BOUND = 125;
@ -25,10 +33,13 @@ const VideoListItem = (props) => {
makeDragOperations, dragging, draggingOver, isRTL, isStream,
} = props;
const intl = useIntl();
const [videoDataLoaded, setVideoDataLoaded] = useState(false);
const [isStreamHealthy, setIsStreamHealthy] = useState(false);
const [isMirrored, setIsMirrored] = useState(VideoService.mirrorOwnWebcam(user?.userId));
const [isVideoSqueezed, setIsVideoSqueezed] = useState(false);
const [isSelfViewDisabled, setIsSelfViewDisabled] = useState(false);
const resizeObserver = new ResizeObserver((entry) => {
if (entry && entry[0]?.contentRect?.width < VIDEO_CONTAINER_WIDTH_BOUND) {
@ -40,7 +51,7 @@ const VideoListItem = (props) => {
const videoTag = useRef();
const videoContainer = useRef();
const videoIsReady = isStreamHealthy && videoDataLoaded;
const videoIsReady = isStreamHealthy && videoDataLoaded && !isSelfViewDisabled;
const { animations } = Settings.application;
const talking = voiceUser?.talking;
@ -88,14 +99,13 @@ const VideoListItem = (props) => {
});
}
};
// This is here to prevent the videos from freezing when they're
// moved around the dom by react, e.g., when changing the user status
// see https://bugs.chromium.org/p/chromium/issues/detail?id=382879
if (videoDataLoaded) {
if (!isSelfViewDisabled && videoDataLoaded) {
playElement(videoTag.current);
}
}, [videoDataLoaded]);
if (isSelfViewDisabled && user.userId === Auth.userID) {
videoTag.current.pause();
}
}, [isSelfViewDisabled, videoDataLoaded]);
// component will unmount
useEffect(() => () => {
@ -103,6 +113,10 @@ const VideoListItem = (props) => {
onVideoItemUnmount(cameraId);
}, []);
useEffect(() => {
setIsSelfViewDisabled(Settings.application.selfViewDisable);
}, [Settings.application.selfViewDisable]);
const renderSqueezedButton = () => (
<UserActions
name={name}
@ -116,6 +130,7 @@ const VideoListItem = (props) => {
onHandleMirror={() => setIsMirrored((value) => !value)}
isRTL={isRTL}
isStream={isStream}
onHandleDisableCam={() => setIsSelfViewDisabled((value) => !value)}
/>
);
@ -141,6 +156,7 @@ const VideoListItem = (props) => {
onHandleMirror={() => setIsMirrored((value) => !value)}
isRTL={isRTL}
isStream={isStream}
onHandleDisableCam={() => setIsSelfViewDisabled((value) => !value)}
/>
<UserStatus
voiceUser={voiceUser}
@ -175,6 +191,7 @@ const VideoListItem = (props) => {
cameraId={cameraId}
isFullscreenContext={isFullscreenContext}
layoutContextDispatch={layoutContextDispatch}
isStream={isStream}
/>
</Styled.TopBar>
<Styled.BottomBar>
@ -188,6 +205,7 @@ const VideoListItem = (props) => {
onHandleMirror={() => setIsMirrored((value) => !value)}
isRTL={isRTL}
isStream={isStream}
onHandleDisableCam={() => setIsSelfViewDisabled((value) => !value)}
/>
<UserStatus
voiceUser={voiceUser}
@ -209,7 +227,13 @@ const VideoListItem = (props) => {
draggingOver,
}}
>
<Styled.VideoContainer>
{isSelfViewDisabled && user.userId === Auth.userID && (
<Styled.VideoDisabled>
{intl.formatMessage(intlMessages.disableDesc)}
</Styled.VideoDisabled>
)}
<Styled.Video
mirrored={isMirrored}
unhealthyStream={videoDataLoaded && !isStreamHealthy}
@ -222,13 +246,14 @@ const VideoListItem = (props) => {
</Styled.VideoContainer>
{/* eslint-disable-next-line no-nested-ternary */}
{videoIsReady
? (isVideoSqueezed)
? renderSqueezedButton()
: renderDefaultButtons()
: (isVideoSqueezed)
? renderWebcamConnectingSqueezed()
: renderWebcamConnecting()}
{(videoIsReady || isSelfViewDisabled) && (
isVideoSqueezed ? renderSqueezedButton() : renderDefaultButtons()
)}
{!videoIsReady && (!isSelfViewDisabled || !isStream) && (
isVideoSqueezed ? renderWebcamConnectingSqueezed() : renderWebcamConnecting()
)}
</Styled.Content>
);
};

View File

@ -133,6 +133,23 @@ const Video = styled.video`
`}
`;
const VideoDisabled = styled.div`
color: white;
width: 100%;
height: 20%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
position: absolute;
border-radius: 10px;
z-index: 2;
top: 40%;
padding: 20px;
backdrop-filter: blur(10px);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}`;
const TopBar = styled.div`
position: absolute;
display: flex;
@ -161,4 +178,5 @@ export default {
Video,
TopBar,
BottomBar,
VideoDisabled,
};

View File

@ -6,6 +6,9 @@ import FullscreenService from '/imports/ui/components/common/fullscreen-button/s
import BBBMenu from '/imports/ui/components/common/menu/component';
import PropTypes from 'prop-types';
import Styled from './styles';
import Auth from '/imports/ui/services/auth';
import Settings from '/imports/ui/services/settings';
import { updateSettings } from '/imports/ui/components/settings/service';
const intlMessages = defineMessages({
focusLabel: {
@ -26,6 +29,9 @@ const intlMessages = defineMessages({
unpinLabel: {
id: 'app.videoDock.webcamUnpinLabel',
},
disableLabel: {
id: 'app.videoDock.webcamDisableLabel',
},
pinDesc: {
id: 'app.videoDock.webcamPinDesc',
},
@ -46,6 +52,9 @@ const intlMessages = defineMessages({
id: 'app.videoDock.webcamSqueezedButtonLabel',
description: 'User selected webcam squeezed options',
},
disableDesc: {
id: 'app.videoDock.webcamDisableDesc',
},
});
const UserActions = (props) => {
@ -66,30 +75,50 @@ const UserActions = (props) => {
const menuItems = [];
const toggleDisableCam = () => {
const applicationValues = { ...Settings.application };
applicationValues.selfViewDisable = !Settings.application.selfViewDisable;
updateSettings({
...Settings,
application: applicationValues,
});
};
if (isVideoSqueezed) {
menuItems.push({
key: `${cameraId}-name`,
label: name,
description: name,
onClick: () => {},
onClick: () => { },
disabled: true,
});
menuItems.push(
{
key: `${cameraId}-fullscreen`,
label: intl.formatMessage(intlMessages.fullscreenLabel),
description: intl.formatMessage(intlMessages.fullscreenLabel),
onClick: () => FullscreenService.toggleFullScreen(videoContainer.current),
},
);
if (isStream) {
menuItems.push(
{
key: `${cameraId}-fullscreen`,
label: intl.formatMessage(intlMessages.fullscreenLabel),
description: intl.formatMessage(intlMessages.fullscreenLabel),
onClick: () => FullscreenService.toggleFullScreen(videoContainer.current),
},
);
}
}
if (userId === Auth.userID && isStream) {
menuItems.push({
key: `${cameraId}-disable`,
label: intl.formatMessage(intlMessages.disableLabel),
description: intl.formatMessage(intlMessages.disableDesc),
onClick: () => toggleDisableCam(cameraId),
dataTest: 'selfViewDisableBtn',
});
}
menuItems.push({
key: `${cameraId}-mirror`,
label: intl.formatMessage(intlMessages.mirrorLabel),
description: intl.formatMessage(intlMessages.mirrorDesc),
onClick: () => onHandleMirror(),
onClick: () => onHandleMirror(cameraId),
dataTest: 'mirrorWebcamBtn',
});
@ -131,7 +160,7 @@ const UserActions = (props) => {
size="sm"
onClick={() => null}
/>
)}
)}
actions={getAvailableActions()}
/>
</Styled.MenuWrapperSqueezed>
@ -185,14 +214,15 @@ export default UserActions;
UserActions.defaultProps = {
focused: false,
isVideoSqueezed: false,
videoContainer: () => {},
videoContainer: () => { },
onHandleVideoFocus: () => {},
};
UserActions.propTypes = {
name: PropTypes.string.isRequired,
cameraId: PropTypes.string.isRequired,
numOfStreams: PropTypes.number.isRequired,
onHandleVideoFocus: PropTypes.func.isRequired,
onHandleVideoFocus: PropTypes.func,
user: PropTypes.shape({
pin: PropTypes.bool.isRequired,
userId: PropTypes.string.isRequired,
@ -204,4 +234,5 @@ UserActions.propTypes = {
PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
]),
onHandleMirror: PropTypes.func.isRequired,
onHandleDisableCam: PropTypes.func.isRequired,
};

View File

@ -13,7 +13,8 @@ const UserAvatarVideo = (props) => {
presenter, clientType,
} = user;
const { muted, talking } = voiceUser;
const muted = voiceUser?.muted || false;
const talking = voiceUser?.talking || false;
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;

View File

@ -6,7 +6,7 @@ import Styled from './styles';
const ViewActions = (props) => {
const {
name, cameraId, videoContainer, isFullscreenContext, layoutContextDispatch,
name, cameraId, videoContainer, isFullscreenContext, layoutContextDispatch, isStream,
} = props;
const ALLOW_FULLSCREEN = Meteor.settings.public.app.allowFullscreen;
@ -24,7 +24,7 @@ const ViewActions = (props) => {
}
}, []);
if (!ALLOW_FULLSCREEN) return null;
if (!ALLOW_FULLSCREEN || !isStream) return null;
return (
<Styled.FullscreenWrapper>

View File

@ -155,7 +155,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}
@ -227,7 +233,7 @@ const WebcamComponent = ({
}}
style={{
position: 'absolute',
zIndex: cameraDock.zIndex,
zIndex: isCameraSidebar ? 0 : cameraDock.zIndex,
}}
>
<Styled.Draggable
@ -237,9 +243,9 @@ const WebcamComponent = ({
role="region"
draggable={cameraDock.isDraggable && !isFullscreen ? 'true' : undefined}
style={{
width: `${isDragging ? cameraSize.width : cameraDock.width}pt`,
height: `${isDragging ? cameraSize.height : cameraDock.height}pt`,
opacity: isDragging ? 0.5 : undefined,
width: isIphone ? mobileWidth : isDesktopWidth,
height: isIphone ? mobileHeight : isDesktopHeight,
opacity: camOpacity,
background: isCameraSidebar ? colorContentBackground : null,
}}
>

View File

@ -9,10 +9,13 @@ const intlMessages = defineMessages({
},
});
const DropArea = ({ id, style, intl }) => (
const DropArea = ({
id, dataTest, style, intl,
}) => (
<>
<Styled.DropZoneArea
id={id}
data-test={dataTest}
style={
{
...style,

View File

@ -7,7 +7,7 @@ const DropAreaContainer = () => {
return (
Object.keys(dropZoneAreas).map((objectKey) => (
<DropArea key={objectKey} id={objectKey} style={dropZoneAreas[objectKey]} />
<DropArea dataTest={`dropArea-${objectKey}`} key={objectKey} id={objectKey} style={dropZoneAreas[objectKey]} />
))
);
};

View File

@ -50,7 +50,8 @@ const WhiteboardContainer = (props) => {
const hasShapeAccess = (id) => {
const owner = shapes[id]?.userId;
const isBackgroundShape = id?.includes('slide-background');
const hasAccess = !isBackgroundShape
const isPollsResult = shapes[id]?.name?.includes('poll-result');
const hasAccess = !isBackgroundShape && !isPollsResult || isPresenter
&& ((owner && owner === currentUser?.userId) || !owner || isPresenter || isModerator);
return hasAccess;
};

View File

@ -221,7 +221,7 @@ const Cursors = (props) => {
React.useEffect(() => {
const currentCursor = cursorWrapper?.current;
currentCursor?.addEventListener('mouseenter', start);
currentCursor?.addEventListener('touchstart', start);
currentCursor?.addEventListener('touchstart', start);
currentCursor?.addEventListener('mouseleave', end);
currentCursor?.addEventListener('mousedown', handleGrabbing);
currentCursor?.addEventListener('mouseup', handleReleaseGrab);
@ -231,7 +231,7 @@ const Cursors = (props) => {
return () => {
currentCursor?.removeEventListener('mouseenter', start);
currentCursor?.addEventListener('touchstart', start);
currentCursor?.addEventListener('touchstart', start);
currentCursor?.removeEventListener('mouseleave', end);
currentCursor?.removeEventListener('mousedown', handleGrabbing);
currentCursor?.removeEventListener('mouseup', handleReleaseGrab);
@ -241,7 +241,8 @@ const Cursors = (props) => {
};
}, [cursorWrapper, whiteboardId, currentUser.presenter, whiteboardToolbarAutoHide]);
let cursorType = multiUserAccess || currentUser?.presenter ? TOOL_CURSORS[currentTool] || 'none' : 'default';
let cursorType = multiUserAccess || currentUser?.presenter ? TOOL_CURSORS[currentTool] : 'default';
if (isPanning) {
if (panGrabbing) {
cursorType = TOOL_CURSORS.grabbing;
@ -250,7 +251,6 @@ const Cursors = (props) => {
}
}
if (isMoving) cursorType = TOOL_CURSORS.moving;
return (
<span key={`cursor-wrapper-${whiteboardId}`} ref={cursorWrapper}>
<div style={{ height: '100%', cursor: cursorType }}>

View File

@ -1,5 +1,5 @@
import * as React from 'react';
import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import PropTypes from 'prop-types';
import { HUNDRED_PERCENT } from '/imports/utils/slideCalcUtils';
import Styled from '../styles';
@ -77,7 +77,10 @@ class PanToolInjector extends React.Component {
});
const container = document.createElement('span');
parentElement.appendChild(container);
ReactDOM.render(
const root = createRoot(container);
root.render(
<Styled.PanTool
key="bbb-panBtn"
role="button"
@ -107,8 +110,8 @@ class PanToolInjector extends React.Component {
panSelected,
}}
/>,
container,
);
const { lastChild } = parentElement;
const secondChild = parentElement.children[1];
parentElement.insertBefore(lastChild, secondChild);

View File

@ -89,8 +89,11 @@ export function initAnnotationsStreamListener() {
annotationsStreamListener.on('removed', handleRemovedAnnotation);
annotationsStreamListener.on('added', ({ annotations }) => {
annotations.forEach(async (annotation) => handleAddedAnnotation(annotation));
annotationsStreamListener.on('added', async ({ annotations }) => {
await Promise.all(annotations.map(async (annotation) => {
const addedHandeler = await handleAddedAnnotation(annotation);
return addedHandeler;
}));
});
});
}

View File

@ -89,7 +89,7 @@ const TldrawGlobalStyle = createGlobalStyle`
}
}
`}
${({ isPresenter }) => (!isPresenter) && `
${({ isPresenter, hasWBAccess }) => (!isPresenter && !hasWBAccess) && `
#presentationInnerWrapper div{
cursor: default !important;
}

View File

@ -13,6 +13,7 @@ const SETTINGS = [
'cc',
'dataSaving',
'animations',
'selfViewDisable',
];
const CHANGED_SETTINGS = 'changed_settings';
@ -59,7 +60,7 @@ class Settings {
}
loadChanged() {
const Storage = (APP_CONFIG.userSettingsStorage == 'local') ? LocalStorage : SessionStorage;
const Storage = (APP_CONFIG.userSettingsStorage === 'local') ? LocalStorage : SessionStorage;
const savedSettings = {};
SETTINGS.forEach((s) => {
@ -77,7 +78,7 @@ class Settings {
}
save(settings = CHANGED_SETTINGS) {
const Storage = (APP_CONFIG.userSettingsStorage == 'local') ? LocalStorage : SessionStorage;
const Storage = (APP_CONFIG.userSettingsStorage === 'local') ? LocalStorage : SessionStorage;
if (settings === CHANGED_SETTINGS) {
Object.keys(this).forEach((k) => {
const values = this[k].value;

View File

@ -9,14 +9,10 @@ const isTablet = BOWSER_RESULTS.platform.type === 'tablet' || (BOWSER_RESULTS.os
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));
const SUPPORTED_IOS_VERSION = 12.2;
const isIosVersionSupported = () => parseFloat(osVersion) >= SUPPORTED_IOS_VERSION;
const isPortrait = () => window.innerHeight > window.innerWidth;
const deviceInfo = {
@ -29,7 +25,6 @@ const deviceInfo = {
isIos,
isMacos,
isIphone,
isIosVersionSupported,
};
export default deviceInfo;

View File

@ -13,6 +13,7 @@ export const PDF = 'application/pdf';
export const JPEG = 'image/jpeg';
export const PNG = 'image/png';
export const SVG = 'image/svg+xml';
export const WEBP = 'image/webp';
export const UPLOAD_SUPORTED = [
XLS,

View File

@ -22,11 +22,11 @@
}
},
"@babel/helper-annotate-as-pure": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz",
"integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==",
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
"integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
"requires": {
"@babel/types": "^7.15.4"
"@babel/types": "^7.18.6"
}
},
"@babel/helper-function-name": {
@ -938,16 +938,16 @@
}
},
"@radix-ui/react-alert-dialog": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.2.tgz",
"integrity": "sha512-0MtxV53FaEEBOKRgyLnEqHZKKDS5BldQ9oUBsKVXWI5FHbl2jp35qs+0aJET+K5hJDsc40kQUzP7g+wC7tqrqA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.3.tgz",
"integrity": "sha512-QXFy7+bhGi0u+paF2QbJeSCHZs4gLMJIPm6sajUamyW0fro6g1CaSGc5zmc4QmK2NlSGUrq8m+UsUqJYtzvXow==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-dialog": "1.0.2",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-dialog": "1.0.3",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1"
}
},
@ -1063,21 +1063,21 @@
}
},
"@radix-ui/react-dialog": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.2.tgz",
"integrity": "sha512-EKxxp2WNSmUPkx4trtWNmZ4/vAYEg7JkAfa1HKBUnaubw9eHzf1Orr9B472lJYaYz327RHDrd4R95fsw7VR8DA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.3.tgz",
"integrity": "sha512-owNhq36kNPqC2/a+zJRioPg6HHnTn5B/sh/NjTY8r4W9g1L5VJlrzZIVcBr7R9Mg8iLjVmh6MGgMlfoVf/WO/A==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-dismissable-layer": "1.0.2",
"@radix-ui/react-dismissable-layer": "1.0.3",
"@radix-ui/react-focus-guards": "1.0.0",
"@radix-ui/react-focus-scope": "1.0.1",
"@radix-ui/react-focus-scope": "1.0.2",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-portal": "1.0.1",
"@radix-ui/react-portal": "1.0.2",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.0",
"aria-hidden": "^1.1.1",
@ -1093,14 +1093,14 @@
}
},
"@radix-ui/react-dismissable-layer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz",
"integrity": "sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.3.tgz",
"integrity": "sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-escape-keydown": "1.0.2"
}
@ -1149,13 +1149,13 @@
}
},
"@radix-ui/react-focus-scope": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz",
"integrity": "sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.2.tgz",
"integrity": "sha512-spwXlNTfeIprt+kaEWE/qYuYT3ZAqJiAGjN/JgdvgVDTu8yc+HuX+WOWXrKliKnLnwck0F6JDkqIERncnih+4A==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0"
}
},
@ -1274,22 +1274,22 @@
}
},
"@radix-ui/react-popover": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.2.tgz",
"integrity": "sha512-4tqZEl9w95R5mlZ/sFdgBnfhCBOEPepLIurBA5kt/qaAhldJ1tNQd0ngr0ET0AHbPotT4mwxMPr7a+MA/wbK0g==",
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.5.tgz",
"integrity": "sha512-GRHZ8yD12MrN2NLobHPE8Rb5uHTxd9x372DE9PPNnBjpczAQHcZ5ne0KXG4xpf+RDdXSzdLv9ym6mYJCDTaUZg==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-dismissable-layer": "1.0.2",
"@radix-ui/react-dismissable-layer": "1.0.3",
"@radix-ui/react-focus-guards": "1.0.0",
"@radix-ui/react-focus-scope": "1.0.1",
"@radix-ui/react-focus-scope": "1.0.2",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-popper": "1.0.1",
"@radix-ui/react-portal": "1.0.1",
"@radix-ui/react-popper": "1.1.1",
"@radix-ui/react-portal": "1.0.2",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.0",
"aria-hidden": "^1.1.1",
@ -1297,25 +1297,26 @@
},
"dependencies": {
"@radix-ui/react-arrow": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz",
"integrity": "sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.2.tgz",
"integrity": "sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.1"
"@radix-ui/react-primitive": "1.0.2"
}
},
"@radix-ui/react-popper": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz",
"integrity": "sha512-J4Vj7k3k+EHNWgcKrE+BLlQfpewxA7Zd76h5I0bIa+/EqaIZ3DuwrbPj49O3wqN+STnXsBuxiHLiF0iU3yfovw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.1.tgz",
"integrity": "sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==",
"requires": {
"@babel/runtime": "^7.13.10",
"@floating-ui/react-dom": "0.7.2",
"@radix-ui/react-arrow": "1.0.1",
"@radix-ui/react-arrow": "1.0.2",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-layout-effect": "1.0.0",
"@radix-ui/react-use-rect": "1.0.0",
"@radix-ui/react-use-size": "1.0.0",
@ -1362,12 +1363,12 @@
}
},
"@radix-ui/react-portal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.1.tgz",
"integrity": "sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.2.tgz",
"integrity": "sha512-swu32idoCW7KA2VEiUZGBSu9nB6qwGdV6k6HYhUoOo3M1FFpD+VgLzUqtt3mwL1ssz7r2x8MggpLSQach2Xy/Q==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.1"
"@radix-ui/react-primitive": "1.0.2"
}
},
"@radix-ui/react-presence": {
@ -1381,9 +1382,9 @@
}
},
"@radix-ui/react-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz",
"integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
"integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
@ -1436,45 +1437,46 @@
}
},
"@radix-ui/react-tooltip": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.2.tgz",
"integrity": "sha512-11gUlok2rv5mu+KBtxniOKKNKjqC/uTbgFHWoQdbF46vMV+zjDaBvCtVDK9+MTddlpmlisGPGvvojX7Qm0yr+g==",
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.5.tgz",
"integrity": "sha512-cDKVcfzyO6PpckZekODJZDe5ZxZ2fCZlzKzTmPhe4mX9qTHRfLcKgqb0OKf22xLwDequ2tVleim+ZYx3rabD5w==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-dismissable-layer": "1.0.2",
"@radix-ui/react-dismissable-layer": "1.0.3",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-popper": "1.0.1",
"@radix-ui/react-portal": "1.0.1",
"@radix-ui/react-popper": "1.1.1",
"@radix-ui/react-portal": "1.0.2",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.0",
"@radix-ui/react-visually-hidden": "1.0.1"
"@radix-ui/react-visually-hidden": "1.0.2"
},
"dependencies": {
"@radix-ui/react-arrow": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz",
"integrity": "sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.2.tgz",
"integrity": "sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.1"
"@radix-ui/react-primitive": "1.0.2"
}
},
"@radix-ui/react-popper": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz",
"integrity": "sha512-J4Vj7k3k+EHNWgcKrE+BLlQfpewxA7Zd76h5I0bIa+/EqaIZ3DuwrbPj49O3wqN+STnXsBuxiHLiF0iU3yfovw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.1.tgz",
"integrity": "sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==",
"requires": {
"@babel/runtime": "^7.13.10",
"@floating-ui/react-dom": "0.7.2",
"@radix-ui/react-arrow": "1.0.1",
"@radix-ui/react-arrow": "1.0.2",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-layout-effect": "1.0.0",
"@radix-ui/react-use-rect": "1.0.0",
"@radix-ui/react-use-size": "1.0.0",
@ -1536,12 +1538,12 @@
}
},
"@radix-ui/react-visually-hidden": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz",
"integrity": "sha512-K1hJcCMfWfiYUibRqf3V8r5Drpyf7rh44jnrwAbdvI5iCCijilBBeyQv9SKidYNZIopMdCyR9FnIjkHxHN0FcQ==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.2.tgz",
"integrity": "sha512-qirnJxtYn73HEk1rXL12/mXnu2rwsNHDID10th2JGtdK25T9wX+mxRmGt7iPSahw512GbZOc0syZX1nLQGoEOg==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.1"
"@radix-ui/react-primitive": "1.0.2"
}
},
"@radix-ui/rect": {
@ -1558,22 +1560,22 @@
"integrity": "sha512-9g9dWI4gsSVe8bNLlb+lMkBYsnIKCZTmvqvDG+Avnn69XfmHZKiaMrx7cgTaddq7aTPPmXiTsbFcUy0xgI4+wA=="
},
"@tldraw/core": {
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/@tldraw/core/-/core-1.21.0.tgz",
"integrity": "sha512-3hvYLR/XwpMI9GvHIHGfYNmkiaKlokx8vekx0Eq/o/NAkqGkGwnZcTG5shbetWzwQTTi5F4vWInJqA/BfX+OCA==",
"version": "1.23.2",
"resolved": "https://registry.npmjs.org/@tldraw/core/-/core-1.23.2.tgz",
"integrity": "sha512-cx+KfqemSHvVonNGwEolosMOsJt5cl3PGRBaXcZOOXQxnFALF22dnMtm6lbmlQQA71EfqNMP5e+qV3jCwuYaqA==",
"requires": {
"@tldraw/intersect": "^1.8.0",
"@tldraw/vec": "^1.8.0",
"@tldraw/intersect": "^1.9.2",
"@tldraw/vec": "^1.9.2",
"@use-gesture/react": "^10.2.19",
"perfect-freehand": "^1.1.0"
}
},
"@tldraw/intersect": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@tldraw/intersect/-/intersect-1.8.0.tgz",
"integrity": "sha512-0UarshNpyq2+O4o0xHMJIBgF0E630mes5CkMoO+D5xgYppSBIkeqYDcv0ujsmAhMKX1O6Y0ShuuHeflBEULUoQ==",
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/@tldraw/intersect/-/intersect-1.9.2.tgz",
"integrity": "sha512-teUQLy+p5YT4PIKOHaL+zM0NYD1779mPp02xabP+5LGLvv7tt9VaqJ9D899EYppQbBLN6be6CJUrmibrvLtnUQ==",
"requires": {
"@tldraw/vec": "^1.8.0"
"@tldraw/vec": "^1.9.2"
}
},
"@tldraw/tldraw": {
@ -1721,9 +1723,9 @@
}
},
"@tldraw/vec": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@tldraw/vec/-/vec-1.8.0.tgz",
"integrity": "sha512-GiS5Df3CzXY/fPBFcM0CKFERZfI4Cg1X33VPZX+NLo7Fwm/h9zu/aU24N1mG75Q9LuMnwKm7woxKr8BiUXGYCg=="
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/@tldraw/vec/-/vec-1.9.2.tgz",
"integrity": "sha512-k9vH52MRpJHjVcaahWu6VqvhLeE9h1qL5Z2gLobS9zTMpUJ59kBQPNo0VPzPlDYBpXdS4GxuB4jYQMnKvuPAZg=="
},
"@types/hoist-non-react-statics": {
"version": "3.3.1",
@ -1782,16 +1784,16 @@
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA=="
},
"@use-gesture/core": {
"version": "10.2.23",
"resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.23.tgz",
"integrity": "sha512-Ynap/Uh6RX1Vgn3zNmFTyKapapdf7Av+GzAe6h+RsBZaxMF1z3cK6aohHPJP6T1hLrPyH/yehxa7RBqyESG9RA=="
"version": "10.2.26",
"resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.26.tgz",
"integrity": "sha512-NyFpQ3iID9iFBROXyyvU1D0NK+t+dP+WAVByhCvqHUenpxLD2NlRLVRpoK3XGGwksr6mU3PvZ2Nm4q0q+gLJPA=="
},
"@use-gesture/react": {
"version": "10.2.23",
"resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.23.tgz",
"integrity": "sha512-anj9j3Lm4l+/s60Jv1FD2m13r+T+aYstSHUT62hTugojM64LPe9XatfEVHRyWOrGjRU2buQhlm03xN8oxkg/OQ==",
"version": "10.2.26",
"resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.2.26.tgz",
"integrity": "sha512-0QhaE5mhaQbFlip4MX7n1nwCX8gax6Da1LsP2fZ/BU6xW9zyEmV6NX7DPelDxq1rr2NiBJh30vx9RIp80YeA/A==",
"requires": {
"@use-gesture/core": "10.2.23"
"@use-gesture/core": "10.2.26"
}
},
"acorn": {
@ -2275,20 +2277,21 @@
}
},
"babel-plugin-styled-components": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.3.tgz",
"integrity": "sha512-meGStRGv+VuKA/q0/jXxrPNWEm4LPfYIqxooDTdmh8kFsP/Ph7jJG5rUPwUPX3QHUvggwdbgdGpo88P/rRYsVw==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.1.tgz",
"integrity": "sha512-c8lJlszObVQPguHkI+akXv8+Jgb9Ccujx0EetL7oIvwU100LxO6XAGe45qry37wUL40a5U9f23SYrivro2XKhA==",
"requires": {
"@babel/helper-annotate-as-pure": "^7.15.4",
"@babel/helper-module-imports": "^7.15.4",
"@babel/helper-annotate-as-pure": "^7.16.0",
"@babel/helper-module-imports": "^7.16.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.11"
"lodash": "^4.17.21",
"picomatch": "^2.3.0"
}
},
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
"integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw=="
},
"babel-runtime": {
"version": "6.26.0",
@ -4299,6 +4302,14 @@
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
},
"dependencies": {
"yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true
}
}
},
"debug": {
@ -5854,8 +5865,7 @@
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"please-upgrade-node": {
"version": "3.2.0",
@ -5978,12 +5988,11 @@
"integrity": "sha512-dye+7rERqNf/6mDT1iwps+4Gf42420xuZgygF33uX178DxffqcyeuHbBuJ382FIcB5iP6mMZOhfW7kI0uXwb/Q=="
},
"react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
"loose-envify": "^1.1.0"
}
},
"react-autosize-textarea": {
@ -6002,13 +6011,22 @@
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw=="
},
"react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"scheduler": "^0.20.2"
"scheduler": "^0.23.0"
},
"dependencies": {
"scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
"requires": {
"loose-envify": "^1.1.0"
}
}
}
},
"react-draggable": {
@ -7151,9 +7169,9 @@
"dev": true
},
"yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA=="
},
"zustand": {
"version": "4.3.2",

View File

@ -64,10 +64,10 @@
"queue": "^6.0.2",
"radash": "^10.7.0",
"re-resizable": "^4.11.0",
"react": "^17.0.2",
"react": "^18.2.0",
"react-autosize-textarea": "^5.0.1",
"react-colorful": "^5.6.1",
"react-dom": "^17.0.2",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.5",
"react-dropzone": "^7.0.1",
"react-intl": "^6.1.0",
@ -93,7 +93,7 @@
"wasm-check": "^2.0.3",
"webrtc-adapter": "^8.1.1",
"winston": "^3.7.2",
"yaml": "^1.7.2"
"yaml": "^2.2.2"
},
"devDependencies": {
"chai": "~4.2.0",

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
@ -702,7 +702,7 @@ public:
presentation:
allowDownloadable: true
panZoomThrottle: 32
restoreOnUpdate: false
restoreOnUpdate: true
uploadEndpoint: '/bigbluebutton/presentation/upload'
fileUploadConstraintsHint: false
# mirroredFromBBBCore are values controlled in bbb-web properties file. We include a copy here for notification purposes
@ -746,6 +746,8 @@ public:
mime: image/jpeg
- extension: .png
mime: image/png
- extension: .webp
mime: image/webp
selectRandomUser:
enabled: true
countdown: false

View File

@ -450,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Anwendung",
"app.submenu.application.animationsLabel": "Animationen",
"app.submenu.application.audioFilterLabel": "Audiofilter für das Mikrofon",
"app.submenu.application.wbToolbarsAutoHideLabel": "Symbolleisten des Whiteboards automatisch ausblenden",
"app.submenu.application.darkThemeLabel": "Dark-Mode",
"app.submenu.application.fontSizeControlLabel": "Schriftgröße",
"app.submenu.application.increaseFontBtnLabel": "Schriftgröße erhöhen",
@ -1168,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Einschalten (falls verfügbar)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Externes Video teilen",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Teilen von externem Video beenden",
"app.iOSWarning.label": "Bitte auf iOS 12.2 oder höher aktualisieren",
"app.legacy.unsupportedBrowser": "Es scheint, dass der verwendete Browser nicht unterstützt wird. Bitte {0} oder {1} verwenden.",
"app.legacy.upgradeBrowser": "Es sieht so aus, als ob eine veraltete Version eines unterstützten Browsers verwendet wird. Bitte den Browser aktualisieren für den vollen Funktionsumfang.",
"app.legacy.criosBrowser": "Unter iOS verwenden Sie für optimale Unterstützung bitte Safari.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Ενεργοποίηση (εάν είναι διαθέσιμο)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Διαμοιρασμός εξωτερικού βίντεο",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Τερματισμός διαμοιρασμού εξωτερικού βίντεο",
"app.iOSWarning.label": "Παρακαλούμε αναβαθμίστε σε iOS 12.2 ή νεότερο.",
"app.legacy.unsupportedBrowser": "Ο περιηγητής σας δεν υποστηρίζεται. Παρακαλούμε χρησιμοποιήστε {0} ή {1} για πλήρη συμβατότητα.",
"app.legacy.upgradeBrowser": "Φαίνεται πως χρησιμοποιείτε μια παλαιότερη έκδοση ενός υποστηριζόμενου περιηγητή. Παρακαλούμε αναβαθμίστε τον περιηγητή σας για πλήρη υποστήριξη.",
"app.legacy.criosBrowser": "Στο iOS παρακαλούμε χρησιμοποιήστε το Safari για πλήρη υποστήριξη.",

View File

@ -1093,6 +1093,8 @@
"app.videoDock.webcamFocusDesc": "Focus the selected webcam",
"app.videoDock.webcamUnfocusLabel": "Unfocus",
"app.videoDock.webcamUnfocusDesc": "Unfocus the selected webcam",
"app.videoDock.webcamDisableLabel": "Disable/Enable self cam",
"app.videoDock.webcamDisableDesc": "Self cam disabled",
"app.videoDock.webcamPinLabel": "Pin",
"app.videoDock.webcamPinDesc": "Pin the selected webcam",
"app.videoDock.webcamFullscreenLabel": "Fullscreen webcam",
@ -1169,7 +1171,6 @@
"app.externalVideo.subtitlesOff": "Turn on (if available)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Share an external video",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Stop sharing external video",
"app.iOSWarning.label": "Please upgrade to iOS 12.2 or higher",
"app.legacy.unsupportedBrowser": "It looks like you're using a browser that is not supported. Please use either {0} or {1} for full support.",
"app.legacy.upgradeBrowser": "It looks like you're using an older version of a supported browser. Please upgrade your browser for full support.",
"app.legacy.criosBrowser": "On iOS please use Safari for full support.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Encender (si está disponible)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Compartir un video externo",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Dejar de compartir video externo",
"app.iOSWarning.label": "Por favor, actualice a iOS 12.2 o superior",
"app.legacy.unsupportedBrowser": "Parece que está usando un navegador no totalmente soportado. Por favor, utilice uno de los siguientes {0} ó {1} para una compatibilidad completa.",
"app.legacy.upgradeBrowser": "Parece que está usando una versión antigua del navegador. Por favor, actualice su navegador para una compatibilidad completa.",
"app.legacy.criosBrowser": "Utilice Safari en iOS para contar con soporte completo.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Encender (si está disponible)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Compartir un video externo",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Detener compartir video externo",
"app.iOSWarning.label": "Por favor, actualice a iOS 12.2 o mayor",
"app.legacy.unsupportedBrowser": "Parece que estás usando un navegador que no es compatible. Utilice {0} o {1} para obtener soporte completo.",
"app.legacy.upgradeBrowser": "Parece que está usando una versión antigua no soportada del navegador. Por favor, actualice su navegador para soporte total.",
"app.legacy.criosBrowser": "En iOS, use Safari para obtener soporte completo.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Lülita sisse (kui saadaval)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Jaga välist videot",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Lõpeta välise video jagamine",
"app.iOSWarning.label": "Palun uuenda iOS versiooniks 12.2 või hilisemaks",
"app.legacy.unsupportedBrowser": "Paistab, et kasutad veebilehitsejat, mida ei toetata. Täielikuks toetuseks kasuta palun brauserit {0} või {1}.",
"app.legacy.upgradeBrowser": "Paistab, et kasutad toetatud veebilehitseja vanemat versiooni. Täielikuks toetuseks uuenda palun oma veebilehitsejat.",
"app.legacy.criosBrowser": "Täielikuks toetuseks kasuta palun iOSis Safarit.",

View File

@ -450,6 +450,7 @@
"app.submenu.application.applicationSectionTitle": "Aplikazioa",
"app.submenu.application.animationsLabel": "Animazioak",
"app.submenu.application.audioFilterLabel": "Mikrofonorako audio iragazkiak",
"app.submenu.application.wbToolbarsAutoHideLabel": "Ezkutatu automatikoki arbel zuriko tresna-barrak",
"app.submenu.application.darkThemeLabel": "Modu iluna",
"app.submenu.application.fontSizeControlLabel": "Letra tamaina",
"app.submenu.application.increaseFontBtnLabel": "Handitu aplikazioaren letra",
@ -1168,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Piztu (ahal bada)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Partekatu kanpoko bideo bat",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Gelditu kanpoko bideoaren partekatzea",
"app.iOSWarning.label": "Eguneratu iOS 12.2 edo berriagora",
"app.legacy.unsupportedBrowser": "Ematen du onartzen ez den nabigatzailea erabiltzen ari zarela. Erabili {0} edo {1} emaitzak hobetzeko.",
"app.legacy.upgradeBrowser": "Ematen du onartutako nabigatzaile baten bertsio zaharra erabiltzen ari zarela. Emaitzak hobetzeko nabigatzailea eguneratu ezazu .",
"app.legacy.criosBrowser": "iOS sisteman emaitzak hobetzeko Safari erabili ezazu.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "روشن‌کردن (در صورت وجود)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "اشتراک یک ویدیوی خارجی",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "توقف اشتراک‌گذاری ویدیوی خارجی",
"app.iOSWarning.label": "لطفا به iOS نسخه 12.2 یا بالاتر ارتقا دهید",
"app.legacy.unsupportedBrowser": "به نظر می‌رسد شما از مرورگری استفاده می‌کنید که پشتیبانی نمی‌شود. لطفا برای پشتیبانی کامل از {0} یا {1} استفاده کنید.",
"app.legacy.upgradeBrowser": "به نظر می‌رسد شما از نسخه قدیمی یک مرورگر پشتیبانی‌شده استفاده می‌کنید. لطفا برای پشتیبانی کامل مرورگر خود را به‌روزرسانی کنید.",
"app.legacy.criosBrowser": "در iOS برای پشتیبانی کامل لطفا از سافاری استفاده کنید.",

View File

@ -734,7 +734,7 @@
"app.meeting.logout.permissionEjectReason": "Expulsé en raison d'une violation de permission",
"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.userInactivityEjectReason": "Utilisateur trop longtemps inactif",
"app.meeting.logout.maxParticipantsReached": "Le nombre maximum de participants pour cette réunion a été atteint.",
"app.meeting-ended.rating.legendLabel": "Évaluation",
"app.meeting-ended.rating.starLabel": "Favori",
@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Activer (si disponible)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Partager une vidéo externe",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Arrêter le partage de vidéo externe",
"app.iOSWarning.label": "Veuillez mettre à jour vers iOS 12.2 ou supérieur",
"app.legacy.unsupportedBrowser": "Il semblerait que vous utilisiez un navigateur qui n'est pas pris en charge. Veuillez utiliser {0} ou {1} pour une prise en charge complète.",
"app.legacy.upgradeBrowser": "Il semblerait que vous utilisiez une ancienne version d'un navigateur pris en charge. Veuillez mettre à jour votre navigateur pour une prise en charge complète.",
"app.legacy.criosBrowser": "Sur iOS, veuillez utiliser Safari pour un support complet.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Acender (se está dispoñíbel)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Compartir un vídeo externo",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Deixar de compartir o vídeo externo",
"app.iOSWarning.label": "Actualice a iOS 12.2 ou superior",
"app.legacy.unsupportedBrowser": "Parece que estás a usar un navegador que non é compatíbel. Utilice {0} ou {1} para obter unha compatibilidade completa.",
"app.legacy.upgradeBrowser": "Parece que estás a usar unha versión antiga dun navegador compatíbel. Actualice o navegador para obter unha compatibilidade completa. ",
"app.legacy.criosBrowser": "En iOS, use Safari para ter una compatibilidade completa.",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Միացնել (եթե հասանելի է)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Արտաքին աղբյուրից տեսանյութի ցուցադրում",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Դադարեցնել արտաքին աղբյուրից տեսանյութի ցուցադրումը",
"app.iOSWarning.label": "Խնդրում ենք թարմացնել Ձեր օպերացիոն համակարգը iOS 12.2 կամ ավելի թարմ տարբերակի",
"app.legacy.unsupportedBrowser": "Հավանաբար օգտագործում եք բրաուզեր, որը համատեղելի չէ համակարգի հետ Խնդրում ենք օգտագործել {0} կամ {1}",
"app.legacy.upgradeBrowser": "Հավանաբար օգտագործում եք բրաուզերի ավելի հին տարբերակը Համակարգի հետ համատեղելիության համար խնդրում ենք թարմացնել բրաուզերը",
"app.legacy.criosBrowser": "iOS համակարգում լիարժեք աշխատելու համար խնդրում ենք օգտագործել Safari",

View File

@ -367,7 +367,7 @@
"app.poll.liveResult.secretLabel": "これは匿名の投票です。個別の答えは表示されません。",
"app.poll.removePollOpt": "投票の選択肢{0}を削除",
"app.poll.emptyPollOpt": "空白",
"app.polling.pollingTitle": "投票オプション",
"app.polling.pollingTitle": "選択肢",
"app.polling.pollQuestionTitle": "投票の質問",
"app.polling.submitLabel": "送る",
"app.polling.submitAriaLabel": "回答を送る",
@ -717,7 +717,7 @@
"app.audio.captions.button.transcriptionSettings": "文字起こし設定",
"app.audio.captions.speech.title": "自動文字起こし",
"app.audio.captions.speech.disabled": "無効",
"app.audio.captions.speech.unsupported": "お使いのブラウザは音声認識をサポートしていません。音声は書き起こされません。",
"app.audio.captions.speech.unsupported": "お使いのブラウザは音声認識をサポートしていないため、自動書き起こし機能は使用できません。",
"app.audio.captions.select.de-DE": "ドイツ語",
"app.audio.captions.select.en-US": "英語",
"app.audio.captions.select.es-ES": "スペイン語",
@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "(あれば)表示する",
"app.actionsBar.actionsDropdown.shareExternalVideo": "インターネット上の動画を共有",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "動画の共有停止",
"app.iOSWarning.label": "iOS 12.2またはそれ以降のバージョンにアップグレードしてください",
"app.legacy.unsupportedBrowser": "サポート対象外のブラウザを使用している可能性があります。サポート対象の{0}または{1}をお使いください。",
"app.legacy.upgradeBrowser": "ブラウザのバージョンが古い可能性があります。サポート対象のブラウザへアップグレードしてください。",
"app.legacy.criosBrowser": "iOSをお使いの場合、Safariを使ってください",

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Schakel uit (indien beschikbaar)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Deel een externe video",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Stop met het delen van externe video",
"app.iOSWarning.label": "Upgrade naar iOS 12.2 of hoger",
"app.legacy.unsupportedBrowser": "Het lijkt erop dat u een browser gebruikt die niet wordt ondersteund. Gebruik {0} of {1} voor volledige ondersteuning.",
"app.legacy.upgradeBrowser": "Het lijkt erop dat u een oudere versie van een ondersteunde browser gebruikt. Upgrade uw browser voor volledige ondersteuning.",
"app.legacy.criosBrowser": "Gebruik Safari op iOS voor volledige ondersteuning.",

View File

@ -1169,7 +1169,6 @@
"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",
"app.legacy.unsupportedBrowser": "Aparentemente está a usar um navegador não suportado. Por favor use o {0} or {1}. ",
"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",

View File

@ -2,10 +2,11 @@
"app.home.greeting": "Din presentation börjar strax ...",
"app.chat.submitLabel": "Skicka meddelande",
"app.chat.loading": "Inlästa chattmeddelanden: {0}%",
"app.chat.errorMaxMessageLength": "Meddelandet är {0} tecken för långt",
"app.chat.errorMaxMessageLength": "Meddelandet är för långt, överskrider maxgränsen på {0} tecken",
"app.chat.disconnected": "Du är frånkopplad, meddelanden kan inte skickas",
"app.chat.locked": "Chatten är låst, meddelanden kan inte skickas",
"app.chat.inputLabel": "Meddelandeinmatning för chatt {0}",
"app.chat.emojiButtonLabel": "Emoji-väljare",
"app.chat.inputPlaceholder": "Meddelande {0}",
"app.chat.titlePublic": "Publik chatt",
"app.chat.titlePrivate": "Private chatt med {0}",
@ -21,6 +22,7 @@
"app.chat.offline": "Offline",
"app.chat.pollResult": "Resultat Omröstning",
"app.chat.breakoutDurationUpdated": "Grupprumstiden är nu {0} minuter",
"app.chat.breakoutDurationUpdatedModerator": "Tid för grupprum är nu {0} minuter och ett meddelande har skickats.",
"app.chat.emptyLogLabel": "Chatt log tom",
"app.chat.clearPublicChatMessage": "Publika chatthistoriken var rensad av en moderator",
"app.chat.multi.typing": "Flera användare skriver",
@ -28,6 +30,27 @@
"app.chat.two.typing": "{0} och {1} skriver",
"app.chat.copySuccess": "Chatthistorik kopierad",
"app.chat.copyErr": "Kopiering av chatthistorik misslyckades",
"app.emojiPicker.search": "Sök",
"app.emojiPicker.notFound": "Ingen emoji hittades",
"app.emojiPicker.skintext": "Välj din standard hudton",
"app.emojiPicker.clear": "Rensa",
"app.emojiPicker.categories.label": "Emoji-kategorier",
"app.emojiPicker.categories.people": "Människor & Kropp",
"app.emojiPicker.categories.nature": "Djur & Natur",
"app.emojiPicker.categories.foods": "Mat & Dryck",
"app.emojiPicker.categories.places": "Resor & platser",
"app.emojiPicker.categories.activity": "Aktivitet",
"app.emojiPicker.categories.objects": "Objekt",
"app.emojiPicker.categories.symbols": "Symboler",
"app.emojiPicker.categories.flags": "Flaggor",
"app.emojiPicker.categories.recent": "Ofta använd",
"app.emojiPicker.categories.search": "Sökresultat",
"app.emojiPicker.skintones.1": "Standard hudton",
"app.emojiPicker.skintones.2": "Ljus hudton",
"app.emojiPicker.skintones.3": "Medium-Ljus hudton",
"app.emojiPicker.skintones.4": "Medium hudton",
"app.emojiPicker.skintones.5": "Medel-mörk hudton",
"app.emojiPicker.skintones.6": "Mörk hudton",
"app.captions.label": "Textning",
"app.captions.menu.close": "Stäng",
"app.captions.menu.start": "Starta",
@ -45,14 +68,32 @@
"app.captions.menu.cancelLabel": "Avbryt",
"app.captions.hide": "Dölj undertexter",
"app.captions.ownership": "Ta över",
"app.captions.ownershipTooltip": "Du kommer att tilldelas som ägare av {0} bildtexter",
"app.captions.dictationStart": "Starta diktering",
"app.captions.dictationStop": "Stoppa diktering",
"app.captions.dictationOnDesc": "Slår på taligenkänning",
"app.captions.dictationOffDesc": "Stänger av taligenkänning",
"app.captions.speech.start": "Taligenkänning startade",
"app.captions.speech.stop": "Taligenkänningen stoppade",
"app.captions.speech.error": "Taligenkänningen avbröts på grund av webbläsarens inkompatibilitet eller en viss tystnadstid",
"app.confirmation.skipConfirm": "Fråga inte igen",
"app.confirmation.virtualBackground.title": "Starta ny virtuell bakgrund",
"app.confirmation.virtualBackground.description": "{0} kommer att läggas till som virtuell bakgrund. Fortsätta?",
"app.confirmationModal.yesLabel": "Ja",
"app.textInput.sendLabel": "Skicka",
"app.title.defaultViewLabel": "Förvald presentatörsvy",
"app.notes.title": "Delade anteckningar",
"app.notes.titlePinned": "Delade anteckningar (fästa)",
"app.notes.pinnedNotification": "Delade anteckningar är nu fästa på whiteboardtavlan.",
"app.notes.label": "Anteckningar",
"app.notes.hide": "Dölj anteckningar",
"app.notes.locked": "Låst",
"app.notes.disabled": "Fäst på mediaområde",
"app.notes.notesDropdown.covertAndUpload": "Konvertera anteckningarna till presentation",
"app.notes.notesDropdown.pinNotes": "Fäst anteckningar på whiteboarden",
"app.notes.notesDropdown.unpinNotes": "Lossa anteckningarna",
"app.notes.notesDropdown.notesOptions": "Alternativ för anteckningar",
"app.pads.hint": "Tryck på Esc för att fokusera plattans verktygsfält",
"app.user.activityCheck": "Användaraktivitetskontroll",
"app.user.activityCheck.label": "Kontrollera om användaren fortfarande är i mötet ({0})",
"app.user.activityCheck.check": "Kontrollera",
@ -125,6 +166,8 @@
"app.userList.userOptions.savedNames.title": "Lista av användare i mötet {0} av {1}",
"app.userList.userOptions.sortedFirstName.heading": "Sorterat på förnamn",
"app.userList.userOptions.sortedLastName.heading": "Sorterat på efternamn",
"app.userList.userOptions.hideViewersCursor": "Tittarmarkörerna är låsta",
"app.userList.userOptions.showViewersCursor": "Tittarmarkörerna är upplåsta",
"app.media.label": "Media",
"app.media.autoplayAlertDesc": "Tillåta åtkomst",
"app.media.screenshare.start": "Skärmdelning har startats",
@ -146,8 +189,8 @@
"app.meeting.meetingTimeRemaining": "Återstående mötestid: {0}",
"app.meeting.meetingTimeHasEnded": "Tid slutade. Mötet stängs snart",
"app.meeting.endedByUserMessage": "Mötet avslutades av {0}",
"app.meeting.endedByNoModeratorMessageSingular": "Mötet har avslutats för att ingen moderator har varit ansluten på en minut",
"app.meeting.endedByNoModeratorMessagePlural": "Mötet har avslutats för att ingen moderator har varit ansluten på {0} minuter",
"app.meeting.endedByNoModeratorMessageSingular": "Mötet har avslutats eftersom ingen moderator har varit närvarande på en minut",
"app.meeting.endedByNoModeratorMessagePlural": "Mötet har avslutats eftersom ingen moderator har varit närvarande på {0} minuter",
"app.meeting.endedMessage": "Du kommer att vidarebefodras till startskärmen",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Möte stänger om en minut.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Möte stänger om {0} minuter.",
@ -161,9 +204,10 @@
"app.presentation.endSlideContent": "Bild innehåll slut",
"app.presentation.changedSlideContent": "Presentation ändrad till sidan: {0}",
"app.presentation.emptySlideContent": "Inget innehåll för aktuell bildruta",
"app.presentation.options.fullscreen": "Fullskärm",
"app.presentation.options.fullscreen": "Fullskärmspresentation",
"app.presentation.options.exitFullscreen": "Stäng fullskärm",
"app.presentation.options.minimize": "Minimera",
"app.presentation.options.snapshot": "Ögonblicksbild av aktuell bild",
"app.presentation.options.downloading": "Laddar ner...",
"app.presentation.options.downloaded": "Nuvarande presentation blev nedladdad",
"app.presentation.options.downloadFailed": "Kan inte ladda ned nuvarande presentation",
@ -191,9 +235,24 @@
"app.presentation.presentationToolbar.fitToWidth": "Anpassa till bredden",
"app.presentation.presentationToolbar.fitToPage": "Anpassa till sidan",
"app.presentation.presentationToolbar.goToSlide": "Bild {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Dölj verktygsfält",
"app.presentation.presentationToolbar.showToolsDesc": "Visa verktygsfält",
"app.presentation.placeholder": "Där är ingen aktiv presentation",
"app.presentationUploder.title": "Presentation",
"app.presentationUploder.message": "Som presentatör så har du möjlighet att ladda upp Office-dokument eller PDF-filer. Vi rekommenderar PDF-filer för bäst resultat. Säkerställ att en presentation är vald genom att klicka i bocken på högersidan.",
"app.presentationUploder.message": "Som presentatör har du möjlighet att ladda upp vilket officedokument eller PDF-fil som helst. Vi rekommenderar PDF-fil för bästa resultat. Se till att en presentation är markerad med hjälp av cirkelkryssrutan på vänster sida.",
"app.presentationUploader.exportHint": "Om du väljer \"Skicka till chatt\" får användarna en nedladdningsbar länk med kommentarer i offentlig chatt.",
"app.presentationUploader.exportToastHeader": "Skickar till chatt ({0} objekt)",
"app.presentationUploader.exportToastHeaderPlural": "Skickar till chatt ({0} objekt)",
"app.presentationUploader.exporting": "Skickar till chatt",
"app.presentationUploader.sending": "Skickar...",
"app.presentationUploader.collecting": "Extraherar bild {0} av {1}...",
"app.presentationUploader.processing": "Kommenterar bild {0} av {1}...",
"app.presentationUploader.sent": "Skickat",
"app.presentationUploader.exportingTimeout": "Exporten tar för lång tid...",
"app.presentationUploader.export": "Skicka till chatt",
"app.presentationUploader.export.linkAvailable": "Länk för nedladdning av {0} tillgänglig i den Publik Chatten.",
"app.presentationUploader.export.notAccessibleWarning": "kanske inte är tillgänglighetskompatibel",
"app.presentationUploader.currentPresentationLabel": "Aktuell presentation",
"app.presentationUploder.extraHint": "OBS: varje fil för inte överstiga {0} MB och {1} antal sidor.",
"app.presentationUploder.uploadLabel": "Ladda upp",
"app.presentationUploder.confirmLabel": "Bekräfta",
@ -204,11 +263,14 @@
"app.presentationUploder.dropzoneImagesLabel": "Dra bilder hit för uppladdning",
"app.presentationUploder.browseFilesLabel": "eller bläddra efter filer",
"app.presentationUploder.browseImagesLabel": "eller bläddra/fånga bilder",
"app.presentationUploder.externalUploadTitle": "Lägg till innehåll från 3rd party applikation",
"app.presentationUploder.externalUploadLabel": "Bläddra bland filer",
"app.presentationUploder.fileToUpload": "Att ladda upp ...",
"app.presentationUploder.currentBadge": "Nuvarande",
"app.presentationUploder.rejectedError": "Den valda filen(filerna) har blivit avvisad(e). Vänligen kontrollera filtypen(-typerna).",
"app.presentationUploder.connectionClosedError": "Avbruten på grund utav dålig uppkoppling. Försök igen.",
"app.presentationUploder.upload.progress": "Uppladdning ({0}%)",
"app.presentationUploder.conversion.204": "Inget innehåll att fånga",
"app.presentationUploder.upload.413": "Filen är för stor, max filstorlek är {0} MB",
"app.presentationUploder.genericError": "Oj då, nåt blev fel....",
"app.presentationUploder.upload.408": "Begäran för uppladdning tog för lång tid.",
@ -220,14 +282,14 @@
"app.presentationUploder.conversion.generatedSlides": "Bildspel genererade ...",
"app.presentationUploder.conversion.generatingSvg": "Genererar SVG bilder ...",
"app.presentationUploder.conversion.pageCountExceeded": "Antalet sidor överstiger maxgränsen på {0} sidor",
"app.presentationUploder.conversion.invalidMimeType": "Ogiltigt format upptäckt (tillägg={0}, innehållstyp={1})",
"app.presentationUploder.conversion.conversionTimeout": "Bild {0} kunde inte bearbetas inom {1} försök.",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Misslyckades med behandling av Office-dokument. Vänligen ladda upp som PDF istället.",
"app.presentationUploder.conversion.officeDocConversionFailed": "Misslyckades med behandling av Office-dokument. Vänligen ladda upp som PDF istället.",
"app.presentationUploder.conversion.pdfHasBigPage": "Vi kunde inte konvertera PDF-filen, försök spara om den. Max antal sidor är {0}",
"app.presentationUploder.conversion.timeout": "Hoppsan, konverteringen tog för lång tid",
"app.presentationUploder.conversion.pageCountFailed": "Misslyckades med att bestämma antalet sidor.",
"app.presentationUploder.conversion.unsupportedDocument": "Fil-typ stöds ej",
"app.presentationUploder.isDownloadableLabel": "Nerladdning av presentation ej tillåten - klicka här för att tillåta nerladdning av presentation",
"app.presentationUploder.isNotDownloadableLabel": "Nerladdning av presentation tillåten - klicka här för att inte tillåta nerladdning av presentation",
"app.presentationUploder.removePresentationLabel": "Ta bort presentationen",
"app.presentationUploder.setAsCurrentPresentation": "Ange presentation som aktuell",
"app.presentationUploder.tableHeading.filename": "Filnamn",
@ -241,6 +303,10 @@
"app.presentationUploder.clearErrors": "Rensa fel",
"app.presentationUploder.clearErrorsDesc": "Rensa misslyckade uppladdningar av presentationer",
"app.presentationUploder.uploadViewTitle": "Ladda upp presentation",
"app.poll.questionAndoptions.label" : "Frågetext som ska visas.\nA. Omröstningsalternativ *\nB. Omröstningsalternativ (valfritt)\nC. Omröstningsalternativ (valfritt)\nD. Omröstningsalternativ (valfritt)\nE. Omröstningsalternativ (valfritt)",
"app.poll.customInput.label": "Anpassad input",
"app.poll.customInputInstructions.label": "Anpassad input är aktiverad skriv enkätfråga och alternativ(er) i givet format eller dra och släpp en textfil i samma format.",
"app.poll.maxOptionsWarning.label": "Endast de första 5 alternativen kan användas!",
"app.poll.pollPaneTitle": "Omröstning",
"app.poll.enableMultipleResponseLabel": "Tillåt flersvarsalternativ?",
"app.poll.quickPollTitle": "Snabb undersökning",
@ -260,7 +326,7 @@
"app.poll.clickHereToSelect": "Klicka här för att välja",
"app.poll.question.label" : "Skriv din fråga...",
"app.poll.optionalQuestion.label" : "Skriv din fråga (valfritt)...",
"app.poll.userResponse.label" : "Svar från användare",
"app.poll.userResponse.label" : "Skrivet svar",
"app.poll.responseTypes.label" : "Svarstyp",
"app.poll.optionDelete.label" : "Ta bort",
"app.poll.responseChoices.label" : "Svarsalternativ",
@ -319,11 +385,11 @@
"app.muteWarning.disableMessage": "Stäng av varning för avstängd mikrofon tills nästa gång den sätts på",
"app.muteWarning.tooltip": "Klicka för att stänga och inaktivera varning tills nästa gång mikrofonen sätts på",
"app.navBar.settingsDropdown.optionsLabel": "Valmöjligheter",
"app.navBar.settingsDropdown.fullscreenLabel": "Gör fullskärm",
"app.navBar.settingsDropdown.fullscreenLabel": "Helskärmsapplikation",
"app.navBar.settingsDropdown.settingsLabel": "Inställningar",
"app.navBar.settingsDropdown.aboutLabel": "Om",
"app.navBar.settingsDropdown.leaveSessionLabel": "Lämna möte",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Avsluta fullskärmen",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Avsluta helskärm",
"app.navBar.settingsDropdown.fullscreenDesc": "Gör inställningsmenyn fullskärm",
"app.navBar.settingsDropdown.settingsDesc": "Ändra de allmänna inställningarna",
"app.navBar.settingsDropdown.aboutDesc": "Visa information om klienten",
@ -332,6 +398,7 @@
"app.navBar.settingsDropdown.hotkeysLabel": "Tangentbordsgenvägar",
"app.navBar.settingsDropdown.hotkeysDesc": "Lista över tillgängliga tangentbordsgenvägar",
"app.navBar.settingsDropdown.helpLabel": "Hjälp",
"app.navBar.settingsDropdown.openAppLabel": "Open in BigBlueButton Tablet app",
"app.navBar.settingsDropdown.helpDesc": "Länkar användaren till videokollektoiner (öppnar ny flik)",
"app.navBar.settingsDropdown.endMeetingDesc": "Avslutar nuvarande möte",
"app.navBar.settingsDropdown.endMeetingLabel": "Avsluta mötet",
@ -349,7 +416,7 @@
"app.endMeeting.description": "Detta kommer avsluta sessionen för {0} aktiva användare. Är du säker på att du vill avsluta?",
"app.endMeeting.noUserDescription": "Är du säker på att du vill avsluta denna session?",
"app.endMeeting.contentWarning": "Chatt, delade anteckningar, illustrationer på whiteboarden och delade dokument för denna session kommer inte längre vara direkt åtkomligt",
"app.endMeeting.yesLabel": "Ja",
"app.endMeeting.yesLabel": "Avsluta sessionen för alla användare",
"app.endMeeting.noLabel": "Nej",
"app.about.title": "Om",
"app.about.version": "Klientbyggnad:",
@ -359,6 +426,15 @@
"app.about.confirmDesc": "OK",
"app.about.dismissLabel": "Avbryt",
"app.about.dismissDesc": "Stäng om klientinformation",
"app.mobileAppModal.title": "Öppna BigBlueButton Tablet-appen",
"app.mobileAppModal.description": "Har du BigBlueButton Tablet-appen installerad på din enhet?",
"app.mobileAppModal.openApp": "Ja, öppna appen nu",
"app.mobileAppModal.obtainUrlMsg": "Får mötes-URL",
"app.mobileAppModal.obtainUrlErrorMsg": "Fel vid försök att hämta mötes-URL",
"app.mobileAppModal.openStore": "Nej, öppna App Store för att ladda ner",
"app.mobileAppModal.dismissLabel": "Avbryt",
"app.mobileAppModal.dismissDesc": "Stänga",
"app.mobileAppModal.userConnectedWithSameId": "Användaren {0} har precis anslutit med samma ID som du.",
"app.actionsBar.changeStatusLabel": "Ändra status",
"app.actionsBar.muteLabel": "Dämpa",
"app.actionsBar.unmuteLabel": "Dämpa ej",
@ -369,10 +445,13 @@
"app.actionsBar.actionsDropdown.restorePresentationDesc": "Knapp för att återställa presentation efter att den minimerats",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Minimera presentation",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Knapp för att minimera presentation",
"app.actionsBar.actionsDropdown.layoutModal": "Layoutinställningar Modal",
"app.screenshare.screenShareLabel" : "Skärmdelning",
"app.submenu.application.applicationSectionTitle": "Applikation",
"app.submenu.application.animationsLabel": "Animeringar",
"app.submenu.application.audioFilterLabel": "Ljudfilter för mikrofon",
"app.submenu.application.wbToolbarsAutoHideLabel": "Dölj verktygsfält för whiteboard automatiskt",
"app.submenu.application.darkThemeLabel": "Mörkt läge",
"app.submenu.application.fontSizeControlLabel": "Typsnittstorlek",
"app.submenu.application.increaseFontBtnLabel": "Öka applikationstypsnittsstorlek",
"app.submenu.application.decreaseFontBtnLabel": "Minska applikationstypsnittsstorlek",
@ -382,6 +461,69 @@
"app.submenu.application.noLocaleOptionLabel": "Inga aktiva platser",
"app.submenu.application.paginationEnabledLabel": "Videopaginering",
"app.submenu.application.layoutOptionLabel": "Layout typ",
"app.submenu.application.pushLayoutLabel": "Skicka layouten",
"app.submenu.application.localeDropdown.af": "Afrikaans",
"app.submenu.application.localeDropdown.ar": "Arabiska",
"app.submenu.application.localeDropdown.az": "Azerbajdzjanska",
"app.submenu.application.localeDropdown.bg-BG": "Bulgariska",
"app.submenu.application.localeDropdown.bn": "Bengali",
"app.submenu.application.localeDropdown.ca": "Katalanska",
"app.submenu.application.localeDropdown.cs-CZ": "Tjeckiska",
"app.submenu.application.localeDropdown.da": "Danska",
"app.submenu.application.localeDropdown.de": "Tysk",
"app.submenu.application.localeDropdown.dv": "Dhivehi",
"app.submenu.application.localeDropdown.el-GR": "Grekiska (Grekland)",
"app.submenu.application.localeDropdown.en": "Engelsk",
"app.submenu.application.localeDropdown.eo": "Esperanto",
"app.submenu.application.localeDropdown.es": "Spanska",
"app.submenu.application.localeDropdown.es-419": "Spanska (Latinamerika)",
"app.submenu.application.localeDropdown.es-ES": "Spanska (Spanien)",
"app.submenu.application.localeDropdown.es-MX": "Spanska (Mexiko)",
"app.submenu.application.localeDropdown.et": "Estniska",
"app.submenu.application.localeDropdown.eu": "Baskiska",
"app.submenu.application.localeDropdown.fa-IR": "Persiska",
"app.submenu.application.localeDropdown.fi": "Finska",
"app.submenu.application.localeDropdown.fr": "Franska",
"app.submenu.application.localeDropdown.gl": "Galiciska",
"app.submenu.application.localeDropdown.he": "Hebreiska",
"app.submenu.application.localeDropdown.hi-IN": "Hindi",
"app.submenu.application.localeDropdown.hr": "Kroatisk",
"app.submenu.application.localeDropdown.hu-HU": "Ungerska",
"app.submenu.application.localeDropdown.hy": "Armeniska",
"app.submenu.application.localeDropdown.id": "Indonesiska",
"app.submenu.application.localeDropdown.it-IT": "Italienska",
"app.submenu.application.localeDropdown.ja": "Japanska",
"app.submenu.application.localeDropdown.ka": "Georgiska",
"app.submenu.application.localeDropdown.km": "Khmer",
"app.submenu.application.localeDropdown.kn": "Kannada",
"app.submenu.application.localeDropdown.ko-KR": "Koreanska (Korea)",
"app.submenu.application.localeDropdown.lo-LA": "Lao",
"app.submenu.application.localeDropdown.lt-LT": "Litauiska",
"app.submenu.application.localeDropdown.lv": "Lettiska",
"app.submenu.application.localeDropdown.ml": "Malayalam",
"app.submenu.application.localeDropdown.mn-MN": "Mongoliska",
"app.submenu.application.localeDropdown.nb-NO": "Norska (bokmal)",
"app.submenu.application.localeDropdown.nl": "Holländska",
"app.submenu.application.localeDropdown.oc": "Occitanska",
"app.submenu.application.localeDropdown.pl-PL": "Putsa",
"app.submenu.application.localeDropdown.pt": "Portugisiska",
"app.submenu.application.localeDropdown.pt-BR": "Portugisiska (Brasilien)",
"app.submenu.application.localeDropdown.ro-RO": "Rumänska",
"app.submenu.application.localeDropdown.ru": "Ryska",
"app.submenu.application.localeDropdown.sk-SK": "Slovakiska (Slovakien)",
"app.submenu.application.localeDropdown.sl": "Slovenska",
"app.submenu.application.localeDropdown.sr": "Serbiska",
"app.submenu.application.localeDropdown.sv-SE": "Svenska",
"app.submenu.application.localeDropdown.ta": "Tamil",
"app.submenu.application.localeDropdown.te": "Telugu",
"app.submenu.application.localeDropdown.th": "Thai",
"app.submenu.application.localeDropdown.tr": "Turkiska",
"app.submenu.application.localeDropdown.tr-TR": "Turkiska (Turkiet)",
"app.submenu.application.localeDropdown.uk-UA": "Ukrainska",
"app.submenu.application.localeDropdown.vi": "Vietnamesiska",
"app.submenu.application.localeDropdown.vi-VN": "V ietnamesiska (Vietnam)",
"app.submenu.application.localeDropdown.zh-CN": "Kinesiska förenklad (Kina)",
"app.submenu.application.localeDropdown.zh-TW": "Traditionell kinesisk (Taiwan)",
"app.submenu.notification.SectionTitle": "Meddelande",
"app.submenu.notification.Desc": "Ange hur och vad som du ska bli meddelad om",
"app.submenu.notification.audioAlertLabel": "Ljudsignal",
@ -410,7 +552,7 @@
"app.settings.main.save.label.description": "Sparar ändringarna och stänger inställningsmenyn",
"app.settings.dataSavingTab.label": "Datasparande",
"app.settings.dataSavingTab.webcam": "Aktivera webbkameror",
"app.settings.dataSavingTab.screenShare": "Aktivera skrivbordsdelning",
"app.settings.dataSavingTab.screenShare": "Aktivera skrivbordsdelning för andra deltagare",
"app.settings.dataSavingTab.description": "För att spara din bandbredd justera vad som visas för närvarande.",
"app.settings.save-notification.label": "Inställningarna har blivit sparade",
"app.statusNotifier.lowerHands": "Sänk händer",
@ -427,10 +569,9 @@
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ pratade",
"app.talkingIndicator.wasTalking" : "{0} slutade prata",
"app.actionsBar.actionsDropdown.actionsLabel": "Åtgärder",
"app.actionsBar.actionsDropdown.presentationLabel": "Hantera presentationer",
"app.actionsBar.actionsDropdown.presentationLabel": "Ladda upp/hantera presentationer",
"app.actionsBar.actionsDropdown.initPollLabel": "Inled en omröstning",
"app.actionsBar.actionsDropdown.desktopShareLabel": "Dela din skärm",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "Skärmdelning låst",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "Sluta dela din skärm",
"app.actionsBar.actionsDropdown.presentationDesc": "Ladda upp din presentation",
"app.actionsBar.actionsDropdown.initPollDesc": "Inled en omröstning",
@ -447,6 +588,7 @@
"app.actionsBar.actionsDropdown.takePresenterDesc": "Tilldela dig som ny presentatör",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "Välj slumpmässig deltagare",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "Väljer en slumpmässig deltagare",
"app.actionsBar.actionsDropdown.propagateLayoutLabel": "Sprid layout",
"app.actionsBar.emojiMenu.statusTriggerLabel": "Ställ in status",
"app.actionsBar.emojiMenu.awayLabel": "Borta",
"app.actionsBar.emojiMenu.awayDesc": "Ändra din status till borta",
@ -472,8 +614,21 @@
"app.actionsBar.currentStatusDesc": "nuvarande status {0}",
"app.actionsBar.captions.start": "Börja visa dold textning",
"app.actionsBar.captions.stop": "Sluta visa dold textning",
"app.audioNotification.audioFailedError1001": "WebSocket frånkopplad (fel 1001)",
"app.audioNotification.audioFailedError1002": "Kunde inte göra en WebSocket-anslutning (fel 1002)",
"app.audioNotification.audioFailedError1003": "Webbläsarversionen stöds inte (fel 1003)",
"app.audioNotification.audioFailedError1004": "Fel vid samtal (orsak={0}) (fel 1004)",
"app.audioNotification.audioFailedError1005": "Samtalet avslutades oväntat (fel 1005)",
"app.audioNotification.audioFailedError1006": "Samtalet tog timeout (fel 1006)",
"app.audioNotification.audioFailedError1007": "Anslutningsfel (ICE-fel 1007)",
"app.audioNotification.audioFailedError1008": "Överföringen misslyckades (fel 1008)",
"app.audioNotification.audioFailedError1009": "Kunde inte hämta STUN/TURN-serverinformation (fel 1009)",
"app.audioNotification.audioFailedError1010": "Timeout för anslutningsförhandling (ICE-fel 1010)",
"app.audioNotification.audioFailedError1011": "Timeout för anslutning (ICE-fel 1011)",
"app.audioNotification.audioFailedError1012": "Anslutningen stängd (ICE-fel 1012)",
"app.audioNotification.audioFailedMessage": "Din ljudanslutning kunde inte anslutas",
"app.audioNotification.mediaFailedMessage": "getUserMicMedia misslyckades eftersom endast säkra ursprung är tillåtna",
"app.audioNotification.deviceChangeFailed": "Det gick inte att byta ljudenhet. Kontrollera om den valda enheten är korrekt inställd och tillgänglig",
"app.audioNotification.closeLabel": "Stäng",
"app.audioNotificaion.reconnectingAsListenOnly": "Mikrofonen har låsts för åhörarna, du är ansluten som enbart lyssna",
"app.breakoutJoinConfirmation.title": "Gå med i grupprummet",
@ -487,6 +642,7 @@
"app.breakout.dropdown.manageDuration": "Ändra tid",
"app.breakout.dropdown.destroyAll": "Avsluta grupprum",
"app.breakout.dropdown.options": "Grupprumsalternativ",
"app.breakout.dropdown.manageUsers": "Hantera användare",
"app.calculatingBreakoutTimeRemaining": "Beräknar återstående tid ...",
"app.audioModal.ariaTitle": "Gå med i ljudmodal",
"app.audioModal.microphoneLabel": "Mikrofon",
@ -508,6 +664,7 @@
"app.audioModal.settingsTitle": "Ändra dina ljudinställningar",
"app.audioModal.helpTitle": "Det var ett problem med dina medieenheter",
"app.audioModal.helpText": "Gav du tillstånd för åtkomst till din mikrofon? Observera att en dialogruta ska visas när du försöker ansluta till ljud och be om dina medietillbehör, acceptera det för att ansluta till ljudkonferensen. Om så inte är fallet, försök ändra dina mikrofonbehörigheter i webbläsarens inställningar.",
"app.audioModal.help.noSSL": "Den här sidan är osäkrad. För att mikrofonåtkomst ska tillåtas måste sidan serveras via HTTPS. Kontakta serveradministratören.",
"app.audioModal.help.macNotAllowed": "Det verkar som att Mac OS blockerar tillgången till din mikrofon. Öppna Systeminställningar -> Säkerhet & integritet -> Integritet -> Mikrofon, och se till att din webbläsare är förbockad.",
"app.audioModal.audioDialTitle": "Gå med i din telefon",
"app.audioDial.audioDialDescription": "Ring",
@ -532,6 +689,7 @@
"app.audio.changeAudioDevice": "Ändra ljud-enheter",
"app.audio.enterSessionLabel": "Ange session",
"app.audio.playSoundLabel": "Spela upp ljud",
"app.audio.stopAudioFeedback": "Stoppa ljudåterkoppling",
"app.audio.backLabel": "Tillbaka",
"app.audio.loading": "Laddar",
"app.audio.microphones": "Mikrofoner",
@ -544,10 +702,32 @@
"app.audio.audioSettings.testSpeakerLabel": "Testa din högtalare",
"app.audio.audioSettings.microphoneStreamLabel": "Din ljudströmvolym",
"app.audio.audioSettings.retryLabel": "Försök igen",
"app.audio.audioSettings.fallbackInputLabel": "Ljudingång {0}",
"app.audio.audioSettings.fallbackOutputLabel": "Ljudutgång {0}",
"app.audio.audioSettings.defaultOutputDeviceLabel": "Standard",
"app.audio.audioSettings.findingDevicesLabel": "Hittar enheter...",
"app.audio.listenOnly.backLabel": "Tillbaka",
"app.audio.listenOnly.closeLabel": "Stäng",
"app.audio.permissionsOverlay.title": "Tillåt åtkomst till din mikrofon",
"app.audio.permissionsOverlay.hint": "Vi behöver dig att tillåta oss att använda dina medieenheter för att kunna ansluta dig till röstkonferensen :)",
"app.audio.captions.button.start": "Starta textning",
"app.audio.captions.button.stop": "Stoppa textning",
"app.audio.captions.button.language": "Språk",
"app.audio.captions.button.transcription": "Transkription",
"app.audio.captions.button.transcriptionSettings": "Transkriptionsinställningar",
"app.audio.captions.speech.title": "Automatisk transkription",
"app.audio.captions.speech.disabled": "Inaktiverad",
"app.audio.captions.speech.unsupported": "Din webbläsare stöder inte taligenkänning. Ditt ljud kommer inte att transkriberas",
"app.audio.captions.select.de-DE": "Tysk",
"app.audio.captions.select.en-US": "Engelsk",
"app.audio.captions.select.es-ES": "Spanska",
"app.audio.captions.select.fr-FR": "Franska",
"app.audio.captions.select.hi-ID": "Hindi",
"app.audio.captions.select.it-IT": "Italienska",
"app.audio.captions.select.ja-JP": "Japanska",
"app.audio.captions.select.pt-BR": "Portugisiska",
"app.audio.captions.select.ru-RU": "Ryska",
"app.audio.captions.select.zh-CN": "Kinesiska",
"app.error.removed": "Du har tagits bort från konferensen",
"app.error.meeting.ended": "Du har loggat ut från konferensen",
"app.meeting.logout.duplicateUserEjectReason": "Duplikatanvändare att försöka gå med i mötet",
@ -555,6 +735,7 @@
"app.meeting.logout.ejectedFromMeeting": "Du har tagits bort från mötet",
"app.meeting.logout.validateTokenFailedEjectReason": "Misslyckades med att validera behörighetstoken",
"app.meeting.logout.userInactivityEjectReason": "Användaren inaktiv för länge",
"app.meeting.logout.maxParticipantsReached": "Det max tillåtna antalet deltagare för detta möte har uppnåtts",
"app.meeting-ended.rating.legendLabel": "Feedback betyg",
"app.meeting-ended.rating.starLabel": "Stjärna",
"app.modal.close": "Stäng",
@ -576,17 +757,24 @@
"app.error.403": "Du har tagits bort från mötet",
"app.error.404": "Hittades inte",
"app.error.408": "Autentisering misslyckad",
"app.error.409": "Konflikt",
"app.error.410": "Mötet är avslutat",
"app.error.500": "Hoppsan, nånting gick snett",
"app.error.503": "Du har blivit frånkopplad",
"app.error.disconnected.rejoin": "Du kan uppdatera sidan för att gå med igen.",
"app.error.userLoggedOut": "Användaren har en ogiltig sessionstoken på grund av utloggning",
"app.error.ejectedUser": "Användaren har en ogiltig sessionstoken på grund av utkastning",
"app.error.joinedAnotherWindow": "Denna session verkar vara öppen i en annan webbläsare.",
"app.error.userBanned": "Användaren har bannlysts",
"app.error.leaveLabel": "Logga in igen",
"app.error.fallback.presentation.title": "Ett fel uppstod",
"app.error.fallback.presentation.description": "Det har loggats. Försök ladda om sidan.",
"app.error.fallback.presentation.reloadButton": "Ladda om",
"app.guest.waiting": "Väntar på godkännande för att gå med",
"app.guest.errorSeeConsole": "Fel: mer information i konsolen.",
"app.guest.noModeratorResponse": "Inget svar från Moderator.",
"app.guest.noSessionToken": "Ingen sessionstoken mottogs.",
"app.guest.windowTitle": "BigBlueButton - Gästlobby",
"app.guest.missingToken": "Gäst saknar sessionstoken.",
"app.guest.missingSession": "Gäst saknar session.",
"app.guest.missingMeeting": "Mötet finns inte.",
"app.guest.meetingEnded": "Mötet har avslutats.",
@ -596,6 +784,7 @@
"app.guest.allow": "Gäst är godkänd och släpps in i mötet.",
"app.guest.firstPositionInWaitingQueue": "Du är först i kö!",
"app.guest.positionInWaitingQueue": "Din nuvarande placering i kö:",
"app.guest.guestInvalid": "Gästanvändaren är ogiltig",
"app.guest.meetingForciblyEnded": "Du kan inte ansluta till ett möte som redan avslutats",
"app.userList.guest.waitingUsers": "Väntar användare",
"app.userList.guest.waitingUsersTitle": "Användarhantering",
@ -615,14 +804,18 @@
"app.userList.guest.privateMessageLabel": "Meddelande",
"app.userList.guest.acceptLabel": "Acceptera",
"app.userList.guest.denyLabel": "Neka",
"app.userList.guest.feedbackMessage": "Åtgärd tillämpad:",
"app.user-info.title": "Kataloguppslag",
"app.toast.breakoutRoomEnded": "Grupprummet slutade. Vänligen återanslut ljudet.",
"app.toast.chat.public": "Nytt publikt chattmeddelande",
"app.toast.chat.private": "Nytt privat chattmeddelande",
"app.toast.chat.system": "System",
"app.toast.chat.poll": "Omröstningsresultat",
"app.toast.chat.pollClick": "Omröstningsresultat publicerades. Klicka här för att se.",
"app.toast.clearedEmoji.label": "Emoji status rensad",
"app.toast.setEmoji.label": "Emoji-status inställd till {0}",
"app.toast.meetingMuteOn.label": "Alla användare har blivit dämpade",
"app.toast.meetingMuteOnViewers.label": "Alla tittare har stängts av",
"app.toast.meetingMuteOff.label": "Mötesdämpning avstängd",
"app.toast.setEmoji.raiseHand": "Du har sträckt upp handen",
"app.toast.setEmoji.lowerHand": "Din hand har blivit nedtagen",
@ -638,6 +831,7 @@
"app.shortcut-help.title": "Tangentbordsgenvägar",
"app.shortcut-help.accessKeyNotAvailable": "Tillgångstangenterna är inte tillgängliga",
"app.shortcut-help.comboLabel": "Kombo",
"app.shortcut-help.alternativeLabel": "Alternativ",
"app.shortcut-help.functionLabel": "Funktion",
"app.shortcut-help.closeLabel": "Stäng",
"app.shortcut-help.closeDesc": "Stänger kortkommandon modal",
@ -659,6 +853,38 @@
"app.shortcut-help.toggleFullscreenKey": "Enter",
"app.shortcut-help.nextSlideKey": "Höger pil",
"app.shortcut-help.previousSlideKey": "Vänster pil",
"app.shortcut-help.select": "Välj Verktyg",
"app.shortcut-help.pencil": "Penna",
"app.shortcut-help.eraser": "Suddgummi",
"app.shortcut-help.rectangle": "Rektangel",
"app.shortcut-help.elipse": "Elipse",
"app.shortcut-help.triangle": "Triangel",
"app.shortcut-help.line": "Linje",
"app.shortcut-help.arrow": "Pil",
"app.shortcut-help.text": "Textverktyg",
"app.shortcut-help.note": "Post-it lapp",
"app.shortcut-help.general": "Allmän",
"app.shortcut-help.presentation": "Presentation",
"app.shortcut-help.whiteboard": "Whiteboard",
"app.shortcut-help.zoomIn": "Zooma in",
"app.shortcut-help.zoomOut": "Zooma ut",
"app.shortcut-help.zoomFit": "Återställ zoom",
"app.shortcut-help.zoomSelect": "Zooma till urval",
"app.shortcut-help.flipH": "Vänd horisontell",
"app.shortcut-help.flipV": "Vänd vertikalt",
"app.shortcut-help.lock": "Låsa / Låsa upp",
"app.shortcut-help.moveToFront": "Flytta till fronten",
"app.shortcut-help.moveToBack": "Flytta till bak",
"app.shortcut-help.moveForward": "Flytta framåt",
"app.shortcut-help.moveBackward": "Flytta bakåt",
"app.shortcut-help.undo": "Ångra",
"app.shortcut-help.redo": "Göra om",
"app.shortcut-help.cut": "Klippa",
"app.shortcut-help.copy": "Kopiera",
"app.shortcut-help.paste": "Klistra",
"app.shortcut-help.selectAll": "Välj alla",
"app.shortcut-help.delete": "Radera",
"app.shortcut-help.duplicate": "Duplicera",
"app.lock-viewers.title": "Lås åhörare",
"app.lock-viewers.description": "Dessa alternativ låter dig spärra funktioner för användarna.",
"app.lock-viewers.featuresLable": "Funktion",
@ -695,6 +921,7 @@
"app.connection-status.no": "Nej",
"app.connection-status.notification": "Du har problem med din anslutning",
"app.connection-status.offline": "Offline",
"app.connection-status.clientNotRespondingWarning": "Klient svarar inte",
"app.connection-status.audioUploadRate": "Ljud Uppladdning",
"app.connection-status.audioDownloadRate": "Ljud Nedladdning",
"app.connection-status.videoUploadRate": "Video Uppladdning",
@ -708,13 +935,19 @@
"app.connection-status.next": "Nästa sida",
"app.connection-status.prev": "Föregående sida",
"app.learning-dashboard.label": "Deltagarstatistik",
"app.learning-dashboard.description": "Öppna översikt med användarnas aktiviteter",
"app.learning-dashboard.description": "Dashboard med användaraktiviteter",
"app.learning-dashboard.clickHereToOpen": "Öppna Deltagarstatistik",
"app.recording.startTitle": "Starta inspelningen",
"app.recording.stopTitle": "Pausa inspelningen",
"app.recording.resumeTitle": "Fortsätta inspelningen",
"app.recording.startDescription": "Du kan välja inspelningsknappen igen senare för att pausa inspelningen.",
"app.recording.stopDescription": "Är du säker på att du vill pausa inspelningen? Du kan återuppta inspelningen genom att välja inspelningsknappen igen.",
"app.recording.notify.title": "Inspelningen har startat",
"app.recording.notify.description": "En inspelning kommer att finnas tillgänglig baserat på resten av denna session",
"app.recording.notify.continue": "Fortsätta",
"app.recording.notify.leave": "Lämna sessionen",
"app.recording.notify.continueLabel" : "Acceptera inspelningen och fortsätt",
"app.recording.notify.leaveLabel" : "Acceptera inte inspelning och lämna mötet",
"app.videoPreview.cameraLabel": "Kamera",
"app.videoPreview.profileLabel": "Kvalitet",
"app.videoPreview.quality.low": "Låg",
@ -731,15 +964,23 @@
"app.videoPreview.webcamOptionLabel": "Välj webbkamera",
"app.videoPreview.webcamPreviewLabel": "Förhandsgranskning av webbkamera",
"app.videoPreview.webcamSettingsTitle": "Webbkamera inställningar",
"app.videoPreview.webcamEffectsTitle": "Webbkamera visuella effekter",
"app.videoPreview.webcamVirtualBackgroundLabel": "Inställningar för virtuell bakgrund",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Denna enhet stödjer inte virtuella bakgrunder",
"app.videoPreview.webcamNotFoundLabel": "Webbkamera hittades inte",
"app.videoPreview.profileNotFoundLabel": "Ingen stödd kameraprofil",
"app.videoPreview.brightness": "Ljusstyrka",
"app.videoPreview.wholeImageBrightnessLabel": "Hela bilden",
"app.videoPreview.wholeImageBrightnessDesc": "Tillämpar ljusstyrka på stream och bakgrundsbild",
"app.videoPreview.sliderDesc": "Öka eller minska nivåerna av ljusstyrka",
"app.video.joinVideo": "Dela webbkamera",
"app.video.connecting": "Delning av webbkamera startas...",
"app.video.leaveVideo": "Sluta dela webbkamera",
"app.video.videoSettings": "Videoinställningar",
"app.video.visualEffects": "Visuella effekter",
"app.video.advancedVideo": "Öppna avancerade inställningar",
"app.video.iceCandidateError": "Fel vid att lägga till ICE-kandidat",
"app.video.iceConnectionStateError": "Anslutningsfel (ICE-fel 1107)",
"app.video.permissionError": "Fel vid delning av webbkamera. Kontrollera behörigheter",
"app.video.sharingError": "Fel vid delning av webbkamera",
"app.video.abortError": "Ett okänt problem inträffade vilket gjorde att din kamera inte kunde användas.",
@ -752,7 +993,9 @@
"app.video.notReadableError": "Det gick inte att få webbkamera video. Se till att ett annat program inte använder webbkameran",
"app.video.timeoutError": "Webbläsaren svarade inte i tid",
"app.video.genericError": "Ett okänt fel har inträffat med enheten ({0})",
"app.video.inactiveError": "Din webbkamera stannade oväntat. Granska din webbläsares behörigheter",
"app.video.mediaTimedOutError": "Din webbkamera-delning har avbrutits. Prova dela din kamera igen",
"app.video.mediaFlowTimeout1020": "Media kunde inte nå servern (fel 1020)",
"app.video.suggestWebcamLock": "Förbättra låsinställningen till webbläsare för åhörarna?",
"app.video.suggestWebcamLockReason": "(detta kommer att förbättra mötesstabiliteten)",
"app.video.enable": "Aktivera",
@ -773,8 +1016,17 @@
"app.video.virtualBackground.board": "Tavla",
"app.video.virtualBackground.coffeeshop": "Café",
"app.video.virtualBackground.background": "Bakgrund",
"app.video.virtualBackground.backgroundWithIndex": "Bakgrund {0}",
"app.video.virtualBackground.custom": "Ladda upp från din dator",
"app.video.virtualBackground.remove": "Ta bort tillagd bild",
"app.video.virtualBackground.genericError": "Misslyckades att tillämpa kameraeffekt. Prova igen.",
"app.video.virtualBackground.camBgAriaDesc": "Tillämpar virtuell bakgrund på webbkamera till {0}",
"app.video.virtualBackground.maximumFileSizeExceeded": "Maximal filstorlek har överskridits. ({0}MB)",
"app.video.virtualBackground.typeNotAllowed": "Filtyp är inte tillåten.",
"app.video.virtualBackground.errorOnRead": "Något gick fel när filen lästes.",
"app.video.virtualBackground.uploaded": "Uppladdad",
"app.video.virtualBackground.uploading": "Laddar upp...",
"app.video.virtualBackground.button.customDesc": "Lägger till en ny virtuell bakgrundsbild",
"app.video.camCapReached": "Du kan inte dela fler kameror",
"app.video.meetingCamCapReached": "Mötet har maxat kamerakapaciteten",
"app.video.dropZoneLabel": "Släpp här",
@ -783,10 +1035,20 @@
"app.switchButton.expandLabel": "Förstora skärmdelningsvideo",
"app.switchButton.shrinkLabel": "Förminska skärmdelningsvideo",
"app.sfu.mediaServerConnectionError2000": "Misslyckades att ansluta till mediaserver (error 2000)",
"app.sfu.mediaServerOffline2001": "Mediaservern är offline. Försök igen senare (fel 2001)",
"app.sfu.mediaServerNoResources2002": "Mediaservern har inga tillgängliga resurser (fel 2002)",
"app.sfu.mediaServerRequestTimeout2003": "Medieserverförfrågningar tar tidsgräns (fel 2003)",
"app.sfu.serverIceGatheringFailed2021": "Mediaservern kan inte samla in anslutningskandidater (ICE-fel 2021)",
"app.sfu.serverIceGatheringFailed2022": "Mediaserveranslutning misslyckades (ICE-fel 2022)",
"app.sfu.mediaGenericError2200": "Mediaservern kunde inte behandla begäran (fel 2200)",
"app.sfu.invalidSdp2202":"Klienten genererade en ogiltig mediabegäran (SDP-fel 2202)",
"app.sfu.noAvailableCodec2203": "Servern kunde inte hitta en lämplig codec (fel 2203)",
"app.meeting.endNotification.ok.label": "OK",
"app.whiteboard.annotations.poll": "Omröstningens resultat publicerades",
"app.whiteboard.annotations.pollResult": "Omröstningsresultat",
"app.whiteboard.annotations.noResponses": "Inga svar",
"app.whiteboard.annotations.notAllowed": "Du får inte göra denna ändring",
"app.whiteboard.annotations.numberExceeded": "Antalet anteckningar överskred gränsen ({0})",
"app.whiteboard.toolbar.tools": "Verktyg",
"app.whiteboard.toolbar.tools.hand": "Panorera",
"app.whiteboard.toolbar.tools.pencil": "Penna",
@ -813,6 +1075,7 @@
"app.whiteboard.toolbar.color.silver": "Silver",
"app.whiteboard.toolbar.undo": "Ångra annotering",
"app.whiteboard.toolbar.clear": "Rensa alla anteckningar",
"app.whiteboard.toolbar.clearConfirmation": "Är du säker på att du vill rensa alla kommentarer?",
"app.whiteboard.toolbar.multiUserOn": "Slå på multi-whiteboard",
"app.whiteboard.toolbar.multiUserOff": "Slå av multi-whiteboard",
"app.whiteboard.toolbar.palmRejectionOn": "Aktivera bortfiltrering av handtryck vid surfplatta (vid användning av penna)",
@ -832,13 +1095,13 @@
"app.videoDock.webcamUnfocusDesc": "Fokusera inte på den valda webbkameran",
"app.videoDock.webcamPinLabel": "Fäst",
"app.videoDock.webcamPinDesc": "Fäst vald kamera",
"app.videoDock.webcamFullscreenLabel": "Helskärmswebbkamera",
"app.videoDock.webcamSqueezedButtonLabel": "Webbkameraalternativ",
"app.videoDock.webcamUnpinLabel": "Frigör",
"app.videoDock.webcamUnpinLabelDisabled": "Endast moderatorer kan frigöra användare",
"app.videoDock.webcamUnpinDesc": "Frigör vald webbkamera",
"app.videoDock.autoplayBlockedDesc": "Vi behöver din tillåtelse att visa andra användares webbkameror.",
"app.videoDock.autoplayAllowLabel": "Visa webbkameror",
"app.invitation.title": "Gruppruminbjudan",
"app.invitation.confirm": "Inbjudan",
"app.createBreakoutRoom.title": "Grupprum",
"app.createBreakoutRoom.ariaTitle": "Dölj grupprum",
"app.createBreakoutRoom.breakoutRoomLabel": "Grupprum {0}",
@ -870,6 +1133,8 @@
"app.createBreakoutRoom.addRoomTime": "Öka grupprummens tid till",
"app.createBreakoutRoom.addParticipantLabel": "+ Lägg till deltagare",
"app.createBreakoutRoom.freeJoin": "Tillåt användarna att välja ett grupprum att gå med i",
"app.createBreakoutRoom.captureNotes": "Överför de delade anteckningarna när breakout-rummen är avslutade",
"app.createBreakoutRoom.captureSlides": "Överför whiteboarden när grupprum är avslutade",
"app.createBreakoutRoom.leastOneWarnBreakout": "Du måste placera minst en användare i ett grupprum.",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "Minsta tid för ett grupprum är {0} minuter.",
"app.createBreakoutRoom.modalDesc": "Tips: du kan dra och släppa användare för att tilldela dem till ett särskilt grupprum.",
@ -882,6 +1147,14 @@
"app.createBreakoutRoom.setTimeCancel": "Avbryt",
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "Grupprummens tid kan inte vara längre än mötets kvarvarande tid.",
"app.createBreakoutRoom.roomNameInputDesc": "Uppdaterar grupprummets namn",
"app.createBreakoutRoom.movedUserLabel": "Flyttade {0} till rum {1}",
"app.updateBreakoutRoom.modalDesc": "För att uppdatera eller bjuda in en användare drar du dem helt enkelt till önskat rum.",
"app.updateBreakoutRoom.cancelLabel": "Avbryt",
"app.updateBreakoutRoom.title": "Uppdatera Breakout-rum",
"app.updateBreakoutRoom.confirm": "Tillämpa",
"app.updateBreakoutRoom.userChangeRoomNotification": "Du flyttades till rum {0}.",
"app.smartMediaShare.externalVideo": "Externa video(r)",
"app.update.resetRoom": "Återställ användarrummet",
"app.externalVideo.start": "Dela en ny video",
"app.externalVideo.title": "Dela en extern video",
"app.externalVideo.input": "Extern Video URL",
@ -896,16 +1169,25 @@
"app.externalVideo.subtitlesOff": "Sätt på ( om tillgängligt)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Dela en extern video",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Sluta dela extern video",
"app.iOSWarning.label": "Vänligen uppgradera till iOS 12.2 eller senare",
"app.legacy.unsupportedBrowser": "Det verkar som om du använder en webbläsare som inte stöds. Använd antingen {0} eller {1} för fullt stöd.",
"app.legacy.upgradeBrowser": "Det verkar som om du använder en äldre version av en webbläsare som stöds. Uppgradera din webbläsare för fullständigt stöd.",
"app.legacy.criosBrowser": "På iOS använd Safari för fullständigt stöd.",
"app.debugWindow.windowTitle": "Debug",
"app.debugWindow.form.userAgentLabel": "Användaragent",
"app.debugWindow.form.button.copy": "Kopiera",
"app.debugWindow.form.enableAutoarrangeLayoutLabel": "Tillämpa Autolayout",
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(kommer inaktiveras om du ändrar storleken på webbkamera-fältet)",
"app.debugWindow.form.chatLoggerLabel": "Test chatt loggnivå.",
"app.debugWindow.form.button.apply": "Tillämpa",
"app.layout.modal.title": "Layouter",
"app.layout.modal.confirm": "Bekräfta",
"app.layout.modal.cancel": "Avbryt",
"app.layout.modal.layoutLabel": "Välj din layout",
"app.layout.modal.keepPushingLayoutLabel": "Skjut layouten till alla",
"app.layout.modal.pushLayoutLabel": "Skjuta till alla",
"app.layout.modal.layoutToastLabel": "Layoutinställningar ändrade",
"app.layout.modal.layoutSingular": "Layout",
"app.layout.modal.layoutBtnDesc": "Ställer in layout som valt alternativ",
"app.layout.style.custom": "Egen",
"app.layout.style.smart": "Smart layout",
"app.layout.style.presentationFocus": "Fokusera på presentation",
@ -931,8 +1213,12 @@
"playback.player.about.modal.shortcuts.shift": "Shift",
"playback.player.about.modal.shortcuts.fullscreen": "Slå på/av fullskärm",
"playback.player.about.modal.shortcuts.play": "Play/paus",
"playback.player.about.modal.shortcuts.section": "Växla sidosektion",
"playback.player.about.modal.shortcuts.seek.backward": "Sök bakåt",
"playback.player.about.modal.shortcuts.seek.forward": "Sök framåt",
"playback.player.about.modal.shortcuts.skip.next": "Nästa bild",
"playback.player.about.modal.shortcuts.skip.previous": "Föregående bild",
"playback.player.about.modal.shortcuts.swap": "Byt innehåll",
"playback.player.chat.message.poll.name": "Omröstningsresultat",
"playback.player.chat.message.poll.question": "Fråga",
"playback.player.chat.message.poll.options": "Alternativ",
@ -949,7 +1235,9 @@
"playback.player.search.modal.title": "Sök",
"playback.player.search.modal.subtitle": "Hitta presentationsinnehåll",
"playback.player.thumbnails.wrapper.aria": "Miniatyr-fält",
"playback.player.webcams.wrapper.aria": "Webbkameror område",
"app.learningDashboard.dashboardTitle": "Deltagarstatistik",
"app.learningDashboard.bigbluebuttonTitle": "BigBlueButton",
"app.learningDashboard.downloadSessionDataLabel": "Ladda ned sessionsdata",
"app.learningDashboard.lastUpdatedLabel": "Senast uppdaterad",
"app.learningDashboard.sessionDataDownloadedLabel": "Nedladdad!",
@ -974,6 +1262,12 @@
"app.learningDashboard.userDetails.response": "Svar",
"app.learningDashboard.userDetails.mostCommonAnswer": "Vanligaste frågan",
"app.learningDashboard.userDetails.anonymousAnswer": "Anonym omröstning",
"app.learningDashboard.userDetails.talkTime": "Taltid",
"app.learningDashboard.userDetails.messages": "Meddelanden",
"app.learningDashboard.userDetails.emojis": "Emojis",
"app.learningDashboard.userDetails.raiseHands": "Räck upp händerna",
"app.learningDashboard.userDetails.pollVotes": "Omröstningsröster",
"app.learningDashboard.userDetails.onlineIndicator": "{0} onlinetid",
"app.learningDashboard.usersTable.title": "Översikt",
"app.learningDashboard.usersTable.colOnline": "Tid online",
"app.learningDashboard.usersTable.colTalk": "Tid pratat",
@ -997,12 +1291,24 @@
"app.learningDashboard.pollsTable.anonymousRowName": "Anonym",
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "Inga omröstningar har skapats",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "När en omröstning har startats så syns resultatet här.",
"app.learningDashboard.pollsTable.answerTotal": "Total",
"app.learningDashboard.pollsTable.userLabel": "Användare",
"app.learningDashboard.statusTimelineTable.title": "Tidslinje",
"app.learningDashboard.statusTimelineTable.thumbnail": "Presentationsminiatyr",
"app.learningDashboard.statusTimelineTable.presentation": "Presentation",
"app.learningDashboard.statusTimelineTable.pageNumber": "Sida",
"app.learningDashboard.statusTimelineTable.setAt": "Ställs kl",
"app.learningDashboard.errors.invalidToken": "Ogiltig sessionstoken",
"app.learningDashboard.errors.dataUnavailable": "Data är inte längre tillgängligt",
"mobileApp.portals.list.empty.addFirstPortal.label": "Lägg till din första portal med knappen ovan,",
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "eller använd vår demoserver.",
"mobileApp.portals.list.add.button.label": "Lägg till portal",
"mobileApp.portals.fields.name.label": "Portalens namn",
"mobileApp.portals.fields.name.placeholder": "BigBlueButton demo",
"mobileApp.portals.fields.url.label": "Server URL",
"mobileApp.portals.addPortalPopup.confirm.button.label": "Spara",
"mobileApp.portals.drawerNavigation.button.label": "Portaler",
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Obligatoriska fält",
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Namn används redan",
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Fel vid laddning av sidan - kolla adress och uppkoppling"
}

View File

@ -1169,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Aç (olabiliyorsa)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Dışarıdan bir görüntü paylaş",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Dışarından görüntü paylaşımını durdur",
"app.iOSWarning.label": "Lütfen iOS 12.2 ya da üzerindeki bir sürüm kullanın",
"app.legacy.unsupportedBrowser": "Desteklenmeyen bir web tarayıcı kullanıyorsunuz. Lütfen tam destek almak için {0} ya da {1} kullanın.",
"app.legacy.upgradeBrowser": "Desteklenen bir web tarayıcının eski bir sürümünü kullanıyor gibi görünüyorsunuz. Lütfen tam destek almak için web tarayıcınızı güncelleyin.",
"app.legacy.criosBrowser": "Lütfen iOS üzerinde tam destek almak için Safari kullanın.",

View File

@ -2,10 +2,12 @@
"app.home.greeting": "Sunumunuz birazdan başlayacak...",
"app.chat.submitLabel": "Mesaj Gönder",
"app.chat.loading": "Sohbet mesajları yüklendi:% {0}",
"app.chat.errorMaxMessageLength": "Mesaj {0} karakter daha uzun",
"app.chat.errorMaxMessageLength": "İleti çok uzun. En fazla {0} karakter olabilir",
"app.chat.disconnected": "Bağlantınız kesildi, mesaj gönderilemedi",
"app.chat.locked": "Sohbet kapalı durumda, mesaj gönderilemiyor",
"app.chat.inputLabel": "{0} sohbeti için mesaj verisi",
"app.chat.emojiButtonLabel": "Emoji Seçici",
"app.chat.inputPlaceholder": "{0} mesajı",
"app.chat.titlePublic": "Genel Sohbet",
"app.chat.titlePrivate": "{0} ile Özel Sohbet",
"app.chat.partnerDisconnected": "{0} toplantıdan ayrıldı",
@ -20,6 +22,7 @@
"app.chat.offline": "Çevrim Dışı",
"app.chat.pollResult": "Anket sonuçları",
"app.chat.breakoutDurationUpdated": "Çalışma oda zamanı {0} dakika olarak güncellendi",
"app.chat.breakoutDurationUpdatedModerator": "Çalışma oda süresi {0} dakika olarak değiştirildi ve kullanıcılara bildirildi.",
"app.chat.emptyLogLabel": "Sohbet sistem kayıtları boş",
"app.chat.clearPublicChatMessage": "Genel sohbet geçmişi moderatör tarafından temizlendi",
"app.chat.multi.typing": "Birden çok kullanıcı yazıyor",
@ -27,6 +30,27 @@
"app.chat.two.typing": "{0} ve {1} yazıyor...",
"app.chat.copySuccess": "Sohbet yazışmaları kopyalandı",
"app.chat.copyErr": "Sohbet yazışmaları kopyalanırken hata oluştu",
"app.emojiPicker.search": "Ara",
"app.emojiPicker.notFound": "Emoji Bulunamadı",
"app.emojiPicker.skintext": "Varsayılan ten renginizi seçin",
"app.emojiPicker.clear": "Temizle",
"app.emojiPicker.categories.label": "Emoji kategorileri",
"app.emojiPicker.categories.people": "İnsanlar ve beden",
"app.emojiPicker.categories.nature": "Hayvanlar ve Doğa",
"app.emojiPicker.categories.foods": "Yiyecekler ve içecekler",
"app.emojiPicker.categories.places": "Seyahat ve Yerler",
"app.emojiPicker.categories.activity": "Etkinlik",
"app.emojiPicker.categories.objects": "Nesneler",
"app.emojiPicker.categories.symbols": "Semboller",
"app.emojiPicker.categories.flags": "Bayraklar",
"app.emojiPicker.categories.recent": "Sık kullanılanlar",
"app.emojiPicker.categories.search": "Arama Sonuçları",
"app.emojiPicker.skintones.1": "Varsayılan ten rengi",
"app.emojiPicker.skintones.2": "Açık ten rengi",
"app.emojiPicker.skintones.3": "Orta açık ten rengi",
"app.emojiPicker.skintones.4": "Orta ten rengi",
"app.emojiPicker.skintones.5": "Orta koyu ten rengi",
"app.emojiPicker.skintones.6": "Koyu ten rengi",
"app.captions.label": "Altyazılar",
"app.captions.menu.close": "Kapat",
"app.captions.menu.start": "Başlat",
@ -52,12 +76,23 @@
"app.captions.speech.start": "Konuşma tanıma başlatıldı",
"app.captions.speech.stop": "Konuşma tanıma durduruldu",
"app.captions.speech.error": "Tarayıcı uyumsuzluğu veya bir süre sessizlik nedeniyle konuşma tanıma durduruldu",
"app.confirmation.skipConfirm": "bir daha sorma",
"app.confirmation.virtualBackground.title": "Yeni bir sanal arka plan başlat",
"app.confirmation.virtualBackground.description": "{0} sanal arka plan olarak eklenecektir. Devam edilsin mi?",
"app.confirmationModal.yesLabel": "Evet",
"app.textInput.sendLabel": "Gönderildi",
"app.title.defaultViewLabel": "Varsayılan Sunum Görünümü",
"app.notes.title": "Paylaşılan Notlar",
"app.notes.titlePinned": "Paylaşılan Notlar (Sabitlenmiş)",
"app.notes.pinnedNotification": "Paylaşılan Notlar tahtaya sabitlendi.",
"app.notes.label": "notlar",
"app.notes.hide": "Notları gizle",
"app.notes.locked": "Kilitli",
"app.notes.disabled": "Medya alanına sabitlendi",
"app.notes.notesDropdown.covertAndUpload": "Notları sunuma dönüştür",
"app.notes.notesDropdown.pinNotes": "Notları tahtaya sabitle",
"app.notes.notesDropdown.unpinNotes": "Notların sabitlemesini kaldır",
"app.notes.notesDropdown.notesOptions": "Not seçenekleri",
"app.pads.hint": "pad araç çubuğuna odaklanmak için Esc tuşuna basın",
"app.user.activityCheck": "Kullanıcı etkinliği kontrolü",
"app.user.activityCheck.label": "Kullanıcının hala toplantıda olup olmadığını kontrol edin ({0})",
@ -131,6 +166,8 @@
"app.userList.userOptions.savedNames.title": "{1} - {0} toplantısındaki kullanıcı listesi",
"app.userList.userOptions.sortedFirstName.heading": "Ada göre sıralandı:",
"app.userList.userOptions.sortedLastName.heading": "Soyadına göre sıralandı:",
"app.userList.userOptions.hideViewersCursor": "Görüntüleyici imleçleri kilitli",
"app.userList.userOptions.showViewersCursor": "Görüntüleyici imleçleri kilitli değil",
"app.media.label": "Medya",
"app.media.autoplayAlertDesc": "Erişime izin ver",
"app.media.screenshare.start": "Ekran paylaşımı başladı",
@ -152,8 +189,8 @@
"app.meeting.meetingTimeRemaining": "Toplantının bitmesine kalan süre: {0}",
"app.meeting.meetingTimeHasEnded": "Zaman bitti. Toplantı kısa süre sonra kapanacak",
"app.meeting.endedByUserMessage": "Oturum {0} tarafından sonlandırıldı.",
"app.meeting.endedByNoModeratorMessageSingular": "Bir dakika moderatör bulunmadığı için toplantı sona erdi.",
"app.meeting.endedByNoModeratorMessagePlural": "{0} dakika moderatör bulunmadığı için toplantı sona erdi",
"app.meeting.endedByNoModeratorMessageSingular": "Oturumda Bir dakika boyunca moderatör bulunmadığı için toplantı sona erdi",
"app.meeting.endedByNoModeratorMessagePlural": "Oturumda {0} dakika boyunca moderatör bulunmadığı için toplantı sona erdi",
"app.meeting.endedMessage": "Ana ekrana geri yönlendirileceksiniz",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Toplantı bir dakika içinde kapanacak.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Toplantı {0} dakika içinde kapanacak.",
@ -167,6 +204,13 @@
"app.presentation.endSlideContent": "Slayt içeriği bitişi",
"app.presentation.changedSlideContent": "Sunu slayt {0} olarak değiştirildi.",
"app.presentation.emptySlideContent": "Mevcut slayt için içerik yok",
"app.presentation.options.fullscreen": "Sunumu tam ekran görüntüle",
"app.presentation.options.exitFullscreen": "Tam ekrandan çık",
"app.presentation.options.minimize": "Küçült",
"app.presentation.options.snapshot": "Geçerli slaytın ekran görüntüsü",
"app.presentation.options.downloading": "indiriliyor...",
"app.presentation.options.downloaded": "Mevcut sunum indirildi",
"app.presentation.options.downloadFailed": "Mevcut sunum indirilemedi",
"app.presentation.presentationToolbar.noNextSlideDesc": "Sunum sonu",
"app.presentation.presentationToolbar.noPrevSlideDesc": "Sunum başlangıcı",
"app.presentation.presentationToolbar.selectLabel": "Slayt seç",
@ -191,8 +235,24 @@
"app.presentation.presentationToolbar.fitToWidth": "Genişliğe sığdır",
"app.presentation.presentationToolbar.fitToPage": "Sayfaya sığdır",
"app.presentation.presentationToolbar.goToSlide": "Slayt {0}",
"app.presentation.presentationToolbar.hideToolsDesc": "Hide Toolbars",
"app.presentation.presentationToolbar.showToolsDesc": "Show Toolbars",
"app.presentation.placeholder": "Şu anda etkin bir sunum yok",
"app.presentationUploder.title": "Sunum",
"app.presentationUploder.message": "Sunucu olarak, herhangi bir ofis belgesini veya PDF dosyasını yükleyebilirsiniz. En iyi sonuçları elde etmek için PDF dosyası öneririz. Lütfen sağ taraftaki onay kutusunu kullanarak bir sunumun seçildiğinden emin olun.",
"app.presentationUploder.message": "Sunucu olarak, herhangi bir ofis ya da PDF belgesi yükleyebilirsiniz. En iyi sonucu almak için PDF belgesi kullanmanız önerilir. Lütfen sol taraftaki daire işaret kutusunu kullanarak bir sunum seçildiğinden emin olun.",
"app.presentationUploader.exportHint": "\"Sohbete gönder\" seçildiğinde, kullanıcılara herkese açık sohbet için ek açıklamalar bulunan bir indirilebilir bağlantı sunulur.",
"app.presentationUploader.exportToastHeader": "Sohbete gönderiliyor ({0} öge)",
"app.presentationUploader.exportToastHeaderPlural": "Sohbete gönderiliyor ({0} öge)",
"app.presentationUploader.exporting": "sohbete gönderiliyor",
"app.presentationUploader.sending": "gönderiliyor...",
"app.presentationUploader.collecting": "Slayt {0} / {1} ayıklanıyor...",
"app.presentationUploader.processing": "Slayt {0} / {1} açıklanıyor...",
"app.presentationUploader.sent": "Gönderildi",
"app.presentationUploader.exportingTimeout": "Dışa aktarma işlemi çok uzun sürüyor...",
"app.presentationUploader.export": "sohbete gönder",
"app.presentationUploader.export.linkAvailable": "{0} indirmek için bağlantıyı herkese açık sohbette bulabilirsiniz.",
"app.presentationUploader.export.notAccessibleWarning": "erişilebilirlik uyumlu olmayabilir",
"app.presentationUploader.currentPresentationLabel": "Mevcut sunum",
"app.presentationUploder.extraHint": "ÖNEMLİ: her dosya {0} MB boyutu ve {1} sayfayı aşamaz.",
"app.presentationUploder.uploadLabel": "Yükle",
"app.presentationUploder.confirmLabel": "Onayla",
@ -203,11 +263,14 @@
"app.presentationUploder.dropzoneImagesLabel": "Yüklemek istediğiniz belgeleri buraya sürükleyin",
"app.presentationUploder.browseFilesLabel": "ya da dosyalara göz at",
"app.presentationUploder.browseImagesLabel": "veya dosyalara göz atın",
"app.presentationUploder.externalUploadTitle": "3. taraf uygulamadan içerik ekle",
"app.presentationUploder.externalUploadLabel": "Göz at",
"app.presentationUploder.fileToUpload": "Yüklenecek ...",
"app.presentationUploder.currentBadge": "Şimdiki",
"app.presentationUploder.rejectedError": "Seçilen dosya(lar) reddedildi. Lütfen dosya tür(ler)ini kontrol edin.",
"app.presentationUploder.connectionClosedError": "Zayıf bağlantı nedeniyle kesintiye uğradı. Lütfen tekrar deneyin.",
"app.presentationUploder.upload.progress": "Yükleniyor ({0}%)",
"app.presentationUploder.conversion.204": "Yakalanacak bir içerik bulunamadı",
"app.presentationUploder.upload.413": "Dosya çok büyük, maksimum {0} MB'yi aştı",
"app.presentationUploder.genericError": "Bir şeyler yanlış gitti...",
"app.presentationUploder.upload.408": "Yükleme isteği kodunun süresi geçmiş.",
@ -219,14 +282,14 @@
"app.presentationUploder.conversion.generatedSlides": "Slaytlar oluşturuluyor ...",
"app.presentationUploder.conversion.generatingSvg": "SVG görselleri üretiliyor ...",
"app.presentationUploder.conversion.pageCountExceeded": "Sayfa sayısı maksimum {0} sınırını aştı",
"app.presentationUploder.conversion.invalidMimeType": "Geçersiz biçim algılandı (uzantı={0}, içerik türü={1})",
"app.presentationUploder.conversion.conversionTimeout": "{0}. slayt {1} denemede işlenemedi.",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Ofis belgesi işlenemiyor. Lütfen onun yerine PDF yükleyiniz.",
"app.presentationUploder.conversion.officeDocConversionFailed": "Ofis belgesi işlenemiyor. Lütfen onun yerine PDF yükleyiniz.",
"app.presentationUploder.conversion.pdfHasBigPage": "PDF dosyasını dönüştüremedik, lütfen optimize etmeyi deneyin. Maksimum sayfa boyutu {0}",
"app.presentationUploder.conversion.timeout": "Hata, dönüşüm çok uzun sürdü",
"app.presentationUploder.conversion.pageCountFailed": "Sayfa sayısı belirlenemiyor.",
"app.presentationUploder.conversion.unsupportedDocument": "Dosya uzantısı desteklenmiyor",
"app.presentationUploder.isDownloadableLabel": "Sunum indirmeye izin verilmiyor - sunumun indirilmesine izin vermek için tıklayın",
"app.presentationUploder.isNotDownloadableLabel": "Sunum indirmeye izin veriliyor - izni kaldırmak için tıklayın",
"app.presentationUploder.removePresentationLabel": "Sunumu kaldır",
"app.presentationUploder.setAsCurrentPresentation": "Sunumu varsayılan olarak ayarla",
"app.presentationUploder.tableHeading.filename": "Dosya adı",
@ -240,6 +303,10 @@
"app.presentationUploder.clearErrors": "Hataları temizle",
"app.presentationUploder.clearErrorsDesc": "Başarısız sunum yüklemelerini temizler",
"app.presentationUploder.uploadViewTitle": "Sunum Yükle",
"app.poll.questionAndoptions.label" : "Görüntülenecek soru metni.A. Anket seçeneği *B. Anket seçeneği (isteğe bağlı)C. Anket seçeneği (isteğe bağlı)D. Anket seçeneği (isteğe bağlı)E. Anket seçeneği (isteğe bağlı)",
"app.poll.customInput.label": "Özel giriş",
"app.poll.customInputInstructions.label": "Özel giriş etkinleştirildi. Anket sorularını ve seçeneklerini belirtilen biçimde yazın ya da aynı biçimde bir metin dosyasını sürükleyip bırakın.",
"app.poll.maxOptionsWarning.label": "Sadece ilk 5 seçenek kullanılabilir!",
"app.poll.pollPaneTitle": "Anket",
"app.poll.enableMultipleResponseLabel": "Kişilerin birden fazla yanıt gönderebilmesine izin vermek istiyor musunuz?",
"app.poll.quickPollTitle": "Hızlı Anket",
@ -259,7 +326,7 @@
"app.poll.clickHereToSelect": "Seçmek için buraya tıklayın",
"app.poll.question.label" : "Sorunuzu yazın...",
"app.poll.optionalQuestion.label" : "Sorunuzu yazın (isteğe bağlı)...",
"app.poll.userResponse.label" : "Kullanıcı Yanıtı",
"app.poll.userResponse.label" : "Yazılan Yanıt",
"app.poll.responseTypes.label" : "Soru Türleri",
"app.poll.optionDelete.label" : "Silin",
"app.poll.responseChoices.label" : "Soru Seçenekleri",
@ -318,7 +385,7 @@
"app.muteWarning.disableMessage": "Sesi açılıncaya kadar uyarıların sesini kapatma devre dışı bırakıldı",
"app.muteWarning.tooltip": "Kapatmak için tıklayın ve bir sonraki sessize alınana kadar uyarıyı devre dışı bırakın",
"app.navBar.settingsDropdown.optionsLabel": "Seçenekler",
"app.navBar.settingsDropdown.fullscreenLabel": "Tam Ekran",
"app.navBar.settingsDropdown.fullscreenLabel": "Uygulamayı tam ekran görüntüle",
"app.navBar.settingsDropdown.settingsLabel": "Ayarlar",
"app.navBar.settingsDropdown.aboutLabel": "Hakkında",
"app.navBar.settingsDropdown.leaveSessionLabel": "Toplantıdan Ayrıl",
@ -331,6 +398,7 @@
"app.navBar.settingsDropdown.hotkeysLabel": "Klavye Kısayolları",
"app.navBar.settingsDropdown.hotkeysDesc": "Kullanılabilir klavye kısayollarının listesi",
"app.navBar.settingsDropdown.helpLabel": "Yardım",
"app.navBar.settingsDropdown.openAppLabel": "BigBlueButton Tablet uygulamasında aç",
"app.navBar.settingsDropdown.helpDesc": "Kullanıcıyı video derslerine bağlar (yeni sekme açılır)",
"app.navBar.settingsDropdown.endMeetingDesc": "Mevcut toplantıyı sonlandırır",
"app.navBar.settingsDropdown.endMeetingLabel": "Toplantıyı Sonlandır",
@ -348,7 +416,7 @@
"app.endMeeting.description": "Bu işlem, {0} aktif kullanıcı için oturumu sonlandıracak. Bu oturumu sonlandırmak istediğinizden emin misiniz?",
"app.endMeeting.noUserDescription": "Bu oturumu sonlandırmak istediğinizden emin misiniz?",
"app.endMeeting.contentWarning": "Bu oturum için sohbet mesajlarına, notlara, beyaz tahta içeriğine ve paylaşılan belgelere artık doğrudan erişilemeyecek",
"app.endMeeting.yesLabel": "Evet",
"app.endMeeting.yesLabel": "Tüm kullanıcılar için oturumu sonlandır",
"app.endMeeting.noLabel": "Hayır",
"app.about.title": "Hakkında",
"app.about.version": "Müşteri yapısı:",
@ -358,6 +426,15 @@
"app.about.confirmDesc": "TAMAM",
"app.about.dismissLabel": "Vazgeç",
"app.about.dismissDesc": "Kullanıcı bilgilerini kapat",
"app.mobileAppModal.title": "BigBlueButton Tablet uygulamasını aç",
"app.mobileAppModal.description": "Cihazınızda BigBlueButton Tablet uygulaması yüklü mü?",
"app.mobileAppModal.openApp": "Evet, uygulamayı şimdi aç",
"app.mobileAppModal.obtainUrlMsg": "Toplantı bağlantısı alınıyor",
"app.mobileAppModal.obtainUrlErrorMsg": "Toplantı bağlantısı alınırken bir hata oluştu",
"app.mobileAppModal.openStore": "Hayır, indirmek için App Store'u aç",
"app.mobileAppModal.dismissLabel": "İptal",
"app.mobileAppModal.dismissDesc": "Kapat",
"app.mobileAppModal.userConnectedWithSameId": "{0} kullanıcısı sizinle aynı kodu kullanarak bağlandı.",
"app.actionsBar.changeStatusLabel": "Durumu değiştir",
"app.actionsBar.muteLabel": "Sustur",
"app.actionsBar.unmuteLabel": "Sesi Aç",
@ -368,10 +445,13 @@
"app.actionsBar.actionsDropdown.restorePresentationDesc": "Küçültüldükten sonra sunumu geri yükleyen düğme",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Sunumu simge durumuna küçült",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Sunumu simge durumuna küçültmek için kullanılan düğme",
"app.actionsBar.actionsDropdown.layoutModal": "Ekran düzeni ayarları üste açılan penceresi",
"app.screenshare.screenShareLabel" : "Ekran paylaşımı",
"app.submenu.application.applicationSectionTitle": "Uygulama",
"app.submenu.application.animationsLabel": "Animasyonlar",
"app.submenu.application.audioFilterLabel": "Mikrofon için Ses Filtreleri",
"app.submenu.application.wbToolbarsAutoHideLabel": "Auto Hide Whiteboard Toolbars",
"app.submenu.application.darkThemeLabel": "Karanlık mod",
"app.submenu.application.fontSizeControlLabel": "Yazı Büyüklüğü",
"app.submenu.application.increaseFontBtnLabel": "Uygulama Yazı Büyüklüğünü Artır",
"app.submenu.application.decreaseFontBtnLabel": "Uygulama Yazı Büyüklüğünü Azalt",
@ -381,6 +461,69 @@
"app.submenu.application.noLocaleOptionLabel": "Aktif yerel ayar bulunamadı",
"app.submenu.application.paginationEnabledLabel": "Video sayfalama",
"app.submenu.application.layoutOptionLabel": "Yerleşim Türü",
"app.submenu.application.pushLayoutLabel": "Ekran düzenini gönder",
"app.submenu.application.localeDropdown.af": "Afrikaanca",
"app.submenu.application.localeDropdown.ar": "Arapça",
"app.submenu.application.localeDropdown.az": "Azerice",
"app.submenu.application.localeDropdown.bg-BG": "Bulgarca",
"app.submenu.application.localeDropdown.bn": "Bengalce",
"app.submenu.application.localeDropdown.ca": "Katalanca",
"app.submenu.application.localeDropdown.cs-CZ": "Çek",
"app.submenu.application.localeDropdown.da": "Danimarka dili",
"app.submenu.application.localeDropdown.de": "Almanca",
"app.submenu.application.localeDropdown.dv": "divehi dili",
"app.submenu.application.localeDropdown.el-GR": "Yunanca (Yunanistan)",
"app.submenu.application.localeDropdown.en": "İngilizce",
"app.submenu.application.localeDropdown.eo": "Esperanto",
"app.submenu.application.localeDropdown.es": "İspanyolca",
"app.submenu.application.localeDropdown.es-419": "İspanyolca (Latin Amerika)",
"app.submenu.application.localeDropdown.es-ES": "İspanyolca (İspanya)",
"app.submenu.application.localeDropdown.es-MX": "İspanyolca (Meksika)",
"app.submenu.application.localeDropdown.et": "Estonian",
"app.submenu.application.localeDropdown.eu": "Bask",
"app.submenu.application.localeDropdown.fa-IR": "Farsça",
"app.submenu.application.localeDropdown.fi": "Fince",
"app.submenu.application.localeDropdown.fr": "Fransızca",
"app.submenu.application.localeDropdown.gl": "Galiçyaca",
"app.submenu.application.localeDropdown.he": "İbranice",
"app.submenu.application.localeDropdown.hi-IN": "Hintçe",
"app.submenu.application.localeDropdown.hr": "Hırvatça",
"app.submenu.application.localeDropdown.hu-HU": "Macarca",
"app.submenu.application.localeDropdown.hy": "Ermenice",
"app.submenu.application.localeDropdown.id": "Endonezya dili",
"app.submenu.application.localeDropdown.it-IT": "İtalyanca",
"app.submenu.application.localeDropdown.ja": "Japonca",
"app.submenu.application.localeDropdown.ka": "Gürcüce",
"app.submenu.application.localeDropdown.km": "kmer dili",
"app.submenu.application.localeDropdown.kn": "kannada dili",
"app.submenu.application.localeDropdown.ko-KR": "Korece (Kore)",
"app.submenu.application.localeDropdown.lo-LA": "laoca",
"app.submenu.application.localeDropdown.lt-LT": "Litvanyaca",
"app.submenu.application.localeDropdown.lv": "Letonca",
"app.submenu.application.localeDropdown.ml": "malayalam dili",
"app.submenu.application.localeDropdown.mn-MN": "Moğolca",
"app.submenu.application.localeDropdown.nb-NO": "Norveççe (bokmal)",
"app.submenu.application.localeDropdown.nl": "Flemenkçe",
"app.submenu.application.localeDropdown.oc": "Oksitanca",
"app.submenu.application.localeDropdown.pl-PL": "Lehçe",
"app.submenu.application.localeDropdown.pt": "Portekizce",
"app.submenu.application.localeDropdown.pt-BR": "Portekizce (Brezilya)",
"app.submenu.application.localeDropdown.ro-RO": "Romence",
"app.submenu.application.localeDropdown.ru": "Rusça",
"app.submenu.application.localeDropdown.sk-SK": "Slovakça (Slovakya)",
"app.submenu.application.localeDropdown.sl": "Slovence",
"app.submenu.application.localeDropdown.sr": "Sırpça",
"app.submenu.application.localeDropdown.sv-SE": "İsveççe",
"app.submenu.application.localeDropdown.ta": "Tamilce",
"app.submenu.application.localeDropdown.te": "Telugu dili",
"app.submenu.application.localeDropdown.th": "tay dili",
"app.submenu.application.localeDropdown.tr": "Türkçe",
"app.submenu.application.localeDropdown.tr-TR": "Türkçe (Türkiye)",
"app.submenu.application.localeDropdown.uk-UA": "Ukraynaca",
"app.submenu.application.localeDropdown.vi": "Vietnamca",
"app.submenu.application.localeDropdown.vi-VN": "Vietnamca (Vietnam)",
"app.submenu.application.localeDropdown.zh-CN": "Basitleştirilmiş Çince (Çin)",
"app.submenu.application.localeDropdown.zh-TW": "Geleneksel Çince (Tayvan)",
"app.submenu.notification.SectionTitle": "Bildirimler",
"app.submenu.notification.Desc": "Bildirim tercihlerinizi belirleyin.",
"app.submenu.notification.audioAlertLabel": "Sesli Uyarılar",
@ -409,7 +552,7 @@
"app.settings.main.save.label.description": "Değişiklikleri kaydeder ve ayarlar menüsünü kapatır",
"app.settings.dataSavingTab.label": "Veri Tasarrufu",
"app.settings.dataSavingTab.webcam": "Web kameralarını etkinleştir",
"app.settings.dataSavingTab.screenShare": "Masaüstü paylaşımını etkinleştir",
"app.settings.dataSavingTab.screenShare": "Diğer katılımcılar masaüstlerini paylaşabilsin",
"app.settings.dataSavingTab.description": "Bant genişliğinden tasarruf etmek için mevcut gösterimi ayarlayın.",
"app.settings.save-notification.label": "Ayarlar kaydedildi",
"app.statusNotifier.lowerHands": "Elleri indir",
@ -426,10 +569,9 @@
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ konuşuyordu",
"app.talkingIndicator.wasTalking" : "{0} konuşmayı durdurdu",
"app.actionsBar.actionsDropdown.actionsLabel": "Eylemler",
"app.actionsBar.actionsDropdown.presentationLabel": "Sunumları Yönet",
"app.actionsBar.actionsDropdown.presentationLabel": "Sunumları Yükle/Yönet",
"app.actionsBar.actionsDropdown.initPollLabel": "Oylama başlat",
"app.actionsBar.actionsDropdown.desktopShareLabel": "Ekranını paylaş",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "Ekran paylaşımı kilitli",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "Ekran paylaşımını sonlandır",
"app.actionsBar.actionsDropdown.presentationDesc": "Sunumunuzu yükleyin",
"app.actionsBar.actionsDropdown.initPollDesc": "Oylama başlat",
@ -446,6 +588,7 @@
"app.actionsBar.actionsDropdown.takePresenterDesc": "Kendinizi yeni eğitimci olarak atayın",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "Rastgele Kullanıcı Seç",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "Mevcut katılımcılardan rastgele bir kullanıcı seçer",
"app.actionsBar.actionsDropdown.propagateLayoutLabel": "Ekran düzenini yayınla",
"app.actionsBar.emojiMenu.statusTriggerLabel": "Durumu ayarla",
"app.actionsBar.emojiMenu.awayLabel": "Dışarıda",
"app.actionsBar.emojiMenu.awayDesc": "Durumunu dışarıda yap",
@ -485,6 +628,7 @@
"app.audioNotification.audioFailedError1012": "Bağlantı kapatıldı (ICE hatası 1012)",
"app.audioNotification.audioFailedMessage": "Ses bağlantınız sağlanamadı",
"app.audioNotification.mediaFailedMessage": "Yalnızca güvenli kaynaklara izin verildiğinden getUserMicMedia başarısız oldu",
"app.audioNotification.deviceChangeFailed": "Ses aygıtı değiştirilemedi. Seçilen aygıtın doğru şekilde kurulmuş ve kullanılabilir olduğundan emin olun",
"app.audioNotification.closeLabel": "Kapat",
"app.audioNotificaion.reconnectingAsListenOnly": "Mikrofon katılımcılar için kilitlendi, oturuma dinleyici olarak devam edebilirsiniz",
"app.breakoutJoinConfirmation.title": "Çalışma odasına katıl",
@ -495,6 +639,10 @@
"app.breakoutJoinConfirmation.freeJoinMessage": "Katılmak için bir çalışma odası seçin",
"app.breakoutTimeRemainingMessage": "Çalışma odası için kalan zaman: {0}",
"app.breakoutWillCloseMessage": "Süre bitti. Çalışma odası birazdan kapanacak",
"app.breakout.dropdown.manageDuration": "Süreyi değiştir",
"app.breakout.dropdown.destroyAll": "Çalışma odalarını sonlandır",
"app.breakout.dropdown.options": "Çalışma Oda Seçenekleri",
"app.breakout.dropdown.manageUsers": "Kullanıcıları Yönet",
"app.calculatingBreakoutTimeRemaining": "Kalan süre hesaplanıyor...",
"app.audioModal.ariaTitle": "Ses modunda katılın",
"app.audioModal.microphoneLabel": "Mikrofon",
@ -541,6 +689,7 @@
"app.audio.changeAudioDevice": "Ses cihazını değiştir",
"app.audio.enterSessionLabel": "Oturuma Katıl",
"app.audio.playSoundLabel": "Ses çal",
"app.audio.stopAudioFeedback": "Ses geri beslemesini durdur",
"app.audio.backLabel": "Geri",
"app.audio.loading": "Yükleniyor",
"app.audio.microphones": "Mikrofonlar",
@ -550,12 +699,35 @@
"app.audio.audioSettings.descriptionLabel": "Web tarayıcınızda mikrofon paylaşımıyla ilgili iletişim kutusu görünecektir, onaylamayı unutmayınız.",
"app.audio.audioSettings.microphoneSourceLabel": "Mikrofon kaynağı",
"app.audio.audioSettings.speakerSourceLabel": "Hoparlör kaynağı",
"app.audio.audioSettings.testSpeakerLabel": "Hoparlörü test ed",
"app.audio.audioSettings.microphoneStreamLabel": "Sesinizin seviyesi",
"app.audio.audioSettings.retryLabel": "Yeniden Dene",
"app.audio.audioSettings.fallbackInputLabel": "{0} ses girişi",
"app.audio.audioSettings.fallbackOutputLabel": "{0} ses çıkışı",
"app.audio.audioSettings.defaultOutputDeviceLabel": "Varsayılan",
"app.audio.audioSettings.findingDevicesLabel": "Cihazlar aranıyor...",
"app.audio.listenOnly.backLabel": "Geri",
"app.audio.listenOnly.closeLabel": "Kapat",
"app.audio.permissionsOverlay.title": "BigBlueButton'un Medya Cihazlarınızı kullanmasına izin verin",
"app.audio.permissionsOverlay.hint": "Sesli oturuma katılmak için medya cihazlarınızı kullanmamıza izin vermeniz gerekiyor :)",
"app.audio.captions.button.start": "Altyazıları başlat",
"app.audio.captions.button.stop": "Altyazıları durdur",
"app.audio.captions.button.language": "Dil",
"app.audio.captions.button.transcription": "Yazıya dökme",
"app.audio.captions.button.transcriptionSettings": "Transcription settings",
"app.audio.captions.speech.title": "Otomatik yazıya dökme",
"app.audio.captions.speech.disabled": "Devre dışı",
"app.audio.captions.speech.unsupported": "Web tarayıcınız konuşma tanıma özelliğini desteklemiyor. Sesiniz yazıya dökülemeyecek",
"app.audio.captions.select.de-DE": "Almanca",
"app.audio.captions.select.en-US": "İngilizce",
"app.audio.captions.select.es-ES": "İspanyol",
"app.audio.captions.select.fr-FR": "Fransızca",
"app.audio.captions.select.hi-ID": "Hintçe",
"app.audio.captions.select.it-IT": "İtalyanca",
"app.audio.captions.select.ja-JP": "Japonca",
"app.audio.captions.select.pt-BR": "Portekizce",
"app.audio.captions.select.ru-RU": "Rusça",
"app.audio.captions.select.zh-CN": "Çince",
"app.error.removed": "Konferanstan uzaklaştırıldınız",
"app.error.meeting.ended": "Konferanstan ayrıldınız",
"app.meeting.logout.duplicateUserEjectReason": "Toplantıya katılmaya çalışan mükerrer kullanıcı",
@ -563,6 +735,7 @@
"app.meeting.logout.ejectedFromMeeting": "Toplantıdan çıkarıldınız",
"app.meeting.logout.validateTokenFailedEjectReason": "Yetkilendirme belirteci/token doğrulanamadı",
"app.meeting.logout.userInactivityEjectReason": "Kullanıcı uzun süredir aktif değil",
"app.meeting.logout.maxParticipantsReached": "Bu toplantı için izin verilen maksimum katılımcı sayısına ulaşıldı",
"app.meeting-ended.rating.legendLabel": "Geribildirim oylaması",
"app.meeting-ended.rating.starLabel": "Yıldız",
"app.modal.close": "Kapat",
@ -584,16 +757,19 @@
"app.error.403": "Toplantıdan çıkarıldınız",
"app.error.404": "Bulunamadı",
"app.error.408": "Kimlik doğrulama başarısız oldu",
"app.error.409": "Çakışma",
"app.error.410": "Toplantı sona erdi",
"app.error.500": "Hops, birşeyler ters gitti",
"app.error.503": "Bağlantınız kesildi",
"app.error.disconnected.rejoin": "Tekrar katılmak için sayfayı yenileyebilirsiniz.",
"app.error.userLoggedOut": "Kullanıcı oturumu kapattığı için geçersiz bir sessionToken'a sahip",
"app.error.ejectedUser": "Kullanıcı, çıkarma nedeniyle geçersiz bir sessionToken'a sahip",
"app.error.joinedAnotherWindow": "Bu oturum başka bir web tarayıcı penceresinde açık gibi görünüyor.",
"app.error.userBanned": "Kullanıcı yasaklandı",
"app.error.leaveLabel": "Tekrar giriş yap",
"app.error.fallback.presentation.title": "Bir hata oluştu",
"app.error.fallback.presentation.description": "Giriş yapıldı. Lütfen sayfayı yeniden yüklemeyi deneyin.",
"app.error.fallback.presentation.reloadButton": "Tekrar yükle",
"app.guest.waiting": "Katılım onayı bekleniyor",
"app.guest.errorSeeConsole": "Hata: konsolda daha fazla ayrıntı.",
"app.guest.noModeratorResponse": "Moderatörden cevap yok.",
"app.guest.noSessionToken": "Oturum izni alınmadı.",
@ -628,14 +804,18 @@
"app.userList.guest.privateMessageLabel": "Mesaj",
"app.userList.guest.acceptLabel": "Kabul et",
"app.userList.guest.denyLabel": "Reddet",
"app.userList.guest.feedbackMessage": "İşlem uygulandı:",
"app.user-info.title": "Dizin araması",
"app.toast.breakoutRoomEnded": "Çalışma odası sonlandı. Lütfen sesli görüşmeye yeniden katılın.",
"app.toast.chat.public": "Yeni Genel Sohbet mesajı",
"app.toast.chat.private": "Yeni Özel Sohbet mesajı",
"app.toast.chat.system": "Sistem",
"app.toast.chat.poll": "Anket Sonuçları",
"app.toast.chat.pollClick": "Anket sonuçları yayınlandı. Görmek için buraya tıklayın.",
"app.toast.clearedEmoji.label": "Emoji durumu temizlendi",
"app.toast.setEmoji.label": "Emoji durumu {0} olarak ayarlandı",
"app.toast.meetingMuteOn.label": "Tüm kullanıcılar için ses kapatıldı",
"app.toast.meetingMuteOnViewers.label": "Tüm izleyicilerin sesi kapatıldı",
"app.toast.meetingMuteOff.label": "Toplantı sesi açıldı.",
"app.toast.setEmoji.raiseHand": "Elinizi kaldırdınız",
"app.toast.setEmoji.lowerHand": "elin indirildi",
@ -651,6 +831,7 @@
"app.shortcut-help.title": "Klavye kısayolları",
"app.shortcut-help.accessKeyNotAvailable": "Erişim tuşları mevcut değil",
"app.shortcut-help.comboLabel": "Açılan Kutu",
"app.shortcut-help.alternativeLabel": "Alternatif",
"app.shortcut-help.functionLabel": "Fonksiyon",
"app.shortcut-help.closeLabel": "Kapat",
"app.shortcut-help.closeDesc": "Klavye kısayolları modunu kapatır",
@ -668,6 +849,42 @@
"app.shortcut-help.toggleFullscreen": "Tam ekranıın/kapatın (Sunum yapan kişi)",
"app.shortcut-help.nextSlideDesc": "Sonraki Slayt (Eğitimci)",
"app.shortcut-help.previousSlideDesc": "Önceki Slayt (Eğitimci)",
"app.shortcut-help.togglePanKey": "Boşluk çubuğu",
"app.shortcut-help.toggleFullscreenKey": "Enter",
"app.shortcut-help.nextSlideKey": "Sağ ok",
"app.shortcut-help.previousSlideKey": "Sol ok",
"app.shortcut-help.select": "Seçim aracı",
"app.shortcut-help.pencil": "Kalem",
"app.shortcut-help.eraser": "Silgi",
"app.shortcut-help.rectangle": "Dikdörtgen",
"app.shortcut-help.elipse": "Elips",
"app.shortcut-help.triangle": "Üçgen",
"app.shortcut-help.line": "Çizgi",
"app.shortcut-help.arrow": "Ok",
"app.shortcut-help.text": "Metin Aracı",
"app.shortcut-help.note": "Yapışkan not",
"app.shortcut-help.general": "Genel",
"app.shortcut-help.presentation": "Sunum",
"app.shortcut-help.whiteboard": "beyaz tahta",
"app.shortcut-help.zoomIn": "Yakınlaştır",
"app.shortcut-help.zoomOut": "Uzaklaştır",
"app.shortcut-help.zoomFit": "Yakınlaştırmayı Sıfırla",
"app.shortcut-help.zoomSelect": "Seçime Yakınlaştır",
"app.shortcut-help.flipH": "Yatay çevir",
"app.shortcut-help.flipV": "Dikey çevir",
"app.shortcut-help.lock": "Kilitle / kilidi aç",
"app.shortcut-help.moveToFront": "Öne getir",
"app.shortcut-help.moveToBack": "Arkaya götür",
"app.shortcut-help.moveForward": "Daha öne getir",
"app.shortcut-help.moveBackward": "Daha arkaya götür",
"app.shortcut-help.undo": "Geri al",
"app.shortcut-help.redo": "Yenile",
"app.shortcut-help.cut": "Kesmek",
"app.shortcut-help.copy": "Kopyala",
"app.shortcut-help.paste": "Yapıştır",
"app.shortcut-help.selectAll": "Tümünü seç",
"app.shortcut-help.delete": "Sil",
"app.shortcut-help.duplicate": "Çoğalt",
"app.lock-viewers.title": "Katılımcıları Kilitle",
"app.lock-viewers.description": "Bu seçenekler, izleyicilerin belirli özellikleri kullanmasını kısıtlamanıza olanak tanır.",
"app.lock-viewers.featuresLable": "Özellik",
@ -683,6 +900,7 @@
"app.lock-viewers.button.apply": "Uygula",
"app.lock-viewers.button.cancel": "Vazgeç",
"app.lock-viewers.locked": "Kilitli",
"app.lock-viewers.hideViewersCursor": "Diğer izleyicilerin imleçlerini gö",
"app.guest-policy.ariaTitle": "Misafir politikası ayarları modeli",
"app.guest-policy.title": "Misafir Politikası",
"app.guest-policy.description": "Toplantı misafir politika ayarını değiştirin",
@ -703,6 +921,7 @@
"app.connection-status.no": "Hayır",
"app.connection-status.notification": "Bağlantınızda kayıp tespit edildi",
"app.connection-status.offline": "çevrim dışı",
"app.connection-status.clientNotRespondingWarning": "İstemci yanıt vermiyor",
"app.connection-status.audioUploadRate": "Ses Yükleme Hızı",
"app.connection-status.audioDownloadRate": "Ses İndirme Hızı",
"app.connection-status.videoUploadRate": "Video Yükleme Hızı",
@ -716,13 +935,19 @@
"app.connection-status.next": "Sonraki Sayfa",
"app.connection-status.prev": "Önceki sayfa",
"app.learning-dashboard.label": "Öğrenme Analitiği Kontrol Paneli",
"app.learning-dashboard.description": "Kullanıcı etkinlikleriyle birlikte katılım panosunu aç",
"app.learning-dashboard.description": "Kullanıcı etkinlikleriyle katılım panosu",
"app.learning-dashboard.clickHereToOpen": "Öğrenme analitik kontrol panelini aç",
"app.recording.startTitle": "Kaydı Başlat",
"app.recording.stopTitle": "Kaydı Durdur",
"app.recording.resumeTitle": "Kaydı Devam Ettir",
"app.recording.startDescription": "Kaydı duraklatmak için kayıt düğmesini daha sonra tekrar kullanabilirsiniz.",
"app.recording.stopDescription": "Kaydı duraklatmak istediğinizden emin misiniz? Kayıt düğmesine tekrar basarak devam edebilirsiniz.",
"app.recording.notify.title": "kayıt başladı",
"app.recording.notify.description": "Bu oturumun geri kalanının kaydı kullanılabilecek",
"app.recording.notify.continue": "Devam et",
"app.recording.notify.leave": "Oturumdan ayrıl",
"app.recording.notify.continueLabel" : "Kayıt alınacağını onayla ve ilerle",
"app.recording.notify.leaveLabel" : "Kayıt alınmasını reddet ve toplantıdan ayrıl",
"app.videoPreview.cameraLabel": "Kamera",
"app.videoPreview.profileLabel": "Kalite",
"app.videoPreview.quality.low": "düşük",
@ -739,13 +964,20 @@
"app.videoPreview.webcamOptionLabel": "Web kamerası seçin",
"app.videoPreview.webcamPreviewLabel": "Web kamerası ön izlemesi",
"app.videoPreview.webcamSettingsTitle": "Web kamerası ayarları",
"app.videoPreview.webcamEffectsTitle": "Kamera görsel EFEKTLERİ",
"app.videoPreview.webcamVirtualBackgroundLabel": "Sanal arka plan ayarları",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Bu cihaz sanal arka planları desteklemiyor",
"app.videoPreview.webcamNotFoundLabel": "Web kamerası bulunamadı",
"app.videoPreview.profileNotFoundLabel": "Desteklenen kamera profili yok",
"app.videoPreview.brightness": "Parlaklık",
"app.videoPreview.wholeImageBrightnessLabel": "Tam görsel",
"app.videoPreview.wholeImageBrightnessDesc": "Akışa ve arka plan görseline parlaklık uygular",
"app.videoPreview.sliderDesc": "ParlakLIK düzeyini artırın ya da azaltın",
"app.video.joinVideo": "Web kamerası paylaş",
"app.video.connecting": "Web kamerası paylaşımı başlıyor ...",
"app.video.leaveVideo": "Web kamerası paylaşımını durdur",
"app.video.videoSettings": "Video ayarları",
"app.video.visualEffects": "Görsel efektler",
"app.video.advancedVideo": "Gelişmiş ayarları aç",
"app.video.iceCandidateError": "ICE adayı ekleme hatası",
"app.video.iceConnectionStateError": "Bağlantı başarısız (ICE hatası 1107)",
@ -761,6 +993,7 @@
"app.video.notReadableError": "Web kamerası videosu alınamadı. Lütfen başka bir programın web kamerasını kullanmadığından emin olun",
"app.video.timeoutError": "Tarayıcı gerekli zaman içersinde yanıt vermedi.",
"app.video.genericError": "Cihazda bilinmeyen bir hata oluştu (Hata {0})",
"app.video.inactiveError": "Web kameranız beklenmedik bir şekilde durdu. Lütfen web tarayıcınızın izinlerini gözden geçirin",
"app.video.mediaTimedOutError": "Web kamerası akışı kesildi. Tekrar paylaşmayı deneyin",
"app.video.mediaFlowTimeout1020": "Medya, sunucuya ulaşamıyor (hata 1020)",
"app.video.suggestWebcamLock": "İzleyicilerin web kamera ayarlarını kilitlemeye zorla",
@ -783,8 +1016,19 @@
"app.video.virtualBackground.board": "Yazı tahtası",
"app.video.virtualBackground.coffeeshop": "Kafe",
"app.video.virtualBackground.background": "Arka Plan",
"app.video.virtualBackground.backgroundWithIndex": "{0} arka planı",
"app.video.virtualBackground.custom": "Bilgisayarınızdan yükleyin",
"app.video.virtualBackground.remove": "Remove added image",
"app.video.virtualBackground.genericError": "Kamera efekti uygulanamadı. Tekrar deneyin.",
"app.video.virtualBackground.camBgAriaDesc": "Web kamerası sanal arka planını {0} olarak ayarlar",
"app.video.virtualBackground.maximumFileSizeExceeded": "Maksimum dosya boyutu aşıldı. ({0}MB)",
"app.video.virtualBackground.typeNotAllowed": "Dosya türüne izin verilmiyor.",
"app.video.virtualBackground.errorOnRead": "Dosya okunurken bir sorun oluştu.",
"app.video.virtualBackground.uploaded": "yüklendi",
"app.video.virtualBackground.uploading": "yükleniyor...",
"app.video.virtualBackground.button.customDesc": "Yeni bir sanal arka plan görüntüsü ekler",
"app.video.camCapReached": "Daha fazla kamera paylaşamazsınız",
"app.video.meetingCamCapReached": "Toplantıda aynı anda kullanılabilecek kamera sayısı sınırına ulaşıldı",
"app.video.dropZoneLabel": "Buraya bırakın",
"app.fullscreenButton.label": "{0} tam ekran yap",
"app.fullscreenUndoButton.label": "{0} tam ekranı geri al",
@ -803,6 +1047,8 @@
"app.whiteboard.annotations.poll": "Anket sonuçları yayınlandı",
"app.whiteboard.annotations.pollResult": "Anket Sonucu",
"app.whiteboard.annotations.noResponses": "Cevap yok",
"app.whiteboard.annotations.notAllowed": "Bu değişikliği yapmanıza izin verilmiyor",
"app.whiteboard.annotations.numberExceeded": "Dipnot sayısı ({0}) sınırını aştı",
"app.whiteboard.toolbar.tools": "Araçlar",
"app.whiteboard.toolbar.tools.hand": "Sunum araçları",
"app.whiteboard.toolbar.tools.pencil": "Kalem",
@ -829,6 +1075,7 @@
"app.whiteboard.toolbar.color.silver": "Gümüş",
"app.whiteboard.toolbar.undo": "Ek Açıklamayı Geri Al",
"app.whiteboard.toolbar.clear": "Tüm Ek Açıklamaları Temizle",
"app.whiteboard.toolbar.clearConfirmation": "Tüm dipnotları silmek istediğinizden emin misiniz?",
"app.whiteboard.toolbar.multiUserOn": "Çoklu kullanıcı modunu aç",
"app.whiteboard.toolbar.multiUserOff": "Çoklu kullanıcı modunu kapat",
"app.whiteboard.toolbar.palmRejectionOn": "Avuç içi reddetmeyi aç",
@ -848,13 +1095,13 @@
"app.videoDock.webcamUnfocusDesc": "Seçili kameradan uzaklaş",
"app.videoDock.webcamPinLabel": "Sabitle ",
"app.videoDock.webcamPinDesc": "Seçili web kamerasını sabitle",
"app.videoDock.webcamFullscreenLabel": "Kamerayı tam ekran görüntüle",
"app.videoDock.webcamSqueezedButtonLabel": "Web kamerası seçenekleri",
"app.videoDock.webcamUnpinLabel": "Sabitlemeyi kaldır",
"app.videoDock.webcamUnpinLabelDisabled": "Yalnızca moderatörler kullanıcıların sabitlemesini kaldırabilir",
"app.videoDock.webcamUnpinDesc": "Seçili web kamerasının sabitlemesini kaldır",
"app.videoDock.autoplayBlockedDesc": "Size diğer kullanıcıların web kameralarını göstermek için izninize ihtiyacımız var.",
"app.videoDock.autoplayAllowLabel": "Web kameraları görüntüle",
"app.invitation.title": "Çalışma odası davetiyesi",
"app.invitation.confirm": "Davet et",
"app.createBreakoutRoom.title": "Çalışma Odaları",
"app.createBreakoutRoom.ariaTitle": "Çalışma Odalarını Gizle",
"app.createBreakoutRoom.breakoutRoomLabel": "Çalışma Odası {0}",
@ -886,6 +1133,8 @@
"app.createBreakoutRoom.addRoomTime": "Çalışma odası süresini arttırır",
"app.createBreakoutRoom.addParticipantLabel": "+ Katılımcı ekle",
"app.createBreakoutRoom.freeJoin": "Kullanıcıların katılmak için bir çalışma odası seçmesine izin ver",
"app.createBreakoutRoom.captureNotes": "Çalışma odaları sona erdiğinde paylaşılan notları al",
"app.createBreakoutRoom.captureSlides": "Çalışma odaları sona erdiğinde tahtayı al",
"app.createBreakoutRoom.leastOneWarnBreakout": "Bir çalışma odasına en az bir kullanıcı atamalısınız..",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "Çalışma odaları için minimum süre {0} dakikadır.",
"app.createBreakoutRoom.modalDesc": "İpucu: Herhangi bir çalışma odasına atama yapmak için kullanıcının adını sürükleyip bırakabilirsiniz.",
@ -898,6 +1147,14 @@
"app.createBreakoutRoom.setTimeCancel": "İptal",
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "çalışma oda süresi, kalan toplantı süresini aşamaz.",
"app.createBreakoutRoom.roomNameInputDesc": "Tenefüs odasının ismini güncelle",
"app.createBreakoutRoom.movedUserLabel": "{0}, {1} odasına taşındı",
"app.updateBreakoutRoom.modalDesc": "Bir kullanıcıyı güncellemek veya davet etmek için onu istediğiniz odaya sürüklemeniz yeterlidisürükleyin.",
"app.updateBreakoutRoom.cancelLabel": "İptal",
"app.updateBreakoutRoom.title": "Çalışma Odalarını Güncelle",
"app.updateBreakoutRoom.confirm": "Uygula",
"app.updateBreakoutRoom.userChangeRoomNotification": "{0} odasına taşındınız.",
"app.smartMediaShare.externalVideo": "Dış görüntüler",
"app.update.resetRoom": "Kullanıcının odasını sıfırla",
"app.externalVideo.start": "Yeni bir video paylaş",
"app.externalVideo.title": "Harici Video Paylaş",
"app.externalVideo.input": "Harici Video URL",
@ -908,6 +1165,8 @@
"app.externalVideo.refreshLabel": "Video Oynatıcısını Yenile",
"app.externalVideo.fullscreenLabel": "Video Oynatıcı",
"app.externalVideo.noteLabel": "Not: Paylaşılan harici videolar kayıtta görünmeyecektir. YouTube, Vimeo, Instructure Media, Twitch, Dailymotion ve medya dosyası bağlantıları (Ör: https://example.com/xy.mp4) desteklenir.",
"app.externalVideo.subtitlesOn": "Kapat",
"app.externalVideo.subtitlesOff": "Aç (mümkünse)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Harici Video Paylaş",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Harici Video Paylaşını Durdur",
"app.iOSWarning.label": "Lütfen iOS 12.2 veya daha üstüne yükseltin",
@ -921,6 +1180,15 @@
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(web kamerası alanını sürüklerseniz veya yeniden boyutlandırırsanız devre dışı bırakılır)",
"app.debugWindow.form.chatLoggerLabel": "Sohbet Kaydedici Düzeylerini Test Edin",
"app.debugWindow.form.button.apply": "Uygula",
"app.layout.modal.title": "Ekran düzenleri",
"app.layout.modal.confirm": "Onayla",
"app.layout.modal.cancel": "İptal",
"app.layout.modal.layoutLabel": "Ekran düzeninizi seçin",
"app.layout.modal.keepPushingLayoutLabel": "Ekran düzenini herkese gönder",
"app.layout.modal.pushLayoutLabel": "Herkese gönder",
"app.layout.modal.layoutToastLabel": "Ekran düzeni ayarları değişti",
"app.layout.modal.layoutSingular": "Ekran düzeni",
"app.layout.modal.layoutBtnDesc": "Ekran düzenini seçilmiş seçenek olarak ayarla",
"app.layout.style.custom": "Özel",
"app.layout.style.smart": "Otomatik Yerleşim",
"app.layout.style.presentationFocus": "Sunuma Odakla",
@ -937,6 +1205,7 @@
"playback.button.search.aria": "Ara",
"playback.button.section.aria": "yan bölüm",
"playback.button.swap.aria": "İçeriği değiştir",
"playback.button.theme.aria": "Temayı değiştir",
"playback.error.wrapper.aria": "Hata alanı",
"playback.loader.wrapper.aria": "yükleyici alanı",
"playback.player.wrapper.aria": "Oynatıcı alanı",
@ -969,6 +1238,7 @@
"playback.player.thumbnails.wrapper.aria": "Küçük resim alanı",
"playback.player.webcams.wrapper.aria": "Web kamerası alanı",
"app.learningDashboard.dashboardTitle": "Öğrenme Analitiği Kontrol Paneli",
"app.learningDashboard.bigbluebuttonTitle": "BigBlueButton",
"app.learningDashboard.downloadSessionDataLabel": "Oturum Verilerini İndir",
"app.learningDashboard.lastUpdatedLabel": "Son güncelleme tarihi:",
"app.learningDashboard.sessionDataDownloadedLabel": "İndirildi!",
@ -993,6 +1263,12 @@
"app.learningDashboard.userDetails.response": "Cevap",
"app.learningDashboard.userDetails.mostCommonAnswer": "En çok tercih edilen cevap",
"app.learningDashboard.userDetails.anonymousAnswer": "Anonim Anket",
"app.learningDashboard.userDetails.talkTime": "Konuşma süresi",
"app.learningDashboard.userDetails.messages": "Mesajlar",
"app.learningDashboard.userDetails.emojis": "Emojiler",
"app.learningDashboard.userDetails.raiseHands": "El Kaldır",
"app.learningDashboard.userDetails.pollVotes": "Anket Sonuçları",
"app.learningDashboard.userDetails.onlineIndicator": "{0} çevrim içi süresi",
"app.learningDashboard.usersTable.title": "Genel bakış",
"app.learningDashboard.usersTable.colOnline": "Çevrim İçi Süre",
"app.learningDashboard.usersTable.colTalk": "Konuşma Süresi",
@ -1016,10 +1292,24 @@
"app.learningDashboard.pollsTable.anonymousRowName": "İsimsiz",
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "Anket oluşturulmadı",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "Kullanıcılara bir anket gönderildiğinde, sonuçları bu listede görünecektir.",
"app.learningDashboard.pollsTable.answerTotal": "Toplam",
"app.learningDashboard.pollsTable.userLabel": "kullanıcı",
"app.learningDashboard.statusTimelineTable.title": "Zaman çizelgesi",
"app.learningDashboard.statusTimelineTable.thumbnail": "Sunum küçük resmi",
"app.learningDashboard.statusTimelineTable.presentation": "Sunum",
"app.learningDashboard.statusTimelineTable.pageNumber": "Sayfa",
"app.learningDashboard.statusTimelineTable.setAt": "Şu zamana ayarla",
"app.learningDashboard.errors.invalidToken": "Geçersiz oturum anahtarı.",
"app.learningDashboard.errors.dataUnavailable": "Veri artık erişilebilir değil"
"app.learningDashboard.errors.dataUnavailable": "Veri artık erişilebilir değil",
"mobileApp.portals.list.empty.addFirstPortal.label": "Yukarıdaki düğmeyi kullanarak ilk portalinizi ekleyin.",
"mobileApp.portals.list.empty.orUseOurDemoServer.label": "ya da tanıtım sunucumuzu kullanın.",
"mobileApp.portals.list.add.button.label": "portal ekle",
"mobileApp.portals.fields.name.label": "Portal Adı",
"mobileApp.portals.fields.name.placeholder": "BigBlueButton tanıtımı",
"mobileApp.portals.fields.url.label": "Sunucu bağlantısı",
"mobileApp.portals.addPortalPopup.confirm.button.label": "Kaydet",
"mobileApp.portals.drawerNavigation.button.label": "Portallar",
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Zorunlu Alanlar",
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "İsim zaten kullanılıyor",
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Sayfayı yüklemeye çalışırken hata oluştu -URL'yi ve ağ bağlantısını kontrol edin"
}

View File

@ -450,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": "Збільшити розмір шрифту",
@ -1168,7 +1169,6 @@
"app.externalVideo.subtitlesOff": "Увімкнути (якщо доступно)",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Демонстрація зовнішнього відео",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Припинити показ зовнішнього відео",
"app.iOSWarning.label": "Будь ласка, оновіть пристрій з iOS до версії 12.2 або новішої версії",
"app.legacy.unsupportedBrowser": "Схоже, ви використовуєте браузер, який в повному обсязі не підтримується. Будь ласка, використовуйте {0} або {1} для повної підтримки.",
"app.legacy.upgradeBrowser": "Схоже, ви використовуєте старішу версію браузера, який підтримується. Будь ласка, оновіть його для повної підтримки.",
"app.legacy.criosBrowser": "Будь ласка, використовуйте браузер Safari на пристрої з iOS для повної підтримки.",

View File

@ -1,81 +0,0 @@
#!/bin/bash
#colors
RED='\033[0;31m'
GREEN='\033[1;32m'
NC='\033[0m'
SOURCE_LANGUAGE="en"
LOCALES_DIRECTORY="./public/locales"
PULL_SOURCE=false
if [[ ! -e $LOCALES_DIRECTORY ]]; then
echo -e "Directory ${RED}$LOCALES_DIRECTORY${NC} does not exist, creating"
mkdir $LOCALES_DIRECTORY
PULL_SOURCE=true
fi
if [ "$#" = 0 ]
then
echo -e "${RED}ERR${NC}: Usage = ${GREEN}./transifex.sh pt_BR de ${NC}or ${GREEN}./transifex all${NC}"
else
read -p "Enter Transifex Username: " USER
read -p "password: " -s PW
echo -e "\n----------------------------------\nchecking project info\n----------------------------------"
PROJECT_INFO=$( curl -L --user "$USER":"$PW" -X GET https://www.transifex.com/api/2/project/bigbluebutton-v26-html5-client/languages/ )
if [ "$PROJECT_INFO" == "Authorization Required" ]
then
echo -e "${RED}Err${NC} : $PROJECT_INFO"
else
echo -e "Project Information Found :${GREEN}${NC}"
if [ "$PROJECT_INFO" == "Forbidden" ]
then
echo -e "${RED}Err${NC}: Invalid User Permissions"
else
for ARG in "$@"
do
if [ "$ARG" == "all" ]
then
AVAILABLE_TRANSLATIONS=$( echo "$PROJECT_INFO" | grep 'language_code' | cut -d':' -f2 | tr -d '[",]' )
echo "$AVAILABLE_TRANSLATIONS" | while read l
do
LOCALE=$( echo "$l" | tr -d '[:space:]' )
if [ "$LOCALE" == "$SOURCE_LANGUAGE" ] && [ "$PULL_SOURCE" == false ]; then
continue # only pull source file if locales folder did not exist
fi
TRANSLATION=$(curl -L --user "$USER":"$PW" -X GET "https://www.transifex.com/api/2/project/bigbluebutton-v26-html5-client/resource/enjson/translation/$LOCALE/?mode=onlytranslated&file")
NO_EMPTY_STRINGS=$(echo "$TRANSLATION" | sed '/: *\"\"/D' | sed '/}$/D')
if [ $(echo "$NO_EMPTY_STRINGS" | wc -l) -lt 100 ]
then
echo -e "${RED}WARN:${NC} translation file $LOCALE.json contains less than 100 lines\n${RED}WARN:${NC} $LOCALE.json not created"
continue
else
NO_TRAILING_COMMA=$(echo "$NO_EMPTY_STRINGS" | sed '$ s/,$//')
echo "$NO_TRAILING_COMMA" > "$LOCALES_DIRECTORY/$LOCALE".json
echo -e "\n}\n" >> "$LOCALES_DIRECTORY/$LOCALE".json
echo -e "Added translation file $LOCALE.json : ${GREEN}${NC}"
fi
done
else
TRANSLATION=$(curl -L --user "$USER":"$PW" -X GET "https://www.transifex.com/api/2/project/bigbluebutton-v26-html5-client/resource/enjson/translation/$ARG/?mode=onlytranslated&file")
if [ "$TRANSLATION" == "Not Found" ]
then
echo -e "${RED}Err${NC}: Translations not found for locale ->${RED}$ARG${NC}<-"
else
NO_EMPTY_STRINGS=$(echo "$TRANSLATION" | sed '/: *\"\"/D' | sed '/}$/D')
if [ $(echo "$NO_EMPTY_STRINGS" | wc -l) -lt 100 ]
then
echo -e "${RED}WARN:${NC} translation file $ARG.json contains less than 100 lines\n${RED}WARN:${NC} $ARG.json not created"
else
NO_TRAILING_COMMA=$(echo "$NO_EMPTY_STRINGS" | sed '$ s/,//')
echo "$NO_TRAILING_COMMA" > "$LOCALES_DIRECTORY/$ARG".json
echo -e "\n}\n" >> "$LOCALES_DIRECTORY/$ARG".json
echo -e "Added translation file $ARG.json :${GREEN}${NC}"
fi
fi
fi
done
fi
fi
fi

View File

@ -1,57 +1,86 @@
const { expect, default: test } = require('@playwright/test');
const Page = require('../core/page');
const { openChat } = require('./util');
const { openChat, openPrivateChat, checkLastMessageSent } = require('./util');
const p = require('../core/parameters');
const e = require('../core/elements');
const { checkTextContent } = require('../core/util');
const { getSettings } = require('../core/settings');
const { MultiUsers } = require('../user/multiusers');
const { sleep } = require('../core/helpers');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
class Chat extends Page {
constructor(browser, page) {
super(browser, page);
class Chat extends MultiUsers {
constructor(browser, context) {
super(browser, context);
}
async sendPublicMessage() {
await openChat(this);
await this.checkElementCount(e.chatUserMessageText, 0);
await openChat(this.modPage);
await this.modPage.checkElementCount(e.chatUserMessageText, 0);
await this.type(e.chatBox, e.message);
await this.waitAndClick(e.sendButton);
await this.checkElementCount(e.chatUserMessageText, 1);
await this.modPage.type(e.chatBox, e.message);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.checkElementCount(e.chatUserMessageText, 1);
}
async sendPrivateMessage() {
await openPrivateChat(this.modPage);
await this.modPage.waitForSelector(e.hidePrivateChat);
await sleep(500); // prevent a race condition when running on a deployed server
// modPage send message
await this.modPage.type(e.chatBox, e.message1);
await this.modPage.waitAndClick(e.sendButton);
await this.userPage.waitUntilHaveCountSelector(e.chatButton, 2);
await this.userPage.waitAndClickElement(e.chatButton, 1);
await this.userPage.waitForSelector(e.hidePrivateChat);
// check sent messages
await this.modPage.hasText(e.chatUserMessageText, e.message1);
await this.userPage.hasText(e.chatUserMessageText, e.message1);
// userPage send message
await this.userPage.type(e.chatBox, e.message2);
await this.userPage.waitAndClick(e.sendButton);
// check sent messages
await this.modPage.hasText(e.privateChat, e.message2);
await this.userPage.hasText(e.privateChat, e.message2);
await this.modPage.waitAndClick(e.chatButton);
await this.userPage.waitAndClick(e.chatButton);
}
async clearChat() {
await openChat(this);
await openChat(this.modPage);
await this.type(e.chatBox, e.message);
await this.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
const userMessageTextCount = await this.modPage.getSelectorCount(e.chatUserMessageText);
await this.modPage.type(e.chatBox, e.message);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.waitForSelector(e.chatUserMessageText);
// 1 message
await this.checkElementCount(e.chatUserMessageText, 1);
await this.modPage.checkElementCount(e.chatUserMessageText, userMessageTextCount + 1);
// clear
await this.waitAndClick(e.chatOptions);
await this.waitAndClick(e.chatClear);
const clearMessage = this.getLocator(e.chatClearMessageText);
await this.modPage.waitAndClick(e.chatOptions);
await this.modPage.waitAndClick(e.chatClear);
const clearMessage = this.modPage.getLocator(e.chatClearMessageText);
await expect(clearMessage).toBeVisible();
}
async copyChat(context) {
const { publicChatOptionsEnabled } = getSettings();
test.fail(!publicChatOptionsEnabled, 'Public chat options (save and copy) are disabled');
await openChat(this);
await openChat(this.modPage);
// sending a message
await this.type(e.chatBox, e.message);
await this.waitAndClick(e.sendButton);
await this.modPage.type(e.chatBox, e.message);
await this.modPage.waitAndClick(e.sendButton);
await this.waitAndClick(e.chatOptions);
await this.modPage.waitAndClick(e.chatOptions);
await this.waitForSelector(e.chatUserMessageText);
await this.waitAndClick(e.chatCopy);
await this.modPage.waitForSelector(e.chatUserMessageText);
await this.modPage.waitAndClick(e.chatCopy);
// enable access to browser context clipboard
const copiedText = await this.getCopiedText(context);
const copiedText = await this.modPage.getCopiedText(context);
const check = copiedText.includes(`${p.fullName}: ${e.message}`);
await expect(check).toBeTruthy();
}
@ -60,59 +89,76 @@ class Chat extends Page {
const { publicChatOptionsEnabled } = getSettings();
test.fail(!publicChatOptionsEnabled, 'Public chat options (save and copy) are disabled');
await openChat(this);
await this.type(e.chatBox, e.message);
await this.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
await this.waitAndClick(e.chatOptions);
const chatSaveLocator = this.getLocator(e.chatSave);
const { content } = await this.handleDownload(chatSaveLocator, testInfo);
await openChat(this.modPage);
await this.modPage.type(e.chatBox, e.message);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.waitForSelector(e.chatUserMessageText);
await this.modPage.waitAndClick(e.chatOptions);
const chatSaveLocator = this.modPage.getLocator(e.chatSave);
const { content } = await this.modPage.handleDownload(chatSaveLocator, testInfo);
const dataToCheck = [
this.meetingId,
this.username,
this.modPage.meetingId,
this.modPage.username,
e.message,
];
await checkTextContent(content, dataToCheck);
}
async characterLimit() {
await openChat(this);
await openChat(this.modPage);
const { maxMessageLength } = getSettings();
await this.page.fill(e.chatBox, e.uniqueCharacterMessage.repeat(maxMessageLength));
await this.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
await this.checkElementCount(e.chatUserMessageText, 1);
await this.modPage.page.fill(e.chatBox, e.uniqueCharacterMessage.repeat(maxMessageLength));
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.waitForSelector(e.chatUserMessageText);
await this.modPage.checkElementCount(e.chatUserMessageText, 1);
await this.page.fill(e.chatBox, e.uniqueCharacterMessage.repeat(maxMessageLength + 1));
await this.waitForSelector(e.typingIndicator);
await this.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
await this.checkElementCount(e.chatUserMessageText, 1);
await this.modPage.page.fill(e.chatBox, e.uniqueCharacterMessage.repeat(maxMessageLength + 1));
await this.modPage.waitForSelector(e.typingIndicator);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.waitForSelector(e.chatUserMessageText);
await this.modPage.checkElementCount(e.chatUserMessageText, 1);
}
async emptyMessage() {
await openChat(this);
await openChat(this.modPage);
await this.waitAndClick(e.sendButton);
await this.checkElementCount(e.chatUserMessageText, 0);
const userMessageTextCount = await this.modPage.getSelectorCount(e.chatUserMessageText);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.checkElementCount(e.chatUserMessageText, userMessageTextCount);
}
async copyPastePublicMessage() {
await this.modPage.type(e.chatBox, 'test');
await this.modPage.waitAndClick(e.sendButton);
await checkLastMessageSent(this.modPage, /test/);
const text = await this.modPage.getLocator(e.chatUserMessageText).last().boundingBox();
await this.modPage.mouseDoubleClick(text.x, text.y);
await this.modPage.press('Control+KeyC');
await this.modPage.getLocator(e.chatBox).focus();
await this.modPage.press('Control+KeyV');
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.hasText(e.secondChatUserMessageText, /test/);
}
// Emojis
async sendEmoji() {
const { emojiPickerEnabled } = getSettings();
test.fail(!emojiPickerEnabled, 'Emoji Picker is disabled');
await openChat(this);
const message = this.getLocator(e.chatUserMessageText);
await openChat(this.modPage);
const message = this.modPage.getLocator(e.chatUserMessageText);
await expect(message).toHaveCount(0);
await this.waitAndClick(e.emojiPickerButton);
await this.waitAndClick(e.emojiSent);
await this.waitAndClick(e.sendButton);
await this.modPage.waitAndClick(e.emojiPickerButton);
await this.modPage.waitAndClick(e.emojiSent);
await this.modPage.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
await this.modPage.waitForSelector(e.chatUserMessageText);
await expect(message).toHaveCount(1);
}
@ -135,6 +181,28 @@ class Chat extends Page {
await expect(check).toBeTruthy();
}
async closePrivateChat() {
await openPrivateChat(this.modPage);
await this.modPage.waitUntilHaveCountSelector(e.chatButton, 2);
const privateChatLocator = this.modPage.getLocatorByIndex(e.chatButton, -1);
expect(privateChatLocator).toContainText(this.userPage.username);
const chatMessageCount = await this.modPage.getSelectorCount(e.chatUserMessageText);
await this.modPage.hasElement(e.hidePrivateChat);
await this.modPage.hasElement(e.closePrivateChat);
await this.modPage.checkElementCount(e.chatUserMessageText, chatMessageCount);
await this.modPage.type(e.chatBox, e.message1);
await this.modPage.waitAndClick(e.sendButton);
await this.userPage.waitUntilHaveCountSelector(e.chatButton, 2);
await this.modPage.waitAndClick(e.closePrivateChat);
await this.modPage.wasRemoved(e.hidePrivateChat);
await this.modPage.waitUntilHaveCountSelector(e.chatButton, 1, ELEMENT_WAIT_LONGER_TIME);
const userChatCount = await this.userPage.getSelectorCount(e.chatButton);
await this.modPage.waitAndClick(e.chatButton);
expect(userChatCount).toBe(2);
}
async emojiSaveChat(testInfo) {
const { emojiPickerEnabled } = getSettings();
test.fail(!emojiPickerEnabled, 'Emoji Picker is disabled');
@ -156,18 +224,52 @@ class Chat extends Page {
await checkTextContent(content, dataToCheck);
}
async emojiSendPrivateChat() {
const { emojiPickerEnabled } = getSettings();
test.fail(!emojiPickerEnabled, 'Emoji Picker is disabled');
await openPrivateChat(this.modPage);
await this.modPage.waitForSelector(e.hidePrivateChat);
await sleep(500); // prevent a race condition when running on a deployed server
// modPage send message
await this.modPage.waitAndClick(e.emojiPickerButton);
await this.modPage.waitAndClick(e.emojiSent);
await this.modPage.waitAndClick(e.sendButton);
await this.userPage.waitUntilHaveCountSelector(e.chatButton, 2);
await this.userPage.waitAndClickElement(e.chatButton, 1);
await this.userPage.waitForSelector(e.hidePrivateChat);
// check sent messages
await this.modPage.hasText(e.chatUserMessageText, e.frequentlyUsedEmoji);
await this.userPage.hasText(e.chatUserMessageText, e.frequentlyUsedEmoji);
// userPage send message
await this.userPage.waitAndClick(e.emojiPickerButton);
await this.userPage.waitAndClick(e.emojiSent);
await this.userPage.waitAndClick(e.sendButton);
// check sent messages
await this.modPage.hasText(e.privateChat, e.frequentlyUsedEmoji);
await this.userPage.hasText(e.privateChat, e.frequentlyUsedEmoji);
await this.modPage.waitAndClick(e.chatButton);
}
async autoConvertEmojiPublicChat() {
const { autoConvertEmojiEnabled } = getSettings();
test.fail(!autoConvertEmojiEnabled, 'Auto Convert Emoji is disabled');
await openChat(this);
const message = this.getLocator(e.chatUserMessageText);
await expect(message).toHaveCount(0);
try {
await this.modPage.hasElement(e.hidePrivateChat);
await this.modPage.waitAndClick(e.chatButton);
} catch {
await this.modPage.hasElement(e.publicChat);
}
await this.type(e.chatBox, e.autoConvertEmojiMessage);
await this.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
await expect(message).toHaveCount(1);
const message = await this.modPage.getSelectorCount(e.chatUserMessageText);
await this.modPage.checkElementCount(e.chatUserMessageText, message);
await this.modPage.type(e.chatBox, e.autoConvertEmojiMessage);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.waitForSelector(e.chatUserMessageText);
await this.modPage.checkElementCount(e.chatUserMessageText, message + 1);
}
async autoConvertEmojiCopyChat(context) {
@ -192,37 +294,54 @@ class Chat extends Page {
const { autoConvertEmojiEnabled } = getSettings();
test.fail(!autoConvertEmojiEnabled, 'Auto Convert Emoji is disabled');
await openChat(this);
await this.type(e.chatBox, e.autoConvertEmojiMessage);
await this.waitAndClick(e.sendButton);
await this.waitForSelector(e.chatUserMessageText);
await this.waitAndClick(e.chatOptions);
const chatSaveLocator = this.getLocator(e.chatSave);
const { content } = await this.handleDownload(chatSaveLocator, testInfo);
await openChat(this.modPage);
await this.modPage.type(e.chatBox, e.autoConvertEmojiMessage);
await this.modPage.waitAndClick(e.sendButton);
await this.modPage.waitForSelector(e.chatUserMessageText);
await this.modPage.waitAndClick(e.chatOptions);
const chatSaveLocator = this.modPage.getLocator(e.chatSave);
const { content } = await this.modPage.handleDownload(chatSaveLocator, testInfo);
const dataToCheck = [
this.meetingId,
this.username,
this.modPage.meetingId,
this.modPage.username,
e.convertedEmojiMessage,
];
await checkTextContent(content, dataToCheck);
}
async copyPastePublicMessage() {
await this.type(e.chatBox, 'test');
await this.waitAndClick(e.sendButton);
await this.hasText(e.chatUserMessageText, /test/);
async autoConvertEmojiSendPrivateChat() {
const { autoConvertEmojiEnabled } = getSettings();
test.fail(!autoConvertEmojiEnabled, 'Auto Convert Emoji is disabled');
const text = await this.getLocator(e.chatUserMessageText).boundingBox();
await this.mouseDoubleClick(text.x, text.y);
await this.press('Control+KeyC');
await this.getLocator(e.chatBox).focus();
await this.press('Control+KeyV');
await this.waitAndClick(e.sendButton);
await this.hasText(e.secondChatUserMessageText, /test/);
await openPrivateChat(this.modPage);
await this.modPage.waitForSelector(e.hidePrivateChat);
await sleep(500); // prevent a race condition when running on a deployed server
// modPage send message
await this.modPage.type(e.chatBox, e.autoConvertEmojiMessage);
await this.modPage.waitAndClick(e.sendButton);
await this.userPage.waitUntilHaveCountSelector(e.chatButton, 2);
await openPrivateChat(this.userPage);
await this.userPage.waitForSelector(e.hidePrivateChat);
// check sent messages
await checkLastMessageSent(this.modPage, e.convertedEmojiMessage)
await checkLastMessageSent(this.userPage, e.convertedEmojiMessage);
// userPage send message
await this.userPage.type(e.chatBox, e.autoConvertEmojiMessage);
await this.userPage.waitAndClick(e.sendButton);
// check sent messages
await this.modPage.hasText(e.privateChat, e.convertedEmojiMessage);
await this.userPage.hasText(e.privateChat, e.convertedEmojiMessage);
}
async chatDisabledUserLeaves() {
await openPrivateChat(this.modPage);
await this.modPage.waitForSelector(e.sendButton);
await this.userPage.waitAndClick(e.optionsButton);
await this.userPage.waitAndClick(e.logout);
await this.modPage.hasElementDisabled(e.chatBox);
await this.modPage.hasElementDisabled(e.sendButton);
}
}
exports.Chat = Chat;

View File

@ -1,124 +1,93 @@
const { test } = require('@playwright/test');
const { linkIssue } = require('../core/helpers');
const { chat } = require('../customparameters/constants');
const { Chat } = require('./chat');
const { PrivateChat } = require('./privateChat');
test.describe.parallel('Chat', () => {
test.describe.serial('Chat', () => {
const chat = new Chat();
let context;
test.beforeAll(async ({ browser }) => {
context = await browser.newContext();
const page = await context.newPage();
await chat.initModPage(page, true);
await chat.initUserPage(true, context);
});
// https://docs.bigbluebutton.org/2.6/release-tests.html#public-message-automated
test('Send public message @ci', async ({ browser, page }) => {
const chat = new Chat(browser, page);
await chat.init(true, true);
test('Send public message @ci', async () => {
await chat.sendPublicMessage();
});
// https://docs.bigbluebutton.org/2.6/release-tests.html#private-message-automated
test('Send private message @ci', async ({ browser, context, page }) => {
const privateChat = new PrivateChat(browser, context);
await privateChat.initPages(page);
await privateChat.sendPrivateMessage();
test('Send private message @ci', async () => {
await chat.sendPrivateMessage();
});
test('Clear chat', async ({ browser, page }) => {
const chat = new Chat(browser, page);
await chat.init(true, true);
test('Clear chat', async () => {
await chat.clearChat();
});
test('Copy chat', async ({ browser, context, page }, testInfo) => {
test.skip(testInfo.project.use.headless, 'Only works in headed mode');
const chat = new Chat(browser, page);
await chat.init(true, true);
test.skip('Copy chat', async () => {
await chat.copyChat(context);
});
test('Save chat', async ({ browser, page }, testInfo) => {
const chat = new Chat(browser, page);
await chat.init(true, true);
test('Save chat', async ({ context }, testInfo) => {
await chat.saveChat(testInfo);
});
// https://docs.bigbluebutton.org/2.6/release-tests.html#chat-character-limit-automated
test('Verify character limit', async ({ browser, page }) => {
const chat = new Chat(browser, page);
await chat.init(true, true);
test.skip('Verify character limit', async () => {
await chat.characterLimit();
});
// https://docs.bigbluebutton.org/2.6/release-tests.html#sending-empty-chat-message-automated
test('Not able to send an empty message', async ({ browser, page }) => {
const chat = new Chat(browser, page);
await chat.init(true, true);
test('Not able to send an empty message', async () => {
await chat.emptyMessage();
});
test('Copy and paste public message', async ({ browser, page }) => {
test('Copy and paste public message', async () => {
linkIssue('15948');
const chat = new Chat(browser, page);
await chat.init(true, true);
await chat.copyPastePublicMessage();
})
test('Send emoji on public chat', async () => {
await chat.sendEmoji();
});
test('Close private chat @ci', async ({ browser, context, page }) => {
const privateChat = new PrivateChat(browser, context);
await privateChat.initPages(page);
await privateChat.closeChat();
test.skip('Copy chat with emoji', async () => {
// Only works in headed mode
await chat.emojiCopyChat();
});
test('Private chat disabled when user leaves meeting @ci', async ({ browser, context, page }) => {
const privateChat = new PrivateChat(browser, context);
await privateChat.initPages(page);
await privateChat.chatDisabledUserLeaves();
test('Close private chat @ci', async () => {
await chat.closePrivateChat();
});
test.describe.parallel('Emoji', () => {
test('Send emoji on public chat', async ({ browser, page }) => {
const emoji = new Chat(browser, page);
await emoji.init(true, true);
await emoji.sendEmoji();
});
test('Save chat with emoji', async () => {
await chat.emojiSaveChat();
});
test('Copy chat with emoji', async ({ browser, context, page }, testInfo) => {
test.skip(testInfo.project.use.headless, 'Only works in headed mode');
const emoji = new Chat(browser, page);
await emoji.init(true, true);
await emoji.emojiCopyChat(context);
});
test('Send emoji on private chat', async () => {
await chat.emojiSendPrivateChat();
});
test('Save chat with emoji', async ({ browser, page }, testInfo) => {
const emoji = new Chat(browser, page);
await emoji.init(true, true);
await emoji.emojiSaveChat(testInfo);
});
test('Send auto converted emoji on public chat', async () => {
await chat.autoConvertEmojiPublicChat();
});
test('Send emoji on private chat', async ({ browser, context, page }) => {
const emoji = new PrivateChat(browser, context);
await emoji.initPages(page);
await emoji.emojiSendPrivateChat();
});
test.skip('Copy chat with auto converted emoji', async () => {
await chat.autoConvertEmojiCopyChat();
});
test('Send auto converted emoji on public chat', async ({ browser, page }) => {
const emoji = new Chat(browser, page);
await emoji.init(true, true);
await emoji.autoConvertEmojiPublicChat();
});
test('Auto convert emoji save chat', async ({ context }, testInfo) => {
await chat.autoConvertEmojiSaveChat(testInfo);
});
test('Copy chat with auto converted emoji', async ({ browser, context, page }, testInfo) => {
test.skip(testInfo.project.use.headless, 'Only works in headed mode');
const emoji = new Chat(browser, page);
await emoji.init(true, true);
await emoji.autoConvertEmojiCopyChat(context);
});
test('Send auto converted emoji on private chat', async () => {
await chat.autoConvertEmojiSendPrivateChat();
});
test('Save chat with auto converted emoji', async ({ browser, page }, testInfo) => {
const emoji = new Chat(browser, page);
await emoji.init(true, true);
await emoji.autoConvertEmojiSaveChat(testInfo);
});
test('Send auto converted emoji on private chat', async ({ browser, context, page }) => {
const emoji = new PrivateChat(browser, context);
await emoji.initPages(page);
await emoji.autoConvertEmojiSendPrivateChat();
});
test('Private chat disabled when user leaves meeting @ci', async () => {
await chat.chatDisabledUserLeaves();
});
});

View File

@ -29,6 +29,10 @@ class PrivateChat extends MultiUsers {
// check sent messages
await this.modPage.hasText(e.privateChat, e.message2);
await this.userPage.hasText(e.privateChat, e.message2);
await this.modPage.waitAndClick(e.chatButton);
await this.modPage.waitAndClick(e.chatOptions);
await this.modPage.waitAndClick(e.chatClear);
}
async closeChat() {

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