Compare commits

..

2 Commits

Author SHA1 Message Date
Manuel Raynaud c0af8de270 fixup! 🐛(backend) fix wrong permission checj on sub page duplicate action 2025-09-12 09:21:45 +02:00
Manuel Raynaud aff7e9e245 🐛(backend) fix wrong permission checj on sub page duplicate action
A user with only read access to a document and it sub documents should
not be able to duplicate a sub document in the document tree. To avoid
this we have to compute the direct parent abilities to determine if it
can create a new children. Doing so computes the abilities in cascase
from the document to the root tree. To asave some quesries and not
compute again and again the same ability, we create a abilities cache.
The hard part is to invalidate this cache. The cache is invalidated if a
related DocumentAccess instance is updated or deleted and also if the
document link_reach or link_role is updated. To introspect the
modification made on the model it self when the user save it, we decided
to use the library django-dirtyfields
2025-09-09 15:09:10 +02:00
94 changed files with 1897 additions and 1878 deletions
+2 -22
View File
@@ -8,10 +8,7 @@ and this project adheres to
## [Unreleased]
## [3.7.0] - 2025-09-12
### Added
### Added
- ✨(api) add API route to fetch document content #1206
@@ -19,22 +16,6 @@ and this project adheres to
- 🔒️(backend) configure throttle on every viewsets #1343
- ⬆️ Bump eslint to V9 #1071
- ♿(frontend) improve accessibility:
- ♿fix major accessibility issues reported by wave and axe #1344
- ✨unify tab focus style for better visual consistency #1341
- ✨improve modal a11y: structure, labels, and title #1349
- ✨improve accessibility of cdoc content with correct aria tags #1271
- ✨unify tab focus style for better visual consistency #1341
- ♿hide decorative icons, label menus, avoid accessible name… #1362
- ♻️(tilt) use helm dev-backend chart
### Removed
- 🔥(frontend) remove multi column drop cursor #1370
### Fixed
- 🐛(frontend) fix callout emoji list #1366
## [3.6.0] - 2025-09-04
@@ -742,8 +723,7 @@ and this project adheres to
- ✨(frontend) Coming Soon page (#67)
- 🚀 Impress, project to manage your documents easily and collaboratively.
[unreleased]: https://github.com/suitenumerique/docs/compare/v3.7.0...main
[v3.7.0]: https://github.com/suitenumerique/docs/releases/v3.7.0
[unreleased]: https://github.com/suitenumerique/docs/compare/v3.6.0...main
[v3.6.0]: https://github.com/suitenumerique/docs/releases/v3.6.0
[v3.5.0]: https://github.com/suitenumerique/docs/releases/v3.5.0
[v3.4.2]: https://github.com/suitenumerique/docs/releases/v3.4.2
+2 -3
View File
@@ -39,10 +39,9 @@ docker_build(
]
)
k8s_resource('impress-docs-backend-migrate', resource_deps=['dev-backend-postgres'])
k8s_resource('impress-docs-backend-migrate', resource_deps=['postgres-postgresql'])
k8s_resource('impress-docs-backend-createsuperuser', resource_deps=['impress-docs-backend-migrate'])
k8s_resource('dev-backend-keycloak', resource_deps=['dev-backend-keycloak-pg'])
k8s_resource('impress-docs-backend', resource_deps=['impress-docs-backend-migrate', 'dev-backend-redis', 'dev-backend-keycloak', 'dev-backend-postgres', 'dev-backend-minio:statefulset'])
k8s_resource('impress-docs-backend', resource_deps=['impress-docs-backend-migrate'])
k8s_yaml(local('cd ../src/helm && helmfile -n impress -e dev template .'))
migration = '''
-8
View File
@@ -128,11 +128,3 @@ class ListDocumentFilter(DocumentFilter):
queryset_method = queryset.filter if bool(value) else queryset.exclude
return queryset_method(link_traces__user=user, link_traces__is_masked=True)
class UserSearchFilter(django_filters.FilterSet):
"""
Custom filter for searching users.
"""
q = django_filters.CharFilter(min_length=5, max_length=254)
+3 -9
View File
@@ -51,7 +51,7 @@ from core.tasks.mail import send_ask_for_access_mail
from core.utils import extract_attachments, filter_descendants
from . import permissions, serializers, utils
from .filters import DocumentFilter, ListDocumentFilter, UserSearchFilter
from .filters import DocumentFilter, ListDocumentFilter
from .throttling import UserListThrottleBurst, UserListThrottleSustained
logger = logging.getLogger(__name__)
@@ -176,18 +176,12 @@ class UserViewSet(
if self.action != "list":
return queryset
filterset = UserSearchFilter(
self.request.GET, queryset=queryset, request=self.request
)
if not filterset.is_valid():
raise drf.exceptions.ValidationError(filterset.errors)
# Exclude all users already in the given document
if document_id := self.request.query_params.get("document_id", ""):
queryset = queryset.exclude(documentaccess__document_id=document_id)
filter_data = filterset.form.cleaned_data
query = filter_data["q"]
if not (query := self.request.query_params.get("q", "")) or len(query) < 5:
return queryset.none()
# For emails, match emails by Levenstein distance to prevent typing errors
if "@" in query:
+95 -3
View File
@@ -28,6 +28,7 @@ from django.utils.translation import get_language, override
from django.utils.translation import gettext_lazy as _
from botocore.exceptions import ClientError
from dirtyfields import DirtyFieldsMixin
from rest_framework.exceptions import ValidationError
from timezone_field import TimeZoneField
from treebeard.mp_tree import MP_Node, MP_NodeManager, MP_NodeQuerySet
@@ -353,7 +354,7 @@ class DocumentManager(MP_NodeManager.from_queryset(DocumentQuerySet)):
# pylint: disable=too-many-public-methods
class Document(MP_Node, BaseModel):
class Document(DirtyFieldsMixin, MP_Node, BaseModel):
"""Pad document carrying the content."""
title = models.CharField(_("title"), max_length=255, null=True, blank=True)
@@ -403,6 +404,8 @@ class Document(MP_Node, BaseModel):
objects = DocumentManager()
FIELDS_TO_CHECK = ["link_reach", "link_role"]
class Meta:
db_table = "impress_document"
ordering = ("path",)
@@ -426,11 +429,21 @@ class Document(MP_Node, BaseModel):
super().__init__(*args, **kwargs)
self._ancestors_link_definition = None
self._computed_link_definition = None
self._cached_parent_obj = None
def save(self, *args, **kwargs):
"""Write content to object storage only if _content has changed."""
invalidate_abilities_cache = False
if not self._state.adding:
changed_fields = self.get_dirty_fields()
if any(field in changed_fields for field in self.FIELDS_TO_CHECK):
invalidate_abilities_cache = True
super().save(*args, **kwargs)
if invalidate_abilities_cache:
self.invalidate_abilities_cache()
if self._content:
file_key = self.file_key
bytes_content = self._content.encode("utf-8")
@@ -463,6 +476,42 @@ class Document(MP_Node, BaseModel):
"""
return not self.has_deleted_children and self.numchild == 0
def get_ancestors(self):
"""
:returns: A queryset containing the current node object's ancestors,
starting by the root node and descending to the parent.
"""
if self.is_root():
return Document.objects.none()
paths = [self.path[0:pos] for pos in range(self.steplen, len(self.path), self.steplen)]
return (
Document.objects.select_related("creator")
.filter(path__in=paths)
.order_by("depth")
)
def get_parent(self, update=False):
"""
:returns: the parent node of the current node object.
Caches the result in the object itself to help in loops.
"""
depth = int(len(self.path) / self.steplen)
if depth <= 1:
return None
if update:
self._cached_parent_obj = None
if self._cached_parent_obj is not None:
return self._cached_parent_obj
parentpath = self._get_basepath(self.path, depth - 1)
self._cached_parent_obj = Document.objects.select_related("creator").get(
path=parentpath
)
return self._cached_parent_obj
@property
def key_base(self):
"""Key base of the location where the document is stored in object storage."""
@@ -712,10 +761,44 @@ class Document(MP_Node, BaseModel):
"""Actual link role on the document."""
return self.computed_link_definition["link_role"]
def _get_abilities_cache_key(self):
"""Generate a unique cache key for each document."""
return f"document:abilities:{self.path!s}"
def _get_abilities_cache_for_user(self, user):
"""Return the abilities cache for the document and user."""
key = self._get_abilities_cache_key()
document_abilities = cache.get(key, {})
user_id = user.id if user.is_authenticated else "anonymous"
return document_abilities.get(user_id)
def _set_abilities_cache_for_user(self, user, abilities):
"""Set the abilities cache for the document and user."""
key = self._get_abilities_cache_key()
document_abilities = cache.get(key, {})
user_id = user.id if user.is_authenticated else "anonymous"
document_abilities[user_id] = abilities
cache.set(key, document_abilities, settings.DOCUMENT_ABILITIES_CACHE_TIMEOUT)
def invalidate_abilities_cache(self):
"""Invalidate the abilities cache for the document."""
key = self._get_abilities_cache_key()
cache.delete(key)
# Invalidate in cascade the abilities for all children
for child in self.get_children():
child.invalidate_abilities_cache()
def get_abilities(self, user):
"""
Compute and return abilities for a given user on the document.
"""
abilities = self._get_abilities_cache_for_user(user)
if abilities is not None:
return abilities
# First get the role based on specific access
role = self.get_role(user)
@@ -759,6 +842,10 @@ class Document(MP_Node, BaseModel):
if self.is_root()
else (is_owner_or_admin or (user.is_authenticated and self.creator == user))
)
can_duplicate = can_get and user.is_authenticated
if not self.is_root() and user.is_authenticated:
parent_ability = self.get_parent().get_abilities(user)
can_duplicate = parent_ability["children_create"]
ai_allow_reach_from = settings.AI_ALLOW_REACH_FROM
ai_access = any(
@@ -772,7 +859,7 @@ class Document(MP_Node, BaseModel):
]
)
return {
abilities = {
"accesses_manage": is_owner_or_admin,
"accesses_view": has_access_role,
"ai_transform": ai_access,
@@ -787,7 +874,7 @@ class Document(MP_Node, BaseModel):
"cors_proxy": can_get,
"descendants": can_get,
"destroy": can_destroy,
"duplicate": can_get and user.is_authenticated,
"duplicate": can_duplicate,
"favorite": can_get and user.is_authenticated,
"link_configuration": is_owner_or_admin,
"invite_owner": is_owner,
@@ -804,6 +891,8 @@ class Document(MP_Node, BaseModel):
"versions_list": has_access_role,
"versions_retrieve": has_access_role,
}
self._set_abilities_cache_for_user(user, abilities)
return abilities
def send_email(self, subject, emails, context=None, language=None):
"""Generate and send email from a template."""
@@ -889,6 +978,7 @@ class Document(MP_Node, BaseModel):
self.ancestors_deleted_at = self.deleted_at = timezone.now()
self.save()
self.invalidate_nb_accesses_cache()
self.invalidate_abilities_cache()
if self.depth > 1:
self._meta.model.objects.filter(pk=self.get_parent().pk).update(
@@ -1050,6 +1140,7 @@ class DocumentAccess(BaseAccess):
"""Override save to clear the document's cache for number of accesses."""
super().save(*args, **kwargs)
self.document.invalidate_nb_accesses_cache()
self.document.invalidate_abilities_cache()
@property
def target_key(self):
@@ -1060,6 +1151,7 @@ class DocumentAccess(BaseAccess):
"""Override delete to clear the document's cache for number of accesses."""
super().delete(*args, **kwargs)
self.document.invalidate_nb_accesses_cache()
self.document.invalidate_abilities_cache()
def set_user_roles_tuple(self, ancestors_role, current_role):
"""
@@ -98,7 +98,7 @@ def test_api_documents_children_list_anonymous_public_parent(django_assert_num_q
with django_assert_num_queries(9):
APIClient().get(f"/api/v1.0/documents/{document.id!s}/children/")
with django_assert_num_queries(5):
with django_assert_num_queries(4):
response = APIClient().get(f"/api/v1.0/documents/{document.id!s}/children/")
assert response.status_code == 200
@@ -187,7 +187,7 @@ def test_api_documents_children_list_authenticated_unrelated_public_or_authentic
child1, child2 = factories.DocumentFactory.create_batch(2, parent=document)
factories.UserDocumentAccessFactory(document=child1)
with django_assert_num_queries(9):
with django_assert_num_queries(11):
client.get(f"/api/v1.0/documents/{document.id!s}/children/")
with django_assert_num_queries(5):
response = client.get(
@@ -267,10 +267,10 @@ def test_api_documents_children_list_authenticated_public_or_authenticated_paren
child1, child2 = factories.DocumentFactory.create_batch(2, parent=document)
factories.UserDocumentAccessFactory(document=child1)
with django_assert_num_queries(10):
with django_assert_num_queries(17):
client.get(f"/api/v1.0/documents/{document.id!s}/children/")
with django_assert_num_queries(6):
with django_assert_num_queries(5):
response = client.get(f"/api/v1.0/documents/{document.id!s}/children/")
assert response.status_code == 200
@@ -373,7 +373,7 @@ def test_api_documents_children_list_authenticated_related_direct(
child1, child2 = factories.DocumentFactory.create_batch(2, parent=document)
factories.UserDocumentAccessFactory(document=child1)
with django_assert_num_queries(9):
with django_assert_num_queries(11):
response = client.get(
f"/api/v1.0/documents/{document.id!s}/children/",
)
@@ -456,7 +456,7 @@ def test_api_documents_children_list_authenticated_related_parent(
document=grand_parent, user=user
)
with django_assert_num_queries(10):
with django_assert_num_queries(17):
response = client.get(
f"/api/v1.0/documents/{document.id!s}/children/",
)
@@ -591,7 +591,7 @@ def test_api_documents_children_list_authenticated_related_team_members(
access = factories.TeamDocumentAccessFactory(document=document, team="myteam")
with django_assert_num_queries(9):
with django_assert_num_queries(11):
response = client.get(f"/api/v1.0/documents/{document.id!s}/children/")
# pylint: disable=R0801
@@ -152,7 +152,7 @@ def test_api_documents_list_authenticated_direct(django_assert_num_queries):
str(child4_with_access.id),
}
with django_assert_num_queries(14):
with django_assert_num_queries(17):
response = client.get("/api/v1.0/documents/")
# nb_accesses should now be cached
@@ -272,7 +272,7 @@ def test_api_documents_list_authenticated_link_reach_public_or_authenticated(
expected_ids = {str(document1.id), str(document2.id), str(visible_child.id)}
with django_assert_num_queries(11):
with django_assert_num_queries(13):
response = client.get("/api/v1.0/documents/")
# nb_accesses should now be cached
@@ -305,7 +305,7 @@ def test_api_documents_retrieve_authenticated_public_or_authenticated_parent(rea
"cors_proxy": True,
"content": True,
"destroy": False,
"duplicate": True,
"duplicate": grand_parent.link_role == "editor",
"favorite": True,
"invite_owner": False,
"link_configuration": False,
@@ -500,7 +500,7 @@ def test_api_documents_retrieve_authenticated_related_parent():
"cors_proxy": True,
"content": True,
"destroy": access.role in ["administrator", "owner"],
"duplicate": True,
"duplicate": access.role != "reader",
"favorite": True,
"invite_owner": access.role == "owner",
"link_configuration": access.role in ["administrator", "owner"],
@@ -855,7 +855,7 @@ def test_api_documents_retrieve_user_role(django_assert_max_num_queries):
)
expected_role = choices.RoleChoices.max(*[access.role for access in accesses])
with django_assert_max_num_queries(14):
with django_assert_max_num_queries(16):
response = client.get(f"/api/v1.0/documents/{document.id!s}/")
assert response.status_code == 200
@@ -165,7 +165,7 @@ def test_api_documents_trashbin_authenticated_direct(django_assert_num_queries):
expected_ids = {str(document1.id), str(document2.id), str(document3.id)}
with django_assert_num_queries(10):
with django_assert_num_queries(14):
response = client.get("/api/v1.0/documents/trashbin/")
with django_assert_num_queries(4):
@@ -377,7 +377,7 @@ def test_api_documents_tree_list_authenticated_unrelated_public_or_authenticated
document, sibling = factories.DocumentFactory.create_batch(2, parent=parent)
child = factories.DocumentFactory(link_reach="public", parent=document)
with django_assert_num_queries(13):
with django_assert_num_queries(16):
client.get(f"/api/v1.0/documents/{document.id!s}/tree/")
with django_assert_num_queries(5):
+4 -27
View File
@@ -194,41 +194,18 @@ def test_api_users_list_query_short_queries():
factories.UserFactory(email="john.lennon@example.com")
response = client.get("/api/v1.0/users/?q=jo")
assert response.status_code == 400
assert response.json() == {
"q": ["Ensure this value has at least 5 characters (it has 2)."]
}
assert response.status_code == 200
assert response.json() == []
response = client.get("/api/v1.0/users/?q=john")
assert response.status_code == 400
assert response.json() == {
"q": ["Ensure this value has at least 5 characters (it has 4)."]
}
assert response.status_code == 200
assert response.json() == []
response = client.get("/api/v1.0/users/?q=john.")
assert response.status_code == 200
assert len(response.json()) == 2
def test_api_users_list_query_long_queries():
"""
Queries longer than 255 characters should return an empty result set.
"""
user = factories.UserFactory(email="paul@example.com")
client = APIClient()
client.force_login(user)
factories.UserFactory(email="john.doe@example.com")
factories.UserFactory(email="john.lennon@example.com")
query = "a" * 244
response = client.get(f"/api/v1.0/users/?q={query}@example.com")
assert response.status_code == 400
assert response.json() == {
"q": ["Ensure this value has at most 254 characters (it has 256)."]
}
def test_api_users_list_query_inactive():
"""Inactive users should not be listed."""
user = factories.UserFactory()
@@ -318,6 +318,10 @@ def test_models_documents_get_abilities_editor(
nb_queries = 1 if is_authenticated else 0
with django_assert_num_queries(nb_queries):
assert document.get_abilities(user) == expected_abilities
with django_assert_num_queries(0):
assert document.get_abilities(user) == expected_abilities
document.soft_delete()
document.refresh_from_db()
assert all(
@@ -681,6 +685,98 @@ def test_models_documents_get_abilities_children_destroy( # noqa: PLR0913
assert abilities["destroy"] is can_destroy
def test_models_documents_get_abilities_cache(django_assert_num_queries):
"""Abilities should be computed once and cached."""
user = factories.UserFactory()
parent = factories.DocumentFactory(link_reach="restricted", link_role="editor")
document = factories.DocumentFactory(
link_reach="restricted",
link_role="editor",
parent=parent,
)
access = factories.UserDocumentAccessFactory(
document=parent, user=user, role="editor"
)
# 1 for fetching the parent, 2 for computed the roles (parent and document)
with django_assert_num_queries(
3
): # 1 for fetching the parent, 2 for computed the roles (parent and document)
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
# modifying the access should invalidate the cache
access.role = "reader"
access.save()
# 2 for computed the roles (parent and document), the parent is still in document's cache
with django_assert_num_queries(2):
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
# because the parent abilities have alreadby been comptued when
# document abilities were computed, no query is done
with django_assert_num_queries(0):
parent.get_abilities(user)
# deleting the access should invalidate the cache
access.delete()
with django_assert_num_queries(2):
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
# Modifying the document link_reach should invalidate the cache
document.link_reach = "public"
document.save()
# 1 for computed the roles (document), parent abilities are still in cache
with django_assert_num_queries(1):
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
parent.link_reach = "public"
parent.save()
# 2 for computed the roles (parent and document)
with django_assert_num_queries(2):
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
# Modifying the parent link_role should invalidate the cache
document.link_role = "reader"
document.save()
# 1 for computed the roles (document), parent abilities are still in cache
with django_assert_num_queries(1):
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
parent.link_role = "reader"
parent.save()
# 2 for computed the roles (parent and document)
with django_assert_num_queries(2):
document.get_abilities(user)
with django_assert_num_queries(0):
document.get_abilities(user)
# Modifying any other property should not invalidate the cache
document.title = "new title"
document.save()
with django_assert_num_queries(0):
document.get_abilities(user)
@override_settings(AI_ALLOW_REACH_FROM="public")
@pytest.mark.parametrize(
"is_authenticated,reach",
+3 -11
View File
@@ -8,19 +8,11 @@ NB_OBJECTS = {
DEV_USERS = [
{"username": "impress", "email": "impress@impress.world", "language": "en-us"},
{
"username": "user-e2e-webkit",
"email": "user.test@webkit.test",
"language": "en-us",
},
{
"username": "user-e2e-firefox",
"email": "user.test@firefox.test",
"language": "en-us",
},
{"username": "user-e2e-webkit", "email": "user@webkit.test", "language": "en-us"},
{"username": "user-e2e-firefox", "email": "user@firefox.test", "language": "en-us"},
{
"username": "user-e2e-chromium",
"email": "user.test@chromium.test",
"email": "user@chromium.test",
"language": "en-us",
},
]
@@ -119,8 +119,8 @@ def create_demo(stdout):
first_name = random.choice(first_names)
queue.push(
models.User(
admin_email=f"user.test{i:d}@example.com",
email=f"user.test{i:d}@example.com",
admin_email=f"user{i:d}@example.com",
email=f"user{i:d}@example.com",
password="!",
is_superuser=False,
is_active=True,
@@ -33,9 +33,9 @@ def test_commands_create_demo():
# assert dev users have doc accesses
user = models.User.objects.get(email="impress@impress.world")
assert models.DocumentAccess.objects.filter(user=user).exists()
user = models.User.objects.get(email="user.test@webkit.test")
user = models.User.objects.get(email="user@webkit.test")
assert models.DocumentAccess.objects.filter(user=user).exists()
user = models.User.objects.get(email="user.test@firefox.test")
user = models.User.objects.get(email="user@firefox.test")
assert models.DocumentAccess.objects.filter(user=user).exists()
user = models.User.objects.get(email="user.test@chromium.test")
user = models.User.objects.get(email="user@chromium.test")
assert models.DocumentAccess.objects.filter(user=user).exists()
+6
View File
@@ -808,6 +808,12 @@ class Base(Configuration):
),
}
DOCUMENT_ABILITIES_CACHE_TIMEOUT = values.IntegerValue(
default=60 * 60, # 1 hour
environ_name="ABILITIES_CACHE_TIMEOUT",
environ_prefix=None,
)
# pylint: disable=invalid-name
@property
def ENVIRONMENT(self):
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Breton\n"
"Language: br_FR\n"
@@ -70,7 +70,7 @@ msgstr "Doare korf"
msgid "Format"
msgstr "Stumm"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "eilenn {title}"
@@ -225,8 +225,8 @@ msgstr "implijer"
msgid "users"
msgstr "implijerien"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "titl"
@@ -242,155 +242,155 @@ msgstr "Restr"
msgid "Documents"
msgstr "Restroù"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Restr hep titl"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} en deus rannet ur restr ganeoc'h!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} en deus pedet ac'hanoc'h gant ar rol \"{role}\" war ar restr da-heul:"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} en deus rannet ur restr ganeoc'h: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Roud liamm ar restr/an implijer"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Roudoù liamm ar restr/an implijer"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Ur roud liamm a zo dija evit an restr/an implijer."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Restr muiañ-karet"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Restroù muiañ-karet"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Ar restr-mañ a zo ur restr muiañ karet gant an implijer-mañ."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Liamm restr/implijer"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Liammoù restr/implijer"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "An implijer-mañ a zo dija er restr-mañ."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Ar skipailh-mañ a zo dija en restr-mañ."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "An implijer pe ar skipailh a rank bezañ termenet, ket an daou avat."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr "Goulenn tizhout ar restr"
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr "Goulennoù tizhout ar restr"
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr "An implijer en deus goulennet tizhout ar restr-mañ."
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr "{name} en defe c'hoant da dizhout ar restr-mañ!"
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr "{name} en defe c'hoant da dizhout ar restr da-heul:"
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr "{name} en defe c'hoant da dizhout ar restr: {title}"
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "deskrivadur"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "kod"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "publik"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "M'eo foran ar patrom-mañ hag implijus gant n'eus forzh piv."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Patrom"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Patromoù"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Liamm patrom/implijer"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Liammoù patrom/implijer"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "An implijer-mañ a zo dija er patrom-mañ."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Ar skipailh-mañ a zo dija er patrom-mañ."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "postel"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Pedadenn d'ur restr"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Pedadennoù d'ur restr"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Ar postel-mañ a zo liammet ouzh un implijer enskrivet."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -70,7 +70,7 @@ msgstr "Typ"
msgid "Format"
msgstr "Format"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "Kopie von {title}"
@@ -225,8 +225,8 @@ msgstr "Benutzer"
msgid "users"
msgstr "Benutzer"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "Titel"
@@ -242,155 +242,155 @@ msgstr "Dokument"
msgid "Documents"
msgstr "Dokumente"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Unbenanntes Dokument"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} hat ein Dokument mit Ihnen geteilt!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} hat Sie mit der Rolle \"{role}\" zu folgendem Dokument eingeladen:"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} hat ein Dokument mit Ihnen geteilt: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Dokument/Benutzer Linkverfolgung"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Dokument/Benutzer Linkverfolgung"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Für dieses Dokument/ diesen Benutzer ist bereits eine Linkverfolgung vorhanden."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Dokumentenfavorit"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Dokumentfavoriten"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Dieses Dokument ist bereits durch den gleichen Benutzer favorisiert worden."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Dokument/Benutzerbeziehung"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Dokument/Benutzerbeziehungen"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Dieser Benutzer befindet sich bereits in diesem Dokument."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Dieses Team befindet sich bereits in diesem Dokument."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "Benutzer oder Team müssen gesetzt werden, nicht beides."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "Beschreibung"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "Code"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "CSS"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "öffentlich"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Ob diese Vorlage für jedermann öffentlich ist."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Vorlage"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Vorlagen"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Vorlage/Benutzer-Beziehung"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Vorlage/Benutzerbeziehungen"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Dieser Benutzer ist bereits in dieser Vorlage."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Dieses Team ist bereits in diesem Template."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "E-Mail-Adresse"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Einladung zum Dokument"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Dokumenteinladungen"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Diese E-Mail ist bereits einem registrierten Benutzer zugeordnet."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: English\n"
"Language: en_US\n"
@@ -70,7 +70,7 @@ msgstr ""
msgid "Format"
msgstr ""
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr ""
@@ -225,8 +225,8 @@ msgstr ""
msgid "users"
msgstr ""
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr ""
@@ -242,155 +242,155 @@ msgstr ""
msgid "Documents"
msgstr ""
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr ""
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr ""
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr ""
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr ""
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr ""
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr ""
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr ""
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr ""
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr ""
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr ""
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr ""
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr ""
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr ""
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr ""
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr ""
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr ""
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr ""
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr ""
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr ""
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr ""
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr ""
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr ""
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr ""
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr ""
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr ""
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr ""
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr ""
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr ""
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr ""
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr ""
+48 -48
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -70,7 +70,7 @@ msgstr "Tipo de Cuerpo"
msgid "Format"
msgstr "Formato"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "copia de {title}"
@@ -163,7 +163,7 @@ msgstr "sub (UUID)"
#: build/lib/core/models.py:142 core/models.py:142
msgid "Required. 255 characters or fewer. ASCII characters only."
msgstr "Obligatorio. 255 caracteres o menos. Solo caracteres ASCII."
msgstr ""
#: build/lib/core/models.py:150 core/models.py:150
msgid "full name"
@@ -225,8 +225,8 @@ msgstr "usuario"
msgid "users"
msgstr "usuarios"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "título"
@@ -242,155 +242,155 @@ msgstr "Documento"
msgid "Documents"
msgstr "Documentos"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Documento sin título"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "¡{name} ha compartido un documento contigo!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "Te ha invitado {name} al siguiente documento con el rol \"{role}\" :"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} ha compartido un documento contigo: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Traza del enlace de documento/usuario"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Trazas del enlace de documento/usuario"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Ya existe una traza de enlace para este documento/usuario."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Documento favorito"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Documentos favoritos"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Este documento ya ha sido marcado como favorito por el usuario."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Relación documento/usuario"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Relaciones documento/usuario"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Este usuario ya forma parte del documento."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Este equipo ya forma parte del documento."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "Debe establecerse un usuario o un equipo, no ambos."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr "Solicitud de acceso"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr "Solicitud de accesos"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr "Este usuario ya ha solicitado acceso a este documento."
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr "¡{name} desea acceder a un documento!"
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr "{name} desea acceso al siguiente documento:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr "{name} está pidiendo acceso al documento: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "descripción"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "código"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "público"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Si esta plantilla es pública para que cualquiera la utilice."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Plantilla"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Plantillas"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Relación plantilla/usuario"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Relaciones plantilla/usuario"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Este usuario ya forma parte de la plantilla."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Este equipo ya se encuentra en esta plantilla."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "dirección de correo electrónico"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Invitación al documento"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Invitaciones a documentos"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Este correo electrónico está asociado a un usuario registrado."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 11:45\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -70,7 +70,7 @@ msgstr "Type de corps"
msgid "Format"
msgstr "Format"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "copie de {title}"
@@ -225,8 +225,8 @@ msgstr "utilisateur"
msgid "users"
msgstr "utilisateurs"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "titre"
@@ -242,155 +242,155 @@ msgstr "Document"
msgid "Documents"
msgstr "Documents"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Document sans titre"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} a partagé un document avec vous!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} vous a invité avec le rôle \"{role}\" sur le document suivant :"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} a partagé un document avec vous : {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Trace du lien document/utilisateur"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Traces du lien document/utilisateur"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Une trace de lien existe déjà pour ce document/utilisateur."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Document favori"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Documents favoris"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Ce document est déjà un favori de cet utilisateur."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Relation document/utilisateur"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Relations document/utilisateur"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Cet utilisateur est déjà dans ce document."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Cette équipe est déjà dans ce document."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "L'utilisateur ou l'équipe doivent être définis, pas les deux."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr "Demande d'accès au document"
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr "Demande d'accès au document"
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr "Cet utilisateur a déjà demandé l'accès à ce document."
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr "{name} souhaiterait accéder au document suivant !"
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr "{name} souhaiterait accéder au document suivant :"
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr "{name} demande l'accès au document : {title}"
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "description"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "code"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "CSS"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "public"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Si ce modèle est public, utilisable par n'importe qui."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Modèle"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Modèles"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Relation modèle/utilisateur"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Relations modèle/utilisateur"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Cet utilisateur est déjà dans ce modèle."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Cette équipe est déjà modèle."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "adresse e-mail"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Invitation à un document"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Invitations à un document"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Cette adresse email est déjà associée à un utilisateur inscrit."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -70,7 +70,7 @@ msgstr ""
msgid "Format"
msgstr "Formato"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "copia di {title}"
@@ -225,8 +225,8 @@ msgstr "utente"
msgid "users"
msgstr "utenti"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "titolo"
@@ -242,155 +242,155 @@ msgstr "Documento"
msgid "Documents"
msgstr "Documenti"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Documento senza titolo"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} ha condiviso un documento con te!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} ti ha invitato con il ruolo \"{role}\" nel seguente documento:"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} ha condiviso un documento con te: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr ""
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr ""
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr ""
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Documento preferito"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Documenti preferiti"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr ""
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr ""
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr ""
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Questo utente è già presente in questo documento."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Questo team è già presente in questo documento."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr ""
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "descrizione"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "code"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "pubblico"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Indica se questo modello è pubblico per chiunque."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Modello"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Modelli"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr ""
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr ""
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Questo utente è già in questo modello."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Questo team è già in questo modello."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "indirizzo e-mail"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Invito al documento"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Inviti al documento"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Questa email è già associata a un utente registrato."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
@@ -70,7 +70,7 @@ msgstr "Text type"
msgid "Format"
msgstr "Formaat"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "kopie van {title}"
@@ -225,8 +225,8 @@ msgstr "gebruiker"
msgid "users"
msgstr "gebruikers"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "titel"
@@ -242,155 +242,155 @@ msgstr "Document"
msgid "Documents"
msgstr "Documenten"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Naamloos Document"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} heeft een document met gedeeld!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} heeft u uitgenodigd met de rol \"{role}\" op het volgende document:"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} heeft een document met u gedeeld: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Document/gebruiker url"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Document/gebruiker url"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Een url bestaat al voor dit document/deze gebruiker."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Document favoriet"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Document favorieten"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Dit document is al in gebruik als favoriete door dezelfde gebruiker."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Document/gebruiker relatie"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Document/gebruiker relaties"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "De gebruiker is al in dit document."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Het team is al in dit document."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "Een gebruiker of team moet gekozen worden, maar niet beide."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "omschrijving"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "code"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "publiek"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Of dit template als publiek is en door iedereen te gebruiken is."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Template"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Templates"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Template/gebruiker relatie"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Template/gebruiker relaties"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "De gebruiker bestaat al in dit template."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Het team bestaat al in dit template."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "email adres"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Document uitnodiging"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Document uitnodigingen"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Deze email is al geassocieerd met een geregistreerde gebruiker."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Language: pt_PT\n"
@@ -70,7 +70,7 @@ msgstr "Tipo de corpo"
msgid "Format"
msgstr "Formato"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "cópia de {title}"
@@ -225,8 +225,8 @@ msgstr ""
msgid "users"
msgstr ""
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr ""
@@ -242,155 +242,155 @@ msgstr ""
msgid "Documents"
msgstr ""
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr ""
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr ""
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr ""
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr ""
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr ""
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr ""
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr ""
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr ""
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr ""
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr ""
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr ""
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr ""
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr ""
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr ""
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr ""
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr ""
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr ""
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr ""
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr ""
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr ""
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr ""
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr ""
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr ""
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr ""
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr ""
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr ""
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr ""
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr ""
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr ""
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr ""
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
@@ -70,7 +70,7 @@ msgstr "Тип сообщения"
msgid "Format"
msgstr "Формат"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "копия {title}"
@@ -225,8 +225,8 @@ msgstr "пользователь"
msgid "users"
msgstr "пользователи"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "заголовок"
@@ -242,155 +242,155 @@ msgstr "Документ"
msgid "Documents"
msgstr "Документы"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Безымянный документ"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} делится с вами документом!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} приглашает вас присоединиться к следующему документу с ролью \"{role}\":"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} делится с вами документом: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Трассировка связи документ/пользователь"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Трассировка связей документ/пользователь"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Для этого документа/пользователя уже существует трассировка ссылки."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Избранный документ"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Избранные документы"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Этот документ уже помечен как избранный для этого пользователя."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Отношение документ/пользователь"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Отношения документ/пользователь"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Этот пользователь уже имеет доступ к этому документу."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Эта команда уже имеет доступ к этому документу."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "Может быть выбран либо пользователь, либо команда, но не оба варианта сразу."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr "Документ запрашивает доступ"
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr "Документ запрашивает доступы"
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr "Этот пользователь уже запросил доступ к этому документу."
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr "{name} хочет получить доступ к документу!"
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr "{name} хочет получить доступ к следующему документу:"
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr "{name} запрашивает доступ к документу: {title}"
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "описание"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "код"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "доступно всем"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Этот шаблон доступен всем пользователям."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Шаблон"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Шаблоны"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Отношение шаблон/пользователь"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Отношения шаблон/пользователь"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Этот пользователь уже указан в этом шаблоне."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Эта команда уже указана в этом шаблоне."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "адрес электронной почты"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Приглашение для документа"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Приглашения для документов"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Этот адрес уже связан с зарегистрированным пользователем."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Slovenian\n"
"Language: sl_SI\n"
@@ -70,7 +70,7 @@ msgstr "Vrsta telesa"
msgid "Format"
msgstr "Oblika"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr ""
@@ -225,8 +225,8 @@ msgstr "uporabnik"
msgid "users"
msgstr "uporabniki"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "naslov"
@@ -242,155 +242,155 @@ msgstr "Dokument"
msgid "Documents"
msgstr "Dokumenti"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Dokument brez naslova"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} je delil dokument z vami!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} vas je povabil z vlogo \"{role}\" na naslednjem dokumentu:"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} je delil dokument z vami: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Dokument/sled povezave uporabnika"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Sledi povezav dokumenta/uporabnika"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Za ta dokument/uporabnika že obstaja sled povezave."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Priljubljeni dokument"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Priljubljeni dokumenti"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Ta dokument je že ciljno usmerjen s priljubljenim primerkom relacije za istega uporabnika."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Odnos dokument/uporabnik"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Odnosi dokument/uporabnik"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Ta uporabnik je že v tem dokumentu."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Ta ekipa je že v tem dokumentu."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "Nastaviti je treba bodisi uporabnika ali ekipo, a ne obojega."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "opis"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "koda"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "javno"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Ali je ta predloga javna za uporabo."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Predloga"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Predloge"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Odnos predloga/uporabnik"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Odnosi med predlogo in uporabnikom"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Ta uporabnik je že v tej predlogi."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Ta ekipa je že v tej predlogi."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "elektronski naslov"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Vabilo na dokument"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Vabila na dokument"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Ta e-poštni naslov je že povezan z registriranim uporabnikom."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Language: sv_SE\n"
@@ -70,7 +70,7 @@ msgstr ""
msgid "Format"
msgstr "Format"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr ""
@@ -225,8 +225,8 @@ msgstr ""
msgid "users"
msgstr ""
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr ""
@@ -242,155 +242,155 @@ msgstr ""
msgid "Documents"
msgstr ""
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr ""
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr ""
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr ""
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr ""
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr ""
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr ""
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr ""
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr ""
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr ""
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr ""
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr ""
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr ""
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr ""
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr ""
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr ""
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr ""
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr ""
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr ""
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr ""
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr ""
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr ""
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr ""
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr ""
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr ""
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr ""
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr ""
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "e-postadress"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Bjud in dokument"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Inbjudningar dokument"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Denna e-postadress är redan associerad med en registrerad användare."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Language: tr_TR\n"
@@ -70,7 +70,7 @@ msgstr ""
msgid "Format"
msgstr ""
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr ""
@@ -225,8 +225,8 @@ msgstr ""
msgid "users"
msgstr ""
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr ""
@@ -242,155 +242,155 @@ msgstr ""
msgid "Documents"
msgstr ""
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr ""
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr ""
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr ""
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr ""
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr ""
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr ""
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr ""
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr ""
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr ""
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr ""
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr ""
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr ""
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr ""
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr ""
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr ""
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr ""
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr ""
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr ""
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr ""
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr ""
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr ""
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr ""
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr ""
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr ""
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr ""
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr ""
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr ""
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr ""
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr ""
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr ""
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Ukrainian\n"
"Language: uk_UA\n"
@@ -70,7 +70,7 @@ msgstr "Тип вмісту"
msgid "Format"
msgstr "Формат"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "копія {title}"
@@ -225,8 +225,8 @@ msgstr "користувач"
msgid "users"
msgstr "користувачі"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "заголовок"
@@ -242,155 +242,155 @@ msgstr "Документ"
msgid "Documents"
msgstr "Документи"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "Документ без назви"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} ділиться з вами документом!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} запрошує вас для роботи з документом із роллю \"{role}\":"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} ділиться з вами документом: {title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "Трасування посилання Документ/користувач"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "Трасування посилань Документ/користувач"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "Відстеження вже існуючих посилань для цього документа/користувача."
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "Обраний документ"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "Обрані документи"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "Цей документ вже вказаний як обраний для одного користувача."
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "Відносини документ/користувач"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "Відносини документ/користувач"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "Цей користувач вже має доступ до цього документу."
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "Ця команда вже має доступ до цього документа."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "Вкажіть користувача або команду, а не обох."
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr "Запит доступу до документа"
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr "Запит доступу для документа"
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr "Цей користувач вже попросив доступ до цього документа."
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr "{name} хоче отримати доступ до документа!"
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr "{name} бажає отримати доступ до наступного документа:"
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr "{name} запитує доступ до документа: {title}"
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "опис"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "код"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "публічне"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "Чи є цей шаблон публічним для будь-кого користувача."
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "Шаблон"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "Шаблони"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "Відношення шаблон/користувач"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "Відношення шаблон/користувач"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "Цей користувач вже має доступ до цього шаблону."
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "Ця команда вже має доступ до цього шаблону."
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "електронна адреса"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "Запрошення до редагування документа"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "Запрошення до редагування документів"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "Ця електронна пошта вже пов'язана з зареєстрованим користувачем."
+43 -43
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 14:29+0000\n"
"PO-Revision-Date: 2025-09-12 09:50\n"
"POT-Creation-Date: 2025-09-01 21:01+0000\n"
"PO-Revision-Date: 2025-09-04 10:03\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@@ -70,7 +70,7 @@ msgstr "正文类型"
msgid "Format"
msgstr "格式"
#: build/lib/core/api/viewsets.py:965 core/api/viewsets.py:965
#: build/lib/core/api/viewsets.py:960 core/api/viewsets.py:960
#, python-brace-format
msgid "copy of {title}"
msgstr "{title} 的副本"
@@ -225,8 +225,8 @@ msgstr "用户"
msgid "users"
msgstr "个用户"
#: build/lib/core/models.py:359 build/lib/core/models.py:1281
#: core/models.py:359 core/models.py:1281
#: build/lib/core/models.py:359 build/lib/core/models.py:1280
#: core/models.py:359 core/models.py:1280
msgid "title"
msgstr "标题"
@@ -242,155 +242,155 @@ msgstr "文档"
msgid "Documents"
msgstr "个文档"
#: build/lib/core/models.py:422 build/lib/core/models.py:819 core/models.py:422
#: core/models.py:819
#: build/lib/core/models.py:422 build/lib/core/models.py:818 core/models.py:422
#: core/models.py:818
msgid "Untitled Document"
msgstr "未命名文档"
#: build/lib/core/models.py:854 core/models.py:854
#: build/lib/core/models.py:853 core/models.py:853
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr "{name} 与您共享了一个文档!"
#: build/lib/core/models.py:858 core/models.py:858
#: build/lib/core/models.py:857 core/models.py:857
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr "{name} 邀请您以“{role}”角色访问以下文档:"
#: build/lib/core/models.py:864 core/models.py:864
#: build/lib/core/models.py:863 core/models.py:863
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr "{name} 与您共享了一个文档:{title}"
#: build/lib/core/models.py:964 core/models.py:964
#: build/lib/core/models.py:963 core/models.py:963
msgid "Document/user link trace"
msgstr "文档/用户链接跟踪"
#: build/lib/core/models.py:965 core/models.py:965
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link traces"
msgstr "个文档/用户链接跟踪"
#: build/lib/core/models.py:971 core/models.py:971
#: build/lib/core/models.py:970 core/models.py:970
msgid "A link trace already exists for this document/user."
msgstr "此文档/用户的链接跟踪已存在。"
#: build/lib/core/models.py:994 core/models.py:994
#: build/lib/core/models.py:993 core/models.py:993
msgid "Document favorite"
msgstr "文档收藏"
#: build/lib/core/models.py:995 core/models.py:995
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorites"
msgstr "文档收藏夹"
#: build/lib/core/models.py:1001 core/models.py:1001
#: build/lib/core/models.py:1000 core/models.py:1000
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr "该文档已被同一用户的收藏关系实例关联。"
#: build/lib/core/models.py:1023 core/models.py:1023
#: build/lib/core/models.py:1022 core/models.py:1022
msgid "Document/user relation"
msgstr "文档/用户关系"
#: build/lib/core/models.py:1024 core/models.py:1024
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relations"
msgstr "文档/用户关系集"
#: build/lib/core/models.py:1030 core/models.py:1030
#: build/lib/core/models.py:1029 core/models.py:1029
msgid "This user is already in this document."
msgstr "该用户已在此文档中。"
#: build/lib/core/models.py:1036 core/models.py:1036
#: build/lib/core/models.py:1035 core/models.py:1035
msgid "This team is already in this document."
msgstr "该团队已在此文档中。"
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
#: build/lib/core/models.py:1041 build/lib/core/models.py:1366
#: core/models.py:1041 core/models.py:1366
msgid "Either user or team must be set, not both."
msgstr "必须设置用户或团队之一,不能同时设置两者。"
#: build/lib/core/models.py:1188 core/models.py:1188
#: build/lib/core/models.py:1187 core/models.py:1187
msgid "Document ask for access"
msgstr ""
#: build/lib/core/models.py:1189 core/models.py:1189
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for accesses"
msgstr ""
#: build/lib/core/models.py:1195 core/models.py:1195
#: build/lib/core/models.py:1194 core/models.py:1194
msgid "This user has already asked for access to this document."
msgstr ""
#: build/lib/core/models.py:1260 core/models.py:1260
#: build/lib/core/models.py:1259 core/models.py:1259
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
#: build/lib/core/models.py:1264 core/models.py:1264
#: build/lib/core/models.py:1263 core/models.py:1263
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
#: build/lib/core/models.py:1270 core/models.py:1270
#: build/lib/core/models.py:1269 core/models.py:1269
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
#: build/lib/core/models.py:1282 core/models.py:1282
#: build/lib/core/models.py:1281 core/models.py:1281
msgid "description"
msgstr "说明"
#: build/lib/core/models.py:1283 core/models.py:1283
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "code"
msgstr "代码"
#: build/lib/core/models.py:1284 core/models.py:1284
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "css"
msgstr "css"
#: build/lib/core/models.py:1286 core/models.py:1286
#: build/lib/core/models.py:1285 core/models.py:1285
msgid "public"
msgstr "公开"
#: build/lib/core/models.py:1288 core/models.py:1288
#: build/lib/core/models.py:1287 core/models.py:1287
msgid "Whether this template is public for anyone to use."
msgstr "该模板是否公开供任何人使用。"
#: build/lib/core/models.py:1294 core/models.py:1294
#: build/lib/core/models.py:1293 core/models.py:1293
msgid "Template"
msgstr "模板"
#: build/lib/core/models.py:1295 core/models.py:1295
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Templates"
msgstr "模板"
#: build/lib/core/models.py:1348 core/models.py:1348
#: build/lib/core/models.py:1347 core/models.py:1347
msgid "Template/user relation"
msgstr "模板/用户关系"
#: build/lib/core/models.py:1349 core/models.py:1349
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relations"
msgstr "模板/用户关系集"
#: build/lib/core/models.py:1355 core/models.py:1355
#: build/lib/core/models.py:1354 core/models.py:1354
msgid "This user is already in this template."
msgstr "该用户已在此模板中。"
#: build/lib/core/models.py:1361 core/models.py:1361
#: build/lib/core/models.py:1360 core/models.py:1360
msgid "This team is already in this template."
msgstr "该团队已在此模板中。"
#: build/lib/core/models.py:1438 core/models.py:1438
#: build/lib/core/models.py:1437 core/models.py:1437
msgid "email address"
msgstr "电子邮件地址"
#: build/lib/core/models.py:1457 core/models.py:1457
#: build/lib/core/models.py:1456 core/models.py:1456
msgid "Document invitation"
msgstr "文档邀请"
#: build/lib/core/models.py:1458 core/models.py:1458
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitations"
msgstr "文档邀请"
#: build/lib/core/models.py:1478 core/models.py:1478
#: build/lib/core/models.py:1477 core/models.py:1477
msgid "This email is already associated to a registered user."
msgstr "此电子邮件已经与现有注册用户关联。"
+3 -2
View File
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "impress"
version = "3.7.0"
version = "3.6.0"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
@@ -33,13 +33,14 @@ dependencies = [
"django-cors-headers==4.7.0",
"django-countries==7.6.1",
"django-csp==4.0",
"django-dirtyfields==1.9.7",
"django-filter==25.1",
"django-lasuite[all]==0.0.14",
"django-parler==2.3",
"django-redis==6.0.0",
"django-storages[s3]==1.14.6",
"django-timezone-field>=5.1",
"django==5.2.6",
"django==5.2.4",
"django-treebeard==4.7.1",
"djangorestframework==3.16.0",
"drf_spectacular==0.28.0",
@@ -45,8 +45,8 @@ test.describe('Doc Create', () => {
})
.click();
const input = page.getByRole('textbox', { name: 'Document title' });
await expect(input).toHaveText('', { timeout: 10000 });
const input = page.getByRole('textbox', { name: 'doc title input' });
await expect(input).toHaveText('');
await expect(
page.locator('.c__tree-view--row-content').getByText('Untitled document'),
).toBeVisible();
@@ -67,8 +67,8 @@ test.describe('Doc Create', () => {
.getByText('New sub-doc')
.click();
const input = page.getByRole('textbox', { name: 'Document title' });
await expect(input).toHaveText('', { timeout: 10000 });
const input = page.getByRole('textbox', { name: 'doc title input' });
await expect(input).toHaveText('');
await expect(
page.locator('.c__tree-view--row-content').getByText('Untitled document'),
).toBeVisible();
@@ -226,13 +226,9 @@ test.describe('Doc Editor', () => {
await editor.fill('Hello World Doc persisted 2');
await expect(editor.getByText('Hello World Doc persisted 2')).toBeVisible();
await page.waitForTimeout(1000);
const urlDoc = page.url();
await page.goto(urlDoc);
// Wait for editor to load
await expect(editor).toBeVisible();
await expect(editor.getByText('Hello World Doc persisted 2')).toBeVisible();
});
@@ -467,14 +463,12 @@ test.describe('Doc Editor', () => {
await expect(
page.getByRole('button', {
name: 'Download',
exact: true,
}),
).toBeVisible();
void page
.getByRole('button', {
name: 'Download',
exact: true,
})
.click();
@@ -703,20 +697,8 @@ test.describe('Doc Editor', () => {
const emojiButton = calloutBlock.getByRole('button');
await expect(emojiButton).toHaveText('💡');
await emojiButton.click();
// Group smiley
await expect(page.getByRole('button', { name: '🤠' })).toBeVisible();
// Group animals
await page.getByText('Animals & Nature').scrollIntoViewIfNeeded();
await expect(page.getByRole('button', { name: '🦆' })).toBeVisible();
// Group travel
await page.getByText('Travel & Places').scrollIntoViewIfNeeded();
await expect(page.getByRole('button', { name: '🚝' })).toBeVisible();
// Group objects
await page.getByText('Objects').scrollIntoViewIfNeeded();
await expect(page.getByRole('button', { name: '🪇' })).toBeVisible();
// Group symbol
await page.getByText('Symbols').scrollIntoViewIfNeeded();
await expect(page.getByRole('button', { name: '🛃' })).toBeVisible();
await page.locator('button[aria-label="⚠️"]').click();
await expect(emojiButton).toHaveText('⚠️');
await page.locator('.bn-side-menu > button').last().click();
await page.locator('.mantine-Menu-dropdown > button').last().click();
@@ -38,11 +38,9 @@ test.describe('Doc Export', () => {
).toBeVisible();
await expect(page.getByRole('combobox', { name: 'Format' })).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Close the download modal',
}),
page.getByRole('button', { name: 'Close the modal' }),
).toBeVisible();
await expect(page.getByTestId('doc-export-download-button')).toBeVisible();
await expect(page.getByTestId('modal-download-button')).toBeVisible();
});
test('it exports the doc with pdf line break', async ({
@@ -83,7 +81,12 @@ test.describe('Doc Export', () => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
});
void page.getByTestId('doc-export-download-button').click();
void page
.getByRole('button', {
name: 'Download',
exact: true,
})
.click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
@@ -128,13 +131,13 @@ test.describe('Doc Export', () => {
await page.getByRole('combobox', { name: 'Format' }).click();
await page.getByRole('option', { name: 'Docx' }).click();
await expect(page.getByTestId('doc-export-download-button')).toBeVisible();
await expect(page.getByTestId('modal-download-button')).toBeVisible();
const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${randomDoc}.docx`);
});
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.docx`);
@@ -200,7 +203,7 @@ test.describe('Doc Export', () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
await expect(page.getByTestId('doc-export-download-button')).toBeVisible();
await expect(page.getByTestId('modal-download-button')).toBeVisible();
const responseCorsPromise = page.waitForResponse(
(response) =>
@@ -211,7 +214,7 @@ test.describe('Doc Export', () => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
});
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const responseCors = await responseCorsPromise;
expect(responseCors.ok()).toBe(true);
@@ -253,13 +256,13 @@ test.describe('Doc Export', () => {
})
.click();
await expect(page.getByTestId('doc-export-download-button')).toBeVisible();
await expect(page.getByTestId('modal-download-button')).toBeVisible();
const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
});
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
@@ -295,15 +298,13 @@ test.describe('Doc Export', () => {
})
.click();
await expect(
page.getByTestId('doc-open-modal-download-button'),
).toBeVisible();
await expect(page.getByTestId('modal-download-button')).toBeVisible();
const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
});
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
@@ -349,15 +350,13 @@ test.describe('Doc Export', () => {
})
.click();
await expect(
page.getByTestId('doc-open-modal-download-button'),
).toBeVisible();
await expect(page.getByTestId('modal-download-button')).toBeVisible();
const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
});
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
@@ -393,9 +392,14 @@ test.describe('Doc Export', () => {
})
.click();
const input = page.locator('.--docs--doc-title-input[role="textbox"]');
await page.waitForURL('**/docs/**', {
timeout: 10000,
waitUntil: 'domcontentloaded',
});
const input = page.getByLabel('doc title input');
await expect(input).toBeVisible();
await expect(input).toHaveText('', { timeout: 10000 });
await expect(input).toHaveText('');
await input.click();
await input.fill(randomDocFrench);
await input.blur();
@@ -414,7 +418,7 @@ test.describe('Doc Export', () => {
return download.suggestedFilename().includes(`${randomDocFrench}.pdf`);
});
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDocFrench}.pdf`);
@@ -449,23 +453,19 @@ test.describe('Doc Export', () => {
await page.locator('.bn-block-outer').last().fill('/');
await page.getByText('Link a doc').first().click();
const input = page.locator(
"span[data-inline-content-type='interlinkingSearchInline'] input",
);
const searchContainer = page.locator('.quick-search-container');
await page
.locator(
"span[data-inline-content-type='interlinkingSearchInline'] input",
)
.fill('interlink-child');
await input.fill('export-interlink');
await page
.locator('.quick-search-container')
.getByText('interlink-child')
.click();
await expect(searchContainer).toBeVisible();
await expect(searchContainer.getByText(randomDoc)).toBeVisible();
// We are in docChild, we want to create a link to randomDoc (parent)
await searchContainer.getByText(randomDoc).click();
// Search the interlinking link in the editor (not in the document tree)
const editor = page.locator('.ProseMirror.bn-editor');
const interlink = editor.getByRole('link', {
name: randomDoc,
const interlink = page.getByRole('link', {
name: 'interlink-child',
});
await expect(interlink).toBeVisible();
@@ -480,7 +480,7 @@ test.describe('Doc Export', () => {
})
.click();
void page.getByTestId('doc-export-download-button').click();
void page.getByTestId('modal-download-button').click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${docChild}.pdf`);
@@ -488,6 +488,6 @@ test.describe('Doc Export', () => {
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
const pdfData = await pdf(pdfBuffer);
expect(pdfData.text).toContain(randomDoc);
expect(pdfData.text).toContain('interlink-child'); // This is the pdf text
});
});
@@ -80,7 +80,9 @@ test.describe('Documents Grid mobile', () => {
hasText: 'My mocked document',
});
await expect(row.getByTestId('doc-title')).toHaveText('My mocked document');
await expect(
row.locator('[aria-describedby="doc-title"]').nth(0),
).toHaveText('My mocked document');
});
});
@@ -147,7 +149,7 @@ test.describe('Document grid item options', () => {
await page
.getByRole('button', {
name: 'Delete document',
name: 'Confirm deletion',
})
.click();
@@ -293,7 +295,7 @@ test.describe('Documents Grid', () => {
docs = result.results as SmallDoc[];
await expect(page.getByTestId('grid-loader')).toBeHidden();
await expect(page.locator('h2').getByText('All docs')).toBeVisible();
await expect(page.locator('h4').getByText('All docs')).toBeVisible();
const thead = page.getByTestId('docs-grid-header');
await expect(thead.getByText(/Name/i)).toBeVisible();
@@ -25,7 +25,7 @@ test.describe('Doc Header', () => {
'It is the card information about the document.',
);
const docTitle = card.getByRole('textbox', { name: 'Document title' });
const docTitle = card.getByRole('textbox', { name: 'doc title input' });
await expect(docTitle).toBeVisible();
await page.getByRole('button', { name: 'Share' }).click();
@@ -54,7 +54,7 @@ test.describe('Doc Header', () => {
test('it updates the title doc', async ({ page, browserName }) => {
await createDoc(page, 'doc-update', browserName, 1);
const docTitle = page.getByRole('textbox', { name: 'Document title' });
const docTitle = page.getByRole('textbox', { name: 'doc title input' });
await expect(docTitle).toBeVisible();
await docTitle.fill('Hello World');
await docTitle.blur();
@@ -66,7 +66,7 @@ test.describe('Doc Header', () => {
browserName,
}) => {
await createDoc(page, 'doc-update', browserName, 1);
const docTitle = page.getByRole('textbox', { name: 'Document title' });
const docTitle = page.getByRole('textbox', { name: 'doc title input' });
await expect(docTitle).toBeVisible();
await docTitle.fill('👍 Hello Emoji World');
await docTitle.blur();
@@ -100,7 +100,7 @@ test.describe('Doc Header', () => {
await page
.getByRole('button', {
name: 'Delete document',
name: 'Confirm deletion',
})
.click();
@@ -228,27 +228,23 @@ test.describe('Doc Header', () => {
await page.getByRole('button', { name: 'Share' }).click();
const shareModal = page.getByRole('dialog', {
name: 'Share modal content',
});
await expect(shareModal).toBeVisible();
const shareModal = page.getByLabel('Share modal');
await expect(page.getByText('Share the document')).toBeVisible();
await expect(page.getByPlaceholder('Type a name or email')).toBeHidden();
const invitationCard = shareModal.getByLabel('List invitation card');
await expect(invitationCard).toBeVisible();
await expect(
invitationCard.getByText('test@invitation.test').first(),
).toBeVisible();
await expect(invitationCard.getByLabel('Document role text')).toBeVisible();
await expect(invitationCard.getByLabel('doc-role-text')).toBeVisible();
await expect(
invitationCard.getByRole('button', { name: 'more_horiz' }),
).toBeHidden();
const memberCard = shareModal.getByLabel('List members card');
await expect(memberCard.getByText('test@accesses.test')).toBeVisible();
await expect(memberCard.getByLabel('Document role text')).toBeVisible();
await expect(memberCard.getByLabel('doc-role-text')).toBeVisible();
await expect(
memberCard.getByRole('button', { name: 'more_horiz' }),
).toBeHidden();
@@ -300,18 +296,17 @@ test.describe('Doc Header', () => {
await expect(page.getByPlaceholder('Type a name or email')).toBeHidden();
const invitationCard = shareModal.getByLabel('List invitation card');
await expect(invitationCard).toBeVisible();
await expect(
invitationCard.getByText('test@invitation.test').first(),
).toBeVisible();
await expect(invitationCard.getByLabel('Document role text')).toBeVisible();
await expect(invitationCard.getByLabel('doc-role-text')).toBeVisible();
await expect(
invitationCard.getByRole('button', { name: 'more_horiz' }),
).toBeHidden();
const memberCard = shareModal.getByLabel('List members card');
await expect(memberCard.getByText('test@accesses.test')).toBeVisible();
await expect(memberCard.getByLabel('Document role text')).toBeVisible();
await expect(memberCard.getByLabel('doc-role-text')).toBeVisible();
await expect(
memberCard.getByRole('button', { name: 'more_horiz' }),
).toBeHidden();
@@ -15,7 +15,7 @@ test.describe('Document create member', () => {
});
test('it selects 2 users and 1 invitation', async ({ page, browserName }) => {
const inputFill = 'user.test';
const inputFill = 'user ';
const responsePromise = page.waitForResponse(
(response) =>
response.url().includes(`/users/?q=${encodeURIComponent(inputFill)}`) &&
@@ -201,7 +201,7 @@ test.describe('Document create member', () => {
await page.getByLabel('Reader').click();
const moreActions = userInvitation.getByRole('button', {
name: 'Open invitation actions menu',
name: 'more_horiz',
});
await moreActions.click();
@@ -60,37 +60,32 @@ test.describe('Doc Routing', () => {
await page.locator('.ProseMirror.bn-editor').fill('Hello World');
// Wait for the doc link (via its dynamic title) to be visible
const docLink = page.getByRole('link', { name: docTitle });
await expect(docLink).toBeVisible();
const responsePromise = page.route(
/.*\/documents\/.*\/$|users\/me\/$/,
async (route) => {
const request = route.request();
// Intercept GET/PATCH requests to return 401
await page.route(/.*\/documents\/.*\/$|users\/me\/$/, async (route) => {
const request = route.request();
if (
request.method().includes('PATCH') ||
request.method().includes('GET')
) {
await route.fulfill({
status: 401,
json: { detail: 'Log in to access the document' },
});
} else {
await route.continue();
}
});
// Explicitly wait for a 401 response after clicking
const wait401 = page.waitForResponse(
(resp) =>
resp.status() === 401 &&
/\/(documents\/[^/]+\/|users\/me\/)$/.test(resp.url()),
if (
request.method().includes('PATCH') ||
request.method().includes('GET')
) {
await route.fulfill({
status: 401,
json: {
detail: 'Log in to access the document',
},
});
} else {
await route.continue();
}
},
);
await docLink.click();
await wait401;
await page.getByRole('link', { name: '401-doc-parent' }).click();
await expect(page.getByText('Log in to access the document.')).toBeVisible({
await responsePromise;
await expect(page.getByText('Log in to access the document')).toBeVisible({
timeout: 10000,
});
});
@@ -33,7 +33,7 @@ test.describe('Document search', () => {
).toBeVisible();
await expect(
page.getByRole('heading', { name: 'Search docs' }),
page.getByLabel('Search modal').getByText('search'),
).toBeVisible();
const inputSearch = page.getByPlaceholder('Type the name of a document');
@@ -79,7 +79,7 @@ test.describe('Document search', () => {
await page.keyboard.press('Control+k');
await expect(
page.getByRole('heading', { name: 'Search docs' }),
page.getByLabel('Search modal').getByText('search'),
).toBeVisible();
await page.keyboard.press('Escape');
@@ -173,13 +173,12 @@ test.describe('Document search', () => {
.getByRole('combobox', { name: 'Quick search input' })
.fill('sub page search');
// Expect to find the first and second docs in the results list
const resultsList = page.getByRole('listbox');
// Expect to find the first doc
await expect(
resultsList.getByRole('option', { name: firstDocTitle }),
page.getByRole('presentation').getByLabel(firstDocTitle),
).toBeVisible();
await expect(
resultsList.getByRole('option', { name: secondDocTitle }),
page.getByRole('presentation').getByLabel(secondDocTitle),
).toBeVisible();
await page.getByRole('button', { name: 'close' }).click();
@@ -196,15 +195,14 @@ test.describe('Document search', () => {
.fill('second');
// Now there is a sub page - expect to have the focus on the current doc
const updatedResultsList = page.getByRole('listbox');
await expect(
updatedResultsList.getByRole('option', { name: secondDocTitle }),
page.getByRole('presentation').getByLabel(secondDocTitle),
).toBeVisible();
await expect(
updatedResultsList.getByRole('option', { name: secondChildDocTitle }),
page.getByRole('presentation').getByLabel(secondChildDocTitle),
).toBeVisible();
await expect(
updatedResultsList.getByRole('option', { name: firstDocTitle }),
page.getByRole('presentation').getByLabel(firstDocTitle),
).toBeHidden();
});
});
@@ -50,7 +50,7 @@ test.describe('Doc Tree', () => {
await expect(subPageItem).toBeVisible();
await subPageItem.click();
await verifyDocName(page, '');
const input = page.getByRole('textbox', { name: 'Document title' });
const input = page.getByRole('textbox', { name: 'doc title input' });
await input.click();
const [randomDocName] = randomName('doc-tree-test', browserName, 1);
await input.fill(randomDocName);
@@ -196,7 +196,7 @@ test.describe('Doc Tree', () => {
await page.getByText('Move to my docs').click();
await expect(
page.getByRole('textbox', { name: 'Document title' }),
page.getByRole('textbox', { name: 'doc title input' }),
).not.toHaveText(docChild);
const header = page.locator('header').first();
@@ -101,9 +101,10 @@ export const createDoc = async (
waitUntil: 'networkidle',
});
const input = page.getByLabel('Document title');
const input = page.getByLabel('doc title input');
await expect(input).toBeVisible();
await expect(input).toHaveText('');
await input.click();
await input.fill(randomDocs[i]);
await input.blur();
@@ -119,11 +120,10 @@ export const verifyDocName = async (page: Page, docName: string) => {
timeout: 10000,
});
/*replace toHaveText with toContainText to handle cases where emojis or other characters might be added*/
try {
await expect(
page.getByRole('textbox', { name: 'Document title' }),
).toContainText(docName);
page.getByRole('textbox', { name: 'doc title input' }),
).toHaveText(docName);
} catch {
await expect(page.getByRole('heading', { name: docName })).toBeVisible();
}
@@ -172,7 +172,7 @@ export const goToGridDoc = async (
await expect(row).toBeVisible();
const docTitleContent = row.getByTestId('doc-title').first();
const docTitleContent = row.locator('[aria-describedby="doc-title"]').first();
const docTitle = await docTitleContent.textContent();
expect(docTitle).toBeDefined();
@@ -182,9 +182,9 @@ export const goToGridDoc = async (
};
export const updateDocTitle = async (page: Page, title: string) => {
const input = page.getByRole('textbox', { name: 'Document title' });
await expect(input).toHaveText('');
const input = page.getByLabel('doc title input');
await expect(input).toBeVisible();
await expect(input).toHaveText('');
await input.click();
await input.fill(title);
await input.click();
@@ -8,7 +8,7 @@ export const addNewMember = async (
page: Page,
index: number,
role: 'Administrator' | 'Owner' | 'Editor' | 'Reader',
fillText: string = 'user.test',
fillText: string = 'user ',
) => {
const responsePromiseSearchUser = page.waitForResponse(
(response) =>
+2 -6
View File
@@ -1,9 +1,6 @@
{
"name": "app-e2e",
"version": "3.7.0",
"repository": "https://github.com/suitenumerique/docs",
"author": "DINUM",
"license": "MIT",
"version": "3.6.0",
"private": true,
"scripts": {
"lint": "eslint",
@@ -24,6 +21,5 @@
"dependencies": {
"convert-stream": "1.0.2",
"pdf-parse": "1.1.1"
},
"packageManager": "yarn@1.22.22"
}
}
-1
View File
@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
+13 -17
View File
@@ -1,9 +1,6 @@
{
"name": "app-impress",
"version": "3.7.0",
"repository": "https://github.com/suitenumerique/docs",
"author": "DINUM",
"license": "MIT",
"version": "3.6.0",
"private": true,
"scripts": {
"dev": "next dev",
@@ -36,22 +33,22 @@
"@hocuspocus/provider": "2.15.2",
"@openfun/cunningham-react": "3.2.3",
"@react-pdf/renderer": "4.3.0",
"@sentry/nextjs": "10.11.0",
"@tanstack/react-query": "5.87.4",
"@sentry/nextjs": "10.8.0",
"@tanstack/react-query": "5.85.6",
"canvg": "4.0.3",
"clsx": "2.1.1",
"cmdk": "1.1.1",
"crisp-sdk-web": "1.0.25",
"docx": "9.5.0",
"emoji-mart": "5.6.0",
"emoji-regex": "10.5.0",
"i18next": "25.5.2",
"emoji-regex": "10.4.0",
"i18next": "25.4.2",
"i18next-browser-languagedetector": "8.2.0",
"idb": "8.0.3",
"lodash": "4.17.21",
"luxon": "3.7.2",
"next": "15.5.3",
"posthog-js": "1.264.2",
"luxon": "3.7.1",
"next": "15.4.7",
"posthog-js": "1.261.0",
"react": "*",
"react-aria-components": "1.12.1",
"react-dom": "*",
@@ -59,14 +56,14 @@
"react-intersection-observer": "9.16.0",
"react-select": "5.10.2",
"styled-components": "6.1.19",
"use-debounce": "10.0.6",
"use-debounce": "10.0.5",
"y-protocols": "1.0.6",
"yjs": "*",
"zustand": "5.0.8"
},
"devDependencies": {
"@svgr/webpack": "8.1.0",
"@tanstack/react-query-devtools": "5.87.4",
"@tanstack/react-query-devtools": "5.85.6",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.8.0",
"@testing-library/react": "16.3.0",
@@ -78,13 +75,13 @@
"@types/react-dom": "*",
"@vitejs/plugin-react": "5.0.2",
"cross-env": "10.0.0",
"dotenv": "17.2.2",
"dotenv": "17.2.1",
"eslint-plugin-docs": "*",
"fetch-mock": "9.11.0",
"jsdom": "26.1.0",
"node-fetch": "2.7.0",
"prettier": "3.6.2",
"stylelint": "16.24.0",
"stylelint": "16.23.1",
"stylelint-config-standard": "39.0.0",
"stylelint-prettier": "5.0.3",
"typescript": "*",
@@ -92,6 +89,5 @@
"vitest": "3.2.4",
"webpack": "5.101.3",
"workbox-webpack-plugin": "7.1.0"
},
"packageManager": "yarn@1.22.22"
}
}
@@ -28,18 +28,17 @@ const StyledButton = styled(Button)<StyledButtonProps>`
border: none;
background: none;
outline: none;
transition: all 0.2s ease-in-out;
font-weight: 500;
font-size: 0.938rem;
padding: 0;
${({ $css }) => $css};
&:hover {
background-color: var(
--c--components--button--primary-text--background--color-hover
);
}
&:focus-visible {
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-400);
outline: 2px solid var(--c--theme--colors--primary-500);
outline-offset: 2px;
border-radius: 4px;
transition: none;
}
`;
@@ -110,6 +110,7 @@ export const DropdownMenu = ({
$direction="row"
$align="center"
$position="relative"
aria-controls="menu"
>
<Box>{children}</Box>
<Icon
@@ -124,7 +125,9 @@ export const DropdownMenu = ({
/>
</Box>
) : (
<Box ref={blockButtonRef}>{children}</Box>
<Box ref={blockButtonRef} aria-controls="menu">
{children}
</Box>
)
}
>
@@ -204,13 +207,14 @@ export const DropdownMenu = ({
}
&:focus-visible {
outline: 2px solid var(--c--theme--colors--primary-400);
outline: 2px solid var(--c--theme--colors--primary-500);
outline-offset: -2px;
background-color: var(--c--theme--colors--greyscale-050);
}
${isFocused &&
css`
outline: 2px solid var(--c--theme--colors--primary-500);
outline-offset: -2px;
background-color: var(--c--theme--colors--greyscale-050);
`}
@@ -227,7 +231,6 @@ export const DropdownMenu = ({
$theme="greyscale"
$variation={isDisabled ? '400' : '1000'}
iconName={option.icon}
aria-hidden="true"
/>
)}
<Text $variation={isDisabled ? '400' : '1000'}>
@@ -236,12 +239,7 @@ export const DropdownMenu = ({
</Box>
{(option.isSelected ||
selectedValues?.includes(option.value ?? '')) && (
<Icon
iconName="check"
$size="20px"
$theme="greyscale"
aria-hidden="true"
/>
<Icon iconName="check" $size="20px" $theme="greyscale" />
)}
</BoxButton>
{option.showSeparator && (
@@ -30,23 +30,15 @@ export const AlertModal = ({
isOpen={isOpen}
size={ModalSize.MEDIUM}
onClose={onClose}
aria-describedby="alert-modal-title"
title={
<Text
$size="h6"
as="h1"
$margin="0"
id="alert-modal-title"
$align="flex-start"
$variation="1000"
>
<Text $size="h6" $align="flex-start" $variation="1000">
{title}
</Text>
}
rightActions={
<>
<Button
aria-label={`${t('Cancel')} - ${title}`}
aria-label={t('Close the modal')}
color="secondary"
fullWidth
onClick={() => onClose()}
@@ -63,11 +55,12 @@ export const AlertModal = ({
</>
}
>
<Box className="--docs--alert-modal">
<Box
aria-label={t('Confirmation button')}
className="--docs--alert-modal"
>
<Box>
<Text $variation="600" as="p">
{description}
</Text>
<Text $variation="600">{description}</Text>
</Box>
</Box>
</Modal>
@@ -64,7 +64,6 @@ export const QuickSearchInput = ({
role="combobox"
placeholder={placeholder ?? t('Search')}
onValueChange={onFilter}
maxLength={254}
/>
</Box>
{separator && <HorizontalSeparator $withPadding={false} />}
@@ -2,8 +2,7 @@ import { Button } from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, BoxButton } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { BoxButton } from '@/components';
import ProConnectImg from '../assets/button-proconnect.svg';
import { useAuth } from '../hooks';
@@ -12,7 +11,6 @@ import { gotoLogin, gotoLogout } from '../utils';
export const ButtonLogin = () => {
const { t } = useTranslation();
const { authenticated } = useAuth();
const { colorsTokens } = useCunninghamTheme();
if (!authenticated) {
return (
@@ -28,23 +26,14 @@ export const ButtonLogin = () => {
}
return (
<Box
$css={css`
.--docs--button-logout:focus-visible {
box-shadow: 0 0 0 2px ${colorsTokens['primary-400']} !important;
border-radius: 4px;
}
`}
<Button
onClick={gotoLogout}
color="primary-text"
aria-label={t('Logout')}
className="--docs--button-logout"
>
<Button
onClick={gotoLogout}
color="primary-text"
aria-label={t('Logout')}
className="--docs--button-logout"
>
{t('Logout')}
</Button>
</Box>
{t('Logout')}
</Button>
);
};
@@ -44,6 +44,7 @@ import {
} from './custom-inline-content';
import XLMultiColumn from './xl-multi-column';
const multiColumnDropCursor = XLMultiColumn?.multiColumnDropCursor;
const multiColumnLocales = XLMultiColumn?.locales;
const withMultiColumn = XLMultiColumn?.withMultiColumn;
@@ -156,6 +157,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
},
uploadFile,
schema: blockNoteSchema,
dropCursor: multiColumnDropCursor,
},
[collabName, lang, provider, uploadFile],
);
@@ -19,11 +19,10 @@ export const ModalConfirmDownloadUnsafe = ({
isOpen
closeOnClickOutside
onClose={() => onClose()}
aria-describedby="modal-confirm-download-unsafe-title"
rightActions={
<>
<Button
aria-label={t('Cancel the download')}
aria-label={t('Close the modal')}
color="secondary"
onClick={() => onClose()}
>
@@ -32,7 +31,6 @@ export const ModalConfirmDownloadUnsafe = ({
<Button
aria-label={t('Download')}
color="danger"
data-testid="modal-download-unsafe-button"
onClick={() => {
if (onConfirm) {
void onConfirm();
@@ -47,14 +45,11 @@ export const ModalConfirmDownloadUnsafe = ({
size={ModalSize.SMALL}
title={
<Text
as="h1"
id="modal-confirm-download-unsafe-title"
$gap="0.7rem"
$size="h6"
$align="flex-start"
$variation="1000"
$direction="row"
$margin="0"
>
<Icon iconName="warning" $theme="warning" />
{t('Warning')}
@@ -7,12 +7,14 @@ import { Box } from '@/components';
interface EmojiPickerProps {
emojiData: EmojiMartData;
categories: string[];
onClickOutside: () => void;
onEmojiSelect: ({ native }: { native: string }) => void;
}
export const EmojiPicker = ({
emojiData,
categories,
onClickOutside,
onEmojiSelect,
}: EmojiPickerProps) => {
@@ -22,11 +24,14 @@ export const EmojiPicker = ({
<Box $position="absolute" $zIndex={1000} $margin="2rem 0 0 0">
<Picker
data={emojiData}
categories={categories}
locale={i18n.resolvedLanguage}
navPosition="none"
onClickOutside={onClickOutside}
onEmojiSelect={onEmojiSelect}
previewPosition="none"
skinTonePosition="none"
theme="light"
/>
</Box>
);
@@ -10,7 +10,7 @@ import { Box, BoxButton, Icon } from '@/components';
import { DocsBlockNoteEditor } from '../../types';
import { EmojiPicker } from '../EmojiPicker';
import emojidata from './initEmojiCallout';
import InitEmojiCallout from './initEmojiCallout';
export const CalloutBlock = createReactBlockSpec(
{
@@ -79,7 +79,8 @@ export const CalloutBlock = createReactBlockSpec(
{openEmojiPicker && (
<EmojiPicker
emojiData={emojidata}
emojiData={InitEmojiCallout.emojidata}
categories={InitEmojiCallout.calloutCategories}
onClickOutside={onClickOutside}
onEmojiSelect={onEmojiSelect}
/>
@@ -56,4 +56,21 @@ if (!emojidata.categories.some((c) => c.id === CALLOUT_ID)) {
void init({ data: emojidata });
export default emojidata;
const calloutCategories = [
'callout',
'people',
'nature',
'foods',
'activity',
'places',
'flags',
'objects',
'symbols',
];
const calloutEmojiData = {
emojidata,
calloutCategories,
};
export default calloutEmojiData;
@@ -133,11 +133,10 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
closeOnClickOutside
onClose={() => onClose()}
hideCloseButton
aria-describedby="modal-export-title"
rightActions={
<>
<Button
aria-label={t('Cancel the download')}
aria-label={t('Close the modal')}
color="secondary"
fullWidth
onClick={() => onClose()}
@@ -146,12 +145,12 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
{t('Cancel')}
</Button>
<Button
data-testid="doc-export-download-button"
aria-label={t('Download')}
color="primary"
fullWidth
onClick={() => void onSubmit()}
disabled={isExporting}
data-testid="modal-download-button"
>
{t('Download')}
</Button>
@@ -166,9 +165,6 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
$width="100%"
>
<Text
as="h1"
$margin="0"
id="modal-export-title"
$size="h6"
$variation="1000"
$align="flex-start"
@@ -190,7 +186,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
$gap="1rem"
className="--docs--modal-export-content"
>
<Text $variation="600" $size="sm" as="p">
<Text $variation="600" $size="sm">
{t('Download your document in a .docx or .pdf format.')}
</Text>
<Select
@@ -105,7 +105,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
}, [doc]);
return (
<Tooltip content={t('Rename')} aria-hidden={true} placement="top">
<Tooltip content={t('Rename')} placement="top">
<Box
as="span"
role="textbox"
@@ -114,8 +114,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
defaultValue={titleDisplay || undefined}
onKeyDownCapture={handleKeyDown}
suppressContentEditableWarning={true}
aria-label={`${t('Document title')}`}
aria-multiline={false}
aria-label="doc title input"
onBlurCapture={(event) =>
handleTitleSubmit(event.target.textContent || '')
}
@@ -215,7 +215,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
>
<Button
color="tertiary"
aria-label={t('Share button')}
aria-label="Share button"
icon={
<Icon iconName="group" $theme="primary" $variation="800" />
}
@@ -233,15 +233,9 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
{!isSmallMobile && ModalExport && (
<Button
data-testid="doc-open-modal-download-button"
color="tertiary-text"
icon={
<Icon
iconName="download"
$theme="primary"
$variation="800"
aria-hidden={true}
/>
<Icon iconName="download" $theme="primary" $variation="800" />
}
onClick={() => {
setIsModalExportOpen(true);
@@ -250,9 +244,8 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
aria-label={t('Export the document')}
/>
)}
<DropdownMenu options={options} label={t('Open the document options')}>
<DropdownMenu options={options}>
<IconOptions
aria-hidden="true"
isHorizontal
$theme="primary"
$padding={{ all: 'xs' }}
@@ -268,6 +261,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
`
: ''}
`}
aria-label={t('Open the document options')}
/>
</DropdownMenu>
</Box>
@@ -56,11 +56,10 @@ export const ModalRemoveDoc = ({
closeOnClickOutside
hideCloseButton
onClose={() => onClose()}
aria-describedby="modal-remove-doc-title"
rightActions={
<>
<Button
aria-label={t('Cancel the deletion')}
aria-label={t('Close the delete modal')}
color="secondary"
fullWidth
onClick={() => onClose()}
@@ -68,7 +67,7 @@ export const ModalRemoveDoc = ({
{t('Cancel')}
</Button>
<Button
aria-label={t('Delete document')}
aria-label={t('Confirm deletion')}
color="danger"
fullWidth
onClick={() =>
@@ -91,9 +90,8 @@ export const ModalRemoveDoc = ({
>
<Text
$size="h6"
as="h1"
id="modal-remove-doc-title"
$margin="0"
as="h6"
$margin={{ all: '0' }}
$align="flex-start"
$variation="1000"
>
@@ -106,9 +104,12 @@ export const ModalRemoveDoc = ({
</Box>
}
>
<Box className="--docs--modal-remove-doc">
<Box
aria-label={t('Content modal to delete document')}
className="--docs--modal-remove-doc"
>
{!isError && (
<Text $size="sm" $variation="600" $display="inline-block" as="p">
<Text $size="sm" $variation="600" $display="inline-block">
<Trans t={t}>
This document and <strong>any sub-documents</strong> will be
permanently deleted. This action is irreversible.
@@ -82,11 +82,12 @@ export const SimpleDocItem = ({
</Box>
<Box $justify="center" $overflow="auto">
<Text
aria-describedby="doc-title"
aria-label={displayTitle}
$size="sm"
$variation="1000"
$weight="500"
$css={ItemTextCss}
data-testid="doc-title"
>
{displayTitle}
</Text>
@@ -5,7 +5,7 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDebouncedCallback } from 'use-debounce';
import { Box, Text } from '@/components';
import { Box } from '@/components';
import ButtonCloseModal from '@/components/modal/ButtonCloseModal';
import { QuickSearch } from '@/components/quick-search';
import { Doc, useDocUtils } from '@/docs/doc-management';
@@ -65,7 +65,6 @@ const DocSearchModalGlobal = ({
closeOnClickOutside
size={isDesktop ? ModalSize.LARGE : ModalSize.FULL}
hideCloseButton
aria-describedby="doc-search-modal-title"
>
<Box
aria-label={t('Search modal')}
@@ -73,14 +72,6 @@ const DocSearchModalGlobal = ({
$justify="space-between"
className="--docs--doc-search-modal"
>
<Text
as="h1"
$margin="0"
id="doc-search-modal-title"
className="sr-only"
>
{t('Search docs')}
</Text>
<Box $position="absolute" $css="top: 12px; right: 12px;">
<ButtonCloseModal
aria-label={t('Close the search modal')}
@@ -102,7 +102,7 @@ export const DocRoleDropdown = ({
if (!canUpdate) {
return (
<Text aria-label={t('Document role text')} $variation="600">
<Text aria-label="doc-role-text" $variation="600">
{transRole(currentRole)}
</Text>
);
@@ -118,9 +118,8 @@ export const DocShareInvitationItem = ({
<DropdownMenu
data-testid="doc-share-invitation-more-actions"
options={moreActions}
label={t('Open invitation actions menu')}
>
<IconOptions isHorizontal $variation="600" aria-hidden="true" />
<IconOptions isHorizontal $variation="600" />
</DropdownMenu>
)}
</Box>
@@ -159,12 +158,7 @@ export const DocShareModalInviteUserRow = ({
<Text $theme="primary" $variation="800">
{t('Add')}
</Text>
<Icon
$theme="primary"
$variation="800"
iconName="add"
aria-hidden="true"
/>
<Icon $theme="primary" $variation="800" iconName="add" />
</Box>
}
/>
@@ -135,21 +135,12 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
isOpen
closeOnClickOutside
data-testid="doc-share-modal"
aria-describedby="doc-share-modal-title"
aria-label={t('Share modal')}
size={isDesktop ? ModalSize.LARGE : ModalSize.FULL}
onClose={onClose}
title={
<Box $direction="row" $justify="space-between" $align="center">
<Text
as="h1"
id="doc-share-modal-title"
$align="flex-start"
$size="small"
$weight="600"
$margin="0"
>
{t('Share the document')}
</Text>
<Box $align="flex-start">{t('Share the document')}</Box>
<ButtonCloseModal
aria-label={t('Close the share modal')}
onClick={onClose}
@@ -208,7 +199,6 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
$textAlign="center"
$variation="600"
$size="sm"
as="p"
>
{t(
'You can view this document but need additional access to see its members or modify settings.',
@@ -155,7 +155,6 @@ export const DocTreeItemActions = ({
options={options}
isOpen={isOpen}
onOpenChange={onOpenChange}
aria-label={t('Open document actions menu')}
>
<Icon
onClick={(e) => {
@@ -167,7 +166,6 @@ export const DocTreeItemActions = ({
variant="filled"
$theme="primary"
$variation="600"
aria-hidden="true"
/>
</DropdownMenu>
{doc.abilities.children_create && (
@@ -69,11 +69,10 @@ export const ModalConfirmationVersion = ({
isOpen
closeOnClickOutside
onClose={() => onClose()}
aria-describedby="modal-confirmation-version-title"
rightActions={
<>
<Button
aria-label={`${t('Cancel')} - ${t('Warning')}`}
aria-label={t('Close the modal')}
color="secondary"
fullWidth
onClick={() => onClose()}
@@ -103,24 +102,20 @@ export const ModalConfirmationVersion = ({
}
size={ModalSize.SMALL}
title={
<Text
as="h1"
$margin="0"
id="modal-confirmation-version-title"
$size="h6"
$align="flex-start"
$variation="1000"
>
<Text $size="h6" $align="flex-start" $variation="1000">
{t('Warning')}
</Text>
}
>
<Box className="--docs--modal-confirmation-version">
<Box
aria-label={t('Modal confirmation to restore the version')}
className="--docs--modal-confirmation-version"
>
<Box>
<Text $variation="600" as="p">
<Text $variation="600">
{t('Your current document will revert to this version.')}
</Text>
<Text $variation="600" as="p">
<Text $variation="600">
{t('If a member is editing, his works can be lost.')}
</Text>
</Box>
@@ -48,7 +48,6 @@ export const ModalSelectVersion = ({
closeOnClickOutside={true}
size={ModalSize.EXTRA_LARGE}
onClose={onClose}
aria-describedby="modal-select-version-title"
>
<NoPaddingStyle />
<Box
@@ -59,14 +58,6 @@ export const ModalSelectVersion = ({
$maxHeight="calc(100vh - 2em - 12px)"
$overflow="hidden"
>
<Text
as="h1"
$margin="0"
id="modal-select-version-title"
className="sr-only"
>
{t('Version history')}
</Text>
<Box
$css={css`
display: flex;
@@ -191,7 +191,6 @@ export const DraggableDocGridContentList = ({
data-testid="drag-doc-overlay"
$height="auto"
role="alert"
aria-label={t('Drag and drop status')}
>
<Text $size="xs" $variation="000" $weight="500">
{overlayText}
@@ -70,6 +70,7 @@ export const DocsGrid = ({
>
<DocsGridLoader isLoading={isRefetching || loading} />
<Card
role="grid"
data-testid="docs-grid"
$height="100%"
$width="100%"
@@ -83,7 +84,7 @@ export const DocsGrid = ({
}}
>
<Text
as="h2"
as="h4"
$size="h4"
$variation="1000"
$margin={{ top: '0px', bottom: '10px' }}
@@ -100,57 +101,48 @@ export const DocsGrid = ({
)}
{hasDocs && (
<Box $gap="6px" $overflow="auto">
<Box role="grid" aria-label={t('Documents grid')}>
<Box role="rowgroup">
<Box
$direction="row"
$padding={{ horizontal: 'xs' }}
$gap="10px"
data-testid="docs-grid-header"
role="row"
>
<Box $flex={flexLeft} $padding="3xs" role="columnheader">
<Text $size="xs" $variation="600" $weight="500">
{t('Name')}
</Text>
</Box>
{isDesktop && (
<Box
$flex={flexRight}
$padding={{ vertical: '3xs' }}
role="columnheader"
>
<Text $size="xs" $weight="500" $variation="600">
{t('Updated at')}
</Text>
</Box>
)}
<Box
$direction="row"
$padding={{ horizontal: 'xs' }}
$gap="10px"
data-testid="docs-grid-header"
>
<Box $flex={flexLeft} $padding="3xs">
<Text $size="xs" $variation="600" $weight="500">
{t('Name')}
</Text>
</Box>
{isDesktop && (
<Box $flex={flexRight} $padding={{ vertical: '3xs' }}>
<Text $size="xs" $weight="500" $variation="600">
{t('Updated at')}
</Text>
</Box>
</Box>
<Box role="rowgroup">
{isDesktop ? (
<DraggableDocGridContentList docs={docs} />
) : (
<DocGridContentList docs={docs} />
)}
</Box>
{hasNextPage && !loading && (
<InView
data-testid="infinite-scroll-trigger"
as="div"
onChange={loadMore}
>
{!isFetching && hasNextPage && (
<Button
onClick={() => void fetchNextPage()}
color="primary-text"
>
{t('More docs')}
</Button>
)}
</InView>
)}
</Box>
{isDesktop ? (
<DraggableDocGridContentList docs={docs} />
) : (
<DocGridContentList docs={docs} />
)}
{hasNextPage && !loading && (
<InView
data-testid="infinite-scroll-trigger"
as="div"
onChange={loadMore}
>
{!isFetching && hasNextPage && (
<Button
onClick={() => void fetchNextPage()}
color="primary-text"
>
{t('More docs')}
</Button>
)}
</InView>
)}
</Box>
)}
</Card>
@@ -83,23 +83,19 @@ export const DocsGridActions = ({
return (
<>
<DropdownMenu
options={options}
label={menuLabel}
aria-label={t('More options')}
>
<DropdownMenu options={options} label={menuLabel}>
<Icon
data-testid={`docs-grid-actions-button-${doc.id}`}
iconName="more_horiz"
$theme="primary"
$variation="600"
aria-label={t('More options')}
$css={css`
cursor: pointer;
&:hover {
opacity: 0.8;
}
`}
aria-hidden="true"
/>
</DropdownMenu>
@@ -53,86 +53,67 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
`}
className="--docs--doc-grid-item"
>
<Box
$flex={flexLeft}
role="gridcell"
<StyledLink
$css={css`
flex: ${flexLeft};
align-items: center;
min-width: 0;
`}
href={`/docs/${doc.id}`}
>
<StyledLink
$css={css`
width: 100%;
align-items: center;
min-width: 0;
`}
href={`/docs/${doc.id}`}
<Box
data-testid={`docs-grid-name-${doc.id}`}
$direction="row"
$align="center"
$gap={spacingsTokens.xs}
$padding={{ right: isDesktop ? 'md' : '3xs' }}
$maxWidth="100%"
>
<Box
data-testid={`docs-grid-name-${doc.id}`}
$direction="row"
$align="center"
$gap={spacingsTokens.xs}
$padding={{ right: isDesktop ? 'md' : '3xs' }}
$maxWidth="100%"
>
<SimpleDocItem isPinned={doc.is_favorite} doc={doc} />
{isShared && (
<Box
$padding={{ top: !isDesktop ? '4xs' : undefined }}
$css={
!isDesktop
? css`
align-self: flex-start;
`
: undefined
}
>
{dragMode && (
<Icon
$theme="greyscale"
$variation="600"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
aria-label={
isPublic
<SimpleDocItem isPinned={doc.is_favorite} doc={doc} />
{isShared && (
<Box
$padding={{ top: !isDesktop ? '4xs' : undefined }}
$css={
!isDesktop
? css`
align-self: flex-start;
`
: undefined
}
>
{dragMode && (
<Icon
$theme="greyscale"
$variation="600"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
/>
)}
{!dragMode && (
<Tooltip
content={
<Text $textAlign="center" $variation="000">
{isPublic
? t('Accessible to anyone')
: t('Accessible to authenticated users')
}
/>
)}
{!dragMode && (
<Tooltip
content={
<Text $textAlign="center" $variation="000">
{isPublic
? t('Accessible to anyone')
: t('Accessible to authenticated users')}
</Text>
}
placement="top"
>
<div>
<Icon
$theme="greyscale"
$variation="600"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
aria-label={
isPublic
? t('Accessible to anyone')
: t('Accessible to authenticated users')
}
/>
</div>
</Tooltip>
)}
</Box>
)}
</Box>
</StyledLink>
</Box>
: t('Accessible to authenticated users')}
</Text>
}
placement="top"
>
<div>
<Icon
$theme="greyscale"
$variation="600"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
/>
</div>
</Tooltip>
)}
</Box>
)}
</Box>
</StyledLink>
<Box
$flex={flexRight}
@@ -140,7 +121,6 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
$align="center"
$justify={isDesktop ? 'space-between' : 'flex-end'}
$gap="32px"
role="gridcell"
>
{isDesktop && (
<StyledLink href={`/docs/${doc.id}`}>
@@ -1,5 +1,5 @@
import { Loader } from '@openfun/cunningham-react';
import { createGlobalStyle, css } from 'styled-components';
import { createGlobalStyle } from 'styled-components';
import { Box } from '@/components';
@@ -32,9 +32,6 @@ export const DocsGridLoader = ({ isLoading }: DocsGridLoaderProps) => {
$zIndex={998}
$position="absolute"
className="--docs--doc-grid-loader"
$css={css`
pointer-events: none;
`}
>
<Loader />
</Box>
@@ -19,7 +19,6 @@ export const Draggable = <T,>(props: DraggableProps<T>) => {
{...attributes}
data-testid={`draggable-doc-${props.id}`}
className="--docs--grid-draggable"
role="presentation"
>
{props.children}
</div>
@@ -35,7 +35,6 @@ export const Droppable = ({
<Box
ref={setNodeRef}
data-testid={`droppable-doc-${id}`}
role="presentation"
$css={css`
border-radius: 4px;
background-color: ${enableHover
@@ -43,13 +43,6 @@ export const Header = () => {
href="/"
data-testid="header-logo-link"
aria-label={t('Back to homepage')}
$css={css`
outline: none;
&:focus-visible {
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-400) !important;
border-radius: 4px;
}
`}
>
<Box
$align="center"
@@ -33,11 +33,7 @@ export function HomeContent() {
const isFrLanguage = i18n.resolvedLanguage === 'fr';
return (
<Box
as="main"
className="--docs--home-content"
aria-label={t('Main content')}
>
<Box as="main" className="--docs--home-content">
<HomeHeader />
{isSmallMobile && (
<Box $css="& .--docs--left-panel-header{display: none;}">
@@ -41,7 +41,15 @@ export const LanguagePicker = () => {
showArrow
label={t('Select language')}
buttonCss={css`
transition: all 0.15s ease-in-out !important;
&:hover {
background-color: var(
--c--components--button--primary-text--background--color-hover
);
}
&:focus-visible {
outline: 2px solid var(--c--theme--colors--primary-500);
outline-offset: 2px;
}
border-radius: 4px;
padding: 0.5rem 0.6rem;
& > div {
@@ -55,16 +63,12 @@ export const LanguagePicker = () => {
>
<Text
$theme="primary"
aria-label={t('Language')}
$direction="row"
$gap="0.5rem"
className="--docs--language-picker-text"
>
<Icon
iconName="translate"
$color="inherit"
$size="xl"
aria-hidden="true"
/>
<Icon iconName="translate" $color="inherit" $size="xl" />
{currentLanguageLabel}
</Text>
</DropdownMenu>
@@ -85,9 +85,8 @@ export const LeftPanelTargetFilters = () => {
background-color: ${colorsTokens['greyscale-100']};
}
&:focus-visible {
outline: none !important;
box-shadow: 0 0 0 2px ${colorsTokens['primary-500']} !important;
border-radius: 4px;
outline: 2px solid ${colorsTokens['primary-500']};
outline-offset: 2px;
}
`}
>
@@ -31,26 +31,27 @@ export const LeftPanelFavoriteItem = ({ doc }: LeftPanelFavoriteItemProps) => {
.pinned-actions {
opacity: ${isDesktop ? 0 : 1};
}
&:hover {
background-color: ${colorsTokens['greyscale-100']};
}
&:hover,
&:focus-within {
cursor: pointer;
box-shadow: 0 0 0 2px ${colorsTokens['primary-500']} !important;
background-color: var(--c--theme--colors--greyscale-100);
.pinned-actions {
opacity: 1;
}
}
&:focus-visible {
outline: 2px solid ${colorsTokens['primary-500']};
outline-offset: 2px;
border-radius: ${spacingsTokens['3xs']};
}
`}
key={doc.id}
className="--docs--left-panel-favorite-item"
>
<StyledLink
href={`/docs/${doc.id}`}
$css={css`
overflow: auto;
outline: none !important;
`}
$css="overflow: auto;"
aria-label={`${doc.title}, ${t('Updated')} ${DateTime.fromISO(doc.updated_at).toRelative()}`}
>
<SimpleDocItem showAccesses doc={doc} />
@@ -44,21 +44,17 @@ export const LeftPanelFavorites = () => {
>
{t('Pinned documents')}
</Text>
<Box>
<Box as="ul" $padding="none">
{favoriteDocs.map((doc) => (
<LeftPanelFavoriteItem key={doc.id} doc={doc} />
))}
</Box>
{docs.hasNextPage && (
<InfiniteScroll
hasMore={docs.hasNextPage}
isLoading={docs.isFetchingNextPage}
next={() => void docs.fetchNextPage()}
$padding="none"
/>
)}
</Box>
<InfiniteScroll
as="ul"
hasMore={docs.hasNextPage}
isLoading={docs.isFetchingNextPage}
next={() => void docs.fetchNextPage()}
$padding="none"
>
{favoriteDocs.map((doc) => (
<LeftPanelFavoriteItem key={doc.id} doc={doc} />
))}
</InfiniteScroll>
</Box>
</Box>
);
@@ -33,11 +33,15 @@
"Callout": "Kemenn-son",
"Can't load this page, please check your internet connection.": "N'haller ket kargañ ar bajenn-mañ, gwiriit ho kevreadenn internet mar plij.",
"Cancel": "Nullañ",
"Close the modal": "Serriñ ar modal",
"Collaborate": "Kenlabourat",
"Collaborate and write in real time, without layout constraints.": "Kenlabourit ha skrivit en amzer wirion hep kudenn pajennaozañ ebet.",
"Collaborative writing, Simplified.": "Ar skrivañ a-stroll simplaet.",
"Confirm": "Kadarnaat",
"Confirm deletion": "Kadarnaat an dilamadenn",
"Confirmation button": "Bouton kadarnaat",
"Connected": "Kevreet",
"Content modal to delete document": "Endalc'had modal da zilemel ar restr",
"Content modal to explain why the user cannot edit": "Modal endalc'had evit displegañ perak ne c'hall ket an implijer aozañ",
"Content modal to export the document": "Endalc'had modal evit ezporzhiañ ar restr",
"Convert Markdown": "Amdreiñ ar Markdown",
@@ -120,6 +124,7 @@
"Logo": "Logo",
"Logout": "Digevreañ",
"Modal confirmation to download the attachment": "Modal kadarnaat evit pellgargañ ar pezh-stag",
"Modal confirmation to restore the version": "Modal kadarnaat evit assevel ar stumm",
"More docs": "Restroù ouzhpenn",
"More options": "Muioc'h a zibaboù",
"Move": "Fiñval",
@@ -177,6 +182,8 @@
"Select a version on the right to restore": "Dibabit ur stumm a-zehoù da assevel",
"Select language": "Dibab ur yezh",
"Share": "Rannañ",
"Share modal": "Modal rannañ",
"Share modal content": "Endalc'h modal rannañ",
"Share the document": "Rannañ an teul",
"Share with {{count}} users_many": "Rannañ gant {{count}} implijer",
"Share with {{count}} users_one": "Rannañ gant {{count}} implijer",
@@ -259,11 +266,20 @@
"Beautify": "Verschönern",
"Can't load this page, please check your internet connection.": "Diese Seite kann nicht geladen werden. Bitte überprüfen Sie Ihre Internetverbindung.",
"Cancel": "Abbrechen",
"Close the modal": "Pop-up schließen",
"Close the access request modal": "Zugriffsanfrage-Modal schließen",
"Close the delete modal": "Lösch-Modal schließen",
"Close the search modal": "Such-Modal schließen",
"Close the share modal": "Freigabe-Modal schließen",
"Close the version history modal": "Versionsverlauf-Modal schließen",
"Collaborate": "Zusammenarbeiten",
"Collaborate and write in real time, without layout constraints.": "In Echtzeit und ohne Layout-Beschränkungen schreiben und zusammenarbeiten.",
"Collaborative writing, Simplified.": "Kollaboratives Schreiben, vereinfacht.",
"Confirm": "Bestätigen",
"Confirm deletion": "Löschung bestätigen",
"Confirmation button": "Bestätigungsbutton",
"Connected": "Angemeldet",
"Content modal to delete document": "Inhalts-Modal zum Löschen des Dokuments",
"Content modal to export the document": "Inhalte zum Exportieren des Dokuments",
"Convert Markdown": "Markdown konvertieren",
"Copied to clipboard": "In die Zwischenablage kopiert",
@@ -332,6 +348,7 @@
"Login": "Anmelden",
"Logout": "Abmelden",
"Modal confirmation to download the attachment": "Modale Bestätigung zum Herunterladen des Anhangs",
"Modal confirmation to restore the version": "Modale Bestätigung um die Version wiederherzustellen",
"More docs": "Weitere Dokumente",
"Move": "Verschieben",
"Move document": "Dokument verschieben",
@@ -381,6 +398,8 @@
"Select a document": "Dokument auswählen",
"Select a version on the right to restore": "Wählen Sie rechts eine Version zum Wiederherstellen aus",
"Share": "Teilen",
"Share modal": "Teilen-Modal",
"Share modal content": "Teilen-Modal Inhalt",
"Share the document": "Dokument teilen",
"Share with {{count}} users_many": "Teilen mit {{count}} Benutzern",
"Share with {{count}} users_one": "Mit {{count}} Benutzern teilen",
@@ -431,6 +450,17 @@
},
"en": {
"translation": {
"Back to homepage": "Back to Docs homepage",
"Search docs": "Search docs",
"More options": "More options",
"Pinned documents": "Pinned documents",
"Close the access request modal": "Close the access request modal",
"Close the delete modal": "Close the delete modal",
"Close the search modal": "Close the search modal",
"Close the share modal": "Close the share modal",
"Close the version history modal": "Close the version history modal",
"Open actions menu for document: {{title}}": "Open actions menu for document: {{title}}",
"Open the menu of actions for the document: {{title}}": "Open the menu of actions for the document: {{title}}",
"Share with {{count}} users_one": "Share with {{count}} user",
"Shared with {{count}} users_many": "Shared with {{count}} users",
"Shared with {{count}} users_one": "Shared with {{count}} user",
@@ -465,10 +495,18 @@
"Callout": "Destacado",
"Can't load this page, please check your internet connection.": "No se puede cargar esta página, por favor compruebe su conexión a Internet.",
"Cancel": "Cancelar",
"Close the modal": "Cerrar modal",
"Close the access request modal": "Cerrar modal de solicitud de acceso",
"Close the delete modal": "Cerrar modal de eliminación",
"Close the search modal": "Cerrar modal de búsqueda",
"Close the share modal": "Cerrar modal de compartir",
"Close the version history modal": "Cerrar modal de historial de versiones",
"Collaborate": "Colabora",
"Collaborate and write in real time, without layout constraints.": "Colaborar y escribir en tiempo real, sin restricciones de diseño.",
"Collaborative writing, Simplified.": "Escritura colaborativa, más sencilla.",
"Confirm deletion": "Confirmar borrado",
"Connected": "Conectado",
"Content modal to delete document": "Modal para eliminar el documento",
"Content modal to export the document": "Ventana emergente para exportar el documento",
"Convert Markdown": "Convertir a Markdown",
"Copied to clipboard": "Copiado en el portapapeles",
@@ -528,6 +566,7 @@
"Login": "Iniciar sesión",
"Logout": "Cerrar sesión",
"Modal confirmation to download the attachment": "Modal de confirmación para descargar el archivo adjunto",
"Modal confirmation to restore the version": "Modal de confirmación para restaurar la versión",
"More docs": "Más documentos",
"My docs": "Mis documentos",
"Name": "Nombre",
@@ -570,6 +609,8 @@
"Select a document": "Selecciona un documento",
"Select a version on the right to restore": "Seleccione una versión a la derecha para restaurarlo",
"Share": "Compartir",
"Share modal": "Modal para compartir el documento",
"Share modal content": "Contenido del modal para compartir",
"Share the document": "Compartir el documento",
"Share with {{count}} users_many": "Compartir con {{count}} usuarios",
"Share with {{count}} users_one": "Comparte con {{count}} usuario",
@@ -644,19 +685,21 @@
"Callout": "Alerte",
"Can't load this page, please check your internet connection.": "Impossible de charger cette page, veuillez vérifier votre connexion Internet.",
"Cancel": "Annuler",
"Cancel the deletion": "Annuler la suppression",
"Cancel the download": "Annuler le téléchargement",
"Close the access request modal": "Fermer la fenêtre modale de demande d'accès",
"Close the delete modal": "Fermer la fenêtre modale de suppression",
"Close the download modal": "Fermer la fenêtre modale de téléchargement",
"Close the search modal": "Fermer la fenêtre modale de recherche",
"Close the share modal": "Fermer la fenêtre modale de partage",
"Close the version history modal": "Fermer la fenêtre modale de l'historique des versions",
"Close the modal": "Fermer la modale",
"Close the share modal": "Fermer la modale de partage de document",
"Close the access request modal": "Fermer la modale de demande d'accès",
"Close the delete modal": "Fermer la modale de suppression",
"Close the download modal": "Fermer la modale de téléchargement",
"Close the search modal": "Fermer la modale de recherche de document",
"Close the version history modal": "Fermer la modale d'historique des versions",
"Collaborate": "Collaborer",
"Collaborate and write in real time, without layout constraints.": "Collaborez et rédigez en temps réel, sans contrainte de mise en page.",
"Collaborative writing, Simplified.": "L'écriture collaborative simplifiée.",
"Confirm": "Confirmez",
"Confirm deletion": "Confirmer la suppression",
"Confirmation button": "Bouton de confirmation",
"Connected": "Connecté",
"Content modal to delete document": "Contenu modal pour supprimer le document",
"Content modal to explain why the user cannot edit": "Contenu modal pour expliquer pourquoi l'utilisateur ne peut pas modifier",
"Content modal to export the document": "Contenu modal pour exporter le document",
"Convert Markdown": "Convertir le Markdown",
@@ -683,16 +726,12 @@
"Document duplicated successfully!": "Document dupliqué avec succès !",
"Document emoji icon": "Émoticônes du document",
"Document owner": "Propriétaire du document",
"Document role text": "Texte du rôle du document",
"Document sections": "Sections du document",
"Document title": "Titre du document",
"Document visibility": "Visibilité du document",
"Documents grid": "Grille des documents",
"Docx": "Docx",
"Download": "Télécharger",
"Download anyway": "Télécharger malgré tout",
"Download your document in a .docx or .pdf format.": "Téléchargez votre document au format .docx ou .pdf.",
"Drag and drop status": "État du glisser-déposer",
"Duplicate": "Dupliquer",
"Editing": "Édition",
"Editor": "Éditeur",
@@ -744,8 +783,8 @@
"Login": "Connexion",
"Logo": "Logo",
"Logout": "Se déconnecter",
"Main content": "Contenu principal",
"Modal confirmation to download the attachment": "Modale de confirmation pour télécharger la pièce jointe",
"Modal confirmation to restore the version": "Modale de confirmation pour restaurer la version",
"More docs": "Plus de documents",
"More options": "Plus d'options",
"Move": "Déplacer",
@@ -764,8 +803,6 @@
"Offline ?!": "Hors-ligne ?!",
"Only invited people can access": "Seules les personnes invitées peuvent accéder",
"Open Source": "Open Source",
"Open document actions menu": "Menu des actions d'ouverture d'un document",
"Open invitation actions menu": "Menu des actions d'ouverture d'une invitation",
"Open the document options": "Ouvrir les options du document",
"Open the header menu": "Ouvrir le menu d'en-tête",
"Open the menu of actions for the document: {{title}}": "Ouvrir le menu des actions du document : {{title}}",
@@ -805,8 +842,8 @@
"Select a version on the right to restore": "Sélectionnez une version à droite à restaurer",
"Select language": "Sélectionner la langue",
"Share": "Partager",
"Share button": "Bouton de partage",
"Share modal content": "Une fenêtre modale pour partager du contenu",
"Share modal": "Modale de partage",
"Share modal content": "Contenu de la modale de partage",
"Share the document": "Partager le document",
"Share with {{count}} users_many": "Partagé entre {{count}} utilisateurs",
"Share with {{count}} users_one": "Partager avec {{count}} utilisateur",
@@ -823,6 +860,10 @@
"Summarize": "Résumer",
"Summary": "Sommaire",
"Template": "Modèle",
"Document template": "Modèle de document",
"File format": "Format de fichier",
"Choose a template to apply to your document before download": "Choisissez un modèle à appliquer à votre document avant le téléchargement",
"Choose the file format for your download": "Choisissez le format de fichier pour votre téléchargement",
"The antivirus has detected an anomaly in your file.": "L'antivirus a détecté une anomalie dans votre fichier.",
"The document has been deleted.": "Le document a bien été supprimé.",
"The document visibility has been updated.": "La visibilité du document a été mise à jour.",
@@ -887,6 +928,7 @@
"Collaborate": "Collabora",
"Collaborate and write in real time, without layout constraints.": "Collaborare e scrivere in tempo reale, senza vincoli di layout.",
"Collaborative writing, Simplified.": "Scrittura collaborativa, semplificata.",
"Confirm deletion": "Conferma eliminazione",
"Connected": "Connesso",
"Copied to clipboard": "Copiato negli appunti",
"Copy as {{format}}": "Copia come {{format}}",
@@ -1031,10 +1073,18 @@
"Beautify": "Maak mooier",
"Can't load this page, please check your internet connection.": "Kan deze pagina niet laden. Controleer je internetverbinding.",
"Cancel": "Breek af",
"Close the modal": "Sluit het venster",
"Close the access request modal": "Sluit het toegangsverzoek venster",
"Close the delete modal": "Sluit het verwijder venster",
"Close the search modal": "Sluit het zoek venster",
"Close the share modal": "Sluit het delen venster",
"Close the version history modal": "Sluit het versiehistorie venster",
"Collaborate": "Samenwerken",
"Collaborate and write in real time, without layout constraints.": "Samenwerken en schrijven in realtime, zonder lay-out beperkingen.",
"Collaborative writing, Simplified.": "Vereenvoudigd samenwerkend",
"Confirm deletion": "Bevestig verwijdering",
"Connected": "Verbonden",
"Content modal to delete document": "Content venster om het document te verwijderen",
"Content modal to export the document": "Content venster om document te exporteren",
"Convert Markdown": "Converteer naar Markdown formaat",
"Copied to clipboard": "Kopieer naar klembord",
@@ -1093,6 +1143,7 @@
"Login": "Inloggen",
"Logout": "Uitloggen",
"Modal confirmation to download the attachment": "Venster bevestiging om bijlage te downloaden",
"Modal confirmation to restore the version": "Bevestiging modal om de versie te herstellen",
"More docs": "Meer documenten",
"My docs": "Mijn documenten",
"Name": "Naam",
@@ -1133,6 +1184,8 @@
"Select a document": "Selecteer een document",
"Select a version on the right to restore": "Selecteer een versie rechts om te herstellen",
"Share": "Deel",
"Share modal": "Deel model",
"Share modal content": "Deel model inhoud",
"Share the document": "Deel dit document",
"Share with {{count}} users_many": "Gedeeld met {{count}} gebruikers",
"Share with {{count}} users_one": "Delen met {{count}} gebruiker",
@@ -1148,7 +1201,7 @@
"Start Writing": "Begin met schrijven",
"Summarize": "Vat samen",
"Summary": "Samenvatting",
"Template": "Template",
"Template": "Sjabloon",
"The document has been deleted.": "Het document is verwijderd",
"The document visibility has been updated.": "De zichtbaarheid van het document is bijgewerkt",
"The export failed": "Het exporteren is mislukt",
@@ -1208,19 +1261,15 @@
"Callout": "Выноска",
"Can't load this page, please check your internet connection.": "Не удаётся загрузить эту страницу. Пожалуйста, проверьте подключение к Интернету.",
"Cancel": "Отмена",
"Cancel the deletion": "Отменить удаление",
"Cancel the download": "Отменить загрузку",
"Close the access request modal": "Закрыть окно запроса доступа",
"Close the delete modal": "Закрыть окно удаления",
"Close the download modal": "Закрыть окно загрузки",
"Close the search modal": "Закрыть окно поиска",
"Close the share modal": "Закрыть окно общего доступа",
"Close the version history modal": "Закрыть историю версии",
"Close the modal": "Закрыть это окно",
"Collaborate": "Совместный доступ",
"Collaborate and write in real time, without layout constraints.": "Совместная работа и сохранение в реальном времени, без ограничений.",
"Collaborative writing, Simplified.": "Простой совместный доступ к документам.",
"Confirm": "Подтвердить",
"Confirm deletion": "Подтвердите удаление",
"Confirmation button": "Кнопка подтверждения",
"Connected": "Подключено",
"Content modal to delete document": "Подтверждение удаления документа",
"Content modal to explain why the user cannot edit": "Пояснение, почему пользователь не может редактировать документ",
"Content modal to export the document": "Подтверждение экспорта документа",
"Convert Markdown": "Преобразовать разметку",
@@ -1247,16 +1296,12 @@
"Document duplicated successfully!": "Документ успешно дублирован!",
"Document emoji icon": "Значок эмодзи документа",
"Document owner": "Владелец документа",
"Document role text": "Текст роли документа",
"Document sections": "Разделы документа",
"Document title": "Заголовок документа",
"Document visibility": "Видимость документа",
"Documents grid": "Сетка документов",
"Docx": "Docx",
"Download": "Загрузить",
"Download anyway": "Всё равно загрузить",
"Download your document in a .docx or .pdf format.": "Загрузите свой документ в формате .docx или .pdf.",
"Drag and drop status": "Состояние перетаскивания",
"Duplicate": "Дублировать",
"Editing": "Редактирование",
"Editor": "Редактор",
@@ -1308,8 +1353,8 @@
"Login": "Войти",
"Logo": "Логотип",
"Logout": "Выйти",
"Main content": "Основное содержимое",
"Modal confirmation to download the attachment": "Подтверждение загрузки вложения",
"Modal confirmation to restore the version": "Подтверждение восстановления версии",
"More docs": "Больше документов",
"More options": "Больше параметров",
"Move": "Переместить",
@@ -1328,8 +1373,6 @@
"Offline ?!": "Не в сети?!",
"Only invited people can access": "Имеют доступ только приглашенные люди",
"Open Source": "Open Source",
"Open document actions menu": "Меню действий открытия документа",
"Open invitation actions menu": "Меню действий открытия приглашения",
"Open the document options": "Открыть параметры документа",
"Open the header menu": "Открыть меню заголовка",
"Open the menu of actions for the document: {{title}}": "Открыть меню действий для документа: {{title}}",
@@ -1369,8 +1412,7 @@
"Select a version on the right to restore": "Выберите версию для восстановления справа",
"Select language": "Выберите язык",
"Share": "Поделиться",
"Share button": "Кнопка \"Поделиться\"",
"Share modal content": "Поделиться",
"Share modal": "Поделиться документом",
"Share the document": "Поделиться документом",
"Share with {{count}} users_many": "Поделились с {{count}} пользователями",
"Share with {{count}} users_one": "Поделились с пользователями: {{count}}",
@@ -1439,6 +1481,7 @@
"Anonymous": "Anonym",
"Beautify": "Försköna",
"Cancel": "Avbryt",
"Close the modal": "Stäng fönstret",
"Convert Markdown": "Konvertera Markdown",
"Correct": "Korrekt",
"Divider": "Avskiljare",
@@ -1477,6 +1520,7 @@
"Collaborate": "İşbirliği Yapın",
"Collaborate and write in real time, without layout constraints.": "Düzen kısıtlamaları olmadan gerçek zamanlı olarak işbirliği yapın ve yazın.",
"Collaborative writing, Simplified.": "İş birliğiyle yazmak çok daha Kolay.",
"Confirm deletion": "Silme işlemini onaylayın",
"Copied to clipboard": "Panoya kopyalandı",
"Copy as {{format}}": "{{format}} olarak kopyala",
"Copy link": "Bağlantıyı kopyala",
@@ -1568,19 +1612,15 @@
"Callout": "Винесення",
"Can't load this page, please check your internet connection.": "Не вдалося завантажити цю сторінку, будь ласка, перевірте підключення до Інтернету.",
"Cancel": "Скасувати",
"Cancel the deletion": "Скасувати видалення",
"Cancel the download": "Скасувати завантаження",
"Close the access request modal": "Закрити вікно запиту доступу",
"Close the delete modal": "Закрити вікно видалення",
"Close the download modal": "Закрити вікно завантаження",
"Close the search modal": "Закрити вікно пошуку",
"Close the share modal": "Закрити вікно загального доступу",
"Close the version history modal": "Закрити історію версій",
"Close the modal": "Закрити це вікно",
"Collaborate": "Спільна робота",
"Collaborate and write in real time, without layout constraints.": "Сумісна робота і збереження результатів у реальному часі, без обмеження макета.",
"Collaborative writing, Simplified.": "Простий спільний доступ до документів.",
"Confirm": "Підтвердити",
"Confirm deletion": "Підтвердження видалення",
"Confirmation button": "Кнопка підтвердження",
"Connected": "Під'єднано",
"Content modal to delete document": "Підтвердження видалення документа",
"Content modal to explain why the user cannot edit": "Пояснення, чому користувач не може редагувати",
"Content modal to export the document": "Підтвердження експорту документа",
"Convert Markdown": "Перетворити розмітку",
@@ -1607,16 +1647,12 @@
"Document duplicated successfully!": "Документ успішно продубльовано!",
"Document emoji icon": "Піктограма emoji документа",
"Document owner": "Власник документа",
"Document role text": "Текст ролі документа",
"Document sections": "Розділи документу",
"Document title": "Назва документа",
"Document visibility": "Видимість документа",
"Documents grid": "Сітка документів",
"Docx": "Docx",
"Download": "Завантажити",
"Download anyway": "Все одно завантажити",
"Download your document in a .docx or .pdf format.": "Завантажте ваш документ у форматі .docx або .pdf.",
"Drag and drop status": "Стан перетягування",
"Duplicate": "Дублювати",
"Editing": "Редагування",
"Editor": "Редактор",
@@ -1668,8 +1704,8 @@
"Login": "Увійти",
"Logo": "Логотип",
"Logout": "Вийти",
"Main content": "Основний вміст",
"Modal confirmation to download the attachment": "Підтвердження завантаження вкладень",
"Modal confirmation to restore the version": "Підтвердження щодо відновлення версії",
"More docs": "Більше документів",
"More options": "Більше параметрів",
"Move": "Переміщення",
@@ -1688,8 +1724,6 @@
"Offline ?!": "Не в мережі?!",
"Only invited people can access": "Лише запрошені люди можуть мати доступ",
"Open Source": "Open Source",
"Open document actions menu": "Меню дій відкриття документу",
"Open invitation actions menu": "Меню дій відкриття запрошення",
"Open the document options": "Відкрити параметри документа",
"Open the header menu": "Відкрити меню заголовка",
"Open the menu of actions for the document: {{title}}": "Відкрити меню дій для документа: {{title}}",
@@ -1729,8 +1763,7 @@
"Select a version on the right to restore": "Виберіть версію для відновлення праворуч",
"Select language": "Оберіть мову",
"Share": "Поділитися",
"Share button": "Кнопка \"Поділитися\"",
"Share modal content": "Поділитися",
"Share modal": "Підтвердження",
"Share the document": "Поділитися документом",
"Share with {{count}} users_many": "Поділилися з користувачами: {{count}}",
"Share with {{count}} users_one": "Поділилися з користувачами: {{count}}",
@@ -1811,10 +1844,14 @@
"Callout": "标注",
"Can't load this page, please check your internet connection.": "无法加载此页面,请检查您的网络连接。",
"Cancel": "取消",
"Close the modal": "关闭对话框",
"Close the share modal": "关闭分享文档对话框",
"Collaborate": "协作",
"Collaborate and write in real time, without layout constraints.": "实时协作和写入,不受布局限制。",
"Collaborative writing, Simplified.": "协作写入,简体字样。",
"Confirm deletion": "删除确认",
"Connected": "已连接",
"Content modal to delete document": "删除文档对话框",
"Content modal to export the document": "导出文档",
"Convert Markdown": "转换为Markdown格式",
"Copied to clipboard": "已复制到剪贴板",
@@ -1873,6 +1910,7 @@
"Login": "登录",
"Logout": "退出登录",
"Modal confirmation to download the attachment": "下载附件",
"Modal confirmation to restore the version": "恢复版本的方式确认",
"More docs": "更多文档",
"My docs": "我的文档",
"Name": "名称",
@@ -1913,6 +1951,8 @@
"Select a document": "选择一个文档",
"Select a version on the right to restore": "选择要恢复的版本",
"Share": "共享",
"Share modal": "共享模式",
"Share modal content": "共享模式内容",
"Share the document": "共享文档",
"Share with {{count}} users_many": "与{{count}}共享",
"Share with {{count}} users_one": "与{{count}}共享",
@@ -1,5 +1,4 @@
import { PropsWithChildren } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box } from '@/components';
@@ -21,7 +20,6 @@ export function MainLayout({
const { isDesktop } = useResponsiveStore();
const { colorsTokens } = useCunninghamTheme();
const currentBackgroundColor = !isDesktop ? 'white' : backgroundColor;
const { t } = useTranslation();
return (
<Box className="--docs--main-layout">
@@ -34,7 +32,6 @@ export function MainLayout({
<LeftPanel />
<Box
as="main"
aria-label={t('Main content')}
id={MAIN_LAYOUT_ID}
$align="center"
$flex={1}
@@ -1,5 +1,4 @@
import { PropsWithChildren } from 'react';
import { useTranslation } from 'react-i18next';
import { Box } from '@/components';
import { Footer } from '@/features/footer';
@@ -16,7 +15,7 @@ export function PageLayout({
withFooter = true,
}: PropsWithChildren<PageLayoutProps>) {
const { isDesktop } = useResponsiveStore();
const { t } = useTranslation();
return (
<Box
$minHeight={`calc(100vh - ${HEADER_HEIGHT}px)`}
@@ -24,12 +23,7 @@ export function PageLayout({
className="--docs--page-layout"
>
<Header />
<Box
as="main"
$width="100%"
$css="flex-grow:1;"
aria-label={t('Main content')}
>
<Box as="main" $width="100%" $css="flex-grow:1;">
{!isDesktop && <LeftPanel />}
{children}
</Box>
@@ -82,16 +82,3 @@ main ::-webkit-scrollbar-thumb:hover,
nextjs-portal {
display: none;
}
/* Screen reader only - visually hidden but accessible to screen readers */
.sr-only {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip-path: inset(50%) !important;
white-space: nowrap !important;
border: 0 !important;
}
+6 -11
View File
@@ -1,10 +1,7 @@
{
"name": "impress",
"version": "3.7.0",
"version": "3.6.0",
"private": true,
"repository": "https://github.com/suitenumerique/docs",
"author": "DINUM",
"license": "MIT",
"workspaces": {
"packages": [
"apps/*",
@@ -31,17 +28,15 @@
"server:test": "yarn COLLABORATION_SERVER run test"
},
"resolutions": {
"@types/node": "22.18.1",
"@types/node": "22.18.0",
"@types/react": "19.1.12",
"@types/react-dom": "19.1.9",
"@typescript-eslint/eslint-plugin": "8.43.0",
"@typescript-eslint/parser": "8.43.0",
"eslint": "9.35.0",
"@typescript-eslint/eslint-plugin": "8.41.0",
"@typescript-eslint/parser": "8.41.0",
"eslint": "9.32.0",
"react": "19.1.1",
"react-dom": "19.1.1",
"typescript": "5.9.2",
"wrap-ansi": "9.0.2",
"yjs": "13.6.27"
},
"packageManager": "yarn@1.22.22"
}
}
@@ -1,8 +1,6 @@
{
"name": "eslint-plugin-docs",
"version": "3.7.0",
"repository": "https://github.com/suitenumerique/docs",
"author": "DINUM",
"version": "3.6.0",
"license": "MIT",
"main": "index.js",
"keywords": [
@@ -17,11 +15,11 @@
"eslint": ">=9.0.0"
},
"dependencies": {
"@next/eslint-plugin-next": "15.5.3",
"@tanstack/eslint-plugin-query": "5.86.0",
"@next/eslint-plugin-next": "15.5.2",
"@tanstack/eslint-plugin-query": "5.83.1",
"@typescript-eslint/eslint-plugin": "*",
"@typescript-eslint/parser": "*",
"eslint-config-next": "15.5.3",
"eslint-config-next": "15.5.2",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-jest": "29.0.1",
@@ -29,9 +27,8 @@
"eslint-plugin-playwright": "2.2.2",
"eslint-plugin-prettier": "5.5.4",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-testing-library": "7.6.8",
"@vitest/eslint-plugin": "1.0.1",
"eslint-plugin-testing-library": "7.6.6",
"eslint-plugin-vitest": "0.5.4",
"prettier": "3.6.2"
},
"packageManager": "yarn@1.22.22"
}
}
@@ -1,8 +1,8 @@
const typescriptEslint = require('@typescript-eslint/eslint-plugin');
const typescriptParser = require('@typescript-eslint/parser');
const vitest = require('@vitest/eslint-plugin');
const jest = require('eslint-plugin-jest');
const testingLibrary = require('eslint-plugin-testing-library');
const vitest = require('eslint-plugin-vitest');
const testConfig = {
files: [
+3 -7
View File
@@ -1,9 +1,6 @@
{
"name": "packages-i18n",
"version": "3.7.0",
"repository": "https://github.com/suitenumerique/docs",
"author": "DINUM",
"license": "MIT",
"version": "3.6.0",
"private": true,
"scripts": {
"extract-translation": "yarn extract-translation:impress",
@@ -20,10 +17,9 @@
"eslint-plugin-docs": "*",
"eslint-plugin-import": "2.32.0",
"i18next-parser": "9.3.0",
"jest": "30.1.3",
"jest": "30.1.2",
"ts-jest": "29.4.1",
"typescript": "*",
"yargs": "18.0.0"
},
"packageManager": "yarn@1.22.22"
}
}
+6 -7
View File
@@ -1,6 +1,6 @@
{
"name": "server-y-provider",
"version": "3.7.0",
"version": "3.6.0",
"description": "Y.js provider for docs",
"repository": "https://github.com/suitenumerique/docs",
"license": "MIT",
@@ -18,13 +18,13 @@
"dependencies": {
"@blocknote/server-util": "0.37.0",
"@hocuspocus/server": "2.15.2",
"@sentry/node": "10.11.0",
"@sentry/profiling-node": "10.11.0",
"axios": "1.12.0",
"@sentry/node": "10.8.0",
"@sentry/profiling-node": "10.8.0",
"axios": "1.11.0",
"cors": "2.8.5",
"express": "5.1.0",
"express-ws": "5.0.2",
"uuid": "13.0.0",
"uuid": "11.1.0",
"y-protocols": "1.0.6",
"yjs": "*"
},
@@ -46,6 +46,5 @@
"vitest": "3.2.4",
"vitest-mock-extended": "3.1.0",
"ws": "8.18.3"
},
"packageManager": "yarn@1.22.22"
}
}
+486 -468
View File
File diff suppressed because it is too large Load Diff
+35 -45
View File
@@ -16,16 +16,16 @@ backend:
replicas: 1
envVars:
COLLABORATION_SERVER_SECRET: my-secret
DJANGO_CSRF_TRUSTED_ORIGINS: https://docs.127.0.0.1.nip.io
DJANGO_CSRF_TRUSTED_ORIGINS: https://impress.127.0.0.1.nip.io
DJANGO_CONFIGURATION: Feature
DJANGO_ALLOWED_HOSTS: docs.127.0.0.1.nip.io
DJANGO_ALLOWED_HOSTS: impress.127.0.0.1.nip.io
DJANGO_SERVER_TO_SERVER_API_TOKENS: secret-api-key
DJANGO_SECRET_KEY: *djangoSecretKey
DJANGO_SETTINGS_MODULE: impress.settings
DJANGO_SUPERUSER_PASSWORD: admin
DJANGO_EMAIL_BRAND_NAME: "La Suite Numérique"
DJANGO_EMAIL_HOST: "mailcatcher"
DJANGO_EMAIL_LOGO_IMG: https://docs.127.0.0.1.nip.io/assets/logo-suite-numerique.png
DJANGO_EMAIL_LOGO_IMG: https://impress.127.0.0.1.nip.io/assets/logo-suite-numerique.png
DJANGO_EMAIL_PORT: 1025
DJANGO_EMAIL_USE_SSL: False
LOGGING_LEVEL_HANDLERS_CONSOLE: ERROR
@@ -33,38 +33,29 @@ backend:
LOGGING_LEVEL_LOGGERS_APP: INFO
OIDC_USERINFO_SHORTNAME_FIELD: "given_name"
OIDC_USERINFO_FULLNAME_FIELDS: "given_name,usual_name"
OIDC_OP_JWKS_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/docs/protocol/openid-connect/certs
OIDC_OP_AUTHORIZATION_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/docs/protocol/openid-connect/auth
OIDC_OP_TOKEN_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/docs/protocol/openid-connect/token
OIDC_OP_USER_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/docs/protocol/openid-connect/userinfo
OIDC_OP_LOGOUT_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/docs/protocol/openid-connect/logout
OIDC_RP_CLIENT_ID: docs
OIDC_OP_JWKS_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/certs
OIDC_OP_AUTHORIZATION_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/auth
OIDC_OP_TOKEN_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/token
OIDC_OP_USER_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/userinfo
OIDC_OP_LOGOUT_ENDPOINT: https://docs-keycloak.127.0.0.1.nip.io/realms/impress/protocol/openid-connect/logout
OIDC_RP_CLIENT_ID: impress
OIDC_RP_CLIENT_SECRET: ThisIsAnExampleKeyForDevPurposeOnly
OIDC_RP_SIGN_ALGO: RS256
OIDC_RP_SCOPES: "openid email"
LOGIN_REDIRECT_URL: https://docs.127.0.0.1.nip.io
LOGIN_REDIRECT_URL_FAILURE: https://docs.127.0.0.1.nip.io
LOGOUT_REDIRECT_URL: https://docs.127.0.0.1.nip.io
DB_HOST: dev-backend-postgres
DB_NAME:
secretKeyRef:
name: dev-backend-postgres
key: database
DB_USER:
secretKeyRef:
name: dev-backend-postgres
key: username
DB_PASSWORD:
secretKeyRef:
name: dev-backend-postgres
key: password
LOGIN_REDIRECT_URL: https://impress.127.0.0.1.nip.io
LOGIN_REDIRECT_URL_FAILURE: https://impress.127.0.0.1.nip.io
LOGOUT_REDIRECT_URL: https://impress.127.0.0.1.nip.io
DB_HOST: postgres-postgresql
DB_NAME: impress
DB_USER: dinum
DB_PASSWORD: pass
DB_PORT: 5432
REDIS_URL: redis://user:pass@dev-backend-redis:6379/1
DJANGO_CELERY_BROKER_URL: redis://user:pass@dev-backend-redis:6379/1
AWS_S3_ENDPOINT_URL: http://dev-backend-minio.impress.svc.cluster.local:9000
AWS_S3_ACCESS_KEY_ID: dinum
REDIS_URL: redis://default:pass@redis-master:6379/1
DJANGO_CELERY_BROKER_URL: redis://default:pass@redis-master:6379/1
AWS_S3_ENDPOINT_URL: http://minio.impress.svc.cluster.local:9000
AWS_S3_ACCESS_KEY_ID: root
AWS_S3_SECRET_ACCESS_KEY: password
AWS_STORAGE_BUCKET_NAME: docs-media-storage
AWS_STORAGE_BUCKET_NAME: impress-media-storage
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
Y_PROVIDER_API_BASE_URL: http://impress-y-provider:443/api/
Y_PROVIDER_API_KEY: my-secret
@@ -82,7 +73,8 @@ backend:
echo "Database is ready"
python manage.py migrate --no-input
python manage.py migrate --no-input &&
python manage.py create_demo --force
restartPolicy: Never
command:
@@ -128,7 +120,7 @@ backend:
frontend:
envVars:
PORT: 8080
NEXT_PUBLIC_API_ORIGIN: https://docs.127.0.0.1.nip.io
NEXT_PUBLIC_API_ORIGIN: https://impress.127.0.0.1.nip.io
replicas: 1
command:
@@ -149,29 +141,27 @@ yProvider:
tag: "latest"
envVars:
COLLABORATION_BACKEND_BASE_URL: https://docs.127.0.0.1.nip.io
COLLABORATION_BACKEND_BASE_URL: https://impress.127.0.0.1.nip.io
COLLABORATION_LOGGING: true
COLLABORATION_SERVER_ORIGIN: https://docs.127.0.0.1.nip.io
COLLABORATION_SERVER_ORIGIN: https://impress.127.0.0.1.nip.io
COLLABORATION_SERVER_SECRET: my-secret
Y_PROVIDER_API_KEY: my-secret
ingress:
enabled: true
host: docs.127.0.0.1.nip.io
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 10m
host: impress.127.0.0.1.nip.io
ingressCollaborationWS:
enabled: true
host: docs.127.0.0.1.nip.io
host: impress.127.0.0.1.nip.io
ingressCollaborationApi:
enabled: true
host: docs.127.0.0.1.nip.io
host: impress.127.0.0.1.nip.io
ingressAdmin:
enabled: true
host: docs.127.0.0.1.nip.io
host: impress.127.0.0.1.nip.io
posthog:
ingress:
@@ -182,14 +172,14 @@ posthog:
ingressMedia:
enabled: true
host: docs.127.0.0.1.nip.io
host: impress.127.0.0.1.nip.io
annotations:
nginx.ingress.kubernetes.io/auth-url: https://docs.127.0.0.1.nip.io/api/v1.0/documents/media-auth/
nginx.ingress.kubernetes.io/auth-url: https://impress.127.0.0.1.nip.io/api/v1.0/documents/media-auth/
nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256"
nginx.ingress.kubernetes.io/upstream-vhost: dev-backend-minio.impress.svc.cluster.local:9000
nginx.ingress.kubernetes.io/rewrite-target: /docs-media-storage/$1
nginx.ingress.kubernetes.io/upstream-vhost: minio.impress.svc.cluster.local:9000
nginx.ingress.kubernetes.io/rewrite-target: /impress-media-storage/$1
serviceMedia:
host: dev-backend-minio.impress.svc.cluster.local
host: minio.impress.svc.cluster.local
port: 9000
+79 -63
View File
@@ -1,78 +1,94 @@
environments:
dev:
values:
- version: 3.7.0
- version: 3.6.0
---
repositories:
- name: dev-backends
url: https://suitenumerique.github.io/helm-dev-backend
- name: bitnami
url: registry-1.docker.io/bitnamicharts
oci: true
---
releases:
- name: dev-backend
- name: keycloak
installed: {{ eq .Environment.Name "dev" | toYaml }}
missingFileHandler: Warn
namespace: {{ .Namespace }}
chart: dev-backends/dev-backend
version: 0.0.2
chart: bitnami/keycloak
version: 17.3.6
values:
- postgres:
enabled: true
name: postgres
#serviceNameOverride: postgres
image: postgres:16-alpine
username: dinum
password: pass
database: docs
size: 1Gi
- redis:
enabled: true
name: redis
image: redis:8.2-alpine
username: user
password: pass
- minio:
enabled: true
image: minio/minio
name: minio
ingress:
enabled: true
hostname: docs-minio.127.0.0.1.nip.io
tls:
enabled: true
secretName: docs-tls
consoleIngress:
enabled: true
hostname: docs-minio-console.127.0.0.1.nip.io
tls:
enabled: true
secretName: docs-tls
username: dinum
password: password
bucket: docs-media-storage
versioning: true
size: 1Gi
- keycloak:
enabled: true
image: quay.io/keycloak/keycloak:20.0.1
name: keycloak
#serviceNameOverride: keycloak
hostname: docs-keycloak.127.0.0.1.nip.io
username: admin
password: pass
tls:
enabled: true
secretName: docs-tls
db:
username: dinum
password: pass
- postgresql:
auth:
username: keycloak
password: keycloak
database: keycloak
size: 1Gi
image: postgres:16-alpine
realm:
name: docs
username: docs
password: docs
email: docs@example.com
- extraEnvVars:
- name: KEYCLOAK_EXTRA_ARGS
value: "--import-realm"
- name: KC_HOSTNAME_URL
value: https://docs-keycloak.127.0.0.1.nip.io
- extraVolumes:
- name: import
configMap:
name: docs-keycloak
- extraVolumeMounts:
- name: import
mountPath: /opt/bitnami/keycloak/data/import/
- auth:
adminUser: su
adminPassword: su
- proxy: edge
- ingress:
enabled: true
hostname: docs-keycloak.127.0.0.1.nip.io
- extraDeploy:
- apiVersion: v1
kind: ConfigMap
metadata:
name: docs-keycloak
namespace: {{ .Namespace }}
data:
impress.json: |
{{ readFile "../../docker/auth/realm.json" | replace "http://localhost:3200" "https://impress.127.0.0.1.nip.io" | indent 14 }}
- name: postgres
installed: {{ eq .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: bitnami/postgresql
version: 13.1.5
values:
- auth:
username: dinum
password: pass
database: impress
- tls:
enabled: true
autoGenerated: true
- name: minio
installed: {{ eq .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: bitnami/minio
version: 12.10.10
values:
- auth:
rootUser: root
rootPassword: password
- provisioning:
enabled: true
buckets:
- name: impress-media-storage
versioning: true
- name: redis
installed: {{ eq .Environment.Name "dev" | toYaml }}
namespace: {{ .Namespace }}
chart: bitnami/redis
version: 20.6.2
values:
- auth:
password: pass
architecture: standalone
- name: impress
version: {{ .Values.version }}
+1 -1
View File
@@ -1,5 +1,5 @@
apiVersion: v2
type: application
name: docs
version: 3.7.0
version: 3.6.0
appVersion: latest
+1 -2
View File
@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "3.7.0",
"version": "3.6.0",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {
@@ -16,7 +16,6 @@
"volta": {
"node": "22"
},
"packageManager": "yarn@1.22.22",
"repository": "https://github.com/suitenumerique/docs",
"author": "DINUM",
"license": "MIT"