mirror of
https://github.com/suitenumerique/meet.git
synced 2026-09-03 22:25:27 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ac4be27445 | |||
| eb6b3ba1df | |||
| 8473069670 |
@@ -12,9 +12,15 @@ and this project adheres to
|
|||||||
|
|
||||||
- ✨(frontend) add 1080p sending resolution option #1660
|
- ✨(frontend) add 1080p sending resolution option #1660
|
||||||
- ✨(backend) add Traefik support via configurable media-auth url header #1649
|
- ✨(backend) add Traefik support via configurable media-auth url header #1649
|
||||||
|
- ✨(backend) update a room's attributes from the external API
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- ⬆️(dev) pin LiveKit server to v1.13.6
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- 🐛(backend) allow any printable ASCII characters in user sub field #1673
|
||||||
- 🐛(frontend) keep the sending resolution picked while the camera is off #1667
|
- 🐛(frontend) keep the sending resolution picked while the camera is off #1667
|
||||||
|
|
||||||
## [1.30.0] - 2026-09-01
|
## [1.30.0] - 2026-09-01
|
||||||
|
|||||||
+1
-1
@@ -207,7 +207,7 @@ services:
|
|||||||
- kc_postgresql
|
- kc_postgresql
|
||||||
|
|
||||||
livekit:
|
livekit:
|
||||||
image: livekit/livekit-server
|
image: livekit/livekit-server:v1.13.6
|
||||||
entrypoint: /livekit-server --dev --bind 0.0.0.0 --config ./config.yaml
|
entrypoint: /livekit-server --dev --bind 0.0.0.0 --config ./config.yaml
|
||||||
ports:
|
ports:
|
||||||
- "7880:7880"
|
- "7880:7880"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM livekit/livekit-server:v1.9.4
|
FROM livekit/livekit-server:v1.13.6
|
||||||
|
|
||||||
# We inject the nip.io certificate manually because the livekit chart doesn't support volume mounting
|
# We inject the nip.io certificate manually because the livekit chart doesn't support volume mounting
|
||||||
COPY rootCA.pem /etc/ssl/certs/
|
COPY rootCA.pem /etc/ssl/certs/
|
||||||
|
|||||||
+78
-3
@@ -16,11 +16,11 @@ info:
|
|||||||
* `rooms:list` – List rooms accessible to the delegated user.
|
* `rooms:list` – List rooms accessible to the delegated user.
|
||||||
* `rooms:retrieve` – Retrieve details of a specific room.
|
* `rooms:retrieve` – Retrieve details of a specific room.
|
||||||
* `rooms:create` – Create new rooms.
|
* `rooms:create` – Create new rooms.
|
||||||
* `rooms:update` – **Coming soon** Update existing rooms, e.g., add attendees to a room.
|
* `rooms:update` – Update the access level and configuration of existing rooms.
|
||||||
* `rooms:delete` – **Coming soon** Delete rooms generated by the application.
|
* `rooms:delete` – **Coming soon** Delete rooms generated by the application.
|
||||||
|
|
||||||
#### Upcoming Features
|
#### Upcoming Features
|
||||||
|
|
||||||
* **Add attendees to a room:** You will be able to update a room to include a list of attendees, allowing them to bypass the lobby system automatically.
|
* **Add attendees to a room:** You will be able to update a room to include a list of attendees, allowing them to bypass the lobby system automatically.
|
||||||
* **Delete application-generated rooms:** Rooms created via the application can be deleted when no longer needed.
|
* **Delete application-generated rooms:** Rooms created via the application can be deleted when no longer needed.
|
||||||
|
|
||||||
@@ -310,6 +310,67 @@ paths:
|
|||||||
'404':
|
'404':
|
||||||
$ref: '#/components/responses/RoomNotFoundError'
|
$ref: '#/components/responses/RoomNotFoundError'
|
||||||
|
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- Rooms
|
||||||
|
summary: Update a room
|
||||||
|
description: |
|
||||||
|
Partially updates a room. Only the delegated user's rooms where they are
|
||||||
|
administrator or owner can be updated; any other role gets a `403`.
|
||||||
|
|
||||||
|
**Updatable fields:** `access_level` and `configuration`. Every other field
|
||||||
|
(`id`, `name`, `slug`, `pin_code`) is read-only and silently ignored when sent.
|
||||||
|
|
||||||
|
`configuration` is replaced as a whole, it is not merged with the stored one.
|
||||||
|
Send the complete object you want the room to end up with.
|
||||||
|
|
||||||
|
Full replacement (`PUT`) is not supported. Use `PATCH` instead.
|
||||||
|
operationId: updateRoom
|
||||||
|
security:
|
||||||
|
- BearerAuth: [rooms:update]
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: Room UUID
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RoomUpdate'
|
||||||
|
examples:
|
||||||
|
accessLevelOnly:
|
||||||
|
summary: Change the access level
|
||||||
|
value:
|
||||||
|
access_level: "restricted"
|
||||||
|
configurationOnly:
|
||||||
|
summary: Replace the room configuration
|
||||||
|
value:
|
||||||
|
configuration:
|
||||||
|
everyone_can_mute: true
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Room updated successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Room'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequestError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/RoomNotFoundError'
|
||||||
|
'405':
|
||||||
|
description: |
|
||||||
|
Method not allowed, `PUT` is not supported on this endpoint.
|
||||||
|
|
||||||
components:
|
components:
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
BearerAuth:
|
BearerAuth:
|
||||||
@@ -386,6 +447,17 @@ components:
|
|||||||
configuration:
|
configuration:
|
||||||
$ref: '#/components/schemas/RoomConfiguration'
|
$ref: '#/components/schemas/RoomConfiguration'
|
||||||
|
|
||||||
|
RoomUpdate:
|
||||||
|
type: object
|
||||||
|
description: |
|
||||||
|
Fields that can be updated on an existing room. Both are optional, omitted
|
||||||
|
fields keep their current value.
|
||||||
|
properties:
|
||||||
|
access_level:
|
||||||
|
$ref: '#/components/schemas/RoomAccessLevel'
|
||||||
|
configuration:
|
||||||
|
$ref: '#/components/schemas/RoomConfiguration'
|
||||||
|
|
||||||
RoomConfiguration:
|
RoomConfiguration:
|
||||||
type: object
|
type: object
|
||||||
description: |
|
description: |
|
||||||
@@ -427,6 +499,9 @@ components:
|
|||||||
- `public`: Anyone with the room link can join directly, no authentication required.
|
- `public`: Anyone with the room link can join directly, no authentication required.
|
||||||
- `trusted`: Authenticated users join directly. Unauthenticated users wait in the lobby for approval.
|
- `trusted`: Authenticated users join directly. Unauthenticated users wait in the lobby for approval.
|
||||||
- `restricted`: Only participants explicitly trusted by the owner bypass the lobby. Everyone else waits for approval regardless of authentication.
|
- `restricted`: Only participants explicitly trusted by the owner bypass the lobby. Everyone else waits for approval regardless of authentication.
|
||||||
|
|
||||||
|
`public` is rejected with a `400` unless the deployment explicitly enables it
|
||||||
|
for this API. This applies both when creating a room and when updating one.
|
||||||
example: "trusted"
|
example: "trusted"
|
||||||
|
|
||||||
Room:
|
Room:
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ info:
|
|||||||
* `lasuite_visio:rooms:list` – List rooms accessible to the delegated user.
|
* `lasuite_visio:rooms:list` – List rooms accessible to the delegated user.
|
||||||
* `lasuite_visio:rooms:retrieve` – Retrieve details of a specific room.
|
* `lasuite_visio:rooms:retrieve` – Retrieve details of a specific room.
|
||||||
* `lasuite_visio:rooms:create` – Create new rooms.
|
* `lasuite_visio:rooms:create` – Create new rooms.
|
||||||
* `lasuite_visio:rooms:update` – **Coming soon** Update existing rooms, e.g., add attendees to a room.
|
* `lasuite_visio:rooms:update` – Update the access level and configuration of existing rooms.
|
||||||
* `lasuite_visio:rooms:delete` – **Coming soon** Delete rooms generated by the application.
|
* `lasuite_visio:rooms:delete` – **Coming soon** Delete rooms generated by the application.
|
||||||
|
|
||||||
#### Upcoming Features
|
#### Upcoming Features
|
||||||
@@ -206,6 +206,67 @@ paths:
|
|||||||
'404':
|
'404':
|
||||||
$ref: '#/components/responses/RoomNotFoundError'
|
$ref: '#/components/responses/RoomNotFoundError'
|
||||||
|
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- Rooms
|
||||||
|
summary: Update a room
|
||||||
|
description: |
|
||||||
|
Partially updates a room. Only rooms where the user is administrator or
|
||||||
|
owner can be updated; any other role gets a `403`.
|
||||||
|
|
||||||
|
**Updatable fields:** `access_level` and `configuration`. Every other field
|
||||||
|
(`id`, `name`, `slug`, `pin_code`) is read-only and silently ignored when sent.
|
||||||
|
|
||||||
|
`configuration` is replaced as a whole, it is not merged with the stored one.
|
||||||
|
Send the complete object you want the room to end up with.
|
||||||
|
|
||||||
|
Full replacement (`PUT`) is not supported. Use `PATCH` instead.
|
||||||
|
operationId: updateRoom
|
||||||
|
security:
|
||||||
|
- BearerAuth: [rooms:update]
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: Room UUID
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RoomUpdate'
|
||||||
|
examples:
|
||||||
|
accessLevelOnly:
|
||||||
|
summary: Change the access level
|
||||||
|
value:
|
||||||
|
access_level: "restricted"
|
||||||
|
configurationOnly:
|
||||||
|
summary: Replace the room configuration
|
||||||
|
value:
|
||||||
|
configuration:
|
||||||
|
everyone_can_mute: true
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Room updated successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Room'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequestError'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/UnauthorizedError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/ForbiddenError'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/RoomNotFoundError'
|
||||||
|
'405':
|
||||||
|
description: |
|
||||||
|
Method not allowed, `PUT` is not supported on this endpoint.
|
||||||
|
|
||||||
components:
|
components:
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
BearerAuth:
|
BearerAuth:
|
||||||
@@ -227,6 +288,17 @@ components:
|
|||||||
configuration:
|
configuration:
|
||||||
$ref: '#/components/schemas/RoomConfiguration'
|
$ref: '#/components/schemas/RoomConfiguration'
|
||||||
|
|
||||||
|
RoomUpdate:
|
||||||
|
type: object
|
||||||
|
description: |
|
||||||
|
Fields that can be updated on an existing room. Both are optional, omitted
|
||||||
|
fields keep their current value.
|
||||||
|
properties:
|
||||||
|
access_level:
|
||||||
|
$ref: '#/components/schemas/RoomAccessLevel'
|
||||||
|
configuration:
|
||||||
|
$ref: '#/components/schemas/RoomConfiguration'
|
||||||
|
|
||||||
RoomConfiguration:
|
RoomConfiguration:
|
||||||
type: object
|
type: object
|
||||||
description: |
|
description: |
|
||||||
@@ -268,6 +340,9 @@ components:
|
|||||||
- `public`: Anyone with the room link can join directly, no authentication required.
|
- `public`: Anyone with the room link can join directly, no authentication required.
|
||||||
- `trusted`: Authenticated users join directly. Unauthenticated users wait in the lobby for approval.
|
- `trusted`: Authenticated users join directly. Unauthenticated users wait in the lobby for approval.
|
||||||
- `restricted`: Only participants explicitly trusted by the owner bypass the lobby. Everyone else waits for approval regardless of authentication.
|
- `restricted`: Only participants explicitly trusted by the owner bypass the lobby. Everyone else waits for approval regardless of authentication.
|
||||||
|
|
||||||
|
`public` is rejected with a `400` unless the deployment explicitly enables it
|
||||||
|
for this API. This applies both when creating a room and when updating one.
|
||||||
example: "trusted"
|
example: "trusted"
|
||||||
|
|
||||||
Room:
|
Room:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class AnalyticsEvent(StrEnum):
|
|||||||
|
|
||||||
# Rooms
|
# Rooms
|
||||||
ROOM_CREATED = "room_created"
|
ROOM_CREATED = "room_created"
|
||||||
|
ROOM_UPDATED = "room_updated"
|
||||||
|
|
||||||
# Roomkit (meeting-room SIP devices)
|
# Roomkit (meeting-room SIP devices)
|
||||||
ROOMKIT_JOINED = "roomkit_joined"
|
ROOMKIT_JOINED = "roomkit_joined"
|
||||||
|
|||||||
@@ -75,11 +75,7 @@ from core.services.participants_management import (
|
|||||||
ParticipantsManagementException,
|
ParticipantsManagementException,
|
||||||
)
|
)
|
||||||
from core.services.room_creation import RoomCreation
|
from core.services.room_creation import RoomCreation
|
||||||
from core.services.room_management import (
|
from core.services.room_management import RoomManagement
|
||||||
RoomManagement,
|
|
||||||
RoomManagementException,
|
|
||||||
RoomNotFoundException,
|
|
||||||
)
|
|
||||||
from core.services.room_roles import (
|
from core.services.room_roles import (
|
||||||
RoomRoleError,
|
RoomRoleError,
|
||||||
RoomRoleService,
|
RoomRoleService,
|
||||||
@@ -356,26 +352,7 @@ class RoomViewSet(
|
|||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
metadata = {
|
RoomManagement.sync_room_metadata(room)
|
||||||
"configuration": room.configuration,
|
|
||||||
"access_level": room.access_level,
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
RoomManagement().update_metadata(
|
|
||||||
room_name=str(room.id),
|
|
||||||
metadata=metadata,
|
|
||||||
)
|
|
||||||
except RoomNotFoundException:
|
|
||||||
logger.info(
|
|
||||||
"LiveKit room %s does not exist yet, skipping metadata sync",
|
|
||||||
room.id,
|
|
||||||
)
|
|
||||||
except RoomManagementException:
|
|
||||||
logger.warning(
|
|
||||||
"Failed to sync metadata to LiveKit for room %s",
|
|
||||||
room.id,
|
|
||||||
)
|
|
||||||
|
|
||||||
@decorators.action(
|
@decorators.action(
|
||||||
detail=True,
|
detail=True,
|
||||||
|
|||||||
@@ -3,7 +3,11 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
from django.core.exceptions import (
|
||||||
|
ImproperlyConfigured,
|
||||||
|
SuspiciousOperation,
|
||||||
|
ValidationError,
|
||||||
|
)
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from lasuite.oidc_login.backends import (
|
from lasuite.oidc_login.backends import (
|
||||||
@@ -17,6 +21,7 @@ from core.services.marketing import (
|
|||||||
ContactData,
|
ContactData,
|
||||||
get_marketing_service,
|
get_marketing_service,
|
||||||
)
|
)
|
||||||
|
from core.validators import sub_validator
|
||||||
|
|
||||||
|
|
||||||
class OIDCAuthenticationBackend(LaSuiteOIDCAuthenticationBackend):
|
class OIDCAuthenticationBackend(LaSuiteOIDCAuthenticationBackend):
|
||||||
@@ -84,6 +89,19 @@ class OIDCAuthenticationBackend(LaSuiteOIDCAuthenticationBackend):
|
|||||||
|
|
||||||
def get_existing_user(self, sub, email):
|
def get_existing_user(self, sub, email):
|
||||||
"""Fetch existing user by sub or email."""
|
"""Fetch existing user by sub or email."""
|
||||||
|
|
||||||
|
sub = str(sub)
|
||||||
|
|
||||||
|
try:
|
||||||
|
sub_validator(sub)
|
||||||
|
except ValidationError as err:
|
||||||
|
raise SuspiciousOperation(
|
||||||
|
"User info contained an invalid sub claim"
|
||||||
|
) from err
|
||||||
|
|
||||||
|
if len(sub) > 255:
|
||||||
|
raise SuspiciousOperation("User info contained an invalid sub claim")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return User.objects.get(sub=sub)
|
return User.objects.get(sub=sub)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"""External API endpoints"""
|
"""External API endpoints"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -25,6 +26,7 @@ from rest_framework import (
|
|||||||
from core import analytics, api, models
|
from core import analytics, api, models
|
||||||
from core.api.feature_flag import FeatureFlag
|
from core.api.feature_flag import FeatureFlag
|
||||||
from core.services.jwt_token import JwtTokenService
|
from core.services.jwt_token import JwtTokenService
|
||||||
|
from core.services.room_management import RoomManagement
|
||||||
|
|
||||||
from ..services.provisional_user_service import (
|
from ..services.provisional_user_service import (
|
||||||
ProvisionalUserCreationDisabledError,
|
ProvisionalUserCreationDisabledError,
|
||||||
@@ -142,6 +144,7 @@ class RoomViewSet(
|
|||||||
mixins.CreateModelMixin,
|
mixins.CreateModelMixin,
|
||||||
mixins.RetrieveModelMixin,
|
mixins.RetrieveModelMixin,
|
||||||
mixins.ListModelMixin,
|
mixins.ListModelMixin,
|
||||||
|
mixins.UpdateModelMixin,
|
||||||
viewsets.GenericViewSet,
|
viewsets.GenericViewSet,
|
||||||
):
|
):
|
||||||
"""Application-delegated API for room management.
|
"""Application-delegated API for room management.
|
||||||
@@ -154,8 +157,12 @@ class RoomViewSet(
|
|||||||
- list: List rooms the user has access to (requires 'rooms:list' scope)
|
- list: List rooms the user has access to (requires 'rooms:list' scope)
|
||||||
- retrieve: Get room details (requires 'rooms:retrieve' scope)
|
- retrieve: Get room details (requires 'rooms:retrieve' scope)
|
||||||
- create: Create a new room owned by the user (requires 'rooms:create' scope)
|
- create: Create a new room owned by the user (requires 'rooms:create' scope)
|
||||||
|
- partial_update: Update a room's access level and configuration, for
|
||||||
|
administrators and owners only (requires 'rooms:update' scope)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
http_method_names = ["get", "post", "patch", "head", "options"]
|
||||||
|
|
||||||
authentication_classes = [
|
authentication_classes = [
|
||||||
authentication.ApplicationJWTAuthentication,
|
authentication.ApplicationJWTAuthentication,
|
||||||
authentication.AddonsJWTAuthentication,
|
authentication.AddonsJWTAuthentication,
|
||||||
@@ -189,7 +196,39 @@ class RoomViewSet(
|
|||||||
serializer = self.get_serializer(queryset, many=True)
|
serializer = self.get_serializer(queryset, many=True)
|
||||||
return drf_response.Response(serializer.data)
|
return drf_response.Response(serializer.data)
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def _track_room_event(self, room, event, **extra_properties):
|
||||||
|
"""Log a room operation for auditing and forward it to analytics."""
|
||||||
|
|
||||||
|
auth_method = type(self.request.successful_authenticator).__name__
|
||||||
|
client_id = (self.request.auth or {}).get("client_id", "unknown")
|
||||||
|
|
||||||
|
# Log for auditing
|
||||||
|
details = "".join(f", {key}={value}" for key, value in extra_properties.items())
|
||||||
|
logger.info(
|
||||||
|
"Room %s via application: room_id=%s, user_id=%s, client_id=%s, auth_method=%s%s",
|
||||||
|
event.removeprefix("room_"),
|
||||||
|
room.id,
|
||||||
|
self.request.user.id,
|
||||||
|
client_id,
|
||||||
|
auth_method,
|
||||||
|
details,
|
||||||
|
)
|
||||||
|
|
||||||
|
analytics.capture(
|
||||||
|
self.request.user,
|
||||||
|
event,
|
||||||
|
{
|
||||||
|
"room_id": str(room.pk),
|
||||||
|
"access_level": room.access_level,
|
||||||
|
"client_id": client_id,
|
||||||
|
"external_api": True,
|
||||||
|
"auth_method": auth_method,
|
||||||
|
**extra_properties,
|
||||||
|
"$set": {"email": self.request.user.email},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def perform_create(self, serializer: serializers.RoomSerializer):
|
||||||
"""Set the current user as owner of the newly created room."""
|
"""Set the current user as owner of the newly created room."""
|
||||||
room = serializer.save()
|
room = serializer.save()
|
||||||
models.ResourceAccess.objects.create(
|
models.ResourceAccess.objects.create(
|
||||||
@@ -198,27 +237,31 @@ class RoomViewSet(
|
|||||||
role=models.RoleChoices.OWNER,
|
role=models.RoleChoices.OWNER,
|
||||||
)
|
)
|
||||||
|
|
||||||
auth_method = type(self.request.successful_authenticator).__name__
|
self._track_room_event(room, analytics.AnalyticsEvent.ROOM_CREATED)
|
||||||
client_id = (self.request.auth or {}).get("client_id", "unknown")
|
|
||||||
|
|
||||||
# Log for auditing
|
def perform_update(self, serializer: serializers.RoomSerializer):
|
||||||
logger.info(
|
"""Persist the room update, sync it to LiveKit, then log and track it."""
|
||||||
"Room created via application: room_id=%s, user_id=%s, client_id=%s, auth_method=%s",
|
|
||||||
room.id,
|
previous_values = {
|
||||||
self.request.user.id,
|
"access_level": serializer.instance.access_level,
|
||||||
client_id,
|
"configuration": copy.deepcopy(serializer.instance.configuration),
|
||||||
auth_method,
|
}
|
||||||
|
|
||||||
|
room = serializer.save()
|
||||||
|
|
||||||
|
# Report the fields that actually changed, not the ones that were submitted.
|
||||||
|
updated_fields = sorted(
|
||||||
|
field
|
||||||
|
for field, previous_value in previous_values.items()
|
||||||
|
if getattr(room, field) != previous_value
|
||||||
)
|
)
|
||||||
|
|
||||||
analytics.capture(
|
if updated_fields:
|
||||||
self.request.user,
|
RoomManagement.sync_room_metadata(room)
|
||||||
analytics.AnalyticsEvent.ROOM_CREATED,
|
|
||||||
{
|
self._track_room_event(
|
||||||
"room_id": str(room.pk),
|
room,
|
||||||
"access_level": room.access_level,
|
analytics.AnalyticsEvent.ROOM_UPDATED,
|
||||||
"client_id": client_id,
|
updated_fields=updated_fields,
|
||||||
"external_api": True,
|
previous_access_level=previous_values["access_level"],
|
||||||
"auth_method": auth_method,
|
|
||||||
"$set": {"email": self.request.user.email},
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ class ResourceFactory(factory.django.DjangoModelFactory):
|
|||||||
else:
|
else:
|
||||||
UserResourceAccessFactory(resource=self, user=item[0], role=item[1])
|
UserResourceAccessFactory(resource=self, user=item[0], role=item[1])
|
||||||
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
|
|
||||||
class UserResourceAccessFactory(factory.django.DjangoModelFactory):
|
class UserResourceAccessFactory(factory.django.DjangoModelFactory):
|
||||||
"""Create fake resource user accesses for testing."""
|
"""Create fake resource user accesses for testing."""
|
||||||
@@ -97,8 +95,6 @@ class RecordingFactory(factory.django.DjangoModelFactory):
|
|||||||
recording=self, user=item[0], role=item[1]
|
recording=self, user=item[0], role=item[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
|
|
||||||
class UserRecordingAccessFactory(factory.django.DjangoModelFactory):
|
class UserRecordingAccessFactory(factory.django.DjangoModelFactory):
|
||||||
"""Create fake recording user accesses for testing."""
|
"""Create fake recording user accesses for testing."""
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import uuid
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import core.validators
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
@@ -41,7 +43,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='primary key for the record as UUID', primary_key=True, serialize=False, verbose_name='id')),
|
('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='primary key for the record as UUID', primary_key=True, serialize=False, verbose_name='id')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='date and time at which a record was created', verbose_name='created on')),
|
('created_at', models.DateTimeField(auto_now_add=True, help_text='date and time at which a record was created', verbose_name='created on')),
|
||||||
('updated_at', models.DateTimeField(auto_now=True, help_text='date and time at which a record was last updated', verbose_name='updated on')),
|
('updated_at', models.DateTimeField(auto_now=True, help_text='date and time at which a record was last updated', verbose_name='updated on')),
|
||||||
('sub', models.CharField(blank=True, help_text='Optional for pending users; required upon account activation. 255 characters or fewer. Letters, numbers, and @/./+/-/_ characters only.', max_length=255, null=True, unique=True, validators=[django.core.validators.RegexValidator(message='Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_ characters.', regex='^[\\w.@+-]+\\Z')], verbose_name='sub')),
|
('sub', models.CharField(blank=True, help_text='Optional for pending users; required upon account activation. 255 characters or fewer. Printable ASCII characters only.', max_length=255, null=True, unique=True, validators=[core.validators.sub_validator], verbose_name='sub')),
|
||||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='identity email address')),
|
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='identity email address')),
|
||||||
('admin_email', models.EmailField(blank=True, max_length=254, null=True, unique=True, verbose_name='admin email address')),
|
('admin_email', models.EmailField(blank=True, max_length=254, null=True, unique=True, verbose_name='admin email address')),
|
||||||
('language', models.CharField(choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE, help_text='The language in which the user wants to see the interface.', max_length=10, verbose_name='language')),
|
('language', models.CharField(choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE, help_text='The language in which the user wants to see the interface.', max_length=10, verbose_name='language')),
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ from timezone_field import TimeZoneField
|
|||||||
|
|
||||||
from . import fields, utils
|
from . import fields, utils
|
||||||
from .recording.enums import FileExtension
|
from .recording.enums import FileExtension
|
||||||
|
from .validators import sub_validator
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
@@ -145,19 +146,11 @@ class BaseModel(models.Model):
|
|||||||
class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin):
|
class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin):
|
||||||
"""User model to work with OIDC only authentication."""
|
"""User model to work with OIDC only authentication."""
|
||||||
|
|
||||||
sub_validator = validators.RegexValidator(
|
|
||||||
regex=r"^[\w.@+-]+\Z",
|
|
||||||
message=_(
|
|
||||||
"Enter a valid sub. This value may contain only letters, "
|
|
||||||
"numbers, and @/./+/-/_ characters."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
sub = models.CharField(
|
sub = models.CharField(
|
||||||
_("sub"),
|
_("sub"),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Optional for pending users; required upon account activation. "
|
"Optional for pending users; required upon account activation. "
|
||||||
"255 characters or fewer. Letters, numbers, and @/./+/-/_ characters only."
|
"255 characters or fewer. Printable ASCII characters only."
|
||||||
),
|
),
|
||||||
max_length=255,
|
max_length=255,
|
||||||
unique=True,
|
unique=True,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class RecordingEventsService:
|
|||||||
recording_status = status_mapping.get(egress_status)
|
recording_status = status_mapping.get(egress_status)
|
||||||
if recording_status:
|
if recording_status:
|
||||||
try:
|
try:
|
||||||
RoomManagement().update_metadata(
|
RoomManagement.update_metadata(
|
||||||
room_name, {"recording_status": recording_status}
|
room_name, {"recording_status": recording_status}
|
||||||
)
|
)
|
||||||
except RoomNotFoundException:
|
except RoomNotFoundException:
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class WorkerServiceMediator:
|
|||||||
mode = recording.options.get("original_mode", None) or recording.mode
|
mode = recording.options.get("original_mode", None) or recording.mode
|
||||||
|
|
||||||
try:
|
try:
|
||||||
RoomManagement().update_metadata(
|
RoomManagement.update_metadata(
|
||||||
room_name, {"recording_mode": mode, "recording_status": "starting"}
|
room_name, {"recording_mode": mode, "recording_status": "starting"}
|
||||||
)
|
)
|
||||||
except RoomNotFoundException:
|
except RoomNotFoundException:
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ class LiveKitEventsService:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
room_name = str(recording.room.id)
|
room_name = str(recording.room.id)
|
||||||
RoomManagement().update_metadata(
|
RoomManagement.update_metadata(
|
||||||
room_name, remove_keys=["recording_mode", "recording_status"]
|
room_name, remove_keys=["recording_mode", "recording_status"]
|
||||||
)
|
)
|
||||||
except RoomNotFoundException:
|
except RoomNotFoundException:
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ class RoomNotFoundException(RoomManagementException):
|
|||||||
class RoomManagement:
|
class RoomManagement:
|
||||||
"""Service for managing LiveKit rooms."""
|
"""Service for managing LiveKit rooms."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
@async_to_sync
|
@async_to_sync
|
||||||
async def update_metadata(
|
async def update_metadata(
|
||||||
self,
|
cls,
|
||||||
room_name: str,
|
room_name: str,
|
||||||
metadata: Optional[Dict] = None,
|
metadata: Optional[Dict] = None,
|
||||||
remove_keys: Optional[list[str]] = None,
|
remove_keys: Optional[list[str]] = None,
|
||||||
@@ -90,8 +91,9 @@ class RoomManagement:
|
|||||||
finally:
|
finally:
|
||||||
await lkapi.aclose()
|
await lkapi.aclose()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
@async_to_sync
|
@async_to_sync
|
||||||
async def delete_room(self, room_name: str):
|
async def delete_room(cls, room_name: str):
|
||||||
"""Delete a LiveKit room and disconnect all participants.
|
"""Delete a LiveKit room and disconnect all participants.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@@ -116,3 +118,32 @@ class RoomManagement:
|
|||||||
raise RoomManagementException("Could not delete room") from e
|
raise RoomManagementException("Could not delete room") from e
|
||||||
finally:
|
finally:
|
||||||
await lkapi.aclose()
|
await lkapi.aclose()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sync_room_metadata(cls, room):
|
||||||
|
"""Push a room's configuration and access level to its LiveKit room metadata.
|
||||||
|
|
||||||
|
Failures are swallowed: a room that is not live yet, or a LiveKit hiccup,
|
||||||
|
should never fail the request that triggered the update.
|
||||||
|
"""
|
||||||
|
|
||||||
|
metadata = {
|
||||||
|
"configuration": room.configuration,
|
||||||
|
"access_level": room.access_level,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
cls.update_metadata(
|
||||||
|
room_name=str(room.id),
|
||||||
|
metadata=metadata,
|
||||||
|
)
|
||||||
|
except RoomNotFoundException:
|
||||||
|
logger.info(
|
||||||
|
"LiveKit room %s does not exist yet, skipping metadata sync",
|
||||||
|
room.id,
|
||||||
|
)
|
||||||
|
except RoomManagementException:
|
||||||
|
logger.warning(
|
||||||
|
"Failed to sync metadata to LiveKit for room %s",
|
||||||
|
room.id,
|
||||||
|
)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ def delete_connection_test_room(room_name: str):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
RoomManagement().delete_room(room_name)
|
RoomManagement.delete_room(room_name)
|
||||||
except RoomNotFoundException:
|
except RoomNotFoundException:
|
||||||
# Room may already be gone after empty/departure timeout.
|
# Room may already be gone after empty/departure timeout.
|
||||||
logger.info("Connection test room '%s' already gone.", room_name)
|
logger.info("Connection test room '%s' already gone.", room_name)
|
||||||
|
|||||||
@@ -40,6 +40,111 @@ def test_authentication_getter_existing_user(monkeypatch):
|
|||||||
assert user == db_user
|
assert user == db_user
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"sub",
|
||||||
|
[
|
||||||
|
# NUL (U+0000) passes str.isascii() but PostgreSQL text fields
|
||||||
|
# cannot store or compare it (DataError)
|
||||||
|
"auth0|abc\x00def",
|
||||||
|
# lone surrogates cannot be encoded to UTF-8 for the DB lookup
|
||||||
|
# (UnicodeEncodeError), which runs before any model validation
|
||||||
|
"bad\ud800sub",
|
||||||
|
# plainly invalid subs would otherwise escape as ValidationError
|
||||||
|
# on user creation, which mozilla-django-oidc does not catch
|
||||||
|
"\u00e9milie",
|
||||||
|
"a" * 256,
|
||||||
|
# ASCII control characters are rejected by policy
|
||||||
|
"tab\tsub",
|
||||||
|
"del\x7fsub",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_authentication_getter_invalid_sub_rejected_cleanly(monkeypatch, sub):
|
||||||
|
"""
|
||||||
|
Subs that can never be persisted should be rejected with
|
||||||
|
SuspiciousOperation (turned into a clean authentication failure by
|
||||||
|
mozilla-django-oidc) instead of leaking DataError, UnicodeEncodeError
|
||||||
|
or ValidationError as a server error.
|
||||||
|
"""
|
||||||
|
klass = OIDCAuthenticationBackend()
|
||||||
|
|
||||||
|
def get_userinfo_mocked(*args):
|
||||||
|
return {"sub": sub, "email": "john@example.com"}
|
||||||
|
|
||||||
|
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
SuspiciousOperation,
|
||||||
|
match="User info contained an invalid sub claim",
|
||||||
|
):
|
||||||
|
klass.get_or_create_user(access_token="test-token", id_token=None, payload=None)
|
||||||
|
|
||||||
|
assert models.User.objects.exists() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_authentication_getter_numeric_sub(monkeypatch):
|
||||||
|
"""
|
||||||
|
Some providers serialize the sub as a JSON number. It should keep working
|
||||||
|
(CharField coerces it to a string on save) and must not crash the early
|
||||||
|
sub checks in get_existing_user.
|
||||||
|
"""
|
||||||
|
klass = OIDCAuthenticationBackend()
|
||||||
|
|
||||||
|
def get_userinfo_mocked(*args):
|
||||||
|
return {"sub": 12345, "email": "john@example.com"}
|
||||||
|
|
||||||
|
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||||
|
|
||||||
|
user = klass.get_or_create_user(
|
||||||
|
access_token="test-token", id_token=None, payload=None
|
||||||
|
)
|
||||||
|
|
||||||
|
assert user.sub == "12345"
|
||||||
|
assert models.User.objects.count() == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_authentication_getter_new_user_auth0_pipe_sub(monkeypatch):
|
||||||
|
"""
|
||||||
|
A first login with an Auth0-style sub containing a pipe ("provider|user-id")
|
||||||
|
should create the user instead of raising a ValidationError.
|
||||||
|
Regression test for https://github.com/suitenumerique/meet/issues/[XXX].
|
||||||
|
"""
|
||||||
|
klass = OIDCAuthenticationBackend()
|
||||||
|
|
||||||
|
def get_userinfo_mocked(*args):
|
||||||
|
return {"sub": "auth0|644c0bc8f1874ef6d339fb34", "email": "john@example.com"}
|
||||||
|
|
||||||
|
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||||
|
|
||||||
|
user = klass.get_or_create_user(
|
||||||
|
access_token="test-token", id_token=None, payload=None
|
||||||
|
)
|
||||||
|
|
||||||
|
assert user.sub == "auth0|644c0bc8f1874ef6d339fb34"
|
||||||
|
assert user.email == "john@example.com"
|
||||||
|
assert models.User.objects.count() == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_authentication_getter_existing_user_auth0_pipe_sub(monkeypatch):
|
||||||
|
"""
|
||||||
|
A returning user with an Auth0-style pipe sub should be matched by sub,
|
||||||
|
not duplicated or rejected.
|
||||||
|
"""
|
||||||
|
klass = OIDCAuthenticationBackend()
|
||||||
|
db_user = UserFactory(sub="auth0|644c0bc8f1874ef6d339fb34")
|
||||||
|
|
||||||
|
def get_userinfo_mocked(*args):
|
||||||
|
return {"sub": db_user.sub}
|
||||||
|
|
||||||
|
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||||
|
|
||||||
|
user = klass.get_or_create_user(
|
||||||
|
access_token="test-token", id_token=None, payload=None
|
||||||
|
)
|
||||||
|
|
||||||
|
assert user == db_user
|
||||||
|
assert models.User.objects.count() == 1
|
||||||
|
|
||||||
|
|
||||||
def test_authentication_getter_new_user_no_email(monkeypatch):
|
def test_authentication_getter_new_user_no_email(monkeypatch):
|
||||||
"""
|
"""
|
||||||
If no user matches, a user should be created.
|
If no user matches, a user should be created.
|
||||||
|
|||||||
@@ -381,38 +381,11 @@ def test_api_rooms_update_administrators_of_another():
|
|||||||
assert other_room.slug == "old-name"
|
assert other_room.slug == "old-name"
|
||||||
|
|
||||||
|
|
||||||
@patch.object(RoomManagement, "update_metadata", side_effect=RoomNotFoundException)
|
@pytest.mark.parametrize("exception", [RoomNotFoundException, RoomManagementException])
|
||||||
def test_api_rooms_update_livekit_room_not_found(mock_update_metadata):
|
@patch.object(RoomManagement, "update_metadata")
|
||||||
"""Should not fail the API request when the LiveKit room does not exist yet."""
|
def test_api_rooms_update_livekit_sync_failure(mock_update_metadata, exception):
|
||||||
user = UserFactory()
|
|
||||||
room = RoomFactory(
|
|
||||||
users=[(user, random.choice(["administrator", "owner"]))],
|
|
||||||
configuration={},
|
|
||||||
)
|
|
||||||
client = APIClient()
|
|
||||||
client.force_login(user)
|
|
||||||
|
|
||||||
response = client.patch(
|
|
||||||
f"/api/v1.0/rooms/{room.id!s}/",
|
|
||||||
{"configuration": {"can_publish_sources": ["camera"]}},
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
assert response.status_code == 200
|
|
||||||
room.refresh_from_db()
|
|
||||||
assert room.configuration == {"can_publish_sources": ["camera"]}
|
|
||||||
|
|
||||||
mock_update_metadata.assert_called_once_with(
|
|
||||||
room_name=str(room.id),
|
|
||||||
metadata={
|
|
||||||
"access_level": room.access_level,
|
|
||||||
"configuration": {"can_publish_sources": ["camera"]},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@patch.object(RoomManagement, "update_metadata", side_effect=RoomManagementException)
|
|
||||||
def test_api_rooms_update_livekit_sync_failure(mock_update_metadata):
|
|
||||||
"""Should not fail the API request when the LiveKit metadata sync fails."""
|
"""Should not fail the API request when the LiveKit metadata sync fails."""
|
||||||
|
mock_update_metadata.side_effect = exception
|
||||||
user = UserFactory()
|
user = UserFactory()
|
||||||
room = RoomFactory(
|
room = RoomFactory(
|
||||||
users=[(user, random.choice(["administrator", "owner"]))],
|
users=[(user, random.choice(["administrator", "owner"]))],
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ from unittest import mock
|
|||||||
import pytest
|
import pytest
|
||||||
from livekit.api import TwirpError
|
from livekit.api import TwirpError
|
||||||
|
|
||||||
|
from core.factories import RoomFactory
|
||||||
|
from core.models import RoomAccessLevel
|
||||||
from core.services.room_management import (
|
from core.services.room_management import (
|
||||||
RoomManagement,
|
RoomManagement,
|
||||||
RoomManagementException,
|
RoomManagementException,
|
||||||
@@ -20,7 +22,7 @@ def test_delete_room_calls_livekit(mock_create_livekit_client):
|
|||||||
mock_api.aclose = mock.AsyncMock()
|
mock_api.aclose = mock.AsyncMock()
|
||||||
mock_create_livekit_client.return_value = mock_api
|
mock_create_livekit_client.return_value = mock_api
|
||||||
|
|
||||||
RoomManagement().delete_room("room-abc")
|
RoomManagement.delete_room("room-abc")
|
||||||
|
|
||||||
mock_api.room.delete_room.assert_awaited_once()
|
mock_api.room.delete_room.assert_awaited_once()
|
||||||
request = mock_api.room.delete_room.await_args.args[0]
|
request = mock_api.room.delete_room.await_args.args[0]
|
||||||
@@ -39,7 +41,7 @@ def test_delete_room_raises_not_found(mock_create_livekit_client):
|
|||||||
mock_create_livekit_client.return_value = mock_api
|
mock_create_livekit_client.return_value = mock_api
|
||||||
|
|
||||||
with pytest.raises(RoomNotFoundException):
|
with pytest.raises(RoomNotFoundException):
|
||||||
RoomManagement().delete_room("missing-room")
|
RoomManagement.delete_room("missing-room")
|
||||||
|
|
||||||
mock_api.aclose.assert_awaited_once()
|
mock_api.aclose.assert_awaited_once()
|
||||||
|
|
||||||
@@ -55,6 +57,25 @@ def test_delete_room_raises_management_exception(mock_create_livekit_client):
|
|||||||
mock_create_livekit_client.return_value = mock_api
|
mock_create_livekit_client.return_value = mock_api
|
||||||
|
|
||||||
with pytest.raises(RoomManagementException):
|
with pytest.raises(RoomManagementException):
|
||||||
RoomManagement().delete_room("room-abc")
|
RoomManagement.delete_room("room-abc")
|
||||||
|
|
||||||
mock_api.aclose.assert_awaited_once()
|
mock_api.aclose.assert_awaited_once()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_sync_room_metadata_pushes_configuration_and_access_level(mock_update_metadata):
|
||||||
|
"""The room's configuration and access level are forwarded to LiveKit."""
|
||||||
|
room = RoomFactory.build(
|
||||||
|
access_level=RoomAccessLevel.RESTRICTED,
|
||||||
|
configuration={"everyone_can_mute": True},
|
||||||
|
)
|
||||||
|
|
||||||
|
RoomManagement.sync_room_metadata(room)
|
||||||
|
|
||||||
|
mock_update_metadata.assert_called_once_with(
|
||||||
|
room_name=str(room.id),
|
||||||
|
metadata={
|
||||||
|
"configuration": {"everyone_can_mute": True},
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|||||||
@@ -16,8 +16,17 @@ import responses
|
|||||||
from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication
|
from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication
|
||||||
from rest_framework.test import APIClient
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from core.analytics import AnalyticsEvent
|
||||||
from core.factories import ApplicationFactory, RoomFactory, UserFactory
|
from core.factories import ApplicationFactory, RoomFactory, UserFactory
|
||||||
from core.models import ApplicationScope, RoleChoices, Room, RoomAccessLevel, User
|
from core.models import (
|
||||||
|
Application,
|
||||||
|
ApplicationScope,
|
||||||
|
RoleChoices,
|
||||||
|
Room,
|
||||||
|
RoomAccessLevel,
|
||||||
|
User,
|
||||||
|
)
|
||||||
|
from core.services.room_management import RoomManagement
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
@@ -880,6 +889,509 @@ def test_api_rooms_create_public_access_level_when_default_is_public(settings):
|
|||||||
assert response.data["access_level"] == RoomAccessLevel.PUBLIC
|
assert response.data["access_level"] == RoomAccessLevel.PUBLIC
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("core.external_api.viewsets.analytics.capture")
|
||||||
|
def test_api_rooms_create_tracks_analytics(mock_capture):
|
||||||
|
"""Creating a room should emit a ROOM_CREATED analytics event."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_CREATE])
|
||||||
|
application = Application.objects.get()
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.post(
|
||||||
|
"/external-api/v1.0/rooms/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
mock_capture.assert_called_once()
|
||||||
|
captured_user, event, properties = mock_capture.call_args[0]
|
||||||
|
|
||||||
|
assert captured_user == user
|
||||||
|
assert event == AnalyticsEvent.ROOM_CREATED
|
||||||
|
assert properties == {
|
||||||
|
"room_id": response.data["id"],
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
"client_id": str(application.client_id),
|
||||||
|
"external_api": True,
|
||||||
|
"auth_method": "ApplicationJWTAuthentication",
|
||||||
|
"$set": {"email": user.email},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_update_requires_authentication():
|
||||||
|
"""Updating a room without authentication should return 401."""
|
||||||
|
|
||||||
|
room = RoomFactory(users=[(UserFactory(), RoleChoices.OWNER)])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_update_requires_scope():
|
||||||
|
"""Updating a room requires the ROOMS_UPDATE scope."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(users=[(user, RoleChoices.OWNER)])
|
||||||
|
|
||||||
|
# Token without ROOMS_UPDATE scope
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_RETRIEVE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 403
|
||||||
|
assert (
|
||||||
|
"insufficient permissions. required scope: rooms:update"
|
||||||
|
in str(response.data).lower()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_rooms_update_no_scope():
|
||||||
|
"""Updating a room without any scope should return 403."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(users=[(user, RoleChoices.OWNER)])
|
||||||
|
|
||||||
|
token = generate_test_token(user, [])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 403
|
||||||
|
assert "insufficient permissions." in str(response.data).lower()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_owner_success(mock_update_metadata, settings):
|
||||||
|
"""An owner should be able to update the access level and the configuration."""
|
||||||
|
|
||||||
|
settings.APPLICATION_BASE_URL = "http://your-application.com"
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
configuration={},
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
"configuration": {"everyone_can_mute": True},
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["id"] == str(room.id)
|
||||||
|
assert response.data["access_level"] == RoomAccessLevel.RESTRICTED
|
||||||
|
assert response.data["configuration"] == {"everyone_can_mute": True}
|
||||||
|
assert response.data["url"] == f"http://your-application.com/{room.slug}"
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.RESTRICTED
|
||||||
|
assert room.configuration == {"everyone_can_mute": True}
|
||||||
|
|
||||||
|
mock_update_metadata.assert_called_once_with(
|
||||||
|
room_name=str(room.id),
|
||||||
|
metadata={
|
||||||
|
"configuration": {"everyone_can_mute": True},
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_replaces_configuration(mock_update_metadata):
|
||||||
|
"""The configuration is replaced as a whole, it is not merged with the stored one."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
configuration={"can_publish_sources": ["camera"], "everyone_can_mute": True},
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"configuration": {"everyone_can_mute": False}},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
# The keys missing from the payload are dropped, not kept.
|
||||||
|
assert response.data["configuration"] == {"everyone_can_mute": False}
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.configuration == {"everyone_can_mute": False}
|
||||||
|
|
||||||
|
mock_update_metadata.assert_called_once_with(
|
||||||
|
room_name=str(room.id),
|
||||||
|
metadata={
|
||||||
|
"configuration": {"everyone_can_mute": False},
|
||||||
|
"access_level": room.access_level,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_administrator_success(mock_update_metadata):
|
||||||
|
"""An administrator should be able to update a room."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.ADMIN)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.RESTRICTED
|
||||||
|
mock_update_metadata.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_put_not_allowed(mock_update_metadata):
|
||||||
|
"""PUT is not exposed: full replacement is not supported, only PATCH is."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
configuration={},
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.put(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
"configuration": {"everyone_can_mute": True},
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 405
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.TRUSTED
|
||||||
|
assert room.configuration == {}
|
||||||
|
mock_update_metadata.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("role", [RoleChoices.MEMBER, None])
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_without_privileges(mock_update_metadata, role):
|
||||||
|
"""Members and users without any role should not be able to update a room."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
users = [(user, role)] if role else []
|
||||||
|
room = RoomFactory(users=users, access_level=RoomAccessLevel.TRUSTED)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.TRUSTED
|
||||||
|
mock_update_metadata.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_readonly_enforcement(mock_update_metadata):
|
||||||
|
"""Read-only fields provided on update should be ignored, the slug stays immutable."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
expected_id, expected_name = str(room.id), room.name
|
||||||
|
expected_slug, expected_pin_code = room.slug, room.pin_code
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{
|
||||||
|
"id": str(uuid.uuid4()),
|
||||||
|
"name": "fake-name",
|
||||||
|
"slug": "fake-slug",
|
||||||
|
"pin_code": "000000",
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["id"] == expected_id
|
||||||
|
assert response.data["name"] == expected_name
|
||||||
|
assert response.data["slug"] == expected_slug
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert str(room.id) == expected_id
|
||||||
|
assert room.name == expected_name
|
||||||
|
assert room.slug == expected_slug
|
||||||
|
assert room.pin_code == expected_pin_code
|
||||||
|
|
||||||
|
# The one writable field in the payload was applied
|
||||||
|
assert room.access_level == RoomAccessLevel.RESTRICTED
|
||||||
|
mock_update_metadata.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_rejects_invalid_configuration(mock_update_metadata):
|
||||||
|
"""Updating a room with unsupported configuration keys should fail."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(users=[(user, RoleChoices.OWNER)], configuration={})
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"configuration": {"unsupported_flag": True}},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert "extra inputs are not permitted" in str(response.data).lower()
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.configuration == {}
|
||||||
|
mock_update_metadata.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"invalid_configuration",
|
||||||
|
[
|
||||||
|
{"can_publish_sources": ["invalid-source"]},
|
||||||
|
{"everyone_can_mute": "invalid-value"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_rejects_invalid_configuration_values(
|
||||||
|
mock_update_metadata, invalid_configuration
|
||||||
|
):
|
||||||
|
"""Updating a room with invalid configuration values should fail."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(users=[(user, RoleChoices.OWNER)], configuration={})
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"configuration": invalid_configuration},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.configuration == {}
|
||||||
|
mock_update_metadata.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_public_access_disabled_by_default(mock_update_metadata):
|
||||||
|
"""Switching a room to public should be disabled for the external API by default."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.PUBLIC},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert "public rooms are disabled" in str(response.data).lower()
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.TRUSTED
|
||||||
|
mock_update_metadata.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_public_access_enabled_with_settings(
|
||||||
|
mock_update_metadata, settings
|
||||||
|
):
|
||||||
|
"""Switching a room to public should be allowed when explicitly enabled."""
|
||||||
|
|
||||||
|
settings.EXTERNAL_API_ALLOW_PUBLIC_ACCESS = True
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.PUBLIC},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["access_level"] == RoomAccessLevel.PUBLIC
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.PUBLIC
|
||||||
|
mock_update_metadata.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("core.external_api.viewsets.analytics.capture")
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_unchanged_skips_livekit_sync(
|
||||||
|
mock_update_metadata, mock_capture
|
||||||
|
):
|
||||||
|
"""An update that changes nothing should not sync metadata nor report changes."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
configuration={"everyone_can_mute": True},
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{
|
||||||
|
"access_level": RoomAccessLevel.TRUSTED,
|
||||||
|
"configuration": {"everyone_can_mute": True},
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
mock_update_metadata.assert_not_called()
|
||||||
|
|
||||||
|
# The event is still emitted for auditing, but reports an empty delta.
|
||||||
|
_, _, properties = mock_capture.call_args[0]
|
||||||
|
assert properties["updated_fields"] == []
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("core.external_api.viewsets.analytics.capture")
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_tracks_analytics(mock_update_metadata, mock_capture):
|
||||||
|
"""Updating a room should emit a ROOM_UPDATED analytics event."""
|
||||||
|
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
configuration={},
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
application = Application.objects.get()
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
"configuration": {"everyone_can_mute": True},
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
mock_capture.assert_called_once()
|
||||||
|
captured_user, event, properties = mock_capture.call_args[0]
|
||||||
|
|
||||||
|
assert captured_user == user
|
||||||
|
assert event == AnalyticsEvent.ROOM_UPDATED
|
||||||
|
assert properties == {
|
||||||
|
"room_id": str(room.pk),
|
||||||
|
"access_level": RoomAccessLevel.RESTRICTED,
|
||||||
|
"updated_fields": ["access_level", "configuration"],
|
||||||
|
"previous_access_level": RoomAccessLevel.TRUSTED,
|
||||||
|
"client_id": str(application.client_id),
|
||||||
|
"external_api": True,
|
||||||
|
"auth_method": "ApplicationJWTAuthentication",
|
||||||
|
"$set": {"email": user.email},
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_update_metadata.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
def test_api_rooms_response_no_url(settings):
|
def test_api_rooms_response_no_url(settings):
|
||||||
"""Response should not include url field when APPLICATION_BASE_URL is None."""
|
"""Response should not include url field when APPLICATION_BASE_URL is None."""
|
||||||
settings.APPLICATION_BASE_URL = None
|
settings.APPLICATION_BASE_URL = None
|
||||||
@@ -1497,6 +2009,106 @@ def test_resource_server_denies_access_with_insufficient_scopes(settings):
|
|||||||
assert response.status_code == 403
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_resource_server_updates_room_with_prefixed_scope(
|
||||||
|
mock_update_metadata, settings
|
||||||
|
):
|
||||||
|
"""A resource server token carrying the prefixed update scope should be accepted."""
|
||||||
|
|
||||||
|
user = UserFactory(sub="very-specific-sub")
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
settings.OIDC_RS_CLIENT_ID = "some_client_id"
|
||||||
|
settings.OIDC_RS_CLIENT_SECRET = "some_client_secret"
|
||||||
|
settings.OIDC_RS_SCOPES_PREFIX = "lasuite_meet"
|
||||||
|
|
||||||
|
settings.OIDC_OP_URL = "https://oidc.example.com"
|
||||||
|
settings.OIDC_VERIFY_SSL = False
|
||||||
|
settings.OIDC_TIMEOUT = 5
|
||||||
|
settings.OIDC_PROXY = None
|
||||||
|
settings.OIDC_OP_JWKS_ENDPOINT = "https://oidc.example.com/jwks"
|
||||||
|
settings.OIDC_OP_INTROSPECTION_ENDPOINT = "https://oidc.example.com/introspect"
|
||||||
|
|
||||||
|
responses.add(
|
||||||
|
responses.POST,
|
||||||
|
"https://oidc.example.com/introspect",
|
||||||
|
json={
|
||||||
|
"iss": "https://oidc.example.com",
|
||||||
|
"aud": "some_client_id", # settings.OIDC_RS_CLIENT_ID
|
||||||
|
"sub": "very-specific-sub",
|
||||||
|
"client_id": "some_service_provider",
|
||||||
|
"scope": "openid lasuite_meet lasuite_meet:rooms:update",
|
||||||
|
"active": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION="Bearer some_token")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.RESTRICTED
|
||||||
|
mock_update_metadata.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_resource_server_denies_room_update_without_update_scope(settings):
|
||||||
|
"""A resource server token without the update scope should be denied."""
|
||||||
|
|
||||||
|
user = UserFactory(sub="very-specific-sub")
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
settings.OIDC_RS_CLIENT_ID = "some_client_id"
|
||||||
|
settings.OIDC_RS_CLIENT_SECRET = "some_client_secret"
|
||||||
|
settings.OIDC_RS_SCOPES_PREFIX = "lasuite_meet"
|
||||||
|
|
||||||
|
settings.OIDC_OP_URL = "https://oidc.example.com"
|
||||||
|
settings.OIDC_VERIFY_SSL = False
|
||||||
|
settings.OIDC_TIMEOUT = 5
|
||||||
|
settings.OIDC_PROXY = None
|
||||||
|
settings.OIDC_OP_JWKS_ENDPOINT = "https://oidc.example.com/jwks"
|
||||||
|
settings.OIDC_OP_INTROSPECTION_ENDPOINT = "https://oidc.example.com/introspect"
|
||||||
|
|
||||||
|
responses.add(
|
||||||
|
responses.POST,
|
||||||
|
"https://oidc.example.com/introspect",
|
||||||
|
json={
|
||||||
|
"iss": "https://oidc.example.com",
|
||||||
|
"aud": "some_client_id", # settings.OIDC_RS_CLIENT_ID
|
||||||
|
"sub": "very-specific-sub",
|
||||||
|
"client_id": "some_service_provider",
|
||||||
|
"scope": "openid lasuite_meet lasuite_meet:rooms:retrieve",
|
||||||
|
"active": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION="Bearer some_token")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.TRUSTED
|
||||||
|
|
||||||
|
|
||||||
# ==============================
|
# ==============================
|
||||||
# Addons
|
# Addons
|
||||||
# ==============================
|
# ==============================
|
||||||
@@ -1548,6 +2160,32 @@ def test_api_rooms_create_with_valid_addons_token():
|
|||||||
assert room.get_role(user) == RoleChoices.OWNER
|
assert room.get_role(user) == RoleChoices.OWNER
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(RoomManagement, "update_metadata")
|
||||||
|
def test_api_rooms_update_with_valid_addons_token(mock_update_metadata):
|
||||||
|
"""Updating a room with a valid addons token should succeed."""
|
||||||
|
user = UserFactory()
|
||||||
|
room = RoomFactory(
|
||||||
|
users=[(user, RoleChoices.OWNER)],
|
||||||
|
access_level=RoomAccessLevel.TRUSTED,
|
||||||
|
)
|
||||||
|
|
||||||
|
token = generate_addons_test_token(user, [ApplicationScope.ROOMS_UPDATE])
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||||
|
response = client.patch(
|
||||||
|
f"/external-api/v1.0/rooms/{room.id}/",
|
||||||
|
{"access_level": RoomAccessLevel.RESTRICTED},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
room.refresh_from_db()
|
||||||
|
assert room.access_level == RoomAccessLevel.RESTRICTED
|
||||||
|
mock_update_metadata.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
def test_api_rooms_addons_token_inactive_user():
|
def test_api_rooms_addons_token_inactive_user():
|
||||||
"""Addons token for an inactive user should return 401."""
|
"""Addons token for an inactive user should return 401."""
|
||||||
user = UserFactory(is_active=False)
|
user = UserFactory(is_active=False)
|
||||||
|
|||||||
@@ -26,6 +26,64 @@ def test_models_users_id_unique():
|
|||||||
factories.UserFactory(id=user.id)
|
factories.UserFactory(id=user.id)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"sub,is_valid",
|
||||||
|
[
|
||||||
|
# cases from suitenumerique/docs PR #1295 (same validator)
|
||||||
|
("valid_sub.@+-:=/", True),
|
||||||
|
("invalid süb", False),
|
||||||
|
(12345, True),
|
||||||
|
# Auth0 emits "provider|user-id" subject identifiers
|
||||||
|
("auth0|644c0bc8f1874ef6d339fb34", True),
|
||||||
|
("google-oauth2|103547991597142817347", True),
|
||||||
|
# Keycloak-style UUID
|
||||||
|
("f:550e8400-e29b-41d4-a716-446655440000:jdoe", True),
|
||||||
|
# base64/URN-style identifiers
|
||||||
|
("dGVzdC1zdWItdmFsdWU=", True),
|
||||||
|
("urn:example:user/42", True),
|
||||||
|
# legacy format still accepted
|
||||||
|
("user@example.com", True),
|
||||||
|
# space (U+0020) is printable ASCII and remains allowed
|
||||||
|
("sub with space", True),
|
||||||
|
# non-ASCII values are rejected
|
||||||
|
("émilie", False),
|
||||||
|
# ASCII control characters (U+0000-U+001F, U+007F) are rejected:
|
||||||
|
# NUL passes isascii() but cannot be stored in PostgreSQL text
|
||||||
|
# fields, and the others invite log injection and interop issues
|
||||||
|
("nul\x00sub", False),
|
||||||
|
("\x00", False),
|
||||||
|
("tab\tsub", False),
|
||||||
|
("newline\nsub", False),
|
||||||
|
("del\x7fsub", False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_models_users_sub_validator(sub, is_valid):
|
||||||
|
"""
|
||||||
|
The "sub" field should accept any ASCII string as required by
|
||||||
|
OpenID Connect Core 1.0 §2 and RFC 7519 §4.1.2, and reject non-ASCII values.
|
||||||
|
"""
|
||||||
|
user = factories.UserFactory()
|
||||||
|
user.sub = sub
|
||||||
|
if is_valid:
|
||||||
|
user.full_clean()
|
||||||
|
else:
|
||||||
|
with pytest.raises(
|
||||||
|
ValidationError,
|
||||||
|
match="Enter a valid sub. This value should be printable ASCII only.",
|
||||||
|
):
|
||||||
|
user.full_clean()
|
||||||
|
|
||||||
|
|
||||||
|
def test_models_users_sub_max_length():
|
||||||
|
"""The "sub" field should enforce the 255 ASCII characters limit of OIDC Core 1.0 §2."""
|
||||||
|
user = factories.UserFactory(sub="a" * 255)
|
||||||
|
assert user.sub == "a" * 255
|
||||||
|
|
||||||
|
user.sub = "a" * 256
|
||||||
|
with pytest.raises(ValidationError, match="at most 255 characters"):
|
||||||
|
user.full_clean()
|
||||||
|
|
||||||
|
|
||||||
def test_models_users_send_mail_main_existing():
|
def test_models_users_send_mail_main_existing():
|
||||||
"""The "email_user' method should send mail to the user's email address."""
|
"""The "email_user' method should send mail to the user's email address."""
|
||||||
user = factories.UserFactory()
|
user = factories.UserFactory()
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
"""Custom validators for the core app."""
|
||||||
|
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
def sub_validator(value):
|
||||||
|
"""Validate that the sub is printable ASCII only.
|
||||||
|
|
||||||
|
OpenID Connect Core 1.0 (section 2) allows any ASCII (RFC 20) string of
|
||||||
|
at most 255 characters, so no character whitelist is applied: providers
|
||||||
|
legitimately emit "|" (Auth0), ":" (Keycloak), "=", "/", etc. As a
|
||||||
|
deliberate hardening beyond the spec, ASCII control characters
|
||||||
|
(U+0000-U+001F and U+007F) are rejected: no known provider emits them,
|
||||||
|
NUL cannot be stored in PostgreSQL text fields, and the others invite
|
||||||
|
log-injection and interoperability issues. For str values,
|
||||||
|
``isprintable()`` is false exactly for those control characters, while
|
||||||
|
space (U+0020) remains allowed.
|
||||||
|
"""
|
||||||
|
if not value.isascii() or not value.isprintable():
|
||||||
|
raise ValidationError(
|
||||||
|
_("Enter a valid sub. This value should be printable ASCII only.")
|
||||||
|
)
|
||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-07-02 10:47+0000\n"
|
"POT-Creation-Date: 2026-09-02 22:52+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -51,11 +51,11 @@ msgstr ""
|
|||||||
msgid "File preview"
|
msgid "File preview"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:300 core/admin.py:443
|
#: core/admin.py:300 core/admin.py:450
|
||||||
msgid "No owner"
|
msgid "No owner"
|
||||||
msgstr "Kein Eigentümer"
|
msgstr "Kein Eigentümer"
|
||||||
|
|
||||||
#: core/admin.py:303 core/admin.py:446
|
#: core/admin.py:303 core/admin.py:453
|
||||||
msgid "Multiple owners"
|
msgid "Multiple owners"
|
||||||
msgstr "Mehrere Eigentümer"
|
msgstr "Mehrere Eigentümer"
|
||||||
|
|
||||||
@@ -98,11 +98,11 @@ msgstr "%(count)s Aufnahme(n) erfolgreich als ‚Fehler beim Stoppen‘ markiert
|
|||||||
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
||||||
msgstr "%(count)s abgelaufene Aufnahme(n) übersprungen."
|
msgstr "%(count)s abgelaufene Aufnahme(n) übersprungen."
|
||||||
|
|
||||||
#: core/admin.py:510
|
#: core/admin.py:517
|
||||||
msgid "No scopes"
|
msgid "No scopes"
|
||||||
msgstr "Keine Scopes"
|
msgstr "Keine Scopes"
|
||||||
|
|
||||||
#: core/admin.py:512
|
#: core/admin.py:519
|
||||||
msgid "Scopes"
|
msgid "Scopes"
|
||||||
msgstr "Scopes"
|
msgstr "Scopes"
|
||||||
|
|
||||||
@@ -110,185 +110,201 @@ msgstr "Scopes"
|
|||||||
msgid "Creator is me"
|
msgid "Creator is me"
|
||||||
msgstr "Ersteller bin ich"
|
msgstr "Ersteller bin ich"
|
||||||
|
|
||||||
#: core/api/serializers.py:89
|
#: core/api/serializers.py:108
|
||||||
msgid "You must be administrator or owner of a room to add accesses to it."
|
msgid "You must be administrator or owner of a room to add accesses to it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Sie müssen Administrator oder Eigentümer eines Raums sein, um Zugriffe "
|
"Sie müssen Administrator oder Eigentümer eines Raums sein, um Zugriffe "
|
||||||
"hinzuzufügen."
|
"hinzuzufügen."
|
||||||
|
|
||||||
#: core/api/serializers.py:534
|
#: core/api/serializers.py:560
|
||||||
msgid "This file extension is not allowed."
|
msgid "This file extension is not allowed."
|
||||||
msgstr "Diese Dateiendung ist nicht erlaubt."
|
msgstr "Diese Dateiendung ist nicht erlaubt."
|
||||||
|
|
||||||
#: core/api/viewsets.py:1222
|
#: core/api/viewsets.py:1268
|
||||||
msgid "You have reached the maximum number of files for this type."
|
msgid "You have reached the maximum number of files for this type."
|
||||||
msgstr "Sie haben die maximale Anzahl an Dateien dieses Typs erreicht."
|
msgstr "Sie haben die maximale Anzahl an Dateien dieses Typs erreicht."
|
||||||
|
|
||||||
#: core/models.py:37
|
#: core/models.py:38
|
||||||
msgid "Member"
|
msgid "Member"
|
||||||
msgstr "Mitglied"
|
msgstr "Mitglied"
|
||||||
|
|
||||||
#: core/models.py:38
|
#: core/models.py:39
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "Administrator"
|
msgstr "Administrator"
|
||||||
|
|
||||||
#: core/models.py:39
|
#: core/models.py:40
|
||||||
msgid "Owner"
|
msgid "Owner"
|
||||||
msgstr "Eigentümer"
|
msgstr "Eigentümer"
|
||||||
|
|
||||||
#: core/models.py:55
|
#: core/models.py:56
|
||||||
msgid "Initiated"
|
msgid "Initiated"
|
||||||
msgstr "Gestartet"
|
msgstr "Gestartet"
|
||||||
|
|
||||||
#: core/models.py:56
|
#: core/models.py:57
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Aktiv"
|
msgstr "Aktiv"
|
||||||
|
|
||||||
#: core/models.py:57
|
#: core/models.py:58
|
||||||
msgid "Stopped"
|
msgid "Stopped"
|
||||||
msgstr "Beendet"
|
msgstr "Beendet"
|
||||||
|
|
||||||
#: core/models.py:58
|
#: core/models.py:59
|
||||||
msgid "Saved"
|
msgid "Saved"
|
||||||
msgstr "Gespeichert"
|
msgstr "Gespeichert"
|
||||||
|
|
||||||
#: core/models.py:59
|
#: core/models.py:60
|
||||||
msgid "Aborted"
|
msgid "Aborted"
|
||||||
msgstr "Abgebrochen"
|
msgstr "Abgebrochen"
|
||||||
|
|
||||||
#: core/models.py:60
|
#: core/models.py:61
|
||||||
msgid "Failed to Start"
|
msgid "Failed to Start"
|
||||||
msgstr "Start fehlgeschlagen"
|
msgstr "Start fehlgeschlagen"
|
||||||
|
|
||||||
#: core/models.py:61
|
#: core/models.py:62
|
||||||
msgid "Failed to Stop"
|
msgid "Failed to Stop"
|
||||||
msgstr "Stopp fehlgeschlagen"
|
msgstr "Stopp fehlgeschlagen"
|
||||||
|
|
||||||
#: core/models.py:62
|
#: core/models.py:63
|
||||||
msgid "Notification succeeded"
|
msgid "Notification succeeded"
|
||||||
msgstr "Benachrichtigung erfolgreich"
|
msgstr "Benachrichtigung erfolgreich"
|
||||||
|
|
||||||
#: core/models.py:65
|
#: core/models.py:66
|
||||||
msgid "External process successful"
|
msgid "External process successful"
|
||||||
msgstr "Externer Prozess erfolgreich"
|
msgstr "Externer Prozess erfolgreich"
|
||||||
|
|
||||||
#: core/models.py:67
|
#: core/models.py:68
|
||||||
msgid "External process failed"
|
msgid "External process failed"
|
||||||
msgstr "Externer Prozess fehlgeschlagen"
|
msgstr "Externer Prozess fehlgeschlagen"
|
||||||
|
|
||||||
#: core/models.py:96
|
#: core/models.py:97
|
||||||
msgid "SCREEN_RECORDING"
|
msgid "SCREEN_RECORDING"
|
||||||
msgstr "BILDSCHIRMAUFZEICHNUNG"
|
msgstr "BILDSCHIRMAUFZEICHNUNG"
|
||||||
|
|
||||||
#: core/models.py:97
|
#: core/models.py:98
|
||||||
msgid "TRANSCRIPT"
|
msgid "TRANSCRIPT"
|
||||||
msgstr "TRANSKRIPT"
|
msgstr "TRANSKRIPT"
|
||||||
|
|
||||||
#: core/models.py:103
|
#: core/models.py:104
|
||||||
msgid "Public Access"
|
msgid "Public Access"
|
||||||
msgstr "Öffentlicher Zugriff"
|
msgstr "Öffentlicher Zugriff"
|
||||||
|
|
||||||
#: core/models.py:104
|
#: core/models.py:105
|
||||||
msgid "Trusted Access"
|
msgid "Trusted Access"
|
||||||
msgstr "Vertrauenswürdiger Zugriff"
|
msgstr "Vertrauenswürdiger Zugriff"
|
||||||
|
|
||||||
#: core/models.py:105
|
#: core/models.py:106
|
||||||
msgid "Restricted Access"
|
msgid "Restricted Access"
|
||||||
msgstr "Eingeschränkter Zugriff"
|
msgstr "Eingeschränkter Zugriff"
|
||||||
|
|
||||||
#: core/models.py:117
|
#: core/models.py:118
|
||||||
msgid "id"
|
msgid "id"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
|
||||||
#: core/models.py:118
|
#: core/models.py:119
|
||||||
msgid "primary key for the record as UUID"
|
msgid "primary key for the record as UUID"
|
||||||
msgstr "Primärschlüssel des Eintrags als UUID"
|
msgstr "Primärschlüssel des Eintrags als UUID"
|
||||||
|
|
||||||
#: core/models.py:124
|
#: core/models.py:125
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "erstellt am"
|
msgstr "erstellt am"
|
||||||
|
|
||||||
#: core/models.py:125
|
#: core/models.py:126
|
||||||
msgid "date and time at which a record was created"
|
msgid "date and time at which a record was created"
|
||||||
msgstr "Datum und Uhrzeit der Erstellung eines Eintrags"
|
msgstr "Datum und Uhrzeit der Erstellung eines Eintrags"
|
||||||
|
|
||||||
#: core/models.py:130
|
#: core/models.py:131
|
||||||
msgid "updated on"
|
msgid "updated on"
|
||||||
msgstr "aktualisiert am"
|
msgstr "aktualisiert am"
|
||||||
|
|
||||||
#: core/models.py:131
|
#: core/models.py:132
|
||||||
msgid "date and time at which a record was last updated"
|
msgid "date and time at which a record was last updated"
|
||||||
msgstr "Datum und Uhrzeit der letzten Aktualisierung eines Eintrags"
|
msgstr "Datum und Uhrzeit der letzten Aktualisierung eines Eintrags"
|
||||||
|
|
||||||
#: core/models.py:151
|
#: core/models.py:150
|
||||||
msgid ""
|
|
||||||
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
|
|
||||||
"_ characters."
|
|
||||||
msgstr ""
|
|
||||||
"Geben Sie einen gültigen Sub ein. Dieser Wert darf nur Buchstaben, Zahlen "
|
|
||||||
"und die Zeichen @/./+/-/_ enthalten."
|
|
||||||
|
|
||||||
#: core/models.py:157
|
|
||||||
msgid "sub"
|
msgid "sub"
|
||||||
msgstr "Sub"
|
msgstr "Sub"
|
||||||
|
|
||||||
#: core/models.py:159
|
#: core/models.py:152
|
||||||
msgid ""
|
msgid ""
|
||||||
"Optional for pending users; required upon account activation. 255 characters "
|
"Optional for pending users; required upon account activation. 255 characters "
|
||||||
"or fewer. Letters, numbers, and @/./+/-/_ characters only."
|
"or fewer. Printable ASCII characters only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Optional für ausstehende Benutzer; erforderlich nach Kontoaktivierung. "
|
"Optional für ausstehende Benutzer; erforderlich nach Kontoaktivierung. "
|
||||||
"Maximal 255 Zeichen. Nur Buchstaben, Zahlen und @/./+/-/_ Zeichen erlaubt."
|
"Maximal 255 Zeichen. Nur druckbare ASCII-Zeichen erlaubt."
|
||||||
|
|
||||||
#: core/models.py:168
|
#: core/validators.py:22
|
||||||
|
msgid "Enter a valid sub. This value should be printable ASCII only."
|
||||||
|
msgstr "Geben Sie einen gültigen sub ein. Dieser Wert darf nur druckbare ASCII-Zeichen enthalten."
|
||||||
|
|
||||||
|
#: core/models.py:161
|
||||||
msgid "identity email address"
|
msgid "identity email address"
|
||||||
msgstr "Identitäts-E-Mail-Adresse"
|
msgstr "Identitäts-E-Mail-Adresse"
|
||||||
|
|
||||||
#: core/models.py:173
|
#: core/models.py:166
|
||||||
msgid "admin email address"
|
msgid "admin email address"
|
||||||
msgstr "Administrator-E-Mail-Adresse"
|
msgstr "Administrator-E-Mail-Adresse"
|
||||||
|
|
||||||
#: core/models.py:175
|
#: core/models.py:168
|
||||||
msgid "full name"
|
msgid "full name"
|
||||||
msgstr "Vollständiger Name"
|
msgstr "Vollständiger Name"
|
||||||
|
|
||||||
#: core/models.py:177
|
#: core/models.py:170
|
||||||
msgid "short name"
|
msgid "short name"
|
||||||
msgstr "Kurzname"
|
msgstr "Kurzname"
|
||||||
|
|
||||||
#: core/models.py:183
|
#: core/models.py:176
|
||||||
msgid "language"
|
msgid "language"
|
||||||
msgstr "Sprache"
|
msgstr "Sprache"
|
||||||
|
|
||||||
#: core/models.py:184
|
#: core/models.py:177
|
||||||
msgid "The language in which the user wants to see the interface."
|
msgid "The language in which the user wants to see the interface."
|
||||||
msgstr "Die Sprache, in der der Benutzer die Oberfläche sehen möchte."
|
msgstr "Die Sprache, in der der Benutzer die Oberfläche sehen möchte."
|
||||||
|
|
||||||
#: core/models.py:190
|
#: core/models.py:183
|
||||||
msgid "The timezone in which the user wants to see times."
|
msgid "The timezone in which the user wants to see times."
|
||||||
msgstr "Die Zeitzone, in der der Benutzer die Zeiten sehen möchte."
|
msgstr "Die Zeitzone, in der der Benutzer die Zeiten sehen möchte."
|
||||||
|
|
||||||
#: core/models.py:193
|
#: core/models.py:190
|
||||||
|
msgid "default room access level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:192
|
||||||
|
msgid ""
|
||||||
|
"Access level applied by default to new rooms created by this user. When "
|
||||||
|
"empty, the instance default is used."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:199
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Visio room configuration"
|
||||||
|
msgid "default room configuration"
|
||||||
|
msgstr "Visio-Raumkonfiguration"
|
||||||
|
|
||||||
|
#: core/models.py:201
|
||||||
|
msgid "Configurations applied by default to new rooms created by this user."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:205
|
||||||
msgid "device"
|
msgid "device"
|
||||||
msgstr "Gerät"
|
msgstr "Gerät"
|
||||||
|
|
||||||
#: core/models.py:195
|
#: core/models.py:207
|
||||||
msgid "Whether the user is a device or a real user."
|
msgid "Whether the user is a device or a real user."
|
||||||
msgstr "Ob es sich um ein Gerät oder einen echten Benutzer handelt."
|
msgstr "Ob es sich um ein Gerät oder einen echten Benutzer handelt."
|
||||||
|
|
||||||
#: core/models.py:198
|
#: core/models.py:210
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "Mitarbeiterstatus"
|
msgstr "Mitarbeiterstatus"
|
||||||
|
|
||||||
#: core/models.py:200
|
#: core/models.py:212
|
||||||
msgid "Whether the user can log into this admin site."
|
msgid "Whether the user can log into this admin site."
|
||||||
msgstr "Ob der Benutzer sich bei dieser Admin-Seite anmelden kann."
|
msgstr "Ob der Benutzer sich bei dieser Admin-Seite anmelden kann."
|
||||||
|
|
||||||
#: core/models.py:203
|
#: core/models.py:215
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "aktiv"
|
msgstr "aktiv"
|
||||||
|
|
||||||
#: core/models.py:206
|
#: core/models.py:218
|
||||||
msgid ""
|
msgid ""
|
||||||
"Whether this user should be treated as active. Unselect this instead of "
|
"Whether this user should be treated as active. Unselect this instead of "
|
||||||
"deleting accounts."
|
"deleting accounts."
|
||||||
@@ -296,66 +312,66 @@ msgstr ""
|
|||||||
"Ob dieser Benutzer als aktiv behandelt werden soll. Deaktivieren Sie dies "
|
"Ob dieser Benutzer als aktiv behandelt werden soll. Deaktivieren Sie dies "
|
||||||
"anstelle des Löschens des Kontos."
|
"anstelle des Löschens des Kontos."
|
||||||
|
|
||||||
#: core/models.py:219
|
#: core/models.py:231
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "Benutzer"
|
msgstr "Benutzer"
|
||||||
|
|
||||||
#: core/models.py:220
|
#: core/models.py:232
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr "Benutzer"
|
msgstr "Benutzer"
|
||||||
|
|
||||||
#: core/models.py:286
|
#: core/models.py:298
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
msgstr "Ressource"
|
msgstr "Ressource"
|
||||||
|
|
||||||
#: core/models.py:287
|
#: core/models.py:299
|
||||||
msgid "Resources"
|
msgid "Resources"
|
||||||
msgstr "Ressourcen"
|
msgstr "Ressourcen"
|
||||||
|
|
||||||
#: core/models.py:345
|
#: core/models.py:357
|
||||||
msgid "Resource access"
|
msgid "Resource access"
|
||||||
msgstr "Ressourcenzugriff"
|
msgstr "Ressourcenzugriff"
|
||||||
|
|
||||||
#: core/models.py:346
|
#: core/models.py:358
|
||||||
msgid "Resource accesses"
|
msgid "Resource accesses"
|
||||||
msgstr "Ressourcenzugriffe"
|
msgstr "Ressourcenzugriffe"
|
||||||
|
|
||||||
#: core/models.py:352
|
#: core/models.py:364
|
||||||
msgid "Resource access with this User and Resource already exists."
|
msgid "Resource access with this User and Resource already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ein Ressourcenzugriff mit diesem Benutzer und dieser Ressource existiert "
|
"Ein Ressourcenzugriff mit diesem Benutzer und dieser Ressource existiert "
|
||||||
"bereits."
|
"bereits."
|
||||||
|
|
||||||
#: core/models.py:409
|
#: core/models.py:421
|
||||||
msgid "Visio room configuration"
|
msgid "Visio room configuration"
|
||||||
msgstr "Visio-Raumkonfiguration"
|
msgstr "Visio-Raumkonfiguration"
|
||||||
|
|
||||||
#: core/models.py:410
|
#: core/models.py:422
|
||||||
msgid "Values for Visio parameters to configure the room."
|
msgid "Values for Visio parameters to configure the room."
|
||||||
msgstr "Werte für Visio-Parameter zur Konfiguration des Raums."
|
msgstr "Werte für Visio-Parameter zur Konfiguration des Raums."
|
||||||
|
|
||||||
#: core/models.py:417
|
#: core/models.py:429
|
||||||
msgid "Room PIN code"
|
msgid "Room PIN code"
|
||||||
msgstr "PIN-Code für den Raum"
|
msgstr "PIN-Code für den Raum"
|
||||||
|
|
||||||
#: core/models.py:418
|
#: core/models.py:430
|
||||||
msgid "Unique n-digit code that identifies this room in telephony mode."
|
msgid "Unique n-digit code that identifies this room in telephony mode."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Eindeutiger n-stelliger Code, der diesen Raum im Telephonmodus identifiziert."
|
"Eindeutiger n-stelliger Code, der diesen Raum im Telephonmodus identifiziert."
|
||||||
|
|
||||||
#: core/models.py:424 core/models.py:578
|
#: core/models.py:436 core/models.py:597
|
||||||
msgid "Room"
|
msgid "Room"
|
||||||
msgstr "Raum"
|
msgstr "Raum"
|
||||||
|
|
||||||
#: core/models.py:425
|
#: core/models.py:437
|
||||||
msgid "Rooms"
|
msgid "Rooms"
|
||||||
msgstr "Räume"
|
msgstr "Räume"
|
||||||
|
|
||||||
#: core/models.py:589
|
#: core/models.py:608
|
||||||
msgid "Worker ID"
|
msgid "Worker ID"
|
||||||
msgstr "Worker-ID"
|
msgstr "Worker-ID"
|
||||||
|
|
||||||
#: core/models.py:591
|
#: core/models.py:610
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter an identifier for the worker recording.This ID is retained even when "
|
"Enter an identifier for the worker recording.This ID is retained even when "
|
||||||
"the worker stops, allowing for easy tracking."
|
"the worker stops, allowing for easy tracking."
|
||||||
@@ -364,153 +380,153 @@ msgstr ""
|
|||||||
"erhalten, auch wenn der Worker stoppt, was ein einfaches Nachverfolgen "
|
"erhalten, auch wenn der Worker stoppt, was ein einfaches Nachverfolgen "
|
||||||
"ermöglicht."
|
"ermöglicht."
|
||||||
|
|
||||||
#: core/models.py:599
|
#: core/models.py:618
|
||||||
msgid "Recording mode"
|
msgid "Recording mode"
|
||||||
msgstr "Aufzeichnungsmodus"
|
msgstr "Aufzeichnungsmodus"
|
||||||
|
|
||||||
#: core/models.py:600
|
#: core/models.py:619
|
||||||
msgid "Defines the mode of recording being called."
|
msgid "Defines the mode of recording being called."
|
||||||
msgstr "Definiert den aufgerufenen Aufzeichnungsmodus."
|
msgstr "Definiert den aufgerufenen Aufzeichnungsmodus."
|
||||||
|
|
||||||
#: core/models.py:605 core/models.py:606
|
#: core/models.py:624 core/models.py:625
|
||||||
msgid "Recording options"
|
msgid "Recording options"
|
||||||
msgstr "Aufnahmeoptionen"
|
msgstr "Aufnahmeoptionen"
|
||||||
|
|
||||||
#: core/models.py:613
|
#: core/models.py:632
|
||||||
msgid "External Process ID"
|
msgid "External Process ID"
|
||||||
msgstr "External Process ID"
|
msgstr "External Process ID"
|
||||||
|
|
||||||
#: core/models.py:614
|
#: core/models.py:633
|
||||||
msgid "ID of the external process associated with the recording."
|
msgid "ID of the external process associated with the recording."
|
||||||
msgstr "ID des externen Prozesses, der mit der Aufzeichnung verknüpft ist"
|
msgstr "ID des externen Prozesses, der mit der Aufzeichnung verknüpft ist"
|
||||||
|
|
||||||
#: core/models.py:620
|
#: core/models.py:639
|
||||||
msgid "Recording"
|
msgid "Recording"
|
||||||
msgstr "Aufzeichnung"
|
msgstr "Aufzeichnung"
|
||||||
|
|
||||||
#: core/models.py:621
|
#: core/models.py:640
|
||||||
msgid "Recordings"
|
msgid "Recordings"
|
||||||
msgstr "Aufzeichnungen"
|
msgstr "Aufzeichnungen"
|
||||||
|
|
||||||
#: core/models.py:731
|
#: core/models.py:750
|
||||||
msgid "Recording/user relation"
|
msgid "Recording/user relation"
|
||||||
msgstr "Beziehung Aufzeichnung/Benutzer"
|
msgstr "Beziehung Aufzeichnung/Benutzer"
|
||||||
|
|
||||||
#: core/models.py:732
|
#: core/models.py:751
|
||||||
msgid "Recording/user relations"
|
msgid "Recording/user relations"
|
||||||
msgstr "Beziehungen Aufzeichnung/Benutzer"
|
msgstr "Beziehungen Aufzeichnung/Benutzer"
|
||||||
|
|
||||||
#: core/models.py:738
|
#: core/models.py:757
|
||||||
msgid "This user is already in this recording."
|
msgid "This user is already in this recording."
|
||||||
msgstr "Dieser Benutzer ist bereits Teil dieser Aufzeichnung."
|
msgstr "Dieser Benutzer ist bereits Teil dieser Aufzeichnung."
|
||||||
|
|
||||||
#: core/models.py:744
|
#: core/models.py:763
|
||||||
msgid "This team is already in this recording."
|
msgid "This team is already in this recording."
|
||||||
msgstr "Dieses Team ist bereits Teil dieser Aufzeichnung."
|
msgstr "Dieses Team ist bereits Teil dieser Aufzeichnung."
|
||||||
|
|
||||||
#: core/models.py:750
|
#: core/models.py:769
|
||||||
msgid "Either user or team must be set, not both."
|
msgid "Either user or team must be set, not both."
|
||||||
msgstr "Entweder Benutzer oder Team muss festgelegt werden, nicht beides."
|
msgstr "Entweder Benutzer oder Team muss festgelegt werden, nicht beides."
|
||||||
|
|
||||||
#: core/models.py:767
|
#: core/models.py:786
|
||||||
msgid "Create rooms"
|
msgid "Create rooms"
|
||||||
msgstr "Räume erstellen"
|
msgstr "Räume erstellen"
|
||||||
|
|
||||||
#: core/models.py:768
|
#: core/models.py:787
|
||||||
msgid "List rooms"
|
msgid "List rooms"
|
||||||
msgstr "Räume auflisten"
|
msgstr "Räume auflisten"
|
||||||
|
|
||||||
#: core/models.py:769
|
#: core/models.py:788
|
||||||
msgid "Retrieve room details"
|
msgid "Retrieve room details"
|
||||||
msgstr "Raumdetails abrufen"
|
msgstr "Raumdetails abrufen"
|
||||||
|
|
||||||
#: core/models.py:770
|
#: core/models.py:789
|
||||||
msgid "Update rooms"
|
msgid "Update rooms"
|
||||||
msgstr "Räume aktualisieren"
|
msgstr "Räume aktualisieren"
|
||||||
|
|
||||||
#: core/models.py:771
|
#: core/models.py:790
|
||||||
msgid "Delete rooms"
|
msgid "Delete rooms"
|
||||||
msgstr "Räume löschen"
|
msgstr "Räume löschen"
|
||||||
|
|
||||||
#: core/models.py:784
|
#: core/models.py:803
|
||||||
msgid "Application name"
|
msgid "Application name"
|
||||||
msgstr "Anwendungsname"
|
msgstr "Anwendungsname"
|
||||||
|
|
||||||
#: core/models.py:785
|
#: core/models.py:804
|
||||||
msgid "Descriptive name for this application."
|
msgid "Descriptive name for this application."
|
||||||
msgstr "Beschreibender Name für diese Anwendung."
|
msgstr "Beschreibender Name für diese Anwendung."
|
||||||
|
|
||||||
#: core/models.py:795
|
#: core/models.py:814
|
||||||
msgid "Hashed on Save. Copy it now if this is a new secret."
|
msgid "Hashed on Save. Copy it now if this is a new secret."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Beim Speichern gehasht. Jetzt kopieren, wenn dies ein neues Geheimnis ist."
|
"Beim Speichern gehasht. Jetzt kopieren, wenn dies ein neues Geheimnis ist."
|
||||||
|
|
||||||
#: core/models.py:806
|
#: core/models.py:825
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "Anwendung"
|
msgstr "Anwendung"
|
||||||
|
|
||||||
#: core/models.py:807
|
#: core/models.py:826
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Anwendungen"
|
msgstr "Anwendungen"
|
||||||
|
|
||||||
#: core/models.py:830
|
#: core/models.py:849
|
||||||
msgid "Enter a valid domain"
|
msgid "Enter a valid domain"
|
||||||
msgstr "Geben Sie eine gültige Domain ein"
|
msgstr "Geben Sie eine gültige Domain ein"
|
||||||
|
|
||||||
#: core/models.py:833
|
#: core/models.py:852
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Domain"
|
msgstr "Domain"
|
||||||
|
|
||||||
#: core/models.py:834
|
#: core/models.py:853
|
||||||
msgid "Email domain this application can act on behalf of."
|
msgid "Email domain this application can act on behalf of."
|
||||||
msgstr "E-Mail-Domain, im Namen der diese Anwendung handeln kann."
|
msgstr "E-Mail-Domain, im Namen der diese Anwendung handeln kann."
|
||||||
|
|
||||||
#: core/models.py:846
|
#: core/models.py:865
|
||||||
msgid "Application domain"
|
msgid "Application domain"
|
||||||
msgstr "Anwendungsdomain"
|
msgstr "Anwendungsdomain"
|
||||||
|
|
||||||
#: core/models.py:847
|
#: core/models.py:866
|
||||||
msgid "Application domains"
|
msgid "Application domains"
|
||||||
msgstr "Anwendungsdomains"
|
msgstr "Anwendungsdomains"
|
||||||
|
|
||||||
#: core/models.py:865
|
#: core/models.py:884
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "Ausstehend"
|
msgstr "Ausstehend"
|
||||||
|
|
||||||
#: core/models.py:866
|
#: core/models.py:885
|
||||||
msgid "Analyzing"
|
msgid "Analyzing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/models.py:873
|
#: core/models.py:892
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
msgstr "Bereit"
|
msgstr "Bereit"
|
||||||
|
|
||||||
#: core/models.py:879
|
#: core/models.py:898
|
||||||
msgid "Background image"
|
msgid "Background image"
|
||||||
msgstr "Hintergrundbild"
|
msgstr "Hintergrundbild"
|
||||||
|
|
||||||
#: core/models.py:891
|
#: core/models.py:910
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: core/models.py:915
|
#: core/models.py:934
|
||||||
msgid "Malware detection info when the analysis status is unsafe."
|
msgid "Malware detection info when the analysis status is unsafe."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Informationen zur Malware-Erkennung, wenn der Analyse-Status unsicher ist."
|
"Informationen zur Malware-Erkennung, wenn der Analyse-Status unsicher ist."
|
||||||
|
|
||||||
#: core/models.py:920
|
#: core/models.py:939
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Datei"
|
msgstr "Datei"
|
||||||
|
|
||||||
#: core/models.py:921
|
#: core/models.py:940
|
||||||
msgid "Files"
|
msgid "Files"
|
||||||
msgstr "Dateien"
|
msgstr "Dateien"
|
||||||
|
|
||||||
#: core/models.py:1041
|
#: core/models.py:1060
|
||||||
msgid "This file is already hard deleted."
|
msgid "This file is already hard deleted."
|
||||||
msgstr "Diese Datei wurde bereits endgültig gelöscht."
|
msgstr "Diese Datei wurde bereits endgültig gelöscht."
|
||||||
|
|
||||||
#: core/models.py:1051
|
#: core/models.py:1070
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "To hard delete a file, it must first be soft deleted."
|
#| msgid "To hard delete a file, it must first be soft deleted."
|
||||||
msgid "To hard delete a file, it must first be soft deleted."
|
msgid "To hard delete a file, it must first be soft deleted."
|
||||||
@@ -518,15 +534,15 @@ msgstr ""
|
|||||||
"Um eine Datei endgültig zu löschen, muss sie zuvor weich gelöscht worden "
|
"Um eine Datei endgültig zu löschen, muss sie zuvor weich gelöscht worden "
|
||||||
"sein."
|
"sein."
|
||||||
|
|
||||||
#: core/recording/event/notification.py:123
|
#: core/recording/event/notification.py:124
|
||||||
msgid "Your recording is ready"
|
msgid "Your recording is ready"
|
||||||
msgstr "Ihre Aufzeichnung ist bereit"
|
msgstr "Ihre Aufzeichnung ist bereit"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:194
|
#: core/recording/event/notification.py:195
|
||||||
msgid "Transcription"
|
msgid "Transcription"
|
||||||
msgstr "Transkription"
|
msgstr "Transkription"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:204
|
#: core/recording/event/notification.py:206
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -537,25 +553,25 @@ msgstr ""
|
|||||||
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
||||||
msgstr "Videoanruf läuft: {sender.email} wartet auf Ihre Teilnahme"
|
msgstr "Videoanruf läuft: {sender.email} wartet auf Ihre Teilnahme"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:159
|
#: core/templates/mail/html/invitation.html:151
|
||||||
#: core/templates/mail/html/screen_recording.html:159
|
#: core/templates/mail/html/screen_recording.html:151
|
||||||
#: core/templates/mail/text/invitation.txt:3
|
#: core/templates/mail/text/invitation.txt:4
|
||||||
#: core/templates/mail/text/screen_recording.txt:3
|
#: core/templates/mail/text/screen_recording.txt:4
|
||||||
msgid "Logo email"
|
msgid "Logo email"
|
||||||
msgstr "Logo-E-Mail"
|
msgstr "Logo-E-Mail"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:189
|
#: core/templates/mail/html/invitation.html:181
|
||||||
#: core/templates/mail/text/invitation.txt:5
|
#: core/templates/mail/text/invitation.txt:6
|
||||||
msgid "invites you to join an ongoing video call"
|
msgid "invites you to join an ongoing video call"
|
||||||
msgstr "lädt Sie zu einem laufenden Videoanruf ein"
|
msgstr "lädt Sie zu einem laufenden Videoanruf ein"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:200
|
#: core/templates/mail/html/invitation.html:192
|
||||||
#: core/templates/mail/text/invitation.txt:7
|
#: core/templates/mail/text/invitation.txt:8
|
||||||
msgid "JOIN THE CALL"
|
msgid "JOIN THE CALL"
|
||||||
msgstr "AM ANRUF TEILNEHMEN"
|
msgstr "AM ANRUF TEILNEHMEN"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:227
|
#: core/templates/mail/html/invitation.html:219
|
||||||
#: core/templates/mail/text/invitation.txt:13
|
#: core/templates/mail/text/invitation.txt:14
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you can't click the button, copy and paste the URL into your browser to "
|
"If you can't click the button, copy and paste the URL into your browser to "
|
||||||
"join the call."
|
"join the call."
|
||||||
@@ -563,41 +579,47 @@ msgstr ""
|
|||||||
"Wenn Sie den Button nicht anklicken können, kopieren Sie die URL und fügen "
|
"Wenn Sie den Button nicht anklicken können, kopieren Sie die URL und fügen "
|
||||||
"Sie sie in Ihren Browser ein, um am Anruf teilzunehmen."
|
"Sie sie in Ihren Browser ein, um am Anruf teilzunehmen."
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:235
|
#: core/templates/mail/html/invitation.html:227
|
||||||
#: core/templates/mail/text/invitation.txt:15
|
#: core/templates/mail/text/invitation.txt:16
|
||||||
msgid "Tips for a better experience:"
|
msgid "Tips for a better experience:"
|
||||||
msgstr "Tipps für ein besseres Erlebnis:"
|
msgstr "Tipps für ein besseres Erlebnis:"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:237
|
#: core/templates/mail/html/invitation.html:229
|
||||||
#: core/templates/mail/text/invitation.txt:17
|
#: core/templates/mail/text/invitation.txt:18
|
||||||
msgid "Use Chrome or Firefox for better call quality"
|
msgid "Use Chrome or Firefox for better call quality"
|
||||||
msgstr "Verwenden Sie Chrome oder Firefox für eine bessere Anrufqualität"
|
msgstr "Verwenden Sie Chrome oder Firefox für eine bessere Anrufqualität"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:238
|
#: core/templates/mail/html/invitation.html:230
|
||||||
#: core/templates/mail/text/invitation.txt:18
|
#: core/templates/mail/text/invitation.txt:19
|
||||||
msgid "Test your microphone and camera before joining"
|
msgid "Test your microphone and camera before joining"
|
||||||
msgstr "Testen Sie Ihr Mikrofon und Ihre Kamera vor dem Beitritt"
|
msgstr "Testen Sie Ihr Mikrofon und Ihre Kamera vor dem Beitritt"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:239
|
#: core/templates/mail/html/invitation.html:231
|
||||||
#: core/templates/mail/text/invitation.txt:19
|
#: core/templates/mail/text/invitation.txt:20
|
||||||
msgid "Make sure you have a stable internet connection"
|
msgid "Make sure you have a stable internet connection"
|
||||||
msgstr "Stellen Sie sicher, dass Sie eine stabile Internetverbindung haben"
|
msgstr "Stellen Sie sicher, dass Sie eine stabile Internetverbindung haben"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:248
|
#: core/templates/mail/html/invitation.html:240
|
||||||
#: core/templates/mail/html/screen_recording.html:245
|
#: core/templates/mail/html/screen_recording.html:237
|
||||||
#: core/templates/mail/text/invitation.txt:21
|
#: core/templates/mail/text/invitation.txt:22
|
||||||
#: core/templates/mail/text/screen_recording.txt:23
|
#: core/templates/mail/text/screen_recording.txt:24
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " Thank you for using %(brandname)s. "
|
msgid " Thank you for using %(brandname)s. "
|
||||||
msgstr " Vielen Dank für die Nutzung von %(brandname)s. "
|
msgstr " Vielen Dank für die Nutzung von %(brandname)s. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:188
|
#: core/templates/mail/html/invitation.html:271
|
||||||
#: core/templates/mail/text/screen_recording.txt:6
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"This mail has been sent to %(email)s by <a href=\"%(href)s\">%(name)s</a>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/html/screen_recording.html:180
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:7
|
||||||
msgid "Your recording is ready!"
|
msgid "Your recording is ready!"
|
||||||
msgstr "Ihre Aufzeichnung ist fertig!"
|
msgstr "Ihre Aufzeichnung ist fertig!"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
||||||
@@ -606,14 +628,14 @@ msgstr ""
|
|||||||
" Ihre Aufzeichnung von \"%(room_name)s\" am %(recording_date)s um "
|
" Ihre Aufzeichnung von \"%(room_name)s\" am %(recording_date)s um "
|
||||||
"%(recording_time)s steht nun zum Herunterladen bereit. "
|
"%(recording_time)s steht nun zum Herunterladen bereit. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " The recording will expire in %(days)s days. "
|
msgid " The recording will expire in %(days)s days. "
|
||||||
msgstr " Die Aufzeichnung wird in %(days)s Tagen ablaufen. "
|
msgstr " Die Aufzeichnung wird in %(days)s Tagen ablaufen. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:200
|
#: core/templates/mail/html/screen_recording.html:192
|
||||||
#: core/templates/mail/text/screen_recording.txt:9
|
#: core/templates/mail/text/screen_recording.txt:10
|
||||||
msgid ""
|
msgid ""
|
||||||
" Sharing the recording via link is not yet available. Only organizers can "
|
" Sharing the recording via link is not yet available. Only organizers can "
|
||||||
"download it. "
|
"download it. "
|
||||||
@@ -621,33 +643,33 @@ msgstr ""
|
|||||||
" Die Freigabe der Aufzeichnung per Link ist noch nicht verfügbar. Nur "
|
" Die Freigabe der Aufzeichnung per Link ist noch nicht verfügbar. Nur "
|
||||||
"Organisatoren können sie herunterladen. "
|
"Organisatoren können sie herunterladen. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:206
|
#: core/templates/mail/html/screen_recording.html:198
|
||||||
#: core/templates/mail/text/screen_recording.txt:11
|
#: core/templates/mail/text/screen_recording.txt:12
|
||||||
msgid "To keep this recording permanently:"
|
msgid "To keep this recording permanently:"
|
||||||
msgstr "So speichern Sie diese Aufzeichnung dauerhaft:"
|
msgstr "So speichern Sie diese Aufzeichnung dauerhaft:"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:208
|
#: core/templates/mail/html/screen_recording.html:200
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgstr "Klicken Sie auf den Link „<a href=\"%(link)s\">Öffnen</a>\" unten "
|
msgstr "Klicken Sie auf den Link „<a href=\"%(link)s\">Öffnen</a>\" unten "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:209
|
#: core/templates/mail/html/screen_recording.html:201
|
||||||
#: core/templates/mail/text/screen_recording.txt:14
|
#: core/templates/mail/text/screen_recording.txt:15
|
||||||
msgid "Use the \"Download\" button in the interface "
|
msgid "Use the \"Download\" button in the interface "
|
||||||
msgstr "Verwenden Sie den Button „Herunterladen“ in der Oberfläche "
|
msgstr "Verwenden Sie den Button „Herunterladen“ in der Oberfläche "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:210
|
#: core/templates/mail/html/screen_recording.html:202
|
||||||
#: core/templates/mail/text/screen_recording.txt:15
|
#: core/templates/mail/text/screen_recording.txt:16
|
||||||
msgid "Save the file to your preferred location"
|
msgid "Save the file to your preferred location"
|
||||||
msgstr "Speichern Sie die Datei an einem gewünschten Ort"
|
msgstr "Speichern Sie die Datei an einem gewünschten Ort"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:221
|
#: core/templates/mail/html/screen_recording.html:213
|
||||||
#: core/templates/mail/text/screen_recording.txt:17
|
#: core/templates/mail/text/screen_recording.txt:18
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Öffnen"
|
msgstr "Öffnen"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:230
|
#: core/templates/mail/html/screen_recording.html:222
|
||||||
#: core/templates/mail/text/screen_recording.txt:19
|
#: core/templates/mail/text/screen_recording.txt:20
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" If you have any questions or need assistance, please contact our support "
|
" If you have any questions or need assistance, please contact our support "
|
||||||
@@ -656,28 +678,33 @@ msgstr ""
|
|||||||
" Wenn Sie Fragen haben oder Unterstützung benötigen, wenden Sie sich bitte "
|
" Wenn Sie Fragen haben oder Unterstützung benötigen, wenden Sie sich bitte "
|
||||||
"an unser Support-Team unter %(support_email)s. "
|
"an unser Support-Team unter %(support_email)s. "
|
||||||
|
|
||||||
#: core/templates/mail/text/screen_recording.txt:13
|
#: core/templates/mail/text/invitation.txt:24
|
||||||
|
#, python-format
|
||||||
|
msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:14
|
||||||
#, fuzzy, python-format
|
#, fuzzy, python-format
|
||||||
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgid "Click the \"Open [%(link)s]\" link below "
|
msgid "Click the \"Open [%(link)s]\" link below "
|
||||||
msgstr "Klicken Sie auf den Link „<a href=\"%(link)s\">Öffnen</a>\" unten "
|
msgstr "Klicken Sie auf den Link „<a href=\"%(link)s\">Öffnen</a>\" unten "
|
||||||
|
|
||||||
#: meet/settings.py:228
|
#: meet/settings.py:238
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Englisch"
|
msgstr "Englisch"
|
||||||
|
|
||||||
#: meet/settings.py:229
|
#: meet/settings.py:239
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Französisch"
|
msgstr "Französisch"
|
||||||
|
|
||||||
#: meet/settings.py:230
|
#: meet/settings.py:240
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Niederländisch"
|
msgstr "Niederländisch"
|
||||||
|
|
||||||
#: meet/settings.py:231
|
#: meet/settings.py:241
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Deutsch"
|
msgstr "Deutsch"
|
||||||
|
|
||||||
#: meet/settings.py:233
|
#: meet/settings.py:242
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Spanisch"
|
msgstr "Spanisch"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-07-02 10:47+0000\n"
|
"POT-Creation-Date: 2026-09-02 22:52+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -51,11 +51,11 @@ msgstr ""
|
|||||||
msgid "File preview"
|
msgid "File preview"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:300 core/admin.py:443
|
#: core/admin.py:300 core/admin.py:450
|
||||||
msgid "No owner"
|
msgid "No owner"
|
||||||
msgstr "No owner"
|
msgstr "No owner"
|
||||||
|
|
||||||
#: core/admin.py:303 core/admin.py:446
|
#: core/admin.py:303 core/admin.py:453
|
||||||
msgid "Multiple owners"
|
msgid "Multiple owners"
|
||||||
msgstr "Multiple owners"
|
msgstr "Multiple owners"
|
||||||
|
|
||||||
@@ -98,11 +98,11 @@ msgstr "%(count)s recording(s) successfully marked as 'Failed to Stop'."
|
|||||||
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
||||||
msgstr "Skipped %(count)s expired recording(s)."
|
msgstr "Skipped %(count)s expired recording(s)."
|
||||||
|
|
||||||
#: core/admin.py:510
|
#: core/admin.py:517
|
||||||
msgid "No scopes"
|
msgid "No scopes"
|
||||||
msgstr "No scopes"
|
msgstr "No scopes"
|
||||||
|
|
||||||
#: core/admin.py:512
|
#: core/admin.py:519
|
||||||
msgid "Scopes"
|
msgid "Scopes"
|
||||||
msgstr "Scopes"
|
msgstr "Scopes"
|
||||||
|
|
||||||
@@ -110,183 +110,199 @@ msgstr "Scopes"
|
|||||||
msgid "Creator is me"
|
msgid "Creator is me"
|
||||||
msgstr "Creator is me"
|
msgstr "Creator is me"
|
||||||
|
|
||||||
#: core/api/serializers.py:89
|
#: core/api/serializers.py:108
|
||||||
msgid "You must be administrator or owner of a room to add accesses to it."
|
msgid "You must be administrator or owner of a room to add accesses to it."
|
||||||
msgstr "You must be administrator or owner of a room to add accesses to it."
|
msgstr "You must be administrator or owner of a room to add accesses to it."
|
||||||
|
|
||||||
#: core/api/serializers.py:534
|
#: core/api/serializers.py:560
|
||||||
msgid "This file extension is not allowed."
|
msgid "This file extension is not allowed."
|
||||||
msgstr "This file extension is not allowed."
|
msgstr "This file extension is not allowed."
|
||||||
|
|
||||||
#: core/api/viewsets.py:1222
|
#: core/api/viewsets.py:1268
|
||||||
msgid "You have reached the maximum number of files for this type."
|
msgid "You have reached the maximum number of files for this type."
|
||||||
msgstr "You have reached the maximum number of files for this type."
|
msgstr "You have reached the maximum number of files for this type."
|
||||||
|
|
||||||
#: core/models.py:37
|
#: core/models.py:38
|
||||||
msgid "Member"
|
msgid "Member"
|
||||||
msgstr "Member"
|
msgstr "Member"
|
||||||
|
|
||||||
#: core/models.py:38
|
#: core/models.py:39
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "Administrator"
|
msgstr "Administrator"
|
||||||
|
|
||||||
#: core/models.py:39
|
#: core/models.py:40
|
||||||
msgid "Owner"
|
msgid "Owner"
|
||||||
msgstr "Owner"
|
msgstr "Owner"
|
||||||
|
|
||||||
#: core/models.py:55
|
#: core/models.py:56
|
||||||
msgid "Initiated"
|
msgid "Initiated"
|
||||||
msgstr "Initiated"
|
msgstr "Initiated"
|
||||||
|
|
||||||
#: core/models.py:56
|
#: core/models.py:57
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Active"
|
msgstr "Active"
|
||||||
|
|
||||||
#: core/models.py:57
|
#: core/models.py:58
|
||||||
msgid "Stopped"
|
msgid "Stopped"
|
||||||
msgstr "Stopped"
|
msgstr "Stopped"
|
||||||
|
|
||||||
#: core/models.py:58
|
#: core/models.py:59
|
||||||
msgid "Saved"
|
msgid "Saved"
|
||||||
msgstr "Saved"
|
msgstr "Saved"
|
||||||
|
|
||||||
#: core/models.py:59
|
#: core/models.py:60
|
||||||
msgid "Aborted"
|
msgid "Aborted"
|
||||||
msgstr "Aborted"
|
msgstr "Aborted"
|
||||||
|
|
||||||
#: core/models.py:60
|
#: core/models.py:61
|
||||||
msgid "Failed to Start"
|
msgid "Failed to Start"
|
||||||
msgstr "Failed to Start"
|
msgstr "Failed to Start"
|
||||||
|
|
||||||
#: core/models.py:61
|
#: core/models.py:62
|
||||||
msgid "Failed to Stop"
|
msgid "Failed to Stop"
|
||||||
msgstr "Failed to Stop"
|
msgstr "Failed to Stop"
|
||||||
|
|
||||||
#: core/models.py:62
|
#: core/models.py:63
|
||||||
msgid "Notification succeeded"
|
msgid "Notification succeeded"
|
||||||
msgstr "Notification succeeded"
|
msgstr "Notification succeeded"
|
||||||
|
|
||||||
#: core/models.py:65
|
#: core/models.py:66
|
||||||
msgid "External process successful"
|
msgid "External process successful"
|
||||||
msgstr "External process successful"
|
msgstr "External process successful"
|
||||||
|
|
||||||
#: core/models.py:67
|
#: core/models.py:68
|
||||||
msgid "External process failed"
|
msgid "External process failed"
|
||||||
msgstr "External process failed"
|
msgstr "External process failed"
|
||||||
|
|
||||||
#: core/models.py:96
|
#: core/models.py:97
|
||||||
msgid "SCREEN_RECORDING"
|
msgid "SCREEN_RECORDING"
|
||||||
msgstr "SCREEN_RECORDING"
|
msgstr "SCREEN_RECORDING"
|
||||||
|
|
||||||
#: core/models.py:97
|
#: core/models.py:98
|
||||||
msgid "TRANSCRIPT"
|
msgid "TRANSCRIPT"
|
||||||
msgstr "TRANSCRIPT"
|
msgstr "TRANSCRIPT"
|
||||||
|
|
||||||
#: core/models.py:103
|
#: core/models.py:104
|
||||||
msgid "Public Access"
|
msgid "Public Access"
|
||||||
msgstr "Public Access"
|
msgstr "Public Access"
|
||||||
|
|
||||||
#: core/models.py:104
|
#: core/models.py:105
|
||||||
msgid "Trusted Access"
|
msgid "Trusted Access"
|
||||||
msgstr "Trusted Access"
|
msgstr "Trusted Access"
|
||||||
|
|
||||||
#: core/models.py:105
|
#: core/models.py:106
|
||||||
msgid "Restricted Access"
|
msgid "Restricted Access"
|
||||||
msgstr "Restricted Access"
|
msgstr "Restricted Access"
|
||||||
|
|
||||||
#: core/models.py:117
|
#: core/models.py:118
|
||||||
msgid "id"
|
msgid "id"
|
||||||
msgstr "id"
|
msgstr "id"
|
||||||
|
|
||||||
#: core/models.py:118
|
#: core/models.py:119
|
||||||
msgid "primary key for the record as UUID"
|
msgid "primary key for the record as UUID"
|
||||||
msgstr "primary key for the record as UUID"
|
msgstr "primary key for the record as UUID"
|
||||||
|
|
||||||
#: core/models.py:124
|
#: core/models.py:125
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "created on"
|
msgstr "created on"
|
||||||
|
|
||||||
#: core/models.py:125
|
#: core/models.py:126
|
||||||
msgid "date and time at which a record was created"
|
msgid "date and time at which a record was created"
|
||||||
msgstr "date and time at which a record was created"
|
msgstr "date and time at which a record was created"
|
||||||
|
|
||||||
#: core/models.py:130
|
#: core/models.py:131
|
||||||
msgid "updated on"
|
msgid "updated on"
|
||||||
msgstr "updated on"
|
msgstr "updated on"
|
||||||
|
|
||||||
#: core/models.py:131
|
#: core/models.py:132
|
||||||
msgid "date and time at which a record was last updated"
|
msgid "date and time at which a record was last updated"
|
||||||
msgstr "date and time at which a record was last updated"
|
msgstr "date and time at which a record was last updated"
|
||||||
|
|
||||||
#: core/models.py:151
|
#: core/models.py:150
|
||||||
msgid ""
|
|
||||||
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
|
|
||||||
"_ characters."
|
|
||||||
msgstr ""
|
|
||||||
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
|
|
||||||
"_ characters."
|
|
||||||
|
|
||||||
#: core/models.py:157
|
|
||||||
msgid "sub"
|
msgid "sub"
|
||||||
msgstr "sub"
|
msgstr "sub"
|
||||||
|
|
||||||
#: core/models.py:159
|
#: core/models.py:152
|
||||||
msgid ""
|
msgid ""
|
||||||
"Optional for pending users; required upon account activation. 255 characters "
|
"Optional for pending users; required upon account activation. 255 characters "
|
||||||
"or fewer. Letters, numbers, and @/./+/-/_ characters only."
|
"or fewer. Printable ASCII characters only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_ "
|
"Optional for pending users; required upon account activation. 255 characters "
|
||||||
"characters only."
|
"or fewer. Printable ASCII characters only."
|
||||||
|
|
||||||
#: core/models.py:168
|
#: core/validators.py:22
|
||||||
|
msgid "Enter a valid sub. This value should be printable ASCII only."
|
||||||
|
msgstr "Enter a valid sub. This value should be printable ASCII only."
|
||||||
|
|
||||||
|
#: core/models.py:161
|
||||||
msgid "identity email address"
|
msgid "identity email address"
|
||||||
msgstr "identity email address"
|
msgstr "identity email address"
|
||||||
|
|
||||||
#: core/models.py:173
|
#: core/models.py:166
|
||||||
msgid "admin email address"
|
msgid "admin email address"
|
||||||
msgstr "admin email address"
|
msgstr "admin email address"
|
||||||
|
|
||||||
#: core/models.py:175
|
#: core/models.py:168
|
||||||
msgid "full name"
|
msgid "full name"
|
||||||
msgstr "full name"
|
msgstr "full name"
|
||||||
|
|
||||||
#: core/models.py:177
|
#: core/models.py:170
|
||||||
msgid "short name"
|
msgid "short name"
|
||||||
msgstr "short name"
|
msgstr "short name"
|
||||||
|
|
||||||
#: core/models.py:183
|
#: core/models.py:176
|
||||||
msgid "language"
|
msgid "language"
|
||||||
msgstr "language"
|
msgstr "language"
|
||||||
|
|
||||||
#: core/models.py:184
|
#: core/models.py:177
|
||||||
msgid "The language in which the user wants to see the interface."
|
msgid "The language in which the user wants to see the interface."
|
||||||
msgstr "The language in which the user wants to see the interface."
|
msgstr "The language in which the user wants to see the interface."
|
||||||
|
|
||||||
#: core/models.py:190
|
#: core/models.py:183
|
||||||
msgid "The timezone in which the user wants to see times."
|
msgid "The timezone in which the user wants to see times."
|
||||||
msgstr "The timezone in which the user wants to see times."
|
msgstr "The timezone in which the user wants to see times."
|
||||||
|
|
||||||
#: core/models.py:193
|
#: core/models.py:190
|
||||||
|
msgid "default room access level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:192
|
||||||
|
msgid ""
|
||||||
|
"Access level applied by default to new rooms created by this user. When "
|
||||||
|
"empty, the instance default is used."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:199
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Visio room configuration"
|
||||||
|
msgid "default room configuration"
|
||||||
|
msgstr "Visio room configuration"
|
||||||
|
|
||||||
|
#: core/models.py:201
|
||||||
|
msgid "Configurations applied by default to new rooms created by this user."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:205
|
||||||
msgid "device"
|
msgid "device"
|
||||||
msgstr "device"
|
msgstr "device"
|
||||||
|
|
||||||
#: core/models.py:195
|
#: core/models.py:207
|
||||||
msgid "Whether the user is a device or a real user."
|
msgid "Whether the user is a device or a real user."
|
||||||
msgstr "Whether the user is a device or a real user."
|
msgstr "Whether the user is a device or a real user."
|
||||||
|
|
||||||
#: core/models.py:198
|
#: core/models.py:210
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "staff status"
|
msgstr "staff status"
|
||||||
|
|
||||||
#: core/models.py:200
|
#: core/models.py:212
|
||||||
msgid "Whether the user can log into this admin site."
|
msgid "Whether the user can log into this admin site."
|
||||||
msgstr "Whether the user can log into this admin site."
|
msgstr "Whether the user can log into this admin site."
|
||||||
|
|
||||||
#: core/models.py:203
|
#: core/models.py:215
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "active"
|
msgstr "active"
|
||||||
|
|
||||||
#: core/models.py:206
|
#: core/models.py:218
|
||||||
msgid ""
|
msgid ""
|
||||||
"Whether this user should be treated as active. Unselect this instead of "
|
"Whether this user should be treated as active. Unselect this instead of "
|
||||||
"deleting accounts."
|
"deleting accounts."
|
||||||
@@ -294,63 +310,63 @@ msgstr ""
|
|||||||
"Whether this user should be treated as active. Unselect this instead of "
|
"Whether this user should be treated as active. Unselect this instead of "
|
||||||
"deleting accounts."
|
"deleting accounts."
|
||||||
|
|
||||||
#: core/models.py:219
|
#: core/models.py:231
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "user"
|
msgstr "user"
|
||||||
|
|
||||||
#: core/models.py:220
|
#: core/models.py:232
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr "users"
|
msgstr "users"
|
||||||
|
|
||||||
#: core/models.py:286
|
#: core/models.py:298
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
msgstr "Resource"
|
msgstr "Resource"
|
||||||
|
|
||||||
#: core/models.py:287
|
#: core/models.py:299
|
||||||
msgid "Resources"
|
msgid "Resources"
|
||||||
msgstr "Resources"
|
msgstr "Resources"
|
||||||
|
|
||||||
#: core/models.py:345
|
#: core/models.py:357
|
||||||
msgid "Resource access"
|
msgid "Resource access"
|
||||||
msgstr "Resource access"
|
msgstr "Resource access"
|
||||||
|
|
||||||
#: core/models.py:346
|
#: core/models.py:358
|
||||||
msgid "Resource accesses"
|
msgid "Resource accesses"
|
||||||
msgstr "Resource accesses"
|
msgstr "Resource accesses"
|
||||||
|
|
||||||
#: core/models.py:352
|
#: core/models.py:364
|
||||||
msgid "Resource access with this User and Resource already exists."
|
msgid "Resource access with this User and Resource already exists."
|
||||||
msgstr "Resource access with this User and Resource already exists."
|
msgstr "Resource access with this User and Resource already exists."
|
||||||
|
|
||||||
#: core/models.py:409
|
#: core/models.py:421
|
||||||
msgid "Visio room configuration"
|
msgid "Visio room configuration"
|
||||||
msgstr "Visio room configuration"
|
msgstr "Visio room configuration"
|
||||||
|
|
||||||
#: core/models.py:410
|
#: core/models.py:422
|
||||||
msgid "Values for Visio parameters to configure the room."
|
msgid "Values for Visio parameters to configure the room."
|
||||||
msgstr "Values for Visio parameters to configure the room."
|
msgstr "Values for Visio parameters to configure the room."
|
||||||
|
|
||||||
#: core/models.py:417
|
#: core/models.py:429
|
||||||
msgid "Room PIN code"
|
msgid "Room PIN code"
|
||||||
msgstr "Room PIN code"
|
msgstr "Room PIN code"
|
||||||
|
|
||||||
#: core/models.py:418
|
#: core/models.py:430
|
||||||
msgid "Unique n-digit code that identifies this room in telephony mode."
|
msgid "Unique n-digit code that identifies this room in telephony mode."
|
||||||
msgstr "Unique n-digit code that identifies this room in telephony mode."
|
msgstr "Unique n-digit code that identifies this room in telephony mode."
|
||||||
|
|
||||||
#: core/models.py:424 core/models.py:578
|
#: core/models.py:436 core/models.py:597
|
||||||
msgid "Room"
|
msgid "Room"
|
||||||
msgstr "Room"
|
msgstr "Room"
|
||||||
|
|
||||||
#: core/models.py:425
|
#: core/models.py:437
|
||||||
msgid "Rooms"
|
msgid "Rooms"
|
||||||
msgstr "Rooms"
|
msgstr "Rooms"
|
||||||
|
|
||||||
#: core/models.py:589
|
#: core/models.py:608
|
||||||
msgid "Worker ID"
|
msgid "Worker ID"
|
||||||
msgstr "Worker ID"
|
msgstr "Worker ID"
|
||||||
|
|
||||||
#: core/models.py:591
|
#: core/models.py:610
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter an identifier for the worker recording.This ID is retained even when "
|
"Enter an identifier for the worker recording.This ID is retained even when "
|
||||||
"the worker stops, allowing for easy tracking."
|
"the worker stops, allowing for easy tracking."
|
||||||
@@ -358,171 +374,171 @@ msgstr ""
|
|||||||
"Enter an identifier for the worker recording.This ID is retained even when "
|
"Enter an identifier for the worker recording.This ID is retained even when "
|
||||||
"the worker stops, allowing for easy tracking."
|
"the worker stops, allowing for easy tracking."
|
||||||
|
|
||||||
#: core/models.py:599
|
#: core/models.py:618
|
||||||
msgid "Recording mode"
|
msgid "Recording mode"
|
||||||
msgstr "Recording mode"
|
msgstr "Recording mode"
|
||||||
|
|
||||||
#: core/models.py:600
|
#: core/models.py:619
|
||||||
msgid "Defines the mode of recording being called."
|
msgid "Defines the mode of recording being called."
|
||||||
msgstr "Defines the mode of recording being called."
|
msgstr "Defines the mode of recording being called."
|
||||||
|
|
||||||
#: core/models.py:605 core/models.py:606
|
#: core/models.py:624 core/models.py:625
|
||||||
msgid "Recording options"
|
msgid "Recording options"
|
||||||
msgstr "Recording options"
|
msgstr "Recording options"
|
||||||
|
|
||||||
#: core/models.py:613
|
#: core/models.py:632
|
||||||
msgid "External Process ID"
|
msgid "External Process ID"
|
||||||
msgstr "External Process ID"
|
msgstr "External Process ID"
|
||||||
|
|
||||||
#: core/models.py:614
|
#: core/models.py:633
|
||||||
msgid "ID of the external process associated with the recording."
|
msgid "ID of the external process associated with the recording."
|
||||||
msgstr "ID of the external process associated with the recording."
|
msgstr "ID of the external process associated with the recording."
|
||||||
|
|
||||||
#: core/models.py:620
|
#: core/models.py:639
|
||||||
msgid "Recording"
|
msgid "Recording"
|
||||||
msgstr "Recording"
|
msgstr "Recording"
|
||||||
|
|
||||||
#: core/models.py:621
|
#: core/models.py:640
|
||||||
msgid "Recordings"
|
msgid "Recordings"
|
||||||
msgstr "Recordings"
|
msgstr "Recordings"
|
||||||
|
|
||||||
#: core/models.py:731
|
#: core/models.py:750
|
||||||
msgid "Recording/user relation"
|
msgid "Recording/user relation"
|
||||||
msgstr "Recording/user relation"
|
msgstr "Recording/user relation"
|
||||||
|
|
||||||
#: core/models.py:732
|
#: core/models.py:751
|
||||||
msgid "Recording/user relations"
|
msgid "Recording/user relations"
|
||||||
msgstr "Recording/user relations"
|
msgstr "Recording/user relations"
|
||||||
|
|
||||||
#: core/models.py:738
|
#: core/models.py:757
|
||||||
msgid "This user is already in this recording."
|
msgid "This user is already in this recording."
|
||||||
msgstr "This user is already in this recording."
|
msgstr "This user is already in this recording."
|
||||||
|
|
||||||
#: core/models.py:744
|
#: core/models.py:763
|
||||||
msgid "This team is already in this recording."
|
msgid "This team is already in this recording."
|
||||||
msgstr "This team is already in this recording."
|
msgstr "This team is already in this recording."
|
||||||
|
|
||||||
#: core/models.py:750
|
#: core/models.py:769
|
||||||
msgid "Either user or team must be set, not both."
|
msgid "Either user or team must be set, not both."
|
||||||
msgstr "Either user or team must be set, not both."
|
msgstr "Either user or team must be set, not both."
|
||||||
|
|
||||||
#: core/models.py:767
|
#: core/models.py:786
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "created on"
|
#| msgid "created on"
|
||||||
msgid "Create rooms"
|
msgid "Create rooms"
|
||||||
msgstr "Create rooms"
|
msgstr "Create rooms"
|
||||||
|
|
||||||
#: core/models.py:768
|
#: core/models.py:787
|
||||||
msgid "List rooms"
|
msgid "List rooms"
|
||||||
msgstr "List rooms"
|
msgstr "List rooms"
|
||||||
|
|
||||||
#: core/models.py:769
|
#: core/models.py:788
|
||||||
msgid "Retrieve room details"
|
msgid "Retrieve room details"
|
||||||
msgstr "Retrieve room details"
|
msgstr "Retrieve room details"
|
||||||
|
|
||||||
#: core/models.py:770
|
#: core/models.py:789
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "updated on"
|
#| msgid "updated on"
|
||||||
msgid "Update rooms"
|
msgid "Update rooms"
|
||||||
msgstr "Update rooms"
|
msgstr "Update rooms"
|
||||||
|
|
||||||
#: core/models.py:771
|
#: core/models.py:790
|
||||||
msgid "Delete rooms"
|
msgid "Delete rooms"
|
||||||
msgstr "Delete rooms"
|
msgstr "Delete rooms"
|
||||||
|
|
||||||
#: core/models.py:784
|
#: core/models.py:803
|
||||||
msgid "Application name"
|
msgid "Application name"
|
||||||
msgstr "Application name"
|
msgstr "Application name"
|
||||||
|
|
||||||
#: core/models.py:785
|
#: core/models.py:804
|
||||||
msgid "Descriptive name for this application."
|
msgid "Descriptive name for this application."
|
||||||
msgstr "Descriptive name for this application."
|
msgstr "Descriptive name for this application."
|
||||||
|
|
||||||
#: core/models.py:795
|
#: core/models.py:814
|
||||||
msgid "Hashed on Save. Copy it now if this is a new secret."
|
msgid "Hashed on Save. Copy it now if this is a new secret."
|
||||||
msgstr "Hashed on Save. Copy it now if this is a new secret."
|
msgstr "Hashed on Save. Copy it now if this is a new secret."
|
||||||
|
|
||||||
#: core/models.py:806
|
#: core/models.py:825
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "Application"
|
msgstr "Application"
|
||||||
|
|
||||||
#: core/models.py:807
|
#: core/models.py:826
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Applications"
|
msgstr "Applications"
|
||||||
|
|
||||||
#: core/models.py:830
|
#: core/models.py:849
|
||||||
msgid "Enter a valid domain"
|
msgid "Enter a valid domain"
|
||||||
msgstr "Enter a valid domain"
|
msgstr "Enter a valid domain"
|
||||||
|
|
||||||
#: core/models.py:833
|
#: core/models.py:852
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Domain"
|
msgstr "Domain"
|
||||||
|
|
||||||
#: core/models.py:834
|
#: core/models.py:853
|
||||||
msgid "Email domain this application can act on behalf of."
|
msgid "Email domain this application can act on behalf of."
|
||||||
msgstr "Email domain this application can act on behalf of."
|
msgstr "Email domain this application can act on behalf of."
|
||||||
|
|
||||||
#: core/models.py:846
|
#: core/models.py:865
|
||||||
msgid "Application domain"
|
msgid "Application domain"
|
||||||
msgstr "Application domain"
|
msgstr "Application domain"
|
||||||
|
|
||||||
#: core/models.py:847
|
#: core/models.py:866
|
||||||
msgid "Application domains"
|
msgid "Application domains"
|
||||||
msgstr "Application domains"
|
msgstr "Application domains"
|
||||||
|
|
||||||
#: core/models.py:865
|
#: core/models.py:884
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Recording"
|
#| msgid "Recording"
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "Pending"
|
msgstr "Pending"
|
||||||
|
|
||||||
#: core/models.py:866
|
#: core/models.py:885
|
||||||
msgid "Analyzing"
|
msgid "Analyzing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/models.py:873
|
#: core/models.py:892
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
msgstr "Ready"
|
msgstr "Ready"
|
||||||
|
|
||||||
#: core/models.py:879
|
#: core/models.py:898
|
||||||
msgid "Background image"
|
msgid "Background image"
|
||||||
msgstr "Background image"
|
msgstr "Background image"
|
||||||
|
|
||||||
#: core/models.py:891
|
#: core/models.py:910
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "title"
|
msgstr "title"
|
||||||
|
|
||||||
#: core/models.py:915
|
#: core/models.py:934
|
||||||
msgid "Malware detection info when the analysis status is unsafe."
|
msgid "Malware detection info when the analysis status is unsafe."
|
||||||
msgstr "Malware detection info when the analysis status is unsafe."
|
msgstr "Malware detection info when the analysis status is unsafe."
|
||||||
|
|
||||||
#: core/models.py:920
|
#: core/models.py:939
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "File"
|
msgstr "File"
|
||||||
|
|
||||||
#: core/models.py:921
|
#: core/models.py:940
|
||||||
msgid "Files"
|
msgid "Files"
|
||||||
msgstr "Files"
|
msgstr "Files"
|
||||||
|
|
||||||
#: core/models.py:1041
|
#: core/models.py:1060
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "This user is already in this recording."
|
#| msgid "This user is already in this recording."
|
||||||
msgid "This file is already hard deleted."
|
msgid "This file is already hard deleted."
|
||||||
msgstr "This file is already hard deleted."
|
msgstr "This file is already hard deleted."
|
||||||
|
|
||||||
#: core/models.py:1051
|
#: core/models.py:1070
|
||||||
msgid "To hard delete a file, it must first be soft deleted."
|
msgid "To hard delete a file, it must first be soft deleted."
|
||||||
msgstr "To hard delete a file, it must first be soft deleted."
|
msgstr "To hard delete a file, it must first be soft deleted."
|
||||||
|
|
||||||
#: core/recording/event/notification.py:123
|
#: core/recording/event/notification.py:124
|
||||||
msgid "Your recording is ready"
|
msgid "Your recording is ready"
|
||||||
msgstr "Your recording is ready"
|
msgstr "Your recording is ready"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:194
|
#: core/recording/event/notification.py:195
|
||||||
msgid "Transcription"
|
msgid "Transcription"
|
||||||
msgstr "Transcription"
|
msgstr "Transcription"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:204
|
#: core/recording/event/notification.py:206
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
||||||
msgstr "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
msgstr "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
||||||
@@ -532,25 +548,25 @@ msgstr "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
|||||||
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
||||||
msgstr "Video call in progress: {sender.email} is waiting for you to connect"
|
msgstr "Video call in progress: {sender.email} is waiting for you to connect"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:159
|
#: core/templates/mail/html/invitation.html:151
|
||||||
#: core/templates/mail/html/screen_recording.html:159
|
#: core/templates/mail/html/screen_recording.html:151
|
||||||
#: core/templates/mail/text/invitation.txt:3
|
#: core/templates/mail/text/invitation.txt:4
|
||||||
#: core/templates/mail/text/screen_recording.txt:3
|
#: core/templates/mail/text/screen_recording.txt:4
|
||||||
msgid "Logo email"
|
msgid "Logo email"
|
||||||
msgstr "Logo email"
|
msgstr "Logo email"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:189
|
#: core/templates/mail/html/invitation.html:181
|
||||||
#: core/templates/mail/text/invitation.txt:5
|
#: core/templates/mail/text/invitation.txt:6
|
||||||
msgid "invites you to join an ongoing video call"
|
msgid "invites you to join an ongoing video call"
|
||||||
msgstr "invites you to join an ongoing video call"
|
msgstr "invites you to join an ongoing video call"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:200
|
#: core/templates/mail/html/invitation.html:192
|
||||||
#: core/templates/mail/text/invitation.txt:7
|
#: core/templates/mail/text/invitation.txt:8
|
||||||
msgid "JOIN THE CALL"
|
msgid "JOIN THE CALL"
|
||||||
msgstr "JOIN THE CALL"
|
msgstr "JOIN THE CALL"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:227
|
#: core/templates/mail/html/invitation.html:219
|
||||||
#: core/templates/mail/text/invitation.txt:13
|
#: core/templates/mail/text/invitation.txt:14
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you can't click the button, copy and paste the URL into your browser to "
|
"If you can't click the button, copy and paste the URL into your browser to "
|
||||||
"join the call."
|
"join the call."
|
||||||
@@ -558,41 +574,47 @@ msgstr ""
|
|||||||
"If you can't click the button, copy and paste the URL into your browser to "
|
"If you can't click the button, copy and paste the URL into your browser to "
|
||||||
"join the call."
|
"join the call."
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:235
|
#: core/templates/mail/html/invitation.html:227
|
||||||
#: core/templates/mail/text/invitation.txt:15
|
#: core/templates/mail/text/invitation.txt:16
|
||||||
msgid "Tips for a better experience:"
|
msgid "Tips for a better experience:"
|
||||||
msgstr "Tips for a better experience:"
|
msgstr "Tips for a better experience:"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:237
|
#: core/templates/mail/html/invitation.html:229
|
||||||
#: core/templates/mail/text/invitation.txt:17
|
#: core/templates/mail/text/invitation.txt:18
|
||||||
msgid "Use Chrome or Firefox for better call quality"
|
msgid "Use Chrome or Firefox for better call quality"
|
||||||
msgstr "Use Chrome or Firefox for better call quality"
|
msgstr "Use Chrome or Firefox for better call quality"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:238
|
#: core/templates/mail/html/invitation.html:230
|
||||||
#: core/templates/mail/text/invitation.txt:18
|
#: core/templates/mail/text/invitation.txt:19
|
||||||
msgid "Test your microphone and camera before joining"
|
msgid "Test your microphone and camera before joining"
|
||||||
msgstr "Test your microphone and camera before joining"
|
msgstr "Test your microphone and camera before joining"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:239
|
#: core/templates/mail/html/invitation.html:231
|
||||||
#: core/templates/mail/text/invitation.txt:19
|
#: core/templates/mail/text/invitation.txt:20
|
||||||
msgid "Make sure you have a stable internet connection"
|
msgid "Make sure you have a stable internet connection"
|
||||||
msgstr "Make sure you have a stable internet connection"
|
msgstr "Make sure you have a stable internet connection"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:248
|
#: core/templates/mail/html/invitation.html:240
|
||||||
#: core/templates/mail/html/screen_recording.html:245
|
#: core/templates/mail/html/screen_recording.html:237
|
||||||
#: core/templates/mail/text/invitation.txt:21
|
#: core/templates/mail/text/invitation.txt:22
|
||||||
#: core/templates/mail/text/screen_recording.txt:23
|
#: core/templates/mail/text/screen_recording.txt:24
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " Thank you for using %(brandname)s. "
|
msgid " Thank you for using %(brandname)s. "
|
||||||
msgstr " Thank you for using %(brandname)s. "
|
msgstr " Thank you for using %(brandname)s. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:188
|
#: core/templates/mail/html/invitation.html:271
|
||||||
#: core/templates/mail/text/screen_recording.txt:6
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"This mail has been sent to %(email)s by <a href=\"%(href)s\">%(name)s</a>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/html/screen_recording.html:180
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:7
|
||||||
msgid "Your recording is ready!"
|
msgid "Your recording is ready!"
|
||||||
msgstr "Your recording is ready!"
|
msgstr "Your recording is ready!"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
||||||
@@ -601,14 +623,14 @@ msgstr ""
|
|||||||
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
||||||
"%(recording_time)s is now ready to download. "
|
"%(recording_time)s is now ready to download. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " The recording will expire in %(days)s days. "
|
msgid " The recording will expire in %(days)s days. "
|
||||||
msgstr " The recording will expire in %(days)s days. "
|
msgstr " The recording will expire in %(days)s days. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:200
|
#: core/templates/mail/html/screen_recording.html:192
|
||||||
#: core/templates/mail/text/screen_recording.txt:9
|
#: core/templates/mail/text/screen_recording.txt:10
|
||||||
msgid ""
|
msgid ""
|
||||||
" Sharing the recording via link is not yet available. Only organizers can "
|
" Sharing the recording via link is not yet available. Only organizers can "
|
||||||
"download it. "
|
"download it. "
|
||||||
@@ -616,33 +638,33 @@ msgstr ""
|
|||||||
" Sharing the recording via link is not yet available. Only organizers can "
|
" Sharing the recording via link is not yet available. Only organizers can "
|
||||||
"download it. "
|
"download it. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:206
|
#: core/templates/mail/html/screen_recording.html:198
|
||||||
#: core/templates/mail/text/screen_recording.txt:11
|
#: core/templates/mail/text/screen_recording.txt:12
|
||||||
msgid "To keep this recording permanently:"
|
msgid "To keep this recording permanently:"
|
||||||
msgstr "To keep this recording permanently:"
|
msgstr "To keep this recording permanently:"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:208
|
#: core/templates/mail/html/screen_recording.html:200
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgstr "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgstr "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:209
|
#: core/templates/mail/html/screen_recording.html:201
|
||||||
#: core/templates/mail/text/screen_recording.txt:14
|
#: core/templates/mail/text/screen_recording.txt:15
|
||||||
msgid "Use the \"Download\" button in the interface "
|
msgid "Use the \"Download\" button in the interface "
|
||||||
msgstr "Use the \"Download\" button in the interface "
|
msgstr "Use the \"Download\" button in the interface "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:210
|
#: core/templates/mail/html/screen_recording.html:202
|
||||||
#: core/templates/mail/text/screen_recording.txt:15
|
#: core/templates/mail/text/screen_recording.txt:16
|
||||||
msgid "Save the file to your preferred location"
|
msgid "Save the file to your preferred location"
|
||||||
msgstr "Save the file to your preferred location"
|
msgstr "Save the file to your preferred location"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:221
|
#: core/templates/mail/html/screen_recording.html:213
|
||||||
#: core/templates/mail/text/screen_recording.txt:17
|
#: core/templates/mail/text/screen_recording.txt:18
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Open"
|
msgstr "Open"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:230
|
#: core/templates/mail/html/screen_recording.html:222
|
||||||
#: core/templates/mail/text/screen_recording.txt:19
|
#: core/templates/mail/text/screen_recording.txt:20
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" If you have any questions or need assistance, please contact our support "
|
" If you have any questions or need assistance, please contact our support "
|
||||||
@@ -651,28 +673,33 @@ msgstr ""
|
|||||||
" If you have any questions or need assistance, please contact our support "
|
" If you have any questions or need assistance, please contact our support "
|
||||||
"team at %(support_email)s. "
|
"team at %(support_email)s. "
|
||||||
|
|
||||||
#: core/templates/mail/text/screen_recording.txt:13
|
#: core/templates/mail/text/invitation.txt:24
|
||||||
|
#, python-format
|
||||||
|
msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:14
|
||||||
#, fuzzy, python-format
|
#, fuzzy, python-format
|
||||||
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgid "Click the \"Open [%(link)s]\" link below "
|
msgid "Click the \"Open [%(link)s]\" link below "
|
||||||
msgstr "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgstr "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
|
|
||||||
#: meet/settings.py:228
|
#: meet/settings.py:238
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "English"
|
msgstr "English"
|
||||||
|
|
||||||
#: meet/settings.py:229
|
#: meet/settings.py:239
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "French"
|
msgstr "French"
|
||||||
|
|
||||||
#: meet/settings.py:230
|
#: meet/settings.py:240
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Dutch"
|
msgstr "Dutch"
|
||||||
|
|
||||||
#: meet/settings.py:231
|
#: meet/settings.py:241
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "German"
|
msgstr "German"
|
||||||
|
|
||||||
#: meet/settings.py:233
|
#: meet/settings.py:242
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Spanish"
|
msgstr "Spanish"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-07-02 10:47+0000\n"
|
"POT-Creation-Date: 2026-09-02 22:52+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -41,20 +41,20 @@ msgstr "Eliminar Salas"
|
|||||||
msgid "Derived info"
|
msgid "Derived info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:237
|
|
||||||
# 'Marcas de tiempo' is a bad translation for spanish
|
# 'Marcas de tiempo' is a bad translation for spanish
|
||||||
|
#: core/admin.py:237
|
||||||
msgid "Timestamps"
|
msgid "Timestamps"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:240
|
#: core/admin.py:240
|
||||||
msgid "File preview"
|
msgid "File preview"
|
||||||
msgstr "Vista previa"
|
msgstr "Vista previa"
|
||||||
|
|
||||||
#: core/admin.py:300 core/admin.py:443
|
#: core/admin.py:300 core/admin.py:450
|
||||||
msgid "No owner"
|
msgid "No owner"
|
||||||
msgstr "Sin propietario"
|
msgstr "Sin propietario"
|
||||||
|
|
||||||
#: core/admin.py:303 core/admin.py:446
|
#: core/admin.py:303 core/admin.py:453
|
||||||
msgid "Multiple owners"
|
msgid "Multiple owners"
|
||||||
msgstr "Varios propietarios"
|
msgstr "Varios propietarios"
|
||||||
|
|
||||||
@@ -89,18 +89,19 @@ msgstr "Marcar las grabaciones seleccionadas como «Error al detener»"
|
|||||||
#: core/admin.py:386
|
#: core/admin.py:386
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(count)s recording(s) successfully marked as 'Failed to Stop'."
|
msgid "%(count)s recording(s) successfully marked as 'Failed to Stop'."
|
||||||
msgstr "%(count)s grabación(es) marcada(s) correctamente como «Error al detener»."
|
msgstr ""
|
||||||
|
"%(count)s grabación(es) marcada(s) correctamente como «Error al detener»."
|
||||||
|
|
||||||
#: core/admin.py:394
|
#: core/admin.py:394
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
||||||
msgstr "Se han omitido %(count)s grabación(es) con un estado no elegible."
|
msgstr "Se han omitido %(count)s grabación(es) con un estado no elegible."
|
||||||
|
|
||||||
#: core/admin.py:510
|
#: core/admin.py:517
|
||||||
msgid "No scopes"
|
msgid "No scopes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:512
|
#: core/admin.py:519
|
||||||
msgid "Scopes"
|
msgid "Scopes"
|
||||||
msgstr "Ámbitos"
|
msgstr "Ámbitos"
|
||||||
|
|
||||||
@@ -108,545 +109,599 @@ msgstr "Ámbitos"
|
|||||||
msgid "Creator is me"
|
msgid "Creator is me"
|
||||||
msgstr "Yo soy el creador"
|
msgstr "Yo soy el creador"
|
||||||
|
|
||||||
#: core/api/serializers.py:89
|
#: core/api/serializers.py:108
|
||||||
msgid "You must be administrator or owner of a room to add accesses to it."
|
msgid "You must be administrator or owner of a room to add accesses to it."
|
||||||
msgstr "Debes ser administrador o propietario de una reunión para añadirle accesos."
|
msgstr ""
|
||||||
|
"Debes ser administrador o propietario de una reunión para añadirle accesos."
|
||||||
|
|
||||||
#: core/api/serializers.py:534
|
#: core/api/serializers.py:560
|
||||||
msgid "This file extension is not allowed."
|
msgid "This file extension is not allowed."
|
||||||
msgstr "Esta extensión de archivo no está permitida."
|
msgstr "Esta extensión de archivo no está permitida."
|
||||||
|
|
||||||
#: core/api/viewsets.py:1222
|
#: core/api/viewsets.py:1268
|
||||||
msgid "You have reached the maximum number of files for this type."
|
msgid "You have reached the maximum number of files for this type."
|
||||||
msgstr "Has alcanzado el número máximo de archivos de este tipo."
|
msgstr "Has alcanzado el número máximo de archivos de este tipo."
|
||||||
|
|
||||||
#: core/models.py:37
|
#: core/models.py:38
|
||||||
msgid "Member"
|
msgid "Member"
|
||||||
msgstr "Miembro"
|
msgstr "Miembro"
|
||||||
|
|
||||||
#: core/models.py:38
|
#: core/models.py:39
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: core/models.py:39
|
#: core/models.py:40
|
||||||
msgid "Owner"
|
msgid "Owner"
|
||||||
msgstr "Propietario"
|
msgstr "Propietario"
|
||||||
|
|
||||||
#: core/models.py:55
|
|
||||||
# To check here and following lines for gender agreement (Masculine/Feminine)
|
# To check here and following lines for gender agreement (Masculine/Feminine)
|
||||||
|
#: core/models.py:56
|
||||||
msgid "Initiated"
|
msgid "Initiated"
|
||||||
msgstr "Iniciada"
|
msgstr "Iniciada"
|
||||||
|
|
||||||
#: core/models.py:56
|
#: core/models.py:57
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Activa"
|
msgstr "Activa"
|
||||||
|
|
||||||
#: core/models.py:57
|
#: core/models.py:58
|
||||||
msgid "Stopped"
|
msgid "Stopped"
|
||||||
msgstr "Detenida"
|
msgstr "Detenida"
|
||||||
|
|
||||||
#: core/models.py:58
|
#: core/models.py:59
|
||||||
msgid "Saved"
|
msgid "Saved"
|
||||||
msgstr "Guardada"
|
msgstr "Guardada"
|
||||||
|
|
||||||
#: core/models.py:59
|
#: core/models.py:60
|
||||||
msgid "Aborted"
|
msgid "Aborted"
|
||||||
msgstr "Cancelada"
|
msgstr "Cancelada"
|
||||||
|
|
||||||
#: core/models.py:60
|
#: core/models.py:61
|
||||||
msgid "Failed to Start"
|
msgid "Failed to Start"
|
||||||
msgstr "Error al iniciar"
|
msgstr "Error al iniciar"
|
||||||
|
|
||||||
#: core/models.py:61
|
#: core/models.py:62
|
||||||
msgid "Failed to Stop"
|
msgid "Failed to Stop"
|
||||||
msgstr "Error al detener"
|
msgstr "Error al detener"
|
||||||
|
|
||||||
#: core/models.py:62
|
#: core/models.py:63
|
||||||
msgid "Notification succeeded"
|
msgid "Notification succeeded"
|
||||||
msgstr "Notificado correctamente"
|
msgstr "Notificado correctamente"
|
||||||
|
|
||||||
#: core/models.py:65
|
#: core/models.py:66
|
||||||
msgid "External process successful"
|
msgid "External process successful"
|
||||||
msgstr "Proceso externo finalizado correctamente"
|
msgstr "Proceso externo finalizado correctamente"
|
||||||
|
|
||||||
#: core/models.py:67
|
#: core/models.py:68
|
||||||
msgid "External process failed"
|
msgid "External process failed"
|
||||||
msgstr "Error en el Proceso externo"
|
msgstr "Error en el Proceso externo"
|
||||||
|
|
||||||
#: core/models.py:96
|
#: core/models.py:97
|
||||||
msgid "SCREEN_RECORDING"
|
msgid "SCREEN_RECORDING"
|
||||||
msgstr "GRABACIÓN_DE_PANTALLA"
|
msgstr "GRABACIÓN_DE_PANTALLA"
|
||||||
|
|
||||||
#: core/models.py:97
|
#: core/models.py:98
|
||||||
msgid "TRANSCRIPT"
|
msgid "TRANSCRIPT"
|
||||||
msgstr "TRANSCRIPCIÓN"
|
msgstr "TRANSCRIPCIÓN"
|
||||||
|
|
||||||
#: core/models.py:103
|
#: core/models.py:104
|
||||||
msgid "Public Access"
|
msgid "Public Access"
|
||||||
msgstr "Acceso público"
|
msgstr "Acceso público"
|
||||||
|
|
||||||
#: core/models.py:104
|
#: core/models.py:105
|
||||||
msgid "Trusted Access"
|
msgid "Trusted Access"
|
||||||
msgstr "Acceso usuarios autorizados"
|
msgstr "Acceso usuarios autorizados"
|
||||||
|
|
||||||
#: core/models.py:105
|
#: core/models.py:106
|
||||||
msgid "Restricted Access"
|
msgid "Restricted Access"
|
||||||
msgstr "Acceso restringido"
|
msgstr "Acceso restringido"
|
||||||
|
|
||||||
#: core/models.py:117
|
#: core/models.py:118
|
||||||
msgid "id"
|
msgid "id"
|
||||||
msgstr "id"
|
msgstr "id"
|
||||||
|
|
||||||
#: core/models.py:118
|
#: core/models.py:119
|
||||||
msgid "primary key for the record as UUID"
|
msgid "primary key for the record as UUID"
|
||||||
msgstr "clave primaria del registro en forma de UUID"
|
msgstr "clave primaria del registro en forma de UUID"
|
||||||
|
|
||||||
#: core/models.py:124
|
#: core/models.py:125
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "creado el"
|
msgstr "creado el"
|
||||||
|
|
||||||
#: core/models.py:125
|
#: core/models.py:126
|
||||||
msgid "date and time at which a record was created"
|
msgid "date and time at which a record was created"
|
||||||
msgstr "fecha y hora en que se creó un registro"
|
msgstr "fecha y hora en que se creó un registro"
|
||||||
|
|
||||||
#: core/models.py:130
|
#: core/models.py:131
|
||||||
msgid "updated on"
|
msgid "updated on"
|
||||||
msgstr "actualizado el"
|
msgstr "actualizado el"
|
||||||
|
|
||||||
#: core/models.py:131
|
#: core/models.py:132
|
||||||
msgid "date and time at which a record was last updated"
|
msgid "date and time at which a record was last updated"
|
||||||
msgstr "fecha y hora de la última actualización de un registro"
|
msgstr "fecha y hora de la última actualización de un registro"
|
||||||
|
|
||||||
#: core/models.py:151
|
#: core/models.py:150
|
||||||
msgid ""
|
|
||||||
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
|
|
||||||
"_ characters."
|
|
||||||
msgstr "Introduce un sub válido. Este valor solo puede contener letras, números y los caracteres @/./+/-/_."
|
|
||||||
|
|
||||||
#: core/models.py:157
|
|
||||||
msgid "sub"
|
msgid "sub"
|
||||||
msgstr "sub"
|
msgstr "sub"
|
||||||
|
|
||||||
#: core/models.py:159
|
#: core/models.py:152
|
||||||
msgid ""
|
msgid ""
|
||||||
"Optional for pending users; required upon account activation. 255 characters "
|
"Optional for pending users; required upon account activation. 255 characters "
|
||||||
"or fewer. Letters, numbers, and @/./+/-/_ characters only."
|
"or fewer. Printable ASCII characters only."
|
||||||
msgstr "Opcional para los usuarios pendientes; obligatorio al activar la cuenta. 255 caracteres como máximo. Solo letras, números y los caracteres @/./+/-/_."
|
msgstr ""
|
||||||
|
"Opcional para los usuarios pendientes; obligatorio al activar la cuenta. "
|
||||||
|
"255 caracteres como máximo. Solo caracteres ASCII imprimibles."
|
||||||
|
|
||||||
#: core/models.py:168
|
#: core/validators.py:22
|
||||||
|
msgid "Enter a valid sub. This value should be printable ASCII only."
|
||||||
|
msgstr "Introduzca un sub válido. Este valor solo debe contener caracteres ASCII imprimibles."
|
||||||
|
|
||||||
|
#: core/models.py:161
|
||||||
msgid "identity email address"
|
msgid "identity email address"
|
||||||
msgstr "dirección de correo electrónico"
|
msgstr "dirección de correo electrónico"
|
||||||
|
|
||||||
#: core/models.py:173
|
#: core/models.py:166
|
||||||
msgid "admin email address"
|
msgid "admin email address"
|
||||||
msgstr "dirección de correo electrónico de administrador"
|
msgstr "dirección de correo electrónico de administrador"
|
||||||
|
|
||||||
#: core/models.py:175
|
#: core/models.py:168
|
||||||
msgid "full name"
|
msgid "full name"
|
||||||
msgstr "nombre completo"
|
msgstr "nombre completo"
|
||||||
|
|
||||||
#: core/models.py:177
|
#: core/models.py:170
|
||||||
msgid "short name"
|
msgid "short name"
|
||||||
msgstr "nombre corto"
|
msgstr "nombre corto"
|
||||||
|
|
||||||
#: core/models.py:183
|
#: core/models.py:176
|
||||||
msgid "language"
|
msgid "language"
|
||||||
msgstr "idioma"
|
msgstr "idioma"
|
||||||
|
|
||||||
#: core/models.py:184
|
#: core/models.py:177
|
||||||
msgid "The language in which the user wants to see the interface."
|
msgid "The language in which the user wants to see the interface."
|
||||||
msgstr "El idioma preferido de interfaz."
|
msgstr "El idioma preferido de interfaz."
|
||||||
|
|
||||||
#: core/models.py:190
|
#: core/models.py:183
|
||||||
msgid "The timezone in which the user wants to see times."
|
msgid "The timezone in which the user wants to see times."
|
||||||
msgstr "La zona horaria en la que el usuario quiere ver las horas."
|
msgstr "La zona horaria en la que el usuario quiere ver las horas."
|
||||||
|
|
||||||
#: core/models.py:193
|
#: core/models.py:190
|
||||||
|
msgid "default room access level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:192
|
||||||
|
msgid ""
|
||||||
|
"Access level applied by default to new rooms created by this user. When "
|
||||||
|
"empty, the instance default is used."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:199
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Visio room configuration"
|
||||||
|
msgid "default room configuration"
|
||||||
|
msgstr "Configuración de la videoconferencia"
|
||||||
|
|
||||||
|
#: core/models.py:201
|
||||||
|
msgid "Configurations applied by default to new rooms created by this user."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:205
|
||||||
msgid "device"
|
msgid "device"
|
||||||
msgstr "dispositivo"
|
msgstr "dispositivo"
|
||||||
|
|
||||||
#: core/models.py:195
|
#: core/models.py:207
|
||||||
msgid "Whether the user is a device or a real user."
|
msgid "Whether the user is a device or a real user."
|
||||||
msgstr "Si el usuario es un dispositivo o un usuario real."
|
msgstr "Si el usuario es un dispositivo o un usuario real."
|
||||||
|
|
||||||
#: core/models.py:198
|
#: core/models.py:210
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "estado del personal"
|
msgstr "estado del personal"
|
||||||
|
|
||||||
#: core/models.py:200
|
#: core/models.py:212
|
||||||
msgid "Whether the user can log into this admin site."
|
msgid "Whether the user can log into this admin site."
|
||||||
msgstr "Si el usuario puede acceder a este sitio de administración."
|
msgstr "Si el usuario puede acceder a este sitio de administración."
|
||||||
|
|
||||||
#: core/models.py:203
|
#: core/models.py:215
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "activo"
|
msgstr "activo"
|
||||||
|
|
||||||
#: core/models.py:206
|
#: core/models.py:218
|
||||||
msgid ""
|
msgid ""
|
||||||
"Whether this user should be treated as active. Unselect this instead of "
|
"Whether this user should be treated as active. Unselect this instead of "
|
||||||
"deleting accounts."
|
"deleting accounts."
|
||||||
msgstr "Si este usuario debe considerarse activo. Desmarca esta opción en lugar de eliminar cuentas."
|
msgstr ""
|
||||||
|
"Si este usuario debe considerarse activo. Desmarca esta opción en lugar de "
|
||||||
|
"eliminar cuentas."
|
||||||
|
|
||||||
#: core/models.py:219
|
#: core/models.py:231
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "usuario"
|
msgstr "usuario"
|
||||||
|
|
||||||
#: core/models.py:220
|
#: core/models.py:232
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr "usuarios"
|
msgstr "usuarios"
|
||||||
|
|
||||||
#: core/models.py:286
|
#: core/models.py:298
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
msgstr "Recurso"
|
msgstr "Recurso"
|
||||||
|
|
||||||
#: core/models.py:287
|
#: core/models.py:299
|
||||||
msgid "Resources"
|
msgid "Resources"
|
||||||
msgstr "Recursos"
|
msgstr "Recursos"
|
||||||
|
|
||||||
#: core/models.py:345
|
#: core/models.py:357
|
||||||
msgid "Resource access"
|
msgid "Resource access"
|
||||||
msgstr "Acceso a recursos"
|
msgstr "Acceso a recursos"
|
||||||
|
|
||||||
#: core/models.py:346
|
#: core/models.py:358
|
||||||
msgid "Resource accesses"
|
msgid "Resource accesses"
|
||||||
msgstr "Accesos a recursos"
|
msgstr "Accesos a recursos"
|
||||||
|
|
||||||
#: core/models.py:352
|
#: core/models.py:364
|
||||||
msgid "Resource access with this User and Resource already exists."
|
msgid "Resource access with this User and Resource already exists."
|
||||||
msgstr "Ya existe un acceso al recurso con este usuario y este recurso."
|
msgstr "Ya existe un acceso al recurso con este usuario y este recurso."
|
||||||
|
|
||||||
#: core/models.py:409
|
#: core/models.py:421
|
||||||
msgid "Visio room configuration"
|
msgid "Visio room configuration"
|
||||||
msgstr "Configuración de la videoconferencia"
|
msgstr "Configuración de la videoconferencia"
|
||||||
|
|
||||||
#: core/models.py:410
|
#: core/models.py:422
|
||||||
msgid "Values for Visio parameters to configure the room."
|
msgid "Values for Visio parameters to configure the room."
|
||||||
msgstr "Valores de los parámetros de videoconferencia para configurar la reunión."
|
msgstr ""
|
||||||
|
"Valores de los parámetros de videoconferencia para configurar la reunión."
|
||||||
|
|
||||||
#: core/models.py:417
|
#: core/models.py:429
|
||||||
msgid "Room PIN code"
|
msgid "Room PIN code"
|
||||||
msgstr "Código PIN de la reunión"
|
msgstr "Código PIN de la reunión"
|
||||||
|
|
||||||
#: core/models.py:418
|
#: core/models.py:430
|
||||||
msgid "Unique n-digit code that identifies this room in telephony mode."
|
msgid "Unique n-digit code that identifies this room in telephony mode."
|
||||||
msgstr "Código único de n dígitos que identifica esta reunión en modo telefónico."
|
msgstr ""
|
||||||
|
"Código único de n dígitos que identifica esta reunión en modo telefónico."
|
||||||
|
|
||||||
#: core/models.py:424 core/models.py:578
|
#: core/models.py:436 core/models.py:597
|
||||||
msgid "Room"
|
msgid "Room"
|
||||||
msgstr "Reunión"
|
msgstr "Reunión"
|
||||||
|
|
||||||
#: core/models.py:425
|
#: core/models.py:437
|
||||||
msgid "Rooms"
|
msgid "Rooms"
|
||||||
msgstr "Reuniones"
|
msgstr "Reuniones"
|
||||||
|
|
||||||
#: core/models.py:589
|
#: core/models.py:608
|
||||||
msgid "Worker ID"
|
msgid "Worker ID"
|
||||||
msgstr "ID del worker"
|
msgstr "ID del worker"
|
||||||
|
|
||||||
#: core/models.py:591
|
#: core/models.py:610
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter an identifier for the worker recording.This ID is retained even when "
|
"Enter an identifier for the worker recording.This ID is retained even when "
|
||||||
"the worker stops, allowing for easy tracking."
|
"the worker stops, allowing for easy tracking."
|
||||||
msgstr "Introduce un identificador para la grabación del worker. Este identificador se conserva incluso cuando el worker se detiene, lo que permite un seguimiento sencillo."
|
msgstr ""
|
||||||
|
"Introduce un identificador para la grabación del worker. Este identificador "
|
||||||
|
"se conserva incluso cuando el worker se detiene, lo que permite un "
|
||||||
|
"seguimiento sencillo."
|
||||||
|
|
||||||
#: core/models.py:599
|
#: core/models.py:618
|
||||||
msgid "Recording mode"
|
msgid "Recording mode"
|
||||||
msgstr "Modo de grabación"
|
msgstr "Modo de grabación"
|
||||||
|
|
||||||
#: core/models.py:600
|
#: core/models.py:619
|
||||||
msgid "Defines the mode of recording being called."
|
msgid "Defines the mode of recording being called."
|
||||||
msgstr "Define el modo de grabación a utilizar."
|
msgstr "Define el modo de grabación a utilizar."
|
||||||
|
|
||||||
#: core/models.py:605 core/models.py:606
|
#: core/models.py:624 core/models.py:625
|
||||||
msgid "Recording options"
|
msgid "Recording options"
|
||||||
msgstr "Opciones de grabación"
|
msgstr "Opciones de grabación"
|
||||||
|
|
||||||
#: core/models.py:613
|
#: core/models.py:632
|
||||||
msgid "External Process ID"
|
msgid "External Process ID"
|
||||||
msgstr "ID del proceso externo"
|
msgstr "ID del proceso externo"
|
||||||
|
|
||||||
#: core/models.py:614
|
#: core/models.py:633
|
||||||
msgid "ID of the external process associated with the recording."
|
msgid "ID of the external process associated with the recording."
|
||||||
msgstr "ID del proceso externo asociado a la grabación."
|
msgstr "ID del proceso externo asociado a la grabación."
|
||||||
|
|
||||||
#: core/models.py:620
|
#: core/models.py:639
|
||||||
msgid "Recording"
|
msgid "Recording"
|
||||||
msgstr "Grabación"
|
msgstr "Grabación"
|
||||||
|
|
||||||
#: core/models.py:621
|
#: core/models.py:640
|
||||||
msgid "Recordings"
|
msgid "Recordings"
|
||||||
msgstr "Grabaciones"
|
msgstr "Grabaciones"
|
||||||
|
|
||||||
#: core/models.py:731
|
#: core/models.py:750
|
||||||
msgid "Recording/user relation"
|
msgid "Recording/user relation"
|
||||||
msgstr "Relación grabación/usuario"
|
msgstr "Relación grabación/usuario"
|
||||||
|
|
||||||
#: core/models.py:732
|
#: core/models.py:751
|
||||||
msgid "Recording/user relations"
|
msgid "Recording/user relations"
|
||||||
msgstr "Relaciones grabación/usuario"
|
msgstr "Relaciones grabación/usuario"
|
||||||
|
|
||||||
#: core/models.py:738
|
#: core/models.py:757
|
||||||
msgid "This user is already in this recording."
|
msgid "This user is already in this recording."
|
||||||
msgstr "Este usuario ya está en esta grabación."
|
msgstr "Este usuario ya está en esta grabación."
|
||||||
|
|
||||||
#: core/models.py:744
|
#: core/models.py:763
|
||||||
msgid "This team is already in this recording."
|
msgid "This team is already in this recording."
|
||||||
msgstr "Este equipo ya está en esta grabación."
|
msgstr "Este equipo ya está en esta grabación."
|
||||||
|
|
||||||
#: core/models.py:750
|
#: core/models.py:769
|
||||||
msgid "Either user or team must be set, not both."
|
msgid "Either user or team must be set, not both."
|
||||||
msgstr "Debe definirse el usuario o el equipo, pero no ambos."
|
msgstr "Debe definirse el usuario o el equipo, pero no ambos."
|
||||||
|
|
||||||
#: core/models.py:767
|
#: core/models.py:786
|
||||||
msgid "Create rooms"
|
msgid "Create rooms"
|
||||||
msgstr "Crear reunión"
|
msgstr "Crear reunión"
|
||||||
|
|
||||||
#: core/models.py:768
|
#: core/models.py:787
|
||||||
msgid "List rooms"
|
msgid "List rooms"
|
||||||
msgstr "Listar reuniones"
|
msgstr "Listar reuniones"
|
||||||
|
|
||||||
#: core/models.py:769
|
#: core/models.py:788
|
||||||
msgid "Retrieve room details"
|
msgid "Retrieve room details"
|
||||||
msgstr "Ver los detalles de una reunión"
|
msgstr "Ver los detalles de una reunión"
|
||||||
|
|
||||||
#: core/models.py:770
|
#: core/models.py:789
|
||||||
msgid "Update rooms"
|
msgid "Update rooms"
|
||||||
msgstr "Actualizar las reuniones"
|
msgstr "Actualizar las reuniones"
|
||||||
|
|
||||||
#: core/models.py:771
|
#: core/models.py:790
|
||||||
msgid "Delete rooms"
|
msgid "Delete rooms"
|
||||||
msgstr "Eliminar las reuniones"
|
msgstr "Eliminar las reuniones"
|
||||||
|
|
||||||
#: core/models.py:784
|
#: core/models.py:803
|
||||||
msgid "Application name"
|
msgid "Application name"
|
||||||
msgstr "Nombre de la aplicación"
|
msgstr "Nombre de la aplicación"
|
||||||
|
|
||||||
#: core/models.py:785
|
#: core/models.py:804
|
||||||
msgid "Descriptive name for this application."
|
msgid "Descriptive name for this application."
|
||||||
msgstr "Nombre descriptivo de esta aplicación."
|
msgstr "Nombre descriptivo de esta aplicación."
|
||||||
|
|
||||||
#: core/models.py:795
|
#: core/models.py:814
|
||||||
msgid "Hashed on Save. Copy it now if this is a new secret."
|
msgid "Hashed on Save. Copy it now if this is a new secret."
|
||||||
msgstr "Se cifra al guardar. Cópialo ahora si se trata de un secreto nuevo."
|
msgstr "Se cifra al guardar. Cópialo ahora si se trata de un secreto nuevo."
|
||||||
|
|
||||||
#: core/models.py:806
|
#: core/models.py:825
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "Aplicación"
|
msgstr "Aplicación"
|
||||||
|
|
||||||
#: core/models.py:807
|
#: core/models.py:826
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Aplicaciones"
|
msgstr "Aplicaciones"
|
||||||
|
|
||||||
#: core/models.py:830
|
#: core/models.py:849
|
||||||
msgid "Enter a valid domain"
|
msgid "Enter a valid domain"
|
||||||
msgstr "Introduce un dominio válido"
|
msgstr "Introduce un dominio válido"
|
||||||
|
|
||||||
#: core/models.py:833
|
#: core/models.py:852
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Dominio"
|
msgstr "Dominio"
|
||||||
|
|
||||||
#: core/models.py:834
|
#: core/models.py:853
|
||||||
msgid "Email domain this application can act on behalf of."
|
msgid "Email domain this application can act on behalf of."
|
||||||
msgstr "Dominio de correo electrónico en cuyo nombre puede actuar esta aplicación."
|
msgstr ""
|
||||||
|
"Dominio de correo electrónico en cuyo nombre puede actuar esta aplicación."
|
||||||
|
|
||||||
#: core/models.py:846
|
#: core/models.py:865
|
||||||
msgid "Application domain"
|
msgid "Application domain"
|
||||||
msgstr "Dominio de aplicación"
|
msgstr "Dominio de aplicación"
|
||||||
|
|
||||||
#: core/models.py:847
|
#: core/models.py:866
|
||||||
msgid "Application domains"
|
msgid "Application domains"
|
||||||
msgstr "Dominios de aplicación"
|
msgstr "Dominios de aplicación"
|
||||||
|
|
||||||
#: core/models.py:865
|
#: core/models.py:884
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "Pendiente"
|
msgstr "Pendiente"
|
||||||
|
|
||||||
#: core/models.py:866
|
#: core/models.py:885
|
||||||
msgid "Analyzing"
|
msgid "Analyzing"
|
||||||
msgstr "Analizando"
|
msgstr "Analizando"
|
||||||
|
|
||||||
#: core/models.py:873
|
#: core/models.py:892
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
msgstr "Listo"
|
msgstr "Listo"
|
||||||
|
|
||||||
#: core/models.py:879
|
#: core/models.py:898
|
||||||
msgid "Background image"
|
msgid "Background image"
|
||||||
msgstr "Imagen de fondo"
|
msgstr "Imagen de fondo"
|
||||||
|
|
||||||
#: core/models.py:891
|
#: core/models.py:910
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "título"
|
msgstr "título"
|
||||||
|
|
||||||
#: core/models.py:915
|
#: core/models.py:934
|
||||||
msgid "Malware detection info when the analysis status is unsafe."
|
msgid "Malware detection info when the analysis status is unsafe."
|
||||||
msgstr "Información sobre la detección de malware cuando el estado del análisis no es seguro."
|
msgstr ""
|
||||||
|
"Información sobre la detección de malware cuando el estado del análisis no "
|
||||||
|
"es seguro."
|
||||||
|
|
||||||
#: core/models.py:920
|
#: core/models.py:939
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Archivo"
|
msgstr "Archivo"
|
||||||
|
|
||||||
#: core/models.py:921
|
#: core/models.py:940
|
||||||
msgid "Files"
|
msgid "Files"
|
||||||
msgstr "Archivos"
|
msgstr "Archivos"
|
||||||
|
|
||||||
#: core/models.py:1041
|
#: core/models.py:1060
|
||||||
msgid "This file is already hard deleted."
|
msgid "This file is already hard deleted."
|
||||||
msgstr "Este archivo ya se ha eliminado definitivamente."
|
msgstr "Este archivo ya se ha eliminado definitivamente."
|
||||||
|
|
||||||
#: core/models.py:1051
|
#: core/models.py:1070
|
||||||
msgid "To hard delete a file, it must first be soft deleted."
|
msgid "To hard delete a file, it must first be soft deleted."
|
||||||
msgstr "Para eliminar definitivamente un archivo, primero debe haberse marcado como eliminado."
|
msgstr ""
|
||||||
|
"Para eliminar definitivamente un archivo, primero debe haberse marcado como "
|
||||||
|
"eliminado."
|
||||||
|
|
||||||
#: core/recording/event/notification.py:123
|
#: core/recording/event/notification.py:124
|
||||||
msgid "Your recording is ready"
|
msgid "Your recording is ready"
|
||||||
msgstr "Tu grabación está lista"
|
msgstr "Tu grabación está lista"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:194
|
#: core/recording/event/notification.py:195
|
||||||
msgid "Transcription"
|
msgid "Transcription"
|
||||||
msgstr "Transcripción"
|
msgstr "Transcripción"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:204
|
#: core/recording/event/notification.py:206
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
||||||
msgstr "Reunión \"{room}\" del {room_recording_date} a las {room_recording_time}"
|
msgstr ""
|
||||||
|
"Reunión \"{room}\" del {room_recording_date} a las {room_recording_time}"
|
||||||
|
|
||||||
#: core/services/invitation.py:44
|
#: core/services/invitation.py:44
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
||||||
msgstr "Videollamada en curso: {sender.email} está esperando a que te conectes"
|
msgstr "Videollamada en curso: {sender.email} está esperando a que te conectes"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:159
|
#: core/templates/mail/html/invitation.html:151
|
||||||
#: core/templates/mail/html/screen_recording.html:159
|
#: core/templates/mail/html/screen_recording.html:151
|
||||||
#: core/templates/mail/text/invitation.txt:3
|
#: core/templates/mail/text/invitation.txt:4
|
||||||
#: core/templates/mail/text/screen_recording.txt:3
|
#: core/templates/mail/text/screen_recording.txt:4
|
||||||
msgid "Logo email"
|
msgid "Logo email"
|
||||||
msgstr "Logotipo del correo"
|
msgstr "Logotipo del correo"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:189
|
#: core/templates/mail/html/invitation.html:181
|
||||||
#: core/templates/mail/text/invitation.txt:5
|
#: core/templates/mail/text/invitation.txt:6
|
||||||
msgid "invites you to join an ongoing video call"
|
msgid "invites you to join an ongoing video call"
|
||||||
msgstr "te invita a unirte a una videollamada en curso"
|
msgstr "te invita a unirte a una videollamada en curso"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:200
|
#: core/templates/mail/html/invitation.html:192
|
||||||
#: core/templates/mail/text/invitation.txt:7
|
#: core/templates/mail/text/invitation.txt:8
|
||||||
msgid "JOIN THE CALL"
|
msgid "JOIN THE CALL"
|
||||||
msgstr "UNIRSE A LA LLAMADA"
|
msgstr "UNIRSE A LA LLAMADA"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:227
|
#: core/templates/mail/html/invitation.html:219
|
||||||
#: core/templates/mail/text/invitation.txt:13
|
#: core/templates/mail/text/invitation.txt:14
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you can't click the button, copy and paste the URL into your browser to "
|
"If you can't click the button, copy and paste the URL into your browser to "
|
||||||
"join the call."
|
"join the call."
|
||||||
msgstr "Si no puedes hacer clic en el botón, copia y pega la URL en tu navegador para unirte a la llamada."
|
msgstr ""
|
||||||
|
"Si no puedes hacer clic en el botón, copia y pega la URL en tu navegador "
|
||||||
|
"para unirte a la llamada."
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:235
|
#: core/templates/mail/html/invitation.html:227
|
||||||
#: core/templates/mail/text/invitation.txt:15
|
#: core/templates/mail/text/invitation.txt:16
|
||||||
msgid "Tips for a better experience:"
|
msgid "Tips for a better experience:"
|
||||||
msgstr "Consejos para una mejor experiencia:"
|
msgstr "Consejos para una mejor experiencia:"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:237
|
#: core/templates/mail/html/invitation.html:229
|
||||||
#: core/templates/mail/text/invitation.txt:17
|
#: core/templates/mail/text/invitation.txt:18
|
||||||
msgid "Use Chrome or Firefox for better call quality"
|
msgid "Use Chrome or Firefox for better call quality"
|
||||||
msgstr "Usa Chrome o Firefox para una mejor calidad de llamada"
|
msgstr "Usa Chrome o Firefox para una mejor calidad de llamada"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:238
|
#: core/templates/mail/html/invitation.html:230
|
||||||
#: core/templates/mail/text/invitation.txt:18
|
#: core/templates/mail/text/invitation.txt:19
|
||||||
msgid "Test your microphone and camera before joining"
|
msgid "Test your microphone and camera before joining"
|
||||||
msgstr "Prueba tu micrófono y tu cámara antes de unirte"
|
msgstr "Prueba tu micrófono y tu cámara antes de unirte"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:239
|
#: core/templates/mail/html/invitation.html:231
|
||||||
#: core/templates/mail/text/invitation.txt:19
|
#: core/templates/mail/text/invitation.txt:20
|
||||||
msgid "Make sure you have a stable internet connection"
|
msgid "Make sure you have a stable internet connection"
|
||||||
msgstr "Asegúrate de tener una conexión a internet estable"
|
msgstr "Asegúrate de tener una conexión a internet estable"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:248
|
#: core/templates/mail/html/invitation.html:240
|
||||||
#: core/templates/mail/html/screen_recording.html:245
|
#: core/templates/mail/html/screen_recording.html:237
|
||||||
#: core/templates/mail/text/invitation.txt:21
|
#: core/templates/mail/text/invitation.txt:22
|
||||||
#: core/templates/mail/text/screen_recording.txt:23
|
#: core/templates/mail/text/screen_recording.txt:24
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " Thank you for using %(brandname)s. "
|
msgid " Thank you for using %(brandname)s. "
|
||||||
msgstr " Gracias por usar %(brandname)s. "
|
msgstr " Gracias por usar %(brandname)s. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:188
|
#: core/templates/mail/html/invitation.html:271
|
||||||
#: core/templates/mail/text/screen_recording.txt:6
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"This mail has been sent to %(email)s by <a href=\"%(href)s\">%(name)s</a>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/html/screen_recording.html:180
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:7
|
||||||
msgid "Your recording is ready!"
|
msgid "Your recording is ready!"
|
||||||
msgstr "¡Tu grabación está lista!"
|
msgstr "¡Tu grabación está lista!"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
||||||
"%(recording_time)s is now ready to download. "
|
"%(recording_time)s is now ready to download. "
|
||||||
msgstr " Tu grabación de \"%(room_name)s\" del %(recording_date)s a las %(recording_time)s ya está lista para descargar. "
|
msgstr ""
|
||||||
|
" Tu grabación de \"%(room_name)s\" del %(recording_date)s a las "
|
||||||
|
"%(recording_time)s ya está lista para descargar. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " The recording will expire in %(days)s days. "
|
msgid " The recording will expire in %(days)s days. "
|
||||||
msgstr " La grabación caducará dentro de %(days)s días. "
|
msgstr " La grabación caducará dentro de %(days)s días. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:200
|
#: core/templates/mail/html/screen_recording.html:192
|
||||||
#: core/templates/mail/text/screen_recording.txt:9
|
#: core/templates/mail/text/screen_recording.txt:10
|
||||||
msgid ""
|
msgid ""
|
||||||
" Sharing the recording via link is not yet available. Only organizers can "
|
" Sharing the recording via link is not yet available. Only organizers can "
|
||||||
"download it. "
|
"download it. "
|
||||||
msgstr " Compartir la grabación mediante un enlace todavía no está disponible. Solo los organizadores pueden descargarla. "
|
msgstr ""
|
||||||
|
" Compartir la grabación mediante un enlace todavía no está disponible. Solo "
|
||||||
|
"los organizadores pueden descargarla. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:206
|
#: core/templates/mail/html/screen_recording.html:198
|
||||||
#: core/templates/mail/text/screen_recording.txt:11
|
#: core/templates/mail/text/screen_recording.txt:12
|
||||||
msgid "To keep this recording permanently:"
|
msgid "To keep this recording permanently:"
|
||||||
msgstr "Para conservar esta grabación de forma permanente:"
|
msgstr "Para conservar esta grabación de forma permanente:"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:208
|
#: core/templates/mail/html/screen_recording.html:200
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgstr "Haz clic en el enlace \"<a href=\"%(link)s\">Abrir</a>\" que aparece abajo "
|
msgstr ""
|
||||||
|
"Haz clic en el enlace \"<a href=\"%(link)s\">Abrir</a>\" que aparece abajo "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:209
|
#: core/templates/mail/html/screen_recording.html:201
|
||||||
#: core/templates/mail/text/screen_recording.txt:14
|
#: core/templates/mail/text/screen_recording.txt:15
|
||||||
msgid "Use the \"Download\" button in the interface "
|
msgid "Use the \"Download\" button in the interface "
|
||||||
msgstr "Usa el botón \"Descargar\" de la interfaz "
|
msgstr "Usa el botón \"Descargar\" de la interfaz "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:210
|
#: core/templates/mail/html/screen_recording.html:202
|
||||||
#: core/templates/mail/text/screen_recording.txt:15
|
#: core/templates/mail/text/screen_recording.txt:16
|
||||||
msgid "Save the file to your preferred location"
|
msgid "Save the file to your preferred location"
|
||||||
msgstr "Guarda el archivo en la ubicación que prefieras"
|
msgstr "Guarda el archivo en la ubicación que prefieras"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:221
|
#: core/templates/mail/html/screen_recording.html:213
|
||||||
#: core/templates/mail/text/screen_recording.txt:17
|
#: core/templates/mail/text/screen_recording.txt:18
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Abrir"
|
msgstr "Abrir"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:230
|
#: core/templates/mail/html/screen_recording.html:222
|
||||||
#: core/templates/mail/text/screen_recording.txt:19
|
#: core/templates/mail/text/screen_recording.txt:20
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" If you have any questions or need assistance, please contact our support "
|
" If you have any questions or need assistance, please contact our support "
|
||||||
"team at %(support_email)s. "
|
"team at %(support_email)s. "
|
||||||
msgstr " Si tienes alguna pregunta o necesitas ayuda, ponte en contacto con nuestro equipo de soporte en %(support_email)s. "
|
msgstr ""
|
||||||
|
" Si tienes alguna pregunta o necesitas ayuda, ponte en contacto con nuestro "
|
||||||
|
"equipo de soporte en %(support_email)s. "
|
||||||
|
|
||||||
#: core/templates/mail/text/screen_recording.txt:13
|
#: core/templates/mail/text/invitation.txt:24
|
||||||
|
#, python-format
|
||||||
|
msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:14
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Click the \"Open [%(link)s]\" link below "
|
msgid "Click the \"Open [%(link)s]\" link below "
|
||||||
msgstr "Haz clic en el enlace \"Abrir [%(link)s]\" que aparece abajo "
|
msgstr "Haz clic en el enlace \"Abrir [%(link)s]\" que aparece abajo "
|
||||||
|
|
||||||
#: meet/settings.py:228
|
#: meet/settings.py:238
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Inglés"
|
msgstr "Inglés"
|
||||||
|
|
||||||
#: meet/settings.py:229
|
#: meet/settings.py:239
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Francés"
|
msgstr "Francés"
|
||||||
|
|
||||||
#: meet/settings.py:230
|
#: meet/settings.py:240
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Neerlandés"
|
msgstr "Neerlandés"
|
||||||
|
|
||||||
#: meet/settings.py:231
|
#: meet/settings.py:241
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Alemán"
|
msgstr "Alemán"
|
||||||
|
|
||||||
#: meet/settings.py:233
|
#: meet/settings.py:242
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Español"
|
msgstr "Español"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-07-02 10:47+0000\n"
|
"POT-Creation-Date: 2026-09-02 22:52+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: antoine.lebaud@mail.numerique.gouv.fr\n"
|
"Last-Translator: antoine.lebaud@mail.numerique.gouv.fr\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -51,11 +51,11 @@ msgstr ""
|
|||||||
msgid "File preview"
|
msgid "File preview"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:300 core/admin.py:443
|
#: core/admin.py:300 core/admin.py:450
|
||||||
msgid "No owner"
|
msgid "No owner"
|
||||||
msgstr "Pas de propriétaire"
|
msgstr "Pas de propriétaire"
|
||||||
|
|
||||||
#: core/admin.py:303 core/admin.py:446
|
#: core/admin.py:303 core/admin.py:453
|
||||||
msgid "Multiple owners"
|
msgid "Multiple owners"
|
||||||
msgstr "Plusieurs propriétaires"
|
msgstr "Plusieurs propriétaires"
|
||||||
|
|
||||||
@@ -99,11 +99,11 @@ msgstr ""
|
|||||||
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
||||||
msgstr "%(count)s enregistrement(s) avec un statut inéligible ignoré(s)."
|
msgstr "%(count)s enregistrement(s) avec un statut inéligible ignoré(s)."
|
||||||
|
|
||||||
#: core/admin.py:510
|
#: core/admin.py:517
|
||||||
msgid "No scopes"
|
msgid "No scopes"
|
||||||
msgstr "Aucun scopes"
|
msgstr "Aucun scopes"
|
||||||
|
|
||||||
#: core/admin.py:512
|
#: core/admin.py:519
|
||||||
msgid "Scopes"
|
msgid "Scopes"
|
||||||
msgstr "Scopes"
|
msgstr "Scopes"
|
||||||
|
|
||||||
@@ -111,187 +111,203 @@ msgstr "Scopes"
|
|||||||
msgid "Creator is me"
|
msgid "Creator is me"
|
||||||
msgstr "Je suis le créateur"
|
msgstr "Je suis le créateur"
|
||||||
|
|
||||||
#: core/api/serializers.py:89
|
#: core/api/serializers.py:108
|
||||||
msgid "You must be administrator or owner of a room to add accesses to it."
|
msgid "You must be administrator or owner of a room to add accesses to it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous devez être administrateur ou propriétaire d'une salle pour y ajouter "
|
"Vous devez être administrateur ou propriétaire d'une salle pour y ajouter "
|
||||||
"des accès."
|
"des accès."
|
||||||
|
|
||||||
#: core/api/serializers.py:534
|
#: core/api/serializers.py:560
|
||||||
msgid "This file extension is not allowed."
|
msgid "This file extension is not allowed."
|
||||||
msgstr "Cette extension n'est pas autorisée"
|
msgstr "Cette extension n'est pas autorisée"
|
||||||
|
|
||||||
#: core/api/viewsets.py:1222
|
#: core/api/viewsets.py:1268
|
||||||
msgid "You have reached the maximum number of files for this type."
|
msgid "You have reached the maximum number of files for this type."
|
||||||
msgstr "Vous avez atteint le nombre maximum de fichiers de ce type"
|
msgstr "Vous avez atteint le nombre maximum de fichiers de ce type"
|
||||||
|
|
||||||
#: core/models.py:37
|
#: core/models.py:38
|
||||||
msgid "Member"
|
msgid "Member"
|
||||||
msgstr "Membre"
|
msgstr "Membre"
|
||||||
|
|
||||||
#: core/models.py:38
|
#: core/models.py:39
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "Administrateur"
|
msgstr "Administrateur"
|
||||||
|
|
||||||
#: core/models.py:39
|
#: core/models.py:40
|
||||||
msgid "Owner"
|
msgid "Owner"
|
||||||
msgstr "Propriétaire"
|
msgstr "Propriétaire"
|
||||||
|
|
||||||
#: core/models.py:55
|
#: core/models.py:56
|
||||||
msgid "Initiated"
|
msgid "Initiated"
|
||||||
msgstr "Initié"
|
msgstr "Initié"
|
||||||
|
|
||||||
#: core/models.py:56
|
#: core/models.py:57
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Actif"
|
msgstr "Actif"
|
||||||
|
|
||||||
#: core/models.py:57
|
#: core/models.py:58
|
||||||
msgid "Stopped"
|
msgid "Stopped"
|
||||||
msgstr "Arrêté"
|
msgstr "Arrêté"
|
||||||
|
|
||||||
#: core/models.py:58
|
#: core/models.py:59
|
||||||
msgid "Saved"
|
msgid "Saved"
|
||||||
msgstr "Enregistré"
|
msgstr "Enregistré"
|
||||||
|
|
||||||
#: core/models.py:59
|
#: core/models.py:60
|
||||||
msgid "Aborted"
|
msgid "Aborted"
|
||||||
msgstr "Abandonné"
|
msgstr "Abandonné"
|
||||||
|
|
||||||
#: core/models.py:60
|
#: core/models.py:61
|
||||||
msgid "Failed to Start"
|
msgid "Failed to Start"
|
||||||
msgstr "Échec au démarrage"
|
msgstr "Échec au démarrage"
|
||||||
|
|
||||||
#: core/models.py:61
|
#: core/models.py:62
|
||||||
msgid "Failed to Stop"
|
msgid "Failed to Stop"
|
||||||
msgstr "Échec à l'arrêt"
|
msgstr "Échec à l'arrêt"
|
||||||
|
|
||||||
#: core/models.py:62
|
#: core/models.py:63
|
||||||
msgid "Notification succeeded"
|
msgid "Notification succeeded"
|
||||||
msgstr "Notification réussie"
|
msgstr "Notification réussie"
|
||||||
|
|
||||||
#: core/models.py:65
|
#: core/models.py:66
|
||||||
msgid "External process successful"
|
msgid "External process successful"
|
||||||
msgstr "Traitement externe : succès"
|
msgstr "Traitement externe : succès"
|
||||||
|
|
||||||
#: core/models.py:67
|
#: core/models.py:68
|
||||||
msgid "External process failed"
|
msgid "External process failed"
|
||||||
msgstr "Traitement externe : erreur"
|
msgstr "Traitement externe : erreur"
|
||||||
|
|
||||||
#: core/models.py:96
|
#: core/models.py:97
|
||||||
msgid "SCREEN_RECORDING"
|
msgid "SCREEN_RECORDING"
|
||||||
msgstr "ENREGISTREMENT_ÉCRAN"
|
msgstr "ENREGISTREMENT_ÉCRAN"
|
||||||
|
|
||||||
#: core/models.py:97
|
#: core/models.py:98
|
||||||
msgid "TRANSCRIPT"
|
msgid "TRANSCRIPT"
|
||||||
msgstr "TRANSCRIPTION"
|
msgstr "TRANSCRIPTION"
|
||||||
|
|
||||||
#: core/models.py:103
|
#: core/models.py:104
|
||||||
msgid "Public Access"
|
msgid "Public Access"
|
||||||
msgstr "Accès public"
|
msgstr "Accès public"
|
||||||
|
|
||||||
#: core/models.py:104
|
#: core/models.py:105
|
||||||
msgid "Trusted Access"
|
msgid "Trusted Access"
|
||||||
msgstr "Accès de confiance"
|
msgstr "Accès de confiance"
|
||||||
|
|
||||||
#: core/models.py:105
|
#: core/models.py:106
|
||||||
msgid "Restricted Access"
|
msgid "Restricted Access"
|
||||||
msgstr "Accès restreint"
|
msgstr "Accès restreint"
|
||||||
|
|
||||||
#: core/models.py:117
|
#: core/models.py:118
|
||||||
msgid "id"
|
msgid "id"
|
||||||
msgstr "id"
|
msgstr "id"
|
||||||
|
|
||||||
#: core/models.py:118
|
#: core/models.py:119
|
||||||
msgid "primary key for the record as UUID"
|
msgid "primary key for the record as UUID"
|
||||||
msgstr "clé primaire pour l'enregistrement sous forme d'UUID"
|
msgstr "clé primaire pour l'enregistrement sous forme d'UUID"
|
||||||
|
|
||||||
#: core/models.py:124
|
#: core/models.py:125
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "créé le"
|
msgstr "créé le"
|
||||||
|
|
||||||
#: core/models.py:125
|
#: core/models.py:126
|
||||||
msgid "date and time at which a record was created"
|
msgid "date and time at which a record was created"
|
||||||
msgstr "date et heure auxquelles un enregistrement a été créé"
|
msgstr "date et heure auxquelles un enregistrement a été créé"
|
||||||
|
|
||||||
#: core/models.py:130
|
#: core/models.py:131
|
||||||
msgid "updated on"
|
msgid "updated on"
|
||||||
msgstr "mis à jour le"
|
msgstr "mis à jour le"
|
||||||
|
|
||||||
#: core/models.py:131
|
#: core/models.py:132
|
||||||
msgid "date and time at which a record was last updated"
|
msgid "date and time at which a record was last updated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"date et heure auxquelles un enregistrement a été mis à jour pour la dernière "
|
"date et heure auxquelles un enregistrement a été mis à jour pour la dernière "
|
||||||
"fois"
|
"fois"
|
||||||
|
|
||||||
#: core/models.py:151
|
#: core/models.py:150
|
||||||
msgid ""
|
|
||||||
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
|
|
||||||
"_ characters."
|
|
||||||
msgstr ""
|
|
||||||
"Entrez un sub valide. Cette valeur ne peut contenir que des lettres, des "
|
|
||||||
"chiffres et les caractères @/./+/-/_."
|
|
||||||
|
|
||||||
#: core/models.py:157
|
|
||||||
msgid "sub"
|
msgid "sub"
|
||||||
msgstr "sub"
|
msgstr "sub"
|
||||||
|
|
||||||
#: core/models.py:159
|
#: core/models.py:152
|
||||||
msgid ""
|
msgid ""
|
||||||
"Optional for pending users; required upon account activation. 255 characters "
|
"Optional for pending users; required upon account activation. 255 characters "
|
||||||
"or fewer. Letters, numbers, and @/./+/-/_ characters only."
|
"or fewer. Printable ASCII characters only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Optionnel pour les utilisateurs en attente ; requis lors de l'activation du "
|
"Facultatif pour les utilisateurs en attente ; obligatoire lors de l’activation "
|
||||||
"compte. 255 caractères maximum. Lettres, chiffres et @/./+/-/_ uniquement."
|
"du compte. 255 caractères maximum. Caractères ASCII imprimables uniquement."
|
||||||
|
|
||||||
#: core/models.py:168
|
#: core/validators.py:22
|
||||||
|
msgid "Enter a valid sub. This value should be printable ASCII only."
|
||||||
|
msgstr "Saisissez un sub valide. Cette valeur ne doit contenir que des caractères ASCII imprimables."
|
||||||
|
|
||||||
|
#: core/models.py:161
|
||||||
msgid "identity email address"
|
msgid "identity email address"
|
||||||
msgstr "adresse e-mail d'identité"
|
msgstr "adresse e-mail d'identité"
|
||||||
|
|
||||||
#: core/models.py:173
|
#: core/models.py:166
|
||||||
msgid "admin email address"
|
msgid "admin email address"
|
||||||
msgstr "adresse e-mail d'administrateur"
|
msgstr "adresse e-mail d'administrateur"
|
||||||
|
|
||||||
#: core/models.py:175
|
#: core/models.py:168
|
||||||
msgid "full name"
|
msgid "full name"
|
||||||
msgstr "nom complet"
|
msgstr "nom complet"
|
||||||
|
|
||||||
#: core/models.py:177
|
#: core/models.py:170
|
||||||
msgid "short name"
|
msgid "short name"
|
||||||
msgstr "nom court"
|
msgstr "nom court"
|
||||||
|
|
||||||
#: core/models.py:183
|
#: core/models.py:176
|
||||||
msgid "language"
|
msgid "language"
|
||||||
msgstr "langue"
|
msgstr "langue"
|
||||||
|
|
||||||
#: core/models.py:184
|
#: core/models.py:177
|
||||||
msgid "The language in which the user wants to see the interface."
|
msgid "The language in which the user wants to see the interface."
|
||||||
msgstr "La langue dans laquelle l'utilisateur souhaite voir l'interface."
|
msgstr "La langue dans laquelle l'utilisateur souhaite voir l'interface."
|
||||||
|
|
||||||
#: core/models.py:190
|
#: core/models.py:183
|
||||||
msgid "The timezone in which the user wants to see times."
|
msgid "The timezone in which the user wants to see times."
|
||||||
msgstr "Le fuseau horaire dans lequel l'utilisateur souhaite voir les heures."
|
msgstr "Le fuseau horaire dans lequel l'utilisateur souhaite voir les heures."
|
||||||
|
|
||||||
#: core/models.py:193
|
#: core/models.py:190
|
||||||
|
msgid "default room access level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:192
|
||||||
|
msgid ""
|
||||||
|
"Access level applied by default to new rooms created by this user. When "
|
||||||
|
"empty, the instance default is used."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:199
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Visio room configuration"
|
||||||
|
msgid "default room configuration"
|
||||||
|
msgstr "Configuration de la salle de visioconférence"
|
||||||
|
|
||||||
|
#: core/models.py:201
|
||||||
|
msgid "Configurations applied by default to new rooms created by this user."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:205
|
||||||
msgid "device"
|
msgid "device"
|
||||||
msgstr "appareil"
|
msgstr "appareil"
|
||||||
|
|
||||||
#: core/models.py:195
|
#: core/models.py:207
|
||||||
msgid "Whether the user is a device or a real user."
|
msgid "Whether the user is a device or a real user."
|
||||||
msgstr "Si l'utilisateur est un appareil ou un utilisateur réel."
|
msgstr "Si l'utilisateur est un appareil ou un utilisateur réel."
|
||||||
|
|
||||||
#: core/models.py:198
|
#: core/models.py:210
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "statut du personnel"
|
msgstr "statut du personnel"
|
||||||
|
|
||||||
#: core/models.py:200
|
#: core/models.py:212
|
||||||
msgid "Whether the user can log into this admin site."
|
msgid "Whether the user can log into this admin site."
|
||||||
msgstr "Si l'utilisateur peut se connecter à ce site d'administration."
|
msgstr "Si l'utilisateur peut se connecter à ce site d'administration."
|
||||||
|
|
||||||
#: core/models.py:203
|
#: core/models.py:215
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "actif"
|
msgstr "actif"
|
||||||
|
|
||||||
#: core/models.py:206
|
#: core/models.py:218
|
||||||
msgid ""
|
msgid ""
|
||||||
"Whether this user should be treated as active. Unselect this instead of "
|
"Whether this user should be treated as active. Unselect this instead of "
|
||||||
"deleting accounts."
|
"deleting accounts."
|
||||||
@@ -299,65 +315,65 @@ msgstr ""
|
|||||||
"Si cet utilisateur doit être traité comme actif. Désélectionnez cette option "
|
"Si cet utilisateur doit être traité comme actif. Désélectionnez cette option "
|
||||||
"au lieu de supprimer des comptes."
|
"au lieu de supprimer des comptes."
|
||||||
|
|
||||||
#: core/models.py:219
|
#: core/models.py:231
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "utilisateur"
|
msgstr "utilisateur"
|
||||||
|
|
||||||
#: core/models.py:220
|
#: core/models.py:232
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr "utilisateurs"
|
msgstr "utilisateurs"
|
||||||
|
|
||||||
#: core/models.py:286
|
#: core/models.py:298
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
msgstr "Ressource"
|
msgstr "Ressource"
|
||||||
|
|
||||||
#: core/models.py:287
|
#: core/models.py:299
|
||||||
msgid "Resources"
|
msgid "Resources"
|
||||||
msgstr "Ressources"
|
msgstr "Ressources"
|
||||||
|
|
||||||
#: core/models.py:345
|
#: core/models.py:357
|
||||||
msgid "Resource access"
|
msgid "Resource access"
|
||||||
msgstr "Accès aux ressources"
|
msgstr "Accès aux ressources"
|
||||||
|
|
||||||
#: core/models.py:346
|
#: core/models.py:358
|
||||||
msgid "Resource accesses"
|
msgid "Resource accesses"
|
||||||
msgstr "Accès aux ressources"
|
msgstr "Accès aux ressources"
|
||||||
|
|
||||||
#: core/models.py:352
|
#: core/models.py:364
|
||||||
msgid "Resource access with this User and Resource already exists."
|
msgid "Resource access with this User and Resource already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L'accès à la ressource avec cet utilisateur et cette ressource existe déjà."
|
"L'accès à la ressource avec cet utilisateur et cette ressource existe déjà."
|
||||||
|
|
||||||
#: core/models.py:409
|
#: core/models.py:421
|
||||||
msgid "Visio room configuration"
|
msgid "Visio room configuration"
|
||||||
msgstr "Configuration de la salle de visioconférence"
|
msgstr "Configuration de la salle de visioconférence"
|
||||||
|
|
||||||
#: core/models.py:410
|
#: core/models.py:422
|
||||||
msgid "Values for Visio parameters to configure the room."
|
msgid "Values for Visio parameters to configure the room."
|
||||||
msgstr "Valeurs des paramètres de visioconférence pour configurer la salle."
|
msgstr "Valeurs des paramètres de visioconférence pour configurer la salle."
|
||||||
|
|
||||||
#: core/models.py:417
|
#: core/models.py:429
|
||||||
msgid "Room PIN code"
|
msgid "Room PIN code"
|
||||||
msgstr "Code PIN de la salle"
|
msgstr "Code PIN de la salle"
|
||||||
|
|
||||||
#: core/models.py:418
|
#: core/models.py:430
|
||||||
msgid "Unique n-digit code that identifies this room in telephony mode."
|
msgid "Unique n-digit code that identifies this room in telephony mode."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Code unique à n chiffres qui identifie cette salle en mode téléphonique."
|
"Code unique à n chiffres qui identifie cette salle en mode téléphonique."
|
||||||
|
|
||||||
#: core/models.py:424 core/models.py:578
|
#: core/models.py:436 core/models.py:597
|
||||||
msgid "Room"
|
msgid "Room"
|
||||||
msgstr "Salle"
|
msgstr "Salle"
|
||||||
|
|
||||||
#: core/models.py:425
|
#: core/models.py:437
|
||||||
msgid "Rooms"
|
msgid "Rooms"
|
||||||
msgstr "Salles"
|
msgstr "Salles"
|
||||||
|
|
||||||
#: core/models.py:589
|
#: core/models.py:608
|
||||||
msgid "Worker ID"
|
msgid "Worker ID"
|
||||||
msgstr "ID du Worker"
|
msgstr "ID du Worker"
|
||||||
|
|
||||||
#: core/models.py:591
|
#: core/models.py:610
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter an identifier for the worker recording.This ID is retained even when "
|
"Enter an identifier for the worker recording.This ID is retained even when "
|
||||||
"the worker stops, allowing for easy tracking."
|
"the worker stops, allowing for easy tracking."
|
||||||
@@ -365,170 +381,170 @@ msgstr ""
|
|||||||
"Entrez un identifiant pour l'enregistrement du Worker. Cet identifiant est "
|
"Entrez un identifiant pour l'enregistrement du Worker. Cet identifiant est "
|
||||||
"conservé même lorsque le Worker s'arrête, permettant un suivi facile."
|
"conservé même lorsque le Worker s'arrête, permettant un suivi facile."
|
||||||
|
|
||||||
#: core/models.py:599
|
#: core/models.py:618
|
||||||
msgid "Recording mode"
|
msgid "Recording mode"
|
||||||
msgstr "Mode d'enregistrement"
|
msgstr "Mode d'enregistrement"
|
||||||
|
|
||||||
#: core/models.py:600
|
#: core/models.py:619
|
||||||
msgid "Defines the mode of recording being called."
|
msgid "Defines the mode of recording being called."
|
||||||
msgstr "Définit le mode d'enregistrement appelé."
|
msgstr "Définit le mode d'enregistrement appelé."
|
||||||
|
|
||||||
#: core/models.py:605 core/models.py:606
|
#: core/models.py:624 core/models.py:625
|
||||||
msgid "Recording options"
|
msgid "Recording options"
|
||||||
msgstr "Options d'enregistrement"
|
msgstr "Options d'enregistrement"
|
||||||
|
|
||||||
#: core/models.py:613
|
#: core/models.py:632
|
||||||
msgid "External Process ID"
|
msgid "External Process ID"
|
||||||
msgstr "ID Traitement externe"
|
msgstr "ID Traitement externe"
|
||||||
|
|
||||||
#: core/models.py:614
|
#: core/models.py:633
|
||||||
msgid "ID of the external process associated with the recording."
|
msgid "ID of the external process associated with the recording."
|
||||||
msgstr "ID du traitement externe associé avec l'enregistrement."
|
msgstr "ID du traitement externe associé avec l'enregistrement."
|
||||||
|
|
||||||
#: core/models.py:620
|
#: core/models.py:639
|
||||||
msgid "Recording"
|
msgid "Recording"
|
||||||
msgstr "Enregistrement"
|
msgstr "Enregistrement"
|
||||||
|
|
||||||
#: core/models.py:621
|
#: core/models.py:640
|
||||||
msgid "Recordings"
|
msgid "Recordings"
|
||||||
msgstr "Enregistrements"
|
msgstr "Enregistrements"
|
||||||
|
|
||||||
#: core/models.py:731
|
#: core/models.py:750
|
||||||
msgid "Recording/user relation"
|
msgid "Recording/user relation"
|
||||||
msgstr "Relation enregistrement/utilisateur"
|
msgstr "Relation enregistrement/utilisateur"
|
||||||
|
|
||||||
#: core/models.py:732
|
#: core/models.py:751
|
||||||
msgid "Recording/user relations"
|
msgid "Recording/user relations"
|
||||||
msgstr "Relations enregistrement/utilisateur"
|
msgstr "Relations enregistrement/utilisateur"
|
||||||
|
|
||||||
#: core/models.py:738
|
#: core/models.py:757
|
||||||
msgid "This user is already in this recording."
|
msgid "This user is already in this recording."
|
||||||
msgstr "Cet utilisateur est déjà dans cet enregistrement."
|
msgstr "Cet utilisateur est déjà dans cet enregistrement."
|
||||||
|
|
||||||
#: core/models.py:744
|
#: core/models.py:763
|
||||||
msgid "This team is already in this recording."
|
msgid "This team is already in this recording."
|
||||||
msgstr "Cette équipe est déjà dans cet enregistrement."
|
msgstr "Cette équipe est déjà dans cet enregistrement."
|
||||||
|
|
||||||
#: core/models.py:750
|
#: core/models.py:769
|
||||||
msgid "Either user or team must be set, not both."
|
msgid "Either user or team must be set, not both."
|
||||||
msgstr "Soit l'utilisateur, soit l'équipe doit être défini, pas les deux."
|
msgstr "Soit l'utilisateur, soit l'équipe doit être défini, pas les deux."
|
||||||
|
|
||||||
#: core/models.py:767
|
#: core/models.py:786
|
||||||
msgid "Create rooms"
|
msgid "Create rooms"
|
||||||
msgstr "Créer des salles"
|
msgstr "Créer des salles"
|
||||||
|
|
||||||
#: core/models.py:768
|
#: core/models.py:787
|
||||||
msgid "List rooms"
|
msgid "List rooms"
|
||||||
msgstr "Lister les salles"
|
msgstr "Lister les salles"
|
||||||
|
|
||||||
#: core/models.py:769
|
#: core/models.py:788
|
||||||
msgid "Retrieve room details"
|
msgid "Retrieve room details"
|
||||||
msgstr "Afficher les détails d’une salle"
|
msgstr "Afficher les détails d’une salle"
|
||||||
|
|
||||||
#: core/models.py:770
|
#: core/models.py:789
|
||||||
msgid "Update rooms"
|
msgid "Update rooms"
|
||||||
msgstr "Mettre à jour les salles"
|
msgstr "Mettre à jour les salles"
|
||||||
|
|
||||||
#: core/models.py:771
|
#: core/models.py:790
|
||||||
msgid "Delete rooms"
|
msgid "Delete rooms"
|
||||||
msgstr "Supprimer les salles"
|
msgstr "Supprimer les salles"
|
||||||
|
|
||||||
#: core/models.py:784
|
#: core/models.py:803
|
||||||
msgid "Application name"
|
msgid "Application name"
|
||||||
msgstr "Nom de l’application"
|
msgstr "Nom de l’application"
|
||||||
|
|
||||||
#: core/models.py:785
|
#: core/models.py:804
|
||||||
msgid "Descriptive name for this application."
|
msgid "Descriptive name for this application."
|
||||||
msgstr "Nom descriptif de cette application."
|
msgstr "Nom descriptif de cette application."
|
||||||
|
|
||||||
#: core/models.py:795
|
#: core/models.py:814
|
||||||
msgid "Hashed on Save. Copy it now if this is a new secret."
|
msgid "Hashed on Save. Copy it now if this is a new secret."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Haché lors de l’enregistrement. Copiez-le maintenant s’il s’agit d’un "
|
"Haché lors de l’enregistrement. Copiez-le maintenant s’il s’agit d’un "
|
||||||
"nouveau secret."
|
"nouveau secret."
|
||||||
|
|
||||||
#: core/models.py:806
|
#: core/models.py:825
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "Application"
|
msgstr "Application"
|
||||||
|
|
||||||
#: core/models.py:807
|
#: core/models.py:826
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Applications"
|
msgstr "Applications"
|
||||||
|
|
||||||
#: core/models.py:830
|
#: core/models.py:849
|
||||||
msgid "Enter a valid domain"
|
msgid "Enter a valid domain"
|
||||||
msgstr "Saisissez un domaine valide"
|
msgstr "Saisissez un domaine valide"
|
||||||
|
|
||||||
#: core/models.py:833
|
#: core/models.py:852
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Domaine"
|
msgstr "Domaine"
|
||||||
|
|
||||||
#: core/models.py:834
|
#: core/models.py:853
|
||||||
msgid "Email domain this application can act on behalf of."
|
msgid "Email domain this application can act on behalf of."
|
||||||
msgstr "Domaine de messagerie au nom duquel cette application peut agir."
|
msgstr "Domaine de messagerie au nom duquel cette application peut agir."
|
||||||
|
|
||||||
#: core/models.py:846
|
#: core/models.py:865
|
||||||
msgid "Application domain"
|
msgid "Application domain"
|
||||||
msgstr "Domaine d’application"
|
msgstr "Domaine d’application"
|
||||||
|
|
||||||
#: core/models.py:847
|
#: core/models.py:866
|
||||||
msgid "Application domains"
|
msgid "Application domains"
|
||||||
msgstr "Domaines d’application"
|
msgstr "Domaines d’application"
|
||||||
|
|
||||||
#: core/models.py:865
|
#: core/models.py:884
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "En attente"
|
msgstr "En attente"
|
||||||
|
|
||||||
#: core/models.py:866
|
#: core/models.py:885
|
||||||
msgid "Analyzing"
|
msgid "Analyzing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/models.py:873
|
#: core/models.py:892
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
msgstr "Prêt"
|
msgstr "Prêt"
|
||||||
|
|
||||||
#: core/models.py:879
|
#: core/models.py:898
|
||||||
msgid "Background image"
|
msgid "Background image"
|
||||||
msgstr "Image de fond"
|
msgstr "Image de fond"
|
||||||
|
|
||||||
#: core/models.py:891
|
#: core/models.py:910
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titre"
|
msgstr "Titre"
|
||||||
|
|
||||||
#: core/models.py:915
|
#: core/models.py:934
|
||||||
msgid "Malware detection info when the analysis status is unsafe."
|
msgid "Malware detection info when the analysis status is unsafe."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Information concernant la détection de Malware cand le statut n'est pas sain"
|
"Information concernant la détection de Malware cand le statut n'est pas sain"
|
||||||
|
|
||||||
#: core/models.py:920
|
#: core/models.py:939
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Fichier"
|
msgstr "Fichier"
|
||||||
|
|
||||||
#: core/models.py:921
|
#: core/models.py:940
|
||||||
msgid "Files"
|
msgid "Files"
|
||||||
msgstr "Fichiers"
|
msgstr "Fichiers"
|
||||||
|
|
||||||
#: core/models.py:1041
|
#: core/models.py:1060
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "This user is already in this recording."
|
#| msgid "This user is already in this recording."
|
||||||
msgid "This file is already hard deleted."
|
msgid "This file is already hard deleted."
|
||||||
msgstr "Ce fichier a été supprimé."
|
msgstr "Ce fichier a été supprimé."
|
||||||
|
|
||||||
#: core/models.py:1051
|
#: core/models.py:1070
|
||||||
msgid "To hard delete a file, it must first be soft deleted."
|
msgid "To hard delete a file, it must first be soft deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Pour supprimer définitivement un fichier il doit d'abord avoir été marqué "
|
"Pour supprimer définitivement un fichier il doit d'abord avoir été marqué "
|
||||||
"comme supprimé (soft delete)"
|
"comme supprimé (soft delete)"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:123
|
#: core/recording/event/notification.py:124
|
||||||
msgid "Your recording is ready"
|
msgid "Your recording is ready"
|
||||||
msgstr "Votre enregistrement est prêt"
|
msgstr "Votre enregistrement est prêt"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:194
|
#: core/recording/event/notification.py:195
|
||||||
msgid "Transcription"
|
msgid "Transcription"
|
||||||
msgstr "Transcription"
|
msgstr "Transcription"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:204
|
#: core/recording/event/notification.py:206
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
||||||
msgstr "Réunion \"{room}\" du {room_recording_date} à {room_recording_time}"
|
msgstr "Réunion \"{room}\" du {room_recording_date} à {room_recording_time}"
|
||||||
@@ -538,25 +554,25 @@ msgstr "Réunion \"{room}\" du {room_recording_date} à {room_recording_time}"
|
|||||||
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
||||||
msgstr "Appel vidéo en cours : {sender.email} attend que vous vous connectiez"
|
msgstr "Appel vidéo en cours : {sender.email} attend que vous vous connectiez"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:159
|
#: core/templates/mail/html/invitation.html:151
|
||||||
#: core/templates/mail/html/screen_recording.html:159
|
#: core/templates/mail/html/screen_recording.html:151
|
||||||
#: core/templates/mail/text/invitation.txt:3
|
#: core/templates/mail/text/invitation.txt:4
|
||||||
#: core/templates/mail/text/screen_recording.txt:3
|
#: core/templates/mail/text/screen_recording.txt:4
|
||||||
msgid "Logo email"
|
msgid "Logo email"
|
||||||
msgstr "Logo email"
|
msgstr "Logo email"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:189
|
#: core/templates/mail/html/invitation.html:181
|
||||||
#: core/templates/mail/text/invitation.txt:5
|
#: core/templates/mail/text/invitation.txt:6
|
||||||
msgid "invites you to join an ongoing video call"
|
msgid "invites you to join an ongoing video call"
|
||||||
msgstr "vous invite à rejoindre un appel vidéo en cours"
|
msgstr "vous invite à rejoindre un appel vidéo en cours"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:200
|
#: core/templates/mail/html/invitation.html:192
|
||||||
#: core/templates/mail/text/invitation.txt:7
|
#: core/templates/mail/text/invitation.txt:8
|
||||||
msgid "JOIN THE CALL"
|
msgid "JOIN THE CALL"
|
||||||
msgstr "REJOINDRE L'APPEL"
|
msgstr "REJOINDRE L'APPEL"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:227
|
#: core/templates/mail/html/invitation.html:219
|
||||||
#: core/templates/mail/text/invitation.txt:13
|
#: core/templates/mail/text/invitation.txt:14
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you can't click the button, copy and paste the URL into your browser to "
|
"If you can't click the button, copy and paste the URL into your browser to "
|
||||||
"join the call."
|
"join the call."
|
||||||
@@ -564,41 +580,47 @@ msgstr ""
|
|||||||
"Si vous ne pouvez pas cliquer sur le bouton, copiez et collez l'URL dans "
|
"Si vous ne pouvez pas cliquer sur le bouton, copiez et collez l'URL dans "
|
||||||
"votre navigateur pour rejoindre l'appel."
|
"votre navigateur pour rejoindre l'appel."
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:235
|
#: core/templates/mail/html/invitation.html:227
|
||||||
#: core/templates/mail/text/invitation.txt:15
|
#: core/templates/mail/text/invitation.txt:16
|
||||||
msgid "Tips for a better experience:"
|
msgid "Tips for a better experience:"
|
||||||
msgstr "Conseils pour une meilleure expérience :"
|
msgstr "Conseils pour une meilleure expérience :"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:237
|
#: core/templates/mail/html/invitation.html:229
|
||||||
#: core/templates/mail/text/invitation.txt:17
|
#: core/templates/mail/text/invitation.txt:18
|
||||||
msgid "Use Chrome or Firefox for better call quality"
|
msgid "Use Chrome or Firefox for better call quality"
|
||||||
msgstr "Utilisez Chrome ou Firefox pour une meilleure qualité d'appel"
|
msgstr "Utilisez Chrome ou Firefox pour une meilleure qualité d'appel"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:238
|
#: core/templates/mail/html/invitation.html:230
|
||||||
#: core/templates/mail/text/invitation.txt:18
|
#: core/templates/mail/text/invitation.txt:19
|
||||||
msgid "Test your microphone and camera before joining"
|
msgid "Test your microphone and camera before joining"
|
||||||
msgstr "Testez votre microphone et votre caméra avant de rejoindre"
|
msgstr "Testez votre microphone et votre caméra avant de rejoindre"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:239
|
#: core/templates/mail/html/invitation.html:231
|
||||||
#: core/templates/mail/text/invitation.txt:19
|
#: core/templates/mail/text/invitation.txt:20
|
||||||
msgid "Make sure you have a stable internet connection"
|
msgid "Make sure you have a stable internet connection"
|
||||||
msgstr "Assurez-vous d'avoir une connexion Internet stable"
|
msgstr "Assurez-vous d'avoir une connexion Internet stable"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:248
|
#: core/templates/mail/html/invitation.html:240
|
||||||
#: core/templates/mail/html/screen_recording.html:245
|
#: core/templates/mail/html/screen_recording.html:237
|
||||||
#: core/templates/mail/text/invitation.txt:21
|
#: core/templates/mail/text/invitation.txt:22
|
||||||
#: core/templates/mail/text/screen_recording.txt:23
|
#: core/templates/mail/text/screen_recording.txt:24
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " Thank you for using %(brandname)s. "
|
msgid " Thank you for using %(brandname)s. "
|
||||||
msgstr " Merci d'utiliser %(brandname)s. "
|
msgstr " Merci d'utiliser %(brandname)s. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:188
|
#: core/templates/mail/html/invitation.html:271
|
||||||
#: core/templates/mail/text/screen_recording.txt:6
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"This mail has been sent to %(email)s by <a href=\"%(href)s\">%(name)s</a>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/html/screen_recording.html:180
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:7
|
||||||
msgid "Your recording is ready!"
|
msgid "Your recording is ready!"
|
||||||
msgstr "Votre enregistrement est prêt !"
|
msgstr "Votre enregistrement est prêt !"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
||||||
@@ -607,14 +629,14 @@ msgstr ""
|
|||||||
" Votre enregistrement de \"%(room_name)s\" du %(recording_date)s à "
|
" Votre enregistrement de \"%(room_name)s\" du %(recording_date)s à "
|
||||||
"%(recording_time)s est maintenant prêt à être téléchargé. "
|
"%(recording_time)s est maintenant prêt à être téléchargé. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " The recording will expire in %(days)s days. "
|
msgid " The recording will expire in %(days)s days. "
|
||||||
msgstr " L'enregistrement expirera dans %(days)s jours. "
|
msgstr " L'enregistrement expirera dans %(days)s jours. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:200
|
#: core/templates/mail/html/screen_recording.html:192
|
||||||
#: core/templates/mail/text/screen_recording.txt:9
|
#: core/templates/mail/text/screen_recording.txt:10
|
||||||
msgid ""
|
msgid ""
|
||||||
" Sharing the recording via link is not yet available. Only organizers can "
|
" Sharing the recording via link is not yet available. Only organizers can "
|
||||||
"download it. "
|
"download it. "
|
||||||
@@ -622,33 +644,33 @@ msgstr ""
|
|||||||
"Le partage de l'enregistrement via lien n'est pas encore disponible. Seuls "
|
"Le partage de l'enregistrement via lien n'est pas encore disponible. Seuls "
|
||||||
"les organisateurs peuvent le télécharger."
|
"les organisateurs peuvent le télécharger."
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:206
|
#: core/templates/mail/html/screen_recording.html:198
|
||||||
#: core/templates/mail/text/screen_recording.txt:11
|
#: core/templates/mail/text/screen_recording.txt:12
|
||||||
msgid "To keep this recording permanently:"
|
msgid "To keep this recording permanently:"
|
||||||
msgstr "Pour conserver cet enregistrement de façon permanente :"
|
msgstr "Pour conserver cet enregistrement de façon permanente :"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:208
|
#: core/templates/mail/html/screen_recording.html:200
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgstr "Cliquez sur le lien \"<a href=\"%(link)s\">Ouvrir</a>\" ci-dessous "
|
msgstr "Cliquez sur le lien \"<a href=\"%(link)s\">Ouvrir</a>\" ci-dessous "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:209
|
#: core/templates/mail/html/screen_recording.html:201
|
||||||
#: core/templates/mail/text/screen_recording.txt:14
|
#: core/templates/mail/text/screen_recording.txt:15
|
||||||
msgid "Use the \"Download\" button in the interface "
|
msgid "Use the \"Download\" button in the interface "
|
||||||
msgstr "Utilisez le bouton \"Télécharger\" dans l'interface "
|
msgstr "Utilisez le bouton \"Télécharger\" dans l'interface "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:210
|
#: core/templates/mail/html/screen_recording.html:202
|
||||||
#: core/templates/mail/text/screen_recording.txt:15
|
#: core/templates/mail/text/screen_recording.txt:16
|
||||||
msgid "Save the file to your preferred location"
|
msgid "Save the file to your preferred location"
|
||||||
msgstr "Enregistrez le fichier à l'emplacement de votre choix"
|
msgstr "Enregistrez le fichier à l'emplacement de votre choix"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:221
|
#: core/templates/mail/html/screen_recording.html:213
|
||||||
#: core/templates/mail/text/screen_recording.txt:17
|
#: core/templates/mail/text/screen_recording.txt:18
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Ouvrir"
|
msgstr "Ouvrir"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:230
|
#: core/templates/mail/html/screen_recording.html:222
|
||||||
#: core/templates/mail/text/screen_recording.txt:19
|
#: core/templates/mail/text/screen_recording.txt:20
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" If you have any questions or need assistance, please contact our support "
|
" If you have any questions or need assistance, please contact our support "
|
||||||
@@ -657,28 +679,33 @@ msgstr ""
|
|||||||
" Si vous avez des questions ou besoin d'assistance, veuillez contacter notre "
|
" Si vous avez des questions ou besoin d'assistance, veuillez contacter notre "
|
||||||
"équipe d'assistance à %(support_email)s. "
|
"équipe d'assistance à %(support_email)s. "
|
||||||
|
|
||||||
#: core/templates/mail/text/screen_recording.txt:13
|
#: core/templates/mail/text/invitation.txt:24
|
||||||
|
#, python-format
|
||||||
|
msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:14
|
||||||
#, fuzzy, python-format
|
#, fuzzy, python-format
|
||||||
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgid "Click the \"Open [%(link)s]\" link below "
|
msgid "Click the \"Open [%(link)s]\" link below "
|
||||||
msgstr "Cliquez sur le lien \"<a href=\"%(link)s\">Ouvrir</a>\" ci-dessous "
|
msgstr "Cliquez sur le lien \"<a href=\"%(link)s\">Ouvrir</a>\" ci-dessous "
|
||||||
|
|
||||||
#: meet/settings.py:228
|
#: meet/settings.py:238
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Anglais"
|
msgstr "Anglais"
|
||||||
|
|
||||||
#: meet/settings.py:229
|
#: meet/settings.py:239
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Français"
|
msgstr "Français"
|
||||||
|
|
||||||
#: meet/settings.py:230
|
#: meet/settings.py:240
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Néerlandais"
|
msgstr "Néerlandais"
|
||||||
|
|
||||||
#: meet/settings.py:231
|
#: meet/settings.py:241
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Allemand"
|
msgstr "Allemand"
|
||||||
|
|
||||||
#: meet/settings.py:233
|
#: meet/settings.py:242
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Espagnol"
|
msgstr "Espagnol"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-07-02 10:47+0000\n"
|
"POT-Creation-Date: 2026-09-02 22:52+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -51,11 +51,11 @@ msgstr ""
|
|||||||
msgid "File preview"
|
msgid "File preview"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/admin.py:300 core/admin.py:443
|
#: core/admin.py:300 core/admin.py:450
|
||||||
msgid "No owner"
|
msgid "No owner"
|
||||||
msgstr "Geen eigenaar"
|
msgstr "Geen eigenaar"
|
||||||
|
|
||||||
#: core/admin.py:303 core/admin.py:446
|
#: core/admin.py:303 core/admin.py:453
|
||||||
msgid "Multiple owners"
|
msgid "Multiple owners"
|
||||||
msgstr "Meerdere eigenaren"
|
msgstr "Meerdere eigenaren"
|
||||||
|
|
||||||
@@ -98,11 +98,11 @@ msgstr "%(count)s opname(s) succesvol gemarkeerd als 'Mislukt bij stoppen'."
|
|||||||
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
msgid "Skipped %(count)s recording(s) with an ineligible status."
|
||||||
msgstr "%(count)s opname(s) met een niet-toegestane status overgeslagen."
|
msgstr "%(count)s opname(s) met een niet-toegestane status overgeslagen."
|
||||||
|
|
||||||
#: core/admin.py:510
|
#: core/admin.py:517
|
||||||
msgid "No scopes"
|
msgid "No scopes"
|
||||||
msgstr "Geen scopes"
|
msgstr "Geen scopes"
|
||||||
|
|
||||||
#: core/admin.py:512
|
#: core/admin.py:519
|
||||||
msgid "Scopes"
|
msgid "Scopes"
|
||||||
msgstr "Scopes"
|
msgstr "Scopes"
|
||||||
|
|
||||||
@@ -110,184 +110,200 @@ msgstr "Scopes"
|
|||||||
msgid "Creator is me"
|
msgid "Creator is me"
|
||||||
msgstr "Maker ben ik"
|
msgstr "Maker ben ik"
|
||||||
|
|
||||||
#: core/api/serializers.py:89
|
#: core/api/serializers.py:108
|
||||||
msgid "You must be administrator or owner of a room to add accesses to it."
|
msgid "You must be administrator or owner of a room to add accesses to it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Je moet beheerder of eigenaar van een ruimte zijn om toegang toe te voegen."
|
"Je moet beheerder of eigenaar van een ruimte zijn om toegang toe te voegen."
|
||||||
|
|
||||||
#: core/api/serializers.py:534
|
#: core/api/serializers.py:560
|
||||||
msgid "This file extension is not allowed."
|
msgid "This file extension is not allowed."
|
||||||
msgstr "Deze bestandsextensie is niet toegestaan."
|
msgstr "Deze bestandsextensie is niet toegestaan."
|
||||||
|
|
||||||
#: core/api/viewsets.py:1222
|
#: core/api/viewsets.py:1268
|
||||||
msgid "You have reached the maximum number of files for this type."
|
msgid "You have reached the maximum number of files for this type."
|
||||||
msgstr "Het maximale aantal bestanden voor dit type is bereikt."
|
msgstr "Het maximale aantal bestanden voor dit type is bereikt."
|
||||||
|
|
||||||
#: core/models.py:37
|
#: core/models.py:38
|
||||||
msgid "Member"
|
msgid "Member"
|
||||||
msgstr "Lid"
|
msgstr "Lid"
|
||||||
|
|
||||||
#: core/models.py:38
|
#: core/models.py:39
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "Beheerder"
|
msgstr "Beheerder"
|
||||||
|
|
||||||
#: core/models.py:39
|
#: core/models.py:40
|
||||||
msgid "Owner"
|
msgid "Owner"
|
||||||
msgstr "Eigenaar"
|
msgstr "Eigenaar"
|
||||||
|
|
||||||
#: core/models.py:55
|
#: core/models.py:56
|
||||||
msgid "Initiated"
|
msgid "Initiated"
|
||||||
msgstr "Gestart"
|
msgstr "Gestart"
|
||||||
|
|
||||||
#: core/models.py:56
|
#: core/models.py:57
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "Actief"
|
msgstr "Actief"
|
||||||
|
|
||||||
#: core/models.py:57
|
#: core/models.py:58
|
||||||
msgid "Stopped"
|
msgid "Stopped"
|
||||||
msgstr "Gestopt"
|
msgstr "Gestopt"
|
||||||
|
|
||||||
#: core/models.py:58
|
#: core/models.py:59
|
||||||
msgid "Saved"
|
msgid "Saved"
|
||||||
msgstr "Opgeslagen"
|
msgstr "Opgeslagen"
|
||||||
|
|
||||||
#: core/models.py:59
|
#: core/models.py:60
|
||||||
msgid "Aborted"
|
msgid "Aborted"
|
||||||
msgstr "Afgebroken"
|
msgstr "Afgebroken"
|
||||||
|
|
||||||
#: core/models.py:60
|
#: core/models.py:61
|
||||||
msgid "Failed to Start"
|
msgid "Failed to Start"
|
||||||
msgstr "Starten mislukt"
|
msgstr "Starten mislukt"
|
||||||
|
|
||||||
#: core/models.py:61
|
#: core/models.py:62
|
||||||
msgid "Failed to Stop"
|
msgid "Failed to Stop"
|
||||||
msgstr "Stoppen mislukt"
|
msgstr "Stoppen mislukt"
|
||||||
|
|
||||||
#: core/models.py:62
|
#: core/models.py:63
|
||||||
msgid "Notification succeeded"
|
msgid "Notification succeeded"
|
||||||
msgstr "Notificatie geslaagd"
|
msgstr "Notificatie geslaagd"
|
||||||
|
|
||||||
#: core/models.py:65
|
#: core/models.py:66
|
||||||
msgid "External process successful"
|
msgid "External process successful"
|
||||||
msgstr "Externe procedure succesvol"
|
msgstr "Externe procedure succesvol"
|
||||||
|
|
||||||
#: core/models.py:67
|
#: core/models.py:68
|
||||||
msgid "External process failed"
|
msgid "External process failed"
|
||||||
msgstr "Het externe proces is mislukt."
|
msgstr "Het externe proces is mislukt."
|
||||||
|
|
||||||
#: core/models.py:96
|
#: core/models.py:97
|
||||||
msgid "SCREEN_RECORDING"
|
msgid "SCREEN_RECORDING"
|
||||||
msgstr "SCHERM_OPNAME"
|
msgstr "SCHERM_OPNAME"
|
||||||
|
|
||||||
#: core/models.py:97
|
#: core/models.py:98
|
||||||
msgid "TRANSCRIPT"
|
msgid "TRANSCRIPT"
|
||||||
msgstr "TRANSCRIPT"
|
msgstr "TRANSCRIPT"
|
||||||
|
|
||||||
#: core/models.py:103
|
#: core/models.py:104
|
||||||
msgid "Public Access"
|
msgid "Public Access"
|
||||||
msgstr "Openbare toegang"
|
msgstr "Openbare toegang"
|
||||||
|
|
||||||
#: core/models.py:104
|
#: core/models.py:105
|
||||||
msgid "Trusted Access"
|
msgid "Trusted Access"
|
||||||
msgstr "Vertrouwde toegang"
|
msgstr "Vertrouwde toegang"
|
||||||
|
|
||||||
#: core/models.py:105
|
#: core/models.py:106
|
||||||
msgid "Restricted Access"
|
msgid "Restricted Access"
|
||||||
msgstr "Beperkte toegang"
|
msgstr "Beperkte toegang"
|
||||||
|
|
||||||
#: core/models.py:117
|
#: core/models.py:118
|
||||||
msgid "id"
|
msgid "id"
|
||||||
msgstr "id"
|
msgstr "id"
|
||||||
|
|
||||||
#: core/models.py:118
|
#: core/models.py:119
|
||||||
msgid "primary key for the record as UUID"
|
msgid "primary key for the record as UUID"
|
||||||
msgstr "primaire sleutel voor het record als UUID"
|
msgstr "primaire sleutel voor het record als UUID"
|
||||||
|
|
||||||
#: core/models.py:124
|
#: core/models.py:125
|
||||||
msgid "created on"
|
msgid "created on"
|
||||||
msgstr "aangemaakt op"
|
msgstr "aangemaakt op"
|
||||||
|
|
||||||
#: core/models.py:125
|
#: core/models.py:126
|
||||||
msgid "date and time at which a record was created"
|
msgid "date and time at which a record was created"
|
||||||
msgstr "datum en tijd waarop een record werd aangemaakt"
|
msgstr "datum en tijd waarop een record werd aangemaakt"
|
||||||
|
|
||||||
#: core/models.py:130
|
#: core/models.py:131
|
||||||
msgid "updated on"
|
msgid "updated on"
|
||||||
msgstr "bijgewerkt op"
|
msgstr "bijgewerkt op"
|
||||||
|
|
||||||
#: core/models.py:131
|
#: core/models.py:132
|
||||||
msgid "date and time at which a record was last updated"
|
msgid "date and time at which a record was last updated"
|
||||||
msgstr "datum en tijd waarop een record voor het laatst werd bijgewerkt"
|
msgstr "datum en tijd waarop een record voor het laatst werd bijgewerkt"
|
||||||
|
|
||||||
#: core/models.py:151
|
#: core/models.py:150
|
||||||
msgid ""
|
|
||||||
"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
|
|
||||||
"_ characters."
|
|
||||||
msgstr ""
|
|
||||||
"Voer een geldige sub in. Deze waarde mag alleen letters, cijfers en @/./+/-/"
|
|
||||||
"_ tekens bevatten."
|
|
||||||
|
|
||||||
#: core/models.py:157
|
|
||||||
msgid "sub"
|
msgid "sub"
|
||||||
msgstr "sub"
|
msgstr "sub"
|
||||||
|
|
||||||
#: core/models.py:159
|
#: core/models.py:152
|
||||||
msgid ""
|
msgid ""
|
||||||
"Optional for pending users; required upon account activation. 255 characters "
|
"Optional for pending users; required upon account activation. 255 characters "
|
||||||
"or fewer. Letters, numbers, and @/./+/-/_ characters only."
|
"or fewer. Printable ASCII characters only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Optioneel voor gebruikers in afwachting; vereist bij accountactivering. "
|
"Optioneel voor gebruikers in afwachting; verplicht bij het activeren van het "
|
||||||
"Maximum 255 tekens. Alleen letters, cijfers en @/./+/-/_ toegestaan."
|
"account. Maximaal 255 tekens. Alleen afdrukbare ASCII-tekens."
|
||||||
|
|
||||||
#: core/models.py:168
|
#: core/validators.py:22
|
||||||
|
msgid "Enter a valid sub. This value should be printable ASCII only."
|
||||||
|
msgstr "Voer een geldige sub in. Deze waarde mag alleen afdrukbare ASCII-tekens bevatten."
|
||||||
|
|
||||||
|
#: core/models.py:161
|
||||||
msgid "identity email address"
|
msgid "identity email address"
|
||||||
msgstr "identiteit e-mailadres"
|
msgstr "identiteit e-mailadres"
|
||||||
|
|
||||||
#: core/models.py:173
|
#: core/models.py:166
|
||||||
msgid "admin email address"
|
msgid "admin email address"
|
||||||
msgstr "beheerder e-mailadres"
|
msgstr "beheerder e-mailadres"
|
||||||
|
|
||||||
#: core/models.py:175
|
#: core/models.py:168
|
||||||
msgid "full name"
|
msgid "full name"
|
||||||
msgstr "volledige naam"
|
msgstr "volledige naam"
|
||||||
|
|
||||||
#: core/models.py:177
|
#: core/models.py:170
|
||||||
msgid "short name"
|
msgid "short name"
|
||||||
msgstr "korte naam"
|
msgstr "korte naam"
|
||||||
|
|
||||||
#: core/models.py:183
|
#: core/models.py:176
|
||||||
msgid "language"
|
msgid "language"
|
||||||
msgstr "taal"
|
msgstr "taal"
|
||||||
|
|
||||||
#: core/models.py:184
|
#: core/models.py:177
|
||||||
msgid "The language in which the user wants to see the interface."
|
msgid "The language in which the user wants to see the interface."
|
||||||
msgstr "De taal waarin de gebruiker de interface wil zien."
|
msgstr "De taal waarin de gebruiker de interface wil zien."
|
||||||
|
|
||||||
#: core/models.py:190
|
#: core/models.py:183
|
||||||
msgid "The timezone in which the user wants to see times."
|
msgid "The timezone in which the user wants to see times."
|
||||||
msgstr "De tijdzone waarin de gebruiker tijden wil zien."
|
msgstr "De tijdzone waarin de gebruiker tijden wil zien."
|
||||||
|
|
||||||
#: core/models.py:193
|
#: core/models.py:190
|
||||||
|
msgid "default room access level"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:192
|
||||||
|
msgid ""
|
||||||
|
"Access level applied by default to new rooms created by this user. When "
|
||||||
|
"empty, the instance default is used."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:199
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Visio room configuration"
|
||||||
|
msgid "default room configuration"
|
||||||
|
msgstr "Visio-ruimteconfiguratie"
|
||||||
|
|
||||||
|
#: core/models.py:201
|
||||||
|
msgid "Configurations applied by default to new rooms created by this user."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/models.py:205
|
||||||
msgid "device"
|
msgid "device"
|
||||||
msgstr "apparaat"
|
msgstr "apparaat"
|
||||||
|
|
||||||
#: core/models.py:195
|
#: core/models.py:207
|
||||||
msgid "Whether the user is a device or a real user."
|
msgid "Whether the user is a device or a real user."
|
||||||
msgstr "Of de gebruiker een apparaat is of een echte gebruiker."
|
msgstr "Of de gebruiker een apparaat is of een echte gebruiker."
|
||||||
|
|
||||||
#: core/models.py:198
|
#: core/models.py:210
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "personeelsstatus"
|
msgstr "personeelsstatus"
|
||||||
|
|
||||||
#: core/models.py:200
|
#: core/models.py:212
|
||||||
msgid "Whether the user can log into this admin site."
|
msgid "Whether the user can log into this admin site."
|
||||||
msgstr "Of de gebruiker kan inloggen op deze beheersite."
|
msgstr "Of de gebruiker kan inloggen op deze beheersite."
|
||||||
|
|
||||||
#: core/models.py:203
|
#: core/models.py:215
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "actief"
|
msgstr "actief"
|
||||||
|
|
||||||
#: core/models.py:206
|
#: core/models.py:218
|
||||||
msgid ""
|
msgid ""
|
||||||
"Whether this user should be treated as active. Unselect this instead of "
|
"Whether this user should be treated as active. Unselect this instead of "
|
||||||
"deleting accounts."
|
"deleting accounts."
|
||||||
@@ -295,64 +311,64 @@ msgstr ""
|
|||||||
"Of deze gebruiker als actief moet worden behandeld. Deselecteer dit in "
|
"Of deze gebruiker als actief moet worden behandeld. Deselecteer dit in "
|
||||||
"plaats van accounts te verwijderen."
|
"plaats van accounts te verwijderen."
|
||||||
|
|
||||||
#: core/models.py:219
|
#: core/models.py:231
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "gebruiker"
|
msgstr "gebruiker"
|
||||||
|
|
||||||
#: core/models.py:220
|
#: core/models.py:232
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr "gebruikers"
|
msgstr "gebruikers"
|
||||||
|
|
||||||
#: core/models.py:286
|
#: core/models.py:298
|
||||||
msgid "Resource"
|
msgid "Resource"
|
||||||
msgstr "Bron"
|
msgstr "Bron"
|
||||||
|
|
||||||
#: core/models.py:287
|
#: core/models.py:299
|
||||||
msgid "Resources"
|
msgid "Resources"
|
||||||
msgstr "Bronnen"
|
msgstr "Bronnen"
|
||||||
|
|
||||||
#: core/models.py:345
|
#: core/models.py:357
|
||||||
msgid "Resource access"
|
msgid "Resource access"
|
||||||
msgstr "Brontoegang"
|
msgstr "Brontoegang"
|
||||||
|
|
||||||
#: core/models.py:346
|
#: core/models.py:358
|
||||||
msgid "Resource accesses"
|
msgid "Resource accesses"
|
||||||
msgstr "Brontoegangsrechten"
|
msgstr "Brontoegangsrechten"
|
||||||
|
|
||||||
#: core/models.py:352
|
#: core/models.py:364
|
||||||
msgid "Resource access with this User and Resource already exists."
|
msgid "Resource access with this User and Resource already exists."
|
||||||
msgstr "Brontoegang met deze gebruiker en bron bestaat al."
|
msgstr "Brontoegang met deze gebruiker en bron bestaat al."
|
||||||
|
|
||||||
#: core/models.py:409
|
#: core/models.py:421
|
||||||
msgid "Visio room configuration"
|
msgid "Visio room configuration"
|
||||||
msgstr "Visio-ruimteconfiguratie"
|
msgstr "Visio-ruimteconfiguratie"
|
||||||
|
|
||||||
#: core/models.py:410
|
#: core/models.py:422
|
||||||
msgid "Values for Visio parameters to configure the room."
|
msgid "Values for Visio parameters to configure the room."
|
||||||
msgstr "Waarden voor Visio-parameters om de ruimte te configureren."
|
msgstr "Waarden voor Visio-parameters om de ruimte te configureren."
|
||||||
|
|
||||||
#: core/models.py:417
|
#: core/models.py:429
|
||||||
msgid "Room PIN code"
|
msgid "Room PIN code"
|
||||||
msgstr "Pincode van de kamer"
|
msgstr "Pincode van de kamer"
|
||||||
|
|
||||||
#: core/models.py:418
|
#: core/models.py:430
|
||||||
msgid "Unique n-digit code that identifies this room in telephony mode."
|
msgid "Unique n-digit code that identifies this room in telephony mode."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Unieke n-cijferige code die deze kamer identificeert in telefonie-modus."
|
"Unieke n-cijferige code die deze kamer identificeert in telefonie-modus."
|
||||||
|
|
||||||
#: core/models.py:424 core/models.py:578
|
#: core/models.py:436 core/models.py:597
|
||||||
msgid "Room"
|
msgid "Room"
|
||||||
msgstr "Ruimte"
|
msgstr "Ruimte"
|
||||||
|
|
||||||
#: core/models.py:425
|
#: core/models.py:437
|
||||||
msgid "Rooms"
|
msgid "Rooms"
|
||||||
msgstr "Ruimtes"
|
msgstr "Ruimtes"
|
||||||
|
|
||||||
#: core/models.py:589
|
#: core/models.py:608
|
||||||
msgid "Worker ID"
|
msgid "Worker ID"
|
||||||
msgstr "Worker ID"
|
msgstr "Worker ID"
|
||||||
|
|
||||||
#: core/models.py:591
|
#: core/models.py:610
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter an identifier for the worker recording.This ID is retained even when "
|
"Enter an identifier for the worker recording.This ID is retained even when "
|
||||||
"the worker stops, allowing for easy tracking."
|
"the worker stops, allowing for easy tracking."
|
||||||
@@ -360,152 +376,152 @@ msgstr ""
|
|||||||
"Voer een identificatie in voor de worker-opname. Deze ID blijft behouden, "
|
"Voer een identificatie in voor de worker-opname. Deze ID blijft behouden, "
|
||||||
"zelfs wanneer de worker stopt, waardoor eenvoudige tracking mogelijk is."
|
"zelfs wanneer de worker stopt, waardoor eenvoudige tracking mogelijk is."
|
||||||
|
|
||||||
#: core/models.py:599
|
#: core/models.py:618
|
||||||
msgid "Recording mode"
|
msgid "Recording mode"
|
||||||
msgstr "Opnamemodus"
|
msgstr "Opnamemodus"
|
||||||
|
|
||||||
#: core/models.py:600
|
#: core/models.py:619
|
||||||
msgid "Defines the mode of recording being called."
|
msgid "Defines the mode of recording being called."
|
||||||
msgstr "Definieert de modus van opname die wordt aangeroepen."
|
msgstr "Definieert de modus van opname die wordt aangeroepen."
|
||||||
|
|
||||||
#: core/models.py:605 core/models.py:606
|
#: core/models.py:624 core/models.py:625
|
||||||
msgid "Recording options"
|
msgid "Recording options"
|
||||||
msgstr "Opnameopties"
|
msgstr "Opnameopties"
|
||||||
|
|
||||||
#: core/models.py:613
|
#: core/models.py:632
|
||||||
msgid "External Process ID"
|
msgid "External Process ID"
|
||||||
msgstr "Externe proces-ID"
|
msgstr "Externe proces-ID"
|
||||||
|
|
||||||
#: core/models.py:614
|
#: core/models.py:633
|
||||||
msgid "ID of the external process associated with the recording."
|
msgid "ID of the external process associated with the recording."
|
||||||
msgstr "ID van het externe proces dat aan de opname is gekoppeld."
|
msgstr "ID van het externe proces dat aan de opname is gekoppeld."
|
||||||
|
|
||||||
#: core/models.py:620
|
#: core/models.py:639
|
||||||
msgid "Recording"
|
msgid "Recording"
|
||||||
msgstr "Opname"
|
msgstr "Opname"
|
||||||
|
|
||||||
#: core/models.py:621
|
#: core/models.py:640
|
||||||
msgid "Recordings"
|
msgid "Recordings"
|
||||||
msgstr "Opnames"
|
msgstr "Opnames"
|
||||||
|
|
||||||
#: core/models.py:731
|
#: core/models.py:750
|
||||||
msgid "Recording/user relation"
|
msgid "Recording/user relation"
|
||||||
msgstr "Opname/gebruiker-relatie"
|
msgstr "Opname/gebruiker-relatie"
|
||||||
|
|
||||||
#: core/models.py:732
|
#: core/models.py:751
|
||||||
msgid "Recording/user relations"
|
msgid "Recording/user relations"
|
||||||
msgstr "Opname/gebruiker-relaties"
|
msgstr "Opname/gebruiker-relaties"
|
||||||
|
|
||||||
#: core/models.py:738
|
#: core/models.py:757
|
||||||
msgid "This user is already in this recording."
|
msgid "This user is already in this recording."
|
||||||
msgstr "Deze gebruiker is al in deze opname."
|
msgstr "Deze gebruiker is al in deze opname."
|
||||||
|
|
||||||
#: core/models.py:744
|
#: core/models.py:763
|
||||||
msgid "This team is already in this recording."
|
msgid "This team is already in this recording."
|
||||||
msgstr "Dit team is al in deze opname."
|
msgstr "Dit team is al in deze opname."
|
||||||
|
|
||||||
#: core/models.py:750
|
#: core/models.py:769
|
||||||
msgid "Either user or team must be set, not both."
|
msgid "Either user or team must be set, not both."
|
||||||
msgstr "Ofwel gebruiker of team moet worden ingesteld, niet beide."
|
msgstr "Ofwel gebruiker of team moet worden ingesteld, niet beide."
|
||||||
|
|
||||||
#: core/models.py:767
|
#: core/models.py:786
|
||||||
msgid "Create rooms"
|
msgid "Create rooms"
|
||||||
msgstr "Ruimtes aanmaken"
|
msgstr "Ruimtes aanmaken"
|
||||||
|
|
||||||
#: core/models.py:768
|
#: core/models.py:787
|
||||||
msgid "List rooms"
|
msgid "List rooms"
|
||||||
msgstr "Ruimtes weergeven"
|
msgstr "Ruimtes weergeven"
|
||||||
|
|
||||||
#: core/models.py:769
|
#: core/models.py:788
|
||||||
msgid "Retrieve room details"
|
msgid "Retrieve room details"
|
||||||
msgstr "Details van een ruimte ophalen"
|
msgstr "Details van een ruimte ophalen"
|
||||||
|
|
||||||
#: core/models.py:770
|
#: core/models.py:789
|
||||||
msgid "Update rooms"
|
msgid "Update rooms"
|
||||||
msgstr "Ruimtes bijwerken"
|
msgstr "Ruimtes bijwerken"
|
||||||
|
|
||||||
#: core/models.py:771
|
#: core/models.py:790
|
||||||
msgid "Delete rooms"
|
msgid "Delete rooms"
|
||||||
msgstr "Ruimtes verwijderen"
|
msgstr "Ruimtes verwijderen"
|
||||||
|
|
||||||
#: core/models.py:784
|
#: core/models.py:803
|
||||||
msgid "Application name"
|
msgid "Application name"
|
||||||
msgstr "Naam van de applicatie"
|
msgstr "Naam van de applicatie"
|
||||||
|
|
||||||
#: core/models.py:785
|
#: core/models.py:804
|
||||||
msgid "Descriptive name for this application."
|
msgid "Descriptive name for this application."
|
||||||
msgstr "Beschrijvende naam voor deze applicatie."
|
msgstr "Beschrijvende naam voor deze applicatie."
|
||||||
|
|
||||||
#: core/models.py:795
|
#: core/models.py:814
|
||||||
msgid "Hashed on Save. Copy it now if this is a new secret."
|
msgid "Hashed on Save. Copy it now if this is a new secret."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Wordt gehasht bij het opslaan. Kopieer het nu als dit een nieuw geheim is."
|
"Wordt gehasht bij het opslaan. Kopieer het nu als dit een nieuw geheim is."
|
||||||
|
|
||||||
#: core/models.py:806
|
#: core/models.py:825
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "Applicatie"
|
msgstr "Applicatie"
|
||||||
|
|
||||||
#: core/models.py:807
|
#: core/models.py:826
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Applicaties"
|
msgstr "Applicaties"
|
||||||
|
|
||||||
#: core/models.py:830
|
#: core/models.py:849
|
||||||
msgid "Enter a valid domain"
|
msgid "Enter a valid domain"
|
||||||
msgstr "Voer een geldig domein in"
|
msgstr "Voer een geldig domein in"
|
||||||
|
|
||||||
#: core/models.py:833
|
#: core/models.py:852
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Domein"
|
msgstr "Domein"
|
||||||
|
|
||||||
#: core/models.py:834
|
#: core/models.py:853
|
||||||
msgid "Email domain this application can act on behalf of."
|
msgid "Email domain this application can act on behalf of."
|
||||||
msgstr "E-maildomein namens welke deze applicatie kan handelen."
|
msgstr "E-maildomein namens welke deze applicatie kan handelen."
|
||||||
|
|
||||||
#: core/models.py:846
|
#: core/models.py:865
|
||||||
msgid "Application domain"
|
msgid "Application domain"
|
||||||
msgstr "Applicatiedomein"
|
msgstr "Applicatiedomein"
|
||||||
|
|
||||||
#: core/models.py:847
|
#: core/models.py:866
|
||||||
msgid "Application domains"
|
msgid "Application domains"
|
||||||
msgstr "Applicatiedomeinen"
|
msgstr "Applicatiedomeinen"
|
||||||
|
|
||||||
#: core/models.py:865
|
#: core/models.py:884
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "In afwachting"
|
msgstr "In afwachting"
|
||||||
|
|
||||||
#: core/models.py:866
|
#: core/models.py:885
|
||||||
msgid "Analyzing"
|
msgid "Analyzing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/models.py:873
|
#: core/models.py:892
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
msgstr "Klaar"
|
msgstr "Klaar"
|
||||||
|
|
||||||
#: core/models.py:879
|
#: core/models.py:898
|
||||||
msgid "Background image"
|
msgid "Background image"
|
||||||
msgstr "Achtergrondafbeelding"
|
msgstr "Achtergrondafbeelding"
|
||||||
|
|
||||||
#: core/models.py:891
|
#: core/models.py:910
|
||||||
msgid "title"
|
msgid "title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
#: core/models.py:915
|
#: core/models.py:934
|
||||||
msgid "Malware detection info when the analysis status is unsafe."
|
msgid "Malware detection info when the analysis status is unsafe."
|
||||||
msgstr "Informatie over malwaredetectie wanneer de analysestatus onveilig is."
|
msgstr "Informatie over malwaredetectie wanneer de analysestatus onveilig is."
|
||||||
|
|
||||||
#: core/models.py:920
|
#: core/models.py:939
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Bestand"
|
msgstr "Bestand"
|
||||||
|
|
||||||
#: core/models.py:921
|
#: core/models.py:940
|
||||||
msgid "Files"
|
msgid "Files"
|
||||||
msgstr "Bestanden"
|
msgstr "Bestanden"
|
||||||
|
|
||||||
#: core/models.py:1041
|
#: core/models.py:1060
|
||||||
msgid "This file is already hard deleted."
|
msgid "This file is already hard deleted."
|
||||||
msgstr "Dit bestand is al definitief verwijderd."
|
msgstr "Dit bestand is al definitief verwijderd."
|
||||||
|
|
||||||
#: core/models.py:1051
|
#: core/models.py:1070
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "To hard delete a file, it must first be soft deleted."
|
#| msgid "To hard delete a file, it must first be soft deleted."
|
||||||
msgid "To hard delete a file, it must first be soft deleted."
|
msgid "To hard delete a file, it must first be soft deleted."
|
||||||
@@ -513,15 +529,15 @@ msgstr ""
|
|||||||
"Om een bestand definitief te verwijderen, moet het eerst zacht verwijderd "
|
"Om een bestand definitief te verwijderen, moet het eerst zacht verwijderd "
|
||||||
"zijn."
|
"zijn."
|
||||||
|
|
||||||
#: core/recording/event/notification.py:123
|
#: core/recording/event/notification.py:124
|
||||||
msgid "Your recording is ready"
|
msgid "Your recording is ready"
|
||||||
msgstr "Je opname is klaar"
|
msgstr "Je opname is klaar"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:194
|
#: core/recording/event/notification.py:195
|
||||||
msgid "Transcription"
|
msgid "Transcription"
|
||||||
msgstr "Transcriptie"
|
msgstr "Transcriptie"
|
||||||
|
|
||||||
#: core/recording/event/notification.py:204
|
#: core/recording/event/notification.py:206
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
msgid "Meeting \"{room}\" on {room_recording_date} at {room_recording_time}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -532,25 +548,25 @@ msgstr ""
|
|||||||
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
msgid "Video call in progress: {sender.email} is waiting for you to connect"
|
||||||
msgstr "Video-oproep bezig: {sender.email} wacht op je verbinding"
|
msgstr "Video-oproep bezig: {sender.email} wacht op je verbinding"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:159
|
#: core/templates/mail/html/invitation.html:151
|
||||||
#: core/templates/mail/html/screen_recording.html:159
|
#: core/templates/mail/html/screen_recording.html:151
|
||||||
#: core/templates/mail/text/invitation.txt:3
|
#: core/templates/mail/text/invitation.txt:4
|
||||||
#: core/templates/mail/text/screen_recording.txt:3
|
#: core/templates/mail/text/screen_recording.txt:4
|
||||||
msgid "Logo email"
|
msgid "Logo email"
|
||||||
msgstr "Logo e-mail"
|
msgstr "Logo e-mail"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:189
|
#: core/templates/mail/html/invitation.html:181
|
||||||
#: core/templates/mail/text/invitation.txt:5
|
#: core/templates/mail/text/invitation.txt:6
|
||||||
msgid "invites you to join an ongoing video call"
|
msgid "invites you to join an ongoing video call"
|
||||||
msgstr "nodigt je uit om deel te nemen aan een lopende video-oproep"
|
msgstr "nodigt je uit om deel te nemen aan een lopende video-oproep"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:200
|
#: core/templates/mail/html/invitation.html:192
|
||||||
#: core/templates/mail/text/invitation.txt:7
|
#: core/templates/mail/text/invitation.txt:8
|
||||||
msgid "JOIN THE CALL"
|
msgid "JOIN THE CALL"
|
||||||
msgstr "NEEM DEEL AAN DE OPROEP"
|
msgstr "NEEM DEEL AAN DE OPROEP"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:227
|
#: core/templates/mail/html/invitation.html:219
|
||||||
#: core/templates/mail/text/invitation.txt:13
|
#: core/templates/mail/text/invitation.txt:14
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you can't click the button, copy and paste the URL into your browser to "
|
"If you can't click the button, copy and paste the URL into your browser to "
|
||||||
"join the call."
|
"join the call."
|
||||||
@@ -558,41 +574,47 @@ msgstr ""
|
|||||||
"Als je niet op de knop kunt klikken, kopieer en plak dan de URL in je "
|
"Als je niet op de knop kunt klikken, kopieer en plak dan de URL in je "
|
||||||
"browser om deel te nemen aan de oproep."
|
"browser om deel te nemen aan de oproep."
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:235
|
#: core/templates/mail/html/invitation.html:227
|
||||||
#: core/templates/mail/text/invitation.txt:15
|
#: core/templates/mail/text/invitation.txt:16
|
||||||
msgid "Tips for a better experience:"
|
msgid "Tips for a better experience:"
|
||||||
msgstr "Tips voor een betere ervaring:"
|
msgstr "Tips voor een betere ervaring:"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:237
|
#: core/templates/mail/html/invitation.html:229
|
||||||
#: core/templates/mail/text/invitation.txt:17
|
#: core/templates/mail/text/invitation.txt:18
|
||||||
msgid "Use Chrome or Firefox for better call quality"
|
msgid "Use Chrome or Firefox for better call quality"
|
||||||
msgstr "Gebruik Chrome of Firefox voor betere gesprekskwaliteit"
|
msgstr "Gebruik Chrome of Firefox voor betere gesprekskwaliteit"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:238
|
#: core/templates/mail/html/invitation.html:230
|
||||||
#: core/templates/mail/text/invitation.txt:18
|
#: core/templates/mail/text/invitation.txt:19
|
||||||
msgid "Test your microphone and camera before joining"
|
msgid "Test your microphone and camera before joining"
|
||||||
msgstr "Test je microfoon en camera voordat je deelneemt"
|
msgstr "Test je microfoon en camera voordat je deelneemt"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:239
|
#: core/templates/mail/html/invitation.html:231
|
||||||
#: core/templates/mail/text/invitation.txt:19
|
#: core/templates/mail/text/invitation.txt:20
|
||||||
msgid "Make sure you have a stable internet connection"
|
msgid "Make sure you have a stable internet connection"
|
||||||
msgstr "Zorg ervoor dat je een stabiele internetverbinding hebt"
|
msgstr "Zorg ervoor dat je een stabiele internetverbinding hebt"
|
||||||
|
|
||||||
#: core/templates/mail/html/invitation.html:248
|
#: core/templates/mail/html/invitation.html:240
|
||||||
#: core/templates/mail/html/screen_recording.html:245
|
#: core/templates/mail/html/screen_recording.html:237
|
||||||
#: core/templates/mail/text/invitation.txt:21
|
#: core/templates/mail/text/invitation.txt:22
|
||||||
#: core/templates/mail/text/screen_recording.txt:23
|
#: core/templates/mail/text/screen_recording.txt:24
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " Thank you for using %(brandname)s. "
|
msgid " Thank you for using %(brandname)s. "
|
||||||
msgstr " Bedankt voor het gebruik van %(brandname)s. "
|
msgstr " Bedankt voor het gebruik van %(brandname)s. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:188
|
#: core/templates/mail/html/invitation.html:271
|
||||||
#: core/templates/mail/text/screen_recording.txt:6
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"This mail has been sent to %(email)s by <a href=\"%(href)s\">%(name)s</a>"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/html/screen_recording.html:180
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:7
|
||||||
msgid "Your recording is ready!"
|
msgid "Your recording is ready!"
|
||||||
msgstr "Je opname is klaar!"
|
msgstr "Je opname is klaar!"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
" Your recording of \"%(room_name)s\" on %(recording_date)s at "
|
||||||
@@ -601,14 +623,14 @@ msgstr ""
|
|||||||
" Je opname van \"%(room_name)s\" op %(recording_date)s om %(recording_time)s "
|
" Je opname van \"%(room_name)s\" op %(recording_date)s om %(recording_time)s "
|
||||||
"is nu klaar om te downloaden. "
|
"is nu klaar om te downloaden. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:195
|
#: core/templates/mail/html/screen_recording.html:187
|
||||||
#: core/templates/mail/text/screen_recording.txt:8
|
#: core/templates/mail/text/screen_recording.txt:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid " The recording will expire in %(days)s days. "
|
msgid " The recording will expire in %(days)s days. "
|
||||||
msgstr " De opname verloopt over %(days)s dagen. "
|
msgstr " De opname verloopt over %(days)s dagen. "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:200
|
#: core/templates/mail/html/screen_recording.html:192
|
||||||
#: core/templates/mail/text/screen_recording.txt:9
|
#: core/templates/mail/text/screen_recording.txt:10
|
||||||
msgid ""
|
msgid ""
|
||||||
" Sharing the recording via link is not yet available. Only organizers can "
|
" Sharing the recording via link is not yet available. Only organizers can "
|
||||||
"download it. "
|
"download it. "
|
||||||
@@ -616,33 +638,33 @@ msgstr ""
|
|||||||
"Het delen van de opname via een link is nog niet beschikbaar. Alleen "
|
"Het delen van de opname via een link is nog niet beschikbaar. Alleen "
|
||||||
"organisatoren kunnen deze downloaden."
|
"organisatoren kunnen deze downloaden."
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:206
|
#: core/templates/mail/html/screen_recording.html:198
|
||||||
#: core/templates/mail/text/screen_recording.txt:11
|
#: core/templates/mail/text/screen_recording.txt:12
|
||||||
msgid "To keep this recording permanently:"
|
msgid "To keep this recording permanently:"
|
||||||
msgstr "Om deze opname permanent te bewaren:"
|
msgstr "Om deze opname permanent te bewaren:"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:208
|
#: core/templates/mail/html/screen_recording.html:200
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgstr "Klik op de \"<a href=\"%(link)s\">Openen</a>\"-link hieronder "
|
msgstr "Klik op de \"<a href=\"%(link)s\">Openen</a>\"-link hieronder "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:209
|
#: core/templates/mail/html/screen_recording.html:201
|
||||||
#: core/templates/mail/text/screen_recording.txt:14
|
#: core/templates/mail/text/screen_recording.txt:15
|
||||||
msgid "Use the \"Download\" button in the interface "
|
msgid "Use the \"Download\" button in the interface "
|
||||||
msgstr "Gebruik de \"Download\"-knop in de interface "
|
msgstr "Gebruik de \"Download\"-knop in de interface "
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:210
|
#: core/templates/mail/html/screen_recording.html:202
|
||||||
#: core/templates/mail/text/screen_recording.txt:15
|
#: core/templates/mail/text/screen_recording.txt:16
|
||||||
msgid "Save the file to your preferred location"
|
msgid "Save the file to your preferred location"
|
||||||
msgstr "Sla het bestand op naar je gewenste locatie"
|
msgstr "Sla het bestand op naar je gewenste locatie"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:221
|
#: core/templates/mail/html/screen_recording.html:213
|
||||||
#: core/templates/mail/text/screen_recording.txt:17
|
#: core/templates/mail/text/screen_recording.txt:18
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Openen"
|
msgstr "Openen"
|
||||||
|
|
||||||
#: core/templates/mail/html/screen_recording.html:230
|
#: core/templates/mail/html/screen_recording.html:222
|
||||||
#: core/templates/mail/text/screen_recording.txt:19
|
#: core/templates/mail/text/screen_recording.txt:20
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
" If you have any questions or need assistance, please contact our support "
|
" If you have any questions or need assistance, please contact our support "
|
||||||
@@ -651,28 +673,33 @@ msgstr ""
|
|||||||
" Als je vragen hebt of hulp nodig hebt, neem dan contact op met ons support "
|
" Als je vragen hebt of hulp nodig hebt, neem dan contact op met ons support "
|
||||||
"team via %(support_email)s. "
|
"team via %(support_email)s. "
|
||||||
|
|
||||||
#: core/templates/mail/text/screen_recording.txt:13
|
#: core/templates/mail/text/invitation.txt:24
|
||||||
|
#, python-format
|
||||||
|
msgid "This mail has been sent to %(email)s by %(name)s [%(href)s]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/templates/mail/text/screen_recording.txt:14
|
||||||
#, fuzzy, python-format
|
#, fuzzy, python-format
|
||||||
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
#| msgid "Click the \"<a href=\"%(link)s\">Open</a>\" link below "
|
||||||
msgid "Click the \"Open [%(link)s]\" link below "
|
msgid "Click the \"Open [%(link)s]\" link below "
|
||||||
msgstr "Klik op de \"<a href=\"%(link)s\">Openen</a>\"-link hieronder "
|
msgstr "Klik op de \"<a href=\"%(link)s\">Openen</a>\"-link hieronder "
|
||||||
|
|
||||||
#: meet/settings.py:228
|
#: meet/settings.py:238
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Engels"
|
msgstr "Engels"
|
||||||
|
|
||||||
#: meet/settings.py:229
|
#: meet/settings.py:239
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Frans"
|
msgstr "Frans"
|
||||||
|
|
||||||
#: meet/settings.py:230
|
#: meet/settings.py:240
|
||||||
msgid "Dutch"
|
msgid "Dutch"
|
||||||
msgstr "Nederlands"
|
msgstr "Nederlands"
|
||||||
|
|
||||||
#: meet/settings.py:231
|
#: meet/settings.py:241
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr "Duits"
|
msgstr "Duits"
|
||||||
|
|
||||||
#: meet/settings.py:233
|
#: meet/settings.py:242
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr "Spaans"
|
msgstr "Spaans"
|
||||||
|
|||||||
@@ -32,18 +32,14 @@ export interface BackgroundProcessorInterface extends TrackProcessor<Track.Kind>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class BackgroundProcessorFactory {
|
export class BackgroundProcessorFactory {
|
||||||
private static _isSupported?: boolean
|
|
||||||
|
|
||||||
static hasModernApiSupport() {
|
static hasModernApiSupport() {
|
||||||
return ProcessorWrapper.hasModernApiSupport
|
return ProcessorWrapper.hasModernApiSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
static isSupported() {
|
static isSupported() {
|
||||||
if (this._isSupported === undefined) {
|
return (
|
||||||
this._isSupported =
|
supportsBackgroundProcessors() || BackgroundCustomProcessor.isSupported
|
||||||
supportsBackgroundProcessors() || BackgroundCustomProcessor.isSupported
|
)
|
||||||
}
|
|
||||||
return this._isSupported
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getProcessor(
|
static getProcessor(
|
||||||
|
|||||||
Reference in New Issue
Block a user