mirror of
https://github.com/suitenumerique/docs.git
synced 2026-05-06 23:22:15 +02:00
Compare commits
1 Commits
feature/do
...
documentat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0483a80784 |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -6,31 +6,23 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [3.9.0] - 2025-11-10
|
||||
|
||||
### Added
|
||||
|
||||
- ✨(frontend) create skeleton component for DocEditor #1491
|
||||
- ✨(frontend) add an EmojiPicker in the document tree and title #1381
|
||||
- ✨(frontend) ajustable left panel #1456
|
||||
|
||||
### Changed
|
||||
|
||||
- ♻️(frontend) adapt custom blocks to new implementation #1375
|
||||
- ♻️(backend) increase user short_name field length #1510
|
||||
- 🚸(frontend) separate viewers from editors #1509
|
||||
- ♻️(backend) increase user short_name field length
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🐛(frontend) fix duplicate document entries in grid #1479
|
||||
- 🐛(backend) fix trashbin list #1520
|
||||
- 🐛(frontend) show full nested doc names with ajustable bar #1456
|
||||
- 🐛(backend) fix trashbin list
|
||||
- ♿(frontend) improve accessibility:
|
||||
- ♿(frontend) remove empty alt on logo due to Axe a11y error #1516
|
||||
- 🐛(backend) fix s3 version_id validation #1543
|
||||
- 🐛(frontend) retry check media status after page reload #1555
|
||||
- 🐛(frontend) fix Interlinking memory leak #1560
|
||||
- 🐛(frontend) button new doc UI fix #1557
|
||||
- 🐛(frontend) interlinking UI fix #1557
|
||||
|
||||
## [3.8.2] - 2025-10-17
|
||||
|
||||
@@ -843,8 +835,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.9.0...main
|
||||
[v3.9.0]: https://github.com/suitenumerique/docs/releases/v3.9.0
|
||||
[unreleased]: https://github.com/suitenumerique/docs/compare/v3.8.2...main
|
||||
[v3.8.2]: https://github.com/suitenumerique/docs/releases/v3.8.2
|
||||
[v3.8.1]: https://github.com/suitenumerique/docs/releases/v3.8.1
|
||||
[v3.8.0]: https://github.com/suitenumerique/docs/releases/v3.8.0
|
||||
|
||||
1
Makefile
1
Makefile
@@ -213,7 +213,6 @@ logs: ## display app-dev logs (follow mode)
|
||||
.PHONY: logs
|
||||
|
||||
run-backend: ## Start only the backend application and all needed services
|
||||
@$(COMPOSE) up --force-recreate -d docspec
|
||||
@$(COMPOSE) up --force-recreate -d celery-dev
|
||||
@$(COMPOSE) up --force-recreate -d y-provider-development
|
||||
@$(COMPOSE) up --force-recreate -d nginx
|
||||
|
||||
@@ -217,8 +217,3 @@ services:
|
||||
kc_postgresql:
|
||||
condition: service_healthy
|
||||
restart: true
|
||||
|
||||
docspec:
|
||||
image: ghcr.io/docspecio/api:2.0.2
|
||||
ports:
|
||||
- "4000:4000"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/assets/export-template-tutorial/three-dots-copy-as-html.png
Normal file
BIN
docs/assets/export-template-tutorial/three-dots-copy-as-html.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -103,7 +103,6 @@ These are the environment variables you can set for the `impress-backend` contai
|
||||
| USER_OIDC_ESSENTIAL_CLAIMS | Essential claims in OIDC token | [] |
|
||||
| Y_PROVIDER_API_BASE_URL | Y Provider url | |
|
||||
| Y_PROVIDER_API_KEY | Y provider API key | |
|
||||
| DOCSPEC_API_URL | URL to endpoint of DocSpec conversion API | |
|
||||
|
||||
|
||||
## impress-frontend image
|
||||
|
||||
@@ -85,4 +85,44 @@ THEME_CUSTOMIZATION_FILE_PATH=<path>
|
||||
|
||||
### Example of JSON
|
||||
|
||||
The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
|
||||
The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
|
||||
|
||||
----
|
||||
|
||||
# **Custom Export Templates** 📄
|
||||
|
||||
You can define custom export templates to add introductory content, such as headers or titles, to documents before exporting them as PDF, Docx, etc...
|
||||
|
||||
Export Templates are managed through the admin interface and can be selected by users during the export process.
|
||||
|
||||
### Benefits
|
||||
|
||||
This feature offers several advantages:
|
||||
* **Header customization** 📄: Add custom headers, titles, or branding to exported documents.
|
||||
* **No code changes required** 🔧: Templates are managed through the admin interface without needing developer intervention.
|
||||
* **Flexible content** 🌟: Use HTML to create headers that match your organization's style.
|
||||
|
||||
### Limitations ⚠️
|
||||
|
||||
- Currently, templates are only prepended to the document.
|
||||
More complex layouts are not supported at this time.
|
||||
- The `CSS` and `Description` fields are being ignored at this time.
|
||||
- <b>Due to technical conversion limitations, not all HTML can be converted to the internal format!</b>
|
||||
|
||||
### How to Use
|
||||
|
||||
1. Create the Template in a new document.
|
||||

|
||||
2. Copy it as HTML code using the `Copy as HTML` feature:
|
||||

|
||||
3. Log in to the admin interface at `/admin` (backend container).
|
||||
2. Create a new template:
|
||||

|
||||
- **Title**: Enter a descriptive name for the template.
|
||||
- **Code**: Paste the HTML content from step 2.
|
||||
- **Public**: Check this box to make the template available in the frontend export modal.
|
||||
- **Save** the template.
|
||||
|
||||
Once saved, users can select the template from the export modal in the frontend during the export process.
|
||||

|
||||
|
||||
|
||||
@@ -67,7 +67,5 @@ DJANGO_SERVER_TO_SERVER_API_TOKENS=server-api-token
|
||||
Y_PROVIDER_API_BASE_URL=http://y-provider-development:4444/api/
|
||||
Y_PROVIDER_API_KEY=yprovider-api-key
|
||||
|
||||
DOCSPEC_API_URL=http://docspec:4000/conversion
|
||||
|
||||
# Theme customization
|
||||
THEME_CUSTOMIZATION_CACHE_TIMEOUT=15
|
||||
@@ -3,7 +3,6 @@ BURST_THROTTLE_RATES="200/minute"
|
||||
COLLABORATION_API_URL=http://y-provider:4444/collaboration/api/
|
||||
SUSTAINED_THROTTLE_RATES="200/hour"
|
||||
Y_PROVIDER_API_BASE_URL=http://y-provider:4444/api/
|
||||
DOCSPEC_API_URL=http://docspec:4000/conversion
|
||||
|
||||
# Throttle
|
||||
API_DOCUMENT_THROTTLE_RATE=1000/min
|
||||
|
||||
@@ -19,12 +19,6 @@
|
||||
"matchPackageNames": ["redis"],
|
||||
"allowedVersions": "<6.0.0"
|
||||
},
|
||||
{
|
||||
"groupName": "allowed pylint versions",
|
||||
"matchManagers": ["pep621"],
|
||||
"matchPackageNames": ["pylint"],
|
||||
"allowedVersions": "<4.0.0"
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"groupName": "ignored js dependencies",
|
||||
|
||||
@@ -10,7 +10,6 @@ from django.utils.functional import lazy
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from core.services import mime_types
|
||||
import magic
|
||||
from rest_framework import serializers
|
||||
|
||||
@@ -18,7 +17,7 @@ from core import choices, enums, models, utils, validators
|
||||
from core.services.ai_services import AI_ACTIONS
|
||||
from core.services.converter_services import (
|
||||
ConversionError,
|
||||
Converter,
|
||||
YdocConverter,
|
||||
)
|
||||
|
||||
|
||||
@@ -188,7 +187,6 @@ class DocumentSerializer(ListDocumentSerializer):
|
||||
|
||||
content = serializers.CharField(required=False)
|
||||
websocket = serializers.BooleanField(required=False, write_only=True)
|
||||
file = serializers.FileField(required=False, write_only=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.Document
|
||||
@@ -205,7 +203,6 @@ class DocumentSerializer(ListDocumentSerializer):
|
||||
"deleted_at",
|
||||
"depth",
|
||||
"excerpt",
|
||||
"file",
|
||||
"is_favorite",
|
||||
"link_role",
|
||||
"link_reach",
|
||||
@@ -463,11 +460,7 @@ class ServerCreateDocumentSerializer(serializers.Serializer):
|
||||
language = user.language or language
|
||||
|
||||
try:
|
||||
document_content = Converter().convert(
|
||||
validated_data["content"],
|
||||
mime_types.MARKDOWN,
|
||||
mime_types.YJS
|
||||
)
|
||||
document_content = YdocConverter().convert(validated_data["content"])
|
||||
except ConversionError as err:
|
||||
raise serializers.ValidationError(
|
||||
{"content": ["Could not convert content"]}
|
||||
|
||||
@@ -39,12 +39,14 @@ from core import authentication, choices, enums, models
|
||||
from core.services.ai_services import AIService
|
||||
from core.services.collaboration_services import CollaborationService
|
||||
from core.services.converter_services import (
|
||||
ConversionError,
|
||||
ServiceUnavailableError as YProviderServiceUnavailableError,
|
||||
ValidationError as YProviderValidationError,
|
||||
Converter,
|
||||
)
|
||||
from core.services import mime_types
|
||||
from core.services.converter_services import (
|
||||
ValidationError as YProviderValidationError,
|
||||
)
|
||||
from core.services.converter_services import (
|
||||
YdocConverter,
|
||||
)
|
||||
from core.tasks.mail import send_ask_for_access_mail
|
||||
from core.utils import extract_attachments, filter_descendants
|
||||
|
||||
@@ -501,27 +503,6 @@ class DocumentViewSet(
|
||||
"IN SHARE ROW EXCLUSIVE MODE;"
|
||||
)
|
||||
|
||||
# Remove file from validated_data as it's not a model field
|
||||
# Process it if present
|
||||
uploaded_file = serializer.validated_data.pop("file", None)
|
||||
|
||||
# If a file is uploaded, convert it to Yjs format and set as content
|
||||
if uploaded_file:
|
||||
try:
|
||||
file_content = uploaded_file.read()
|
||||
|
||||
converter = Converter()
|
||||
converted_content = converter.convert(
|
||||
file_content,
|
||||
content_type=uploaded_file.content_type,
|
||||
accept=mime_types.YJS
|
||||
)
|
||||
serializer.validated_data["content"] = converted_content
|
||||
except ConversionError as err:
|
||||
raise drf.exceptions.ValidationError(
|
||||
{"file": ["Could not convert file content"]}
|
||||
) from err
|
||||
|
||||
obj = models.Document.add_root(
|
||||
creator=self.request.user,
|
||||
**serializer.validated_data,
|
||||
@@ -1124,7 +1105,7 @@ class DocumentViewSet(
|
||||
@drf.decorators.action(
|
||||
detail=True,
|
||||
methods=["get", "delete"],
|
||||
url_path=r"versions/(?P<version_id>[A-Za-z0-9._+\-=~]{1,1024})",
|
||||
url_path="versions/(?P<version_id>[0-9a-z-]+)",
|
||||
)
|
||||
# pylint: disable=unused-argument
|
||||
def versions_detail(self, request, pk, version_id, *args, **kwargs):
|
||||
@@ -1621,14 +1602,14 @@ class DocumentViewSet(
|
||||
if base64_content is not None:
|
||||
# Convert using the y-provider service
|
||||
try:
|
||||
yprovider = Converter()
|
||||
yprovider = YdocConverter()
|
||||
result = yprovider.convert(
|
||||
base64.b64decode(base64_content),
|
||||
mime_types.YJS,
|
||||
"application/vnd.yjs.doc",
|
||||
{
|
||||
"markdown": mime_types.MARKDOWN,
|
||||
"html": mime_types.HTML,
|
||||
"json": mime_types.JSON,
|
||||
"markdown": "text/markdown",
|
||||
"html": "text/html",
|
||||
"json": "application/json",
|
||||
}[content_format],
|
||||
)
|
||||
content = result
|
||||
|
||||
@@ -5,9 +5,7 @@ from base64 import b64encode
|
||||
from django.conf import settings
|
||||
|
||||
import requests
|
||||
import typing
|
||||
|
||||
from core.services import mime_types
|
||||
|
||||
class ConversionError(Exception):
|
||||
"""Base exception for conversion-related errors."""
|
||||
@@ -21,65 +19,8 @@ class ServiceUnavailableError(ConversionError):
|
||||
"""Raised when the conversion service is unavailable."""
|
||||
|
||||
|
||||
class ConverterProtocol(typing.Protocol):
|
||||
def convert(self, text, content_type, accept): ...
|
||||
|
||||
|
||||
class Converter:
|
||||
docspec: ConverterProtocol
|
||||
ydoc: ConverterProtocol
|
||||
|
||||
def __init__(self):
|
||||
self.docspec = DocSpecConverter()
|
||||
self.ydoc = YdocConverter()
|
||||
|
||||
def convert(self, input, content_type, accept):
|
||||
"""Convert input into other formats using external microservices."""
|
||||
|
||||
if content_type == mime_types.DOCX and accept == mime_types.YJS:
|
||||
return self.convert(
|
||||
self.docspec.convert(input, mime_types.DOCX, mime_types.BLOCKNOTE),
|
||||
mime_types.BLOCKNOTE,
|
||||
mime_types.YJS
|
||||
)
|
||||
|
||||
return self.ydoc.convert(input, content_type, accept)
|
||||
|
||||
|
||||
class DocSpecConverter:
|
||||
"""Service class for DocSpec conversion-related operations."""
|
||||
|
||||
def _request(self, url, data, content_type):
|
||||
"""Make a request to the DocSpec API."""
|
||||
|
||||
response = requests.post(
|
||||
url,
|
||||
headers={"Accept": mime_types.BLOCKNOTE},
|
||||
files={"file": ("document.docx", data, content_type)},
|
||||
timeout=settings.CONVERSION_API_TIMEOUT,
|
||||
verify=settings.CONVERSION_API_SECURE,
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response
|
||||
|
||||
def convert(self, data, content_type, accept):
|
||||
"""Convert a Document to BlockNote."""
|
||||
if not data:
|
||||
raise ValidationError("Input data cannot be empty")
|
||||
|
||||
if content_type != mime_types.DOCX or accept != mime_types.BLOCKNOTE:
|
||||
raise ValidationError(f"Conversion from {content_type} to {accept} is not supported.")
|
||||
|
||||
try:
|
||||
return self._request(settings.DOCSPEC_API_URL, data, content_type).content
|
||||
except requests.RequestException as err:
|
||||
raise ServiceUnavailableError(
|
||||
"Failed to connect to DocSpec conversion service",
|
||||
) from err
|
||||
|
||||
|
||||
class YdocConverter:
|
||||
"""Service class for YDoc conversion-related operations."""
|
||||
"""Service class for conversion-related operations."""
|
||||
|
||||
@property
|
||||
def auth_header(self):
|
||||
@@ -104,7 +45,7 @@ class YdocConverter:
|
||||
return response
|
||||
|
||||
def convert(
|
||||
self, text, content_type=mime_types.MARKDOWN, accept=mime_types.YJS
|
||||
self, text, content_type="text/markdown", accept="application/vnd.yjs.doc"
|
||||
):
|
||||
"""Convert a Markdown text into our internal format using an external microservice."""
|
||||
|
||||
@@ -118,14 +59,14 @@ class YdocConverter:
|
||||
content_type,
|
||||
accept,
|
||||
)
|
||||
if accept == mime_types.YJS:
|
||||
if accept == "application/vnd.yjs.doc":
|
||||
return b64encode(response.content).decode("utf-8")
|
||||
if accept in {mime_types.MARKDOWN, "text/html"}:
|
||||
if accept in {"text/markdown", "text/html"}:
|
||||
return response.text
|
||||
if accept == mime_types.JSON:
|
||||
if accept == "application/json":
|
||||
return response.json()
|
||||
raise ValidationError("Unsupported format")
|
||||
except requests.RequestException as err:
|
||||
raise ServiceUnavailableError(
|
||||
f"Failed to connect to YDoc conversion service {content_type}, {accept}",
|
||||
"Failed to connect to conversion service",
|
||||
) from err
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
BLOCKNOTE = "application/vnd.blocknote+json"
|
||||
YJS = "application/vnd.yjs.doc"
|
||||
MARKDOWN = "text/markdown"
|
||||
JSON = "application/json"
|
||||
DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
HTML = "text/html"
|
||||
@@ -57,7 +57,7 @@ def test_authentication_getter_existing_user_via_email(
|
||||
|
||||
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||
|
||||
with django_assert_num_queries(4): # user by sub, user by mail, update sub
|
||||
with django_assert_num_queries(3): # user by sub, user by mail, update sub
|
||||
user = klass.get_or_create_user(
|
||||
access_token="test-token", id_token=None, payload=None
|
||||
)
|
||||
@@ -214,7 +214,7 @@ def test_authentication_getter_existing_user_change_fields_sub(
|
||||
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||
|
||||
# One and only one additional update query when a field has changed
|
||||
with django_assert_num_queries(3):
|
||||
with django_assert_num_queries(2):
|
||||
authenticated_user = klass.get_or_create_user(
|
||||
access_token="test-token", id_token=None, payload=None
|
||||
)
|
||||
@@ -256,7 +256,7 @@ def test_authentication_getter_existing_user_change_fields_email(
|
||||
monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked)
|
||||
|
||||
# One and only one additional update query when a field has changed
|
||||
with django_assert_num_queries(4):
|
||||
with django_assert_num_queries(3):
|
||||
authenticated_user = klass.get_or_create_user(
|
||||
access_token="test-token", id_token=None, payload=None
|
||||
)
|
||||
|
||||
@@ -680,12 +680,6 @@ class Base(Configuration):
|
||||
environ_prefix=None,
|
||||
)
|
||||
|
||||
# DocSpec API microservice
|
||||
DOCSPEC_API_URL = values.Value(
|
||||
environ_name="DOCSPEC_API_URL",
|
||||
environ_prefix=None
|
||||
)
|
||||
|
||||
# Conversion endpoint
|
||||
CONVERSION_API_ENDPOINT = values.Value(
|
||||
default="convert",
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Breton\n"
|
||||
"Language: br_FR\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Titouroù personel"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Aotreoù"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Deiziadoù a-bouez"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Gwezennadur"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Doare korf"
|
||||
msgid "Format"
|
||||
msgstr "Stumm"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "eilenn {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr "anv klok"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "anv berr"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "postel identelezh"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "postel ar merour"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "yezh"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "Ar yezh a vo implijet evit etrefas an implijer."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Ar gwerzhid-eur a vo implijet evit etrefas an implijer."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "trevnad"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Pe vefe an implijer un aparailh pe un implijer gwirion."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "statud ar skipailh"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Ma c'hall an implijer kevreañ ouzh al lec'hienn verañ-mañ."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "oberiant"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Ma rank bezañ tretet an implijer-mañ evel oberiant. Diziuzit an dra-mañ e-plas dilemel kontoù."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "implijer"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "implijerien"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "titl"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "bomm"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Restr"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Restroù"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Restr hep titl"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} en deus rannet ur restr ganeoc'h!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, 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:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Roud liamm ar restr/an implijer"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Roudoù liamm ar restr/an implijer"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
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:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Restr muiañ-karet"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Restroù muiañ-karet"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
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:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Liamm restr/implijer"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Liammoù restr/implijer"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "An implijer-mañ a zo dija er restr-mañ."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Ar skipailh-mañ a zo dija en restr-mañ."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
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:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "Goulenn tizhout ar restr"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "Goulennoù tizhout ar restr"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
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:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, 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:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, 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:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, 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:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "deskrivadur"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "kod"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "publik"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
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:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Patrom"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Patromoù"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Liamm patrom/implijer"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Liammoù patrom/implijer"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "An implijer-mañ a zo dija er patrom-mañ."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Ar skipailh-mañ a zo dija er patrom-mañ."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "postel"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Pedadenn d'ur restr"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Pedadennoù d'ur restr"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Ar postel-mañ a zo liammet ouzh un implijer enskrivet."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Persönliche Daten"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Berechtigungen"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Wichtige Daten"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Baumstruktur"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Typ"
|
||||
msgid "Format"
|
||||
msgstr "Format"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "Kopie von {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr "Name"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "Kurzbezeichnung"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "Identitäts-E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "Admin E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "Sprache"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "Die Sprache, in der der Benutzer die Benutzeroberfläche sehen möchte."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Die Zeitzone, in der der Nutzer Zeiten sehen möchte."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "Gerät"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Ob der Benutzer ein Gerät oder ein echter Benutzer ist."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "Status des Teammitgliedes"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Gibt an, ob der Benutzer sich in diese Admin-Seite einloggen kann."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "aktiviert"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Ob dieser Benutzer als aktiviert behandelt werden soll. Deaktivieren Sie diese Option, anstatt Konten zu löschen."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "Auszug"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Dokument"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Dokumente"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Unbenanntes Dokument"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} hat ein Dokument mit Ihnen geteilt!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, 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:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Dokument/Benutzer Linkverfolgung"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Dokument/Benutzer Linkverfolgung"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
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:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Dokumentenfavorit"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Dokumentfavoriten"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
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:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Dokument/Benutzerbeziehung"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Dokument/Benutzerbeziehungen"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Dieser Benutzer befindet sich bereits in diesem Dokument."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Dieses Team befindet sich bereits in diesem Dokument."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
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:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "Code"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "CSS"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "öffentlich"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Ob diese Vorlage für jedermann öffentlich ist."
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Vorlage"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Vorlagen"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Vorlage/Benutzer-Beziehung"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Vorlage/Benutzerbeziehungen"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Dieser Benutzer ist bereits in dieser Vorlage."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Dieses Team ist bereits in diesem Template."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Einladung zum Dokument"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Dokumenteinladungen"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Diese E-Mail ist bereits einem registrierten Benutzer zugeordnet."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: English\n"
|
||||
"Language: en_US\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: es_ES\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Información Personal"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Permisos"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Fechas importantes"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Estructura en árbol"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Tipo de Cuerpo"
|
||||
msgid "Format"
|
||||
msgstr "Formato"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "copia de {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr "Obligatorio. 255 caracteres o menos. Solo caracteres ASCII."
|
||||
msgid "full name"
|
||||
msgstr "nombre completo"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "nombre abreviado"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "correo electrónico de identidad"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "correo electrónico del administrador"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "idioma"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "El idioma en el que el usuario desea ver la interfaz."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "La zona horaria en la que el usuario quiere ver los tiempos."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "dispositivo"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Si el usuario es un dispositivo o un usuario real."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "rol en el equipo"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Si el usuario puede iniciar sesión en esta página web de administración."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "activo"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Si este usuario debe ser considerado como activo. Deseleccionar en lugar de eliminar cuentas."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "usuario"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "usuarios"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "título"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "resumen"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Documento"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Documentos"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Documento sin título"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "¡{name} ha compartido un documento contigo!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} ha compartido un documento contigo: {title}"
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Traza del enlace de documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Trazas del enlace de documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
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:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Documento favorito"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Documentos favoritos"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
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:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Relación documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Relaciones documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Este usuario ya forma parte del documento."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Este equipo ya forma parte del documento."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
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:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "Solicitud de acceso"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "Solicitud de accesos"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
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:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr "¡{name} desea acceder a un documento!"
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr "{name} desea acceso al siguiente documento:"
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr "{name} está pidiendo acceso al documento: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "descripción"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "código"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "público"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
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:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Plantilla"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Plantillas"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Relación plantilla/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Relaciones plantilla/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Este usuario ya forma parte de la plantilla."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Este equipo ya se encuentra en esta plantilla."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "dirección de correo electrónico"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Invitación al documento"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Invitaciones a documentos"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Este correo electrónico está asociado a un usuario registrado."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr_FR\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Infos Personnelles"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Permissions"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Dates importantes"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Arborescence"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Type de corps"
|
||||
msgid "Format"
|
||||
msgstr "Format"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "copie de {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr "Obligatoire. 255 caractères ou moins. Caractères ASCII uniquement."
|
||||
msgid "full name"
|
||||
msgstr "nom complet"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "nom court"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "adresse e-mail d'identité"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "adresse e-mail de l'administrateur"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "langue"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "La langue dans laquelle l'utilisateur veut voir l'interface."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Le fuseau horaire dans lequel l'utilisateur souhaite voir les heures."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "appareil"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Si l'utilisateur est un appareil ou un utilisateur réel."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "statut d'équipe"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Si l'utilisateur peut se connecter à ce site d'administration."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "actif"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Si cet utilisateur doit être traité comme actif. Désélectionnez ceci au lieu de supprimer des comptes."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "utilisateurs"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "titre"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "extrait"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Document"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Documents"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Document sans titre"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} a partagé un document avec vous!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, 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:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Trace du lien document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Traces du lien document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
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:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Document favori"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Documents favoris"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
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:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Relation document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Relations document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Cet utilisateur est déjà dans ce document."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Cette équipe est déjà dans ce document."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
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:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "Demande d'accès au document"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "Demande d'accès au document"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
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:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr "{name} souhaiterait accéder au document suivant !"
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, 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:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, 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:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "description"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "code"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "CSS"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "public"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
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:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Modèle"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Modèles"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Relation modèle/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Relations modèle/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Cet utilisateur est déjà dans ce modèle."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Cette équipe est déjà modèle."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "adresse e-mail"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Invitation à un document"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Invitations à un document"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Cette adresse email est déjà associée à un utilisateur inscrit."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Italian\n"
|
||||
"Language: it_IT\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Informazioni personali"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Permessi"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Date importanti"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Struttura ad albero"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr "Formato"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "copia di {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr "nome completo"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "nome"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "indirizzo email di identità"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "Indirizzo email dell'amministratore"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "lingua"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "La lingua in cui l'utente vuole vedere l'interfaccia."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Il fuso orario in cui l'utente vuole vedere gli orari."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "dispositivo"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Se l'utente è un dispositivo o un utente reale."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "stato del personale"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Indica se l'utente può accedere a questo sito amministratore."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "attivo"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Indica se questo utente deve essere trattato come attivo. Deseleziona invece di eliminare gli account."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "utente"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "utenti"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "titolo"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Documento"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Documenti"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Documento senza titolo"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} ha condiviso un documento con te!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, 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:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Documento preferito"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Documenti preferiti"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Questo utente è già presente in questo documento."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Questo team è già presente in questo documento."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "descrizione"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "code"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "pubblico"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Indica se questo modello è pubblico per chiunque."
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Modello"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Modelli"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Questo utente è già in questo modello."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Questo team è già in questo modello."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "indirizzo e-mail"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Invito al documento"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Inviti al documento"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Questa email è già associata a un utente registrato."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Language: nl_NL\n"
|
||||
@@ -17,22 +17,22 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Persoonlijke informatie"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Machtigingen"
|
||||
msgstr "Toestemmingen"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Belangrijke data"
|
||||
msgstr "Belangrijke datums"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Boomstructuur"
|
||||
msgstr "Document structuur"
|
||||
|
||||
#: build/lib/core/api/filters.py:47 core/api/filters.py:47
|
||||
msgid "Title"
|
||||
@@ -40,7 +40,7 @@ msgstr "Titel"
|
||||
|
||||
#: build/lib/core/api/filters.py:61 core/api/filters.py:61
|
||||
msgid "Creator is me"
|
||||
msgstr "Ik ben eigenaar"
|
||||
msgstr "Ik ben Eigenaar"
|
||||
|
||||
#: build/lib/core/api/filters.py:64 core/api/filters.py:64
|
||||
msgid "Masked"
|
||||
@@ -48,15 +48,15 @@ msgstr "Gemaskeerd"
|
||||
|
||||
#: build/lib/core/api/filters.py:67 core/api/filters.py:67
|
||||
msgid "Favorite"
|
||||
msgstr "Favoriet"
|
||||
msgstr "Favoriete"
|
||||
|
||||
#: build/lib/core/api/serializers.py:496 core/api/serializers.py:496
|
||||
msgid "A new document was created on your behalf!"
|
||||
msgstr "Een nieuw document is namens u gemaakt!"
|
||||
msgstr "Een nieuw document was gecreëerd voor u!"
|
||||
|
||||
#: build/lib/core/api/serializers.py:500 core/api/serializers.py:500
|
||||
msgid "You have been granted ownership of a new document:"
|
||||
msgstr "U heeft eigenaarschap van een nieuw document gekregen:"
|
||||
msgstr "U heeft eigenaarschap van een nieuw document:"
|
||||
|
||||
#: build/lib/core/api/serializers.py:536 core/api/serializers.py:536
|
||||
msgid "This field is required."
|
||||
@@ -79,7 +79,7 @@ msgstr "Text type"
|
||||
msgid "Format"
|
||||
msgstr "Formaat"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "kopie van {title}"
|
||||
@@ -92,11 +92,11 @@ msgstr "Lezer"
|
||||
#: build/lib/core/choices.py:36 build/lib/core/choices.py:43 core/choices.py:36
|
||||
#: core/choices.py:43
|
||||
msgid "Editor"
|
||||
msgstr "Redacteur"
|
||||
msgstr "Bewerker"
|
||||
|
||||
#: build/lib/core/choices.py:44 core/choices.py:44
|
||||
msgid "Administrator"
|
||||
msgstr "Beheerder"
|
||||
msgstr "Administrator"
|
||||
|
||||
#: build/lib/core/choices.py:45 core/choices.py:45
|
||||
msgid "Owner"
|
||||
@@ -104,7 +104,7 @@ msgstr "Eigenaar"
|
||||
|
||||
#: build/lib/core/choices.py:56 core/choices.py:56
|
||||
msgid "Restricted"
|
||||
msgstr "Beperkt"
|
||||
msgstr "Niet toegestaan"
|
||||
|
||||
#: build/lib/core/choices.py:60 core/choices.py:60
|
||||
msgid "Authenticated"
|
||||
@@ -148,11 +148,11 @@ msgstr "primaire sleutel voor dossier als UUID"
|
||||
|
||||
#: build/lib/core/models.py:87 core/models.py:87
|
||||
msgid "created on"
|
||||
msgstr "gecreëerd op"
|
||||
msgstr "gemaakt op"
|
||||
|
||||
#: build/lib/core/models.py:88 core/models.py:88
|
||||
msgid "date and time at which a record was created"
|
||||
msgstr "datum en tijd waarop dossier is gecreeërd"
|
||||
msgstr "datum en tijd wanneer dossier was gecreëerd"
|
||||
|
||||
#: build/lib/core/models.py:93 core/models.py:93
|
||||
msgid "updated on"
|
||||
@@ -164,7 +164,7 @@ msgstr "datum en tijd waarop dossier laatst was gewijzigd"
|
||||
|
||||
#: build/lib/core/models.py:130 core/models.py:130
|
||||
msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
|
||||
msgstr "Wij konden geen gebruiker vinden met dit id, maar de email is al geassocieerd met een geregistreerde gebruiker."
|
||||
msgstr "Wij konden geen gebruiker vinden met deze id, maar de email is al geassocieerd met een geregistreerde gebruiker."
|
||||
|
||||
#: build/lib/core/models.py:141 core/models.py:141
|
||||
msgid "sub"
|
||||
@@ -172,234 +172,234 @@ msgstr "id"
|
||||
|
||||
#: build/lib/core/models.py:142 core/models.py:142
|
||||
msgid "Required. 255 characters or fewer. ASCII characters only."
|
||||
msgstr "Vereist. 255 tekens of minder. Alleen ASCII tekens."
|
||||
msgstr "Vereist. Minder dan 255 ASCII tekens."
|
||||
|
||||
#: build/lib/core/models.py:150 core/models.py:150
|
||||
msgid "full name"
|
||||
msgstr "volledige naam"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "gebruikersnaam"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "identiteit emailadres"
|
||||
msgstr "identiteit email adres"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "admin emailadres"
|
||||
msgstr "admin email adres"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "taal"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "De taal waarin de gebruiker de interface wil zien."
|
||||
msgstr "De taal waarin de gebruiker de interface wilt zien."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "De tijdzone waarin de gebruiker de tijden wil zien."
|
||||
msgstr "De tijdzone waarin de gebruiker de tijden wilt zien."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "apparaat"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Of de gebruiker een apparaat is of een echte gebruiker."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "beheerder status"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Of de gebruiker kan inloggen in het beheer gedeelte."
|
||||
msgstr "Of de gebruiker kan inloggen in het admin gedeelte."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "actief"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Of een gebruiker als actief moet worden beschouwd. Deselecteer dit in plaats van het account te deleten."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "gebruiker"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "gebruikers"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "titel"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "uittreksel"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Document"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Documenten"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Naamloos Document"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} heeft een document met u gedeeld!"
|
||||
msgstr "{name} heeft een document met gedeeld!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, 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:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Document/gebruiker link"
|
||||
msgstr "Document/gebruiker url"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Document/gebruiker link"
|
||||
msgstr "Document/gebruiker url"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Een link bestaat al voor dit document/deze gebruiker."
|
||||
msgstr "Een url bestaat al voor dit document/deze gebruiker."
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Document favoriet"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Document favorieten"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Dit document is al in gebruik als favoriet door dezelfde gebruiker."
|
||||
msgstr "Dit document is al in gebruik als favoriete door dezelfde gebruiker."
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Document/gebruiker relatie"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Document/gebruiker relaties"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "De gebruiker bestaat al in dit document."
|
||||
msgstr "De gebruiker is al in dit document."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Dit team bestaat al in dit document."
|
||||
msgstr "Het team is al in dit document."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
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:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "Document verzoekt om toegang"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "Document verzoekt om toegangen"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr "Deze gebruiker heeft al om toegang tot dit document gevraagd."
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr "{name} verzoekt toegang tot een document!"
|
||||
msgstr "{name} wenst toegang tot een document!"
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr "{name} verzoekt toegang tot het volgende document:"
|
||||
msgstr "{name} wenst toegang tot het volgende document:"
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr "{name} verzoekt toegang tot het document: {title}"
|
||||
msgstr "{name} vraagt toegang tot het document: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "omschrijving"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "code"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "publiek"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Of dit sjabloon door iedereen publiekelijk te gebruiken is."
|
||||
msgstr "Of dit template als publiek is en door iedereen te gebruiken is."
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Sjabloon"
|
||||
msgstr "Template"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Sjabloon"
|
||||
msgstr "Templates"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Sjabloon/gebruiker relatie"
|
||||
msgstr "Template/gebruiker relatie"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Sjabloon/gebruiker relaties"
|
||||
msgstr "Template/gebruiker relaties"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "De gebruiker bestaat al in dit sjabloon."
|
||||
msgstr "De gebruiker bestaat al in dit template."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Het team bestaat al in dit sjabloon."
|
||||
msgstr "Het team bestaat al in dit template."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "e-mailadres"
|
||||
msgstr "email adres"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Document uitnodiging"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Document uitnodigingen"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Deze email is al geassocieerd met een geregistreerde gebruiker."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Language: pt_PT\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Informações Pessoais"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Permissões"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Datas importantes"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Estrutura de árvore"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Tipo de corpo"
|
||||
msgid "Format"
|
||||
msgstr "Formato"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "cópia de {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Russian\n"
|
||||
"Language: ru_RU\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Личная информация"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Разрешения"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Важные даты"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Древовидная структура"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Тип сообщения"
|
||||
msgid "Format"
|
||||
msgstr "Формат"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "копия {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr "Обязательно. 255 символов или меньше. Тол
|
||||
msgid "full name"
|
||||
msgstr "полное имя"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "короткое имя"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "личный адрес электронной почты"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "e-mail администратора"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "язык"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "Язык, на котором пользователь хочет видеть интерфейс."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Часовой пояс, в котором пользователь хочет видеть время."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "устройство"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Пользователь является устройством или человеком."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "статус сотрудника"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Может ли пользователь войти на этот административный сайт."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "активный"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Должен ли пользователь рассматриваться как активный. Альтернатива удалению учётных записей."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "пользователь"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "пользователи"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "заголовок"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "отрывок"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Документ"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Документы"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Безымянный документ"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} делится с вами документом!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} приглашает вас присоединиться к следующему документу с ролью \"{role}\":"
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} делится с вами документом: {title}"
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Трассировка связи документ/пользователь"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Трассировка связей документ/пользователь"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Для этого документа/пользователя уже существует трассировка ссылки."
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Избранный документ"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Избранные документы"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Этот документ уже помечен как избранный для этого пользователя."
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Отношение документ/пользователь"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Отношения документ/пользователь"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Этот пользователь уже имеет доступ к этому документу."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Эта команда уже имеет доступ к этому документу."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Может быть выбран либо пользователь, либо команда, но не оба варианта сразу."
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "Документ запрашивает доступ"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "Документ запрашивает доступы"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr "Этот пользователь уже запросил доступ к этому документу."
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr "{name} хочет получить доступ к документу!"
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr "{name} хочет получить доступ к следующему документу:"
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr "{name} запрашивает доступ к документу: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "описание"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "код"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "доступно всем"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Этот шаблон доступен всем пользователям."
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Шаблон"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Шаблоны"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Отношение шаблон/пользователь"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Отношения шаблон/пользователь"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Этот пользователь уже указан в этом шаблоне."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Эта команда уже указана в этом шаблоне."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "адрес электронной почты"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Приглашение для документа"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Приглашения для документов"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Этот адрес уже связан с зарегистрированным пользователем."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Slovenian\n"
|
||||
"Language: sl_SI\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Osebni podatki"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Dovoljenja"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Pomembni datumi"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Drevesna struktura"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Vrsta telesa"
|
||||
msgid "Format"
|
||||
msgstr "Oblika"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr "polno ime"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "kratko ime"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "elektronski naslov identitete"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "elektronski naslov skrbnika"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "jezik"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "Jezik, v katerem uporabnik želi videti vmesnik."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Časovni pas, v katerem želi uporabnik videti uro."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "naprava"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Ali je uporabnik naprava ali pravi uporabnik."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "kadrovski status"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Ali se uporabnik lahko prijavi na to skrbniško mesto."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "aktivni"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Ali je treba tega uporabnika obravnavati kot aktivnega. Namesto brisanja računov počistite to izbiro."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "uporabniki"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "naslov"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "odlomek"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Dokument"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Dokumenti"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Dokument brez naslova"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} je delil dokument z vami!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, 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:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} je delil dokument z vami: {title}"
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Dokument/sled povezave uporabnika"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Sledi povezav dokumenta/uporabnika"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Za ta dokument/uporabnika že obstaja sled povezave."
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Priljubljeni dokument"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Priljubljeni dokumenti"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
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:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Odnos dokument/uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Odnosi dokument/uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Ta uporabnik je že v tem dokumentu."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Ta ekipa je že v tem dokumentu."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
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:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "opis"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "koda"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "javno"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Ali je ta predloga javna za uporabo."
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Predloga"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Predloge"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Odnos predloga/uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Odnosi med predlogo in uporabnikom"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Ta uporabnik je že v tej predlogi."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Ta ekipa je že v tej predlogi."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "elektronski naslov"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Vabilo na dokument"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Vabila na dokument"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Ta e-poštni naslov je že povezan z registriranim uporabnikom."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Swedish\n"
|
||||
"Language: sv_SE\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Personuppgifter"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Behörigheter"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Viktiga datum"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr "Format"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "aktiv"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "e-postadress"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Bjud in dokument"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Inbjudningar dokument"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Denna e-postadress är redan associerad med en registrerad användare."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Turkish\n"
|
||||
"Language: tr_TR\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
@@ -178,228 +178,228 @@ msgstr ""
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Ukrainian\n"
|
||||
"Language: uk_UA\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Особисті дані"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Дозволи"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Важливі дати"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "Ієрархічна структура"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "Тип вмісту"
|
||||
msgid "Format"
|
||||
msgstr "Формат"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "копія {title}"
|
||||
@@ -178,228 +178,228 @@ msgstr "Обов'язкове. 255 символів або менше. Тіль
|
||||
msgid "full name"
|
||||
msgstr "повне ім'я"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "коротке ім'я"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "адреса електронної пошти особи"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "електронна адреса адміністратора"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "мова"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "Мова, якою користувач хоче бачити інтерфейс."
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Часовий пояс, в якому користувач хоче бачити час."
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "пристрій"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Чи є користувач пристроєм чи реальним користувачем."
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "статус співробітника"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Чи може користувач увійти на цей сайт адміністратора."
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "активний"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Чи слід ставитися до цього користувача як до активного. Зніміть вибір замість видалення облікового запису."
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "користувач"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "користувачі"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "заголовок"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "уривок"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "Документ"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "Документи"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "Документ без назви"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} ділиться з вами документом!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} запрошує вас для роботи з документом із роллю \"{role}\":"
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} ділиться з вами документом: {title}"
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Трасування посилання Документ/користувач"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Трасування посилань Документ/користувач"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Відстеження вже існуючих посилань для цього документа/користувача."
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "Обраний документ"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "Обрані документи"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Цей документ вже вказаний як обраний для одного користувача."
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "Відносини документ/користувач"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "Відносини документ/користувач"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Цей користувач вже має доступ до цього документу."
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Ця команда вже має доступ до цього документа."
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Вкажіть користувача або команду, а не обох."
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "Запит доступу до документа"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "Запит доступу для документа"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr "Цей користувач вже попросив доступ до цього документа."
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr "{name} хоче отримати доступ до документа!"
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr "{name} бажає отримати доступ до наступного документа:"
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr "{name} запитує доступ до документа: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "опис"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "код"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "публічне"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Чи є цей шаблон публічним для будь-кого користувача."
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "Шаблон"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "Шаблони"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "Відношення шаблон/користувач"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "Відношення шаблон/користувач"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Цей користувач вже має доступ до цього шаблону."
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Ця команда вже має доступ до цього шаблону."
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "електронна адреса"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "Запрошення до редагування документа"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "Запрошення до редагування документів"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Ця електронна пошта вже пов'язана з зареєстрованим користувачем."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-10-23 11:01+0000\n"
|
||||
"PO-Revision-Date: 2025-11-10 09:54\n"
|
||||
"POT-Creation-Date: 2025-10-14 07:19+0000\n"
|
||||
"PO-Revision-Date: 2025-10-14 13:09\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Language: zh_CN\n"
|
||||
@@ -17,20 +17,20 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:36 core/admin.py:36
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "个人信息"
|
||||
|
||||
#: build/lib/core/admin.py:49 build/lib/core/admin.py:137 core/admin.py:49
|
||||
#: core/admin.py:137
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "权限"
|
||||
|
||||
#: build/lib/core/admin.py:61 core/admin.py:61
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "重要日期"
|
||||
|
||||
#: build/lib/core/admin.py:147 core/admin.py:147
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr "树状结构"
|
||||
|
||||
@@ -79,7 +79,7 @@ msgstr "正文类型"
|
||||
msgid "Format"
|
||||
msgstr "格式"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:1003 core/api/viewsets.py:1003
|
||||
#: build/lib/core/api/viewsets.py:983 core/api/viewsets.py:983
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "{title} 的副本"
|
||||
@@ -178,228 +178,228 @@ msgstr "必填项。限255个字符以内。仅支持ASCII字符。"
|
||||
msgid "full name"
|
||||
msgstr "全名"
|
||||
|
||||
#: build/lib/core/models.py:152 core/models.py:152
|
||||
#: build/lib/core/models.py:151 core/models.py:151
|
||||
msgid "short name"
|
||||
msgstr "简称"
|
||||
|
||||
#: build/lib/core/models.py:155 core/models.py:155
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "identity email address"
|
||||
msgstr "身份电子邮件地址"
|
||||
|
||||
#: build/lib/core/models.py:160 core/models.py:160
|
||||
#: build/lib/core/models.py:158 core/models.py:158
|
||||
msgid "admin email address"
|
||||
msgstr "管理员电子邮件地址"
|
||||
|
||||
#: build/lib/core/models.py:167 core/models.py:167
|
||||
#: build/lib/core/models.py:165 core/models.py:165
|
||||
msgid "language"
|
||||
msgstr "语言"
|
||||
|
||||
#: build/lib/core/models.py:168 core/models.py:168
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "用户希望看到的界面语言。"
|
||||
|
||||
#: build/lib/core/models.py:176 core/models.py:176
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "用户查看时间希望的时区。"
|
||||
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
#: build/lib/core/models.py:177 core/models.py:177
|
||||
msgid "device"
|
||||
msgstr "设备"
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:179 core/models.py:179
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "用户是设备还是真实用户。"
|
||||
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
#: build/lib/core/models.py:182 core/models.py:182
|
||||
msgid "staff status"
|
||||
msgstr "员工状态"
|
||||
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "用户是否可以登录该管理员站点。"
|
||||
|
||||
#: build/lib/core/models.py:189 core/models.py:189
|
||||
#: build/lib/core/models.py:187 core/models.py:187
|
||||
msgid "active"
|
||||
msgstr "激活"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:190 core/models.py:190
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "是否应将此用户视为活跃用户。取消选择此选项而不是删除账户。"
|
||||
|
||||
#: build/lib/core/models.py:204 core/models.py:204
|
||||
#: build/lib/core/models.py:202 core/models.py:202
|
||||
msgid "user"
|
||||
msgstr "用户"
|
||||
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
#: build/lib/core/models.py:203 core/models.py:203
|
||||
msgid "users"
|
||||
msgstr "个用户"
|
||||
|
||||
#: build/lib/core/models.py:361 build/lib/core/models.py:1284
|
||||
#: core/models.py:361 core/models.py:1284
|
||||
#: build/lib/core/models.py:359 build/lib/core/models.py:1282
|
||||
#: core/models.py:359 core/models.py:1282
|
||||
msgid "title"
|
||||
msgstr "标题"
|
||||
|
||||
#: build/lib/core/models.py:362 core/models.py:362
|
||||
#: build/lib/core/models.py:360 core/models.py:360
|
||||
msgid "excerpt"
|
||||
msgstr "摘要"
|
||||
|
||||
#: build/lib/core/models.py:411 core/models.py:411
|
||||
#: build/lib/core/models.py:409 core/models.py:409
|
||||
msgid "Document"
|
||||
msgstr "文档"
|
||||
|
||||
#: build/lib/core/models.py:412 core/models.py:412
|
||||
#: build/lib/core/models.py:410 core/models.py:410
|
||||
msgid "Documents"
|
||||
msgstr "个文档"
|
||||
|
||||
#: build/lib/core/models.py:424 build/lib/core/models.py:822 core/models.py:424
|
||||
#: core/models.py:822
|
||||
#: build/lib/core/models.py:422 build/lib/core/models.py:820 core/models.py:422
|
||||
#: core/models.py:820
|
||||
msgid "Untitled Document"
|
||||
msgstr "未命名文档"
|
||||
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
#: build/lib/core/models.py:855 core/models.py:855
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} 与您共享了一个文档!"
|
||||
|
||||
#: build/lib/core/models.py:861 core/models.py:861
|
||||
#: build/lib/core/models.py:859 core/models.py:859
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} 邀请您以“{role}”角色访问以下文档:"
|
||||
|
||||
#: build/lib/core/models.py:867 core/models.py:867
|
||||
#: build/lib/core/models.py:865 core/models.py:865
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} 与您共享了一个文档:{title}"
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:965 core/models.py:965
|
||||
msgid "Document/user link trace"
|
||||
msgstr "文档/用户链接跟踪"
|
||||
|
||||
#: build/lib/core/models.py:968 core/models.py:968
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
msgid "Document/user link traces"
|
||||
msgstr "个文档/用户链接跟踪"
|
||||
|
||||
#: build/lib/core/models.py:974 core/models.py:974
|
||||
#: build/lib/core/models.py:972 core/models.py:972
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "此文档/用户的链接跟踪已存在。"
|
||||
|
||||
#: build/lib/core/models.py:997 core/models.py:997
|
||||
#: build/lib/core/models.py:995 core/models.py:995
|
||||
msgid "Document favorite"
|
||||
msgstr "文档收藏"
|
||||
|
||||
#: build/lib/core/models.py:998 core/models.py:998
|
||||
#: build/lib/core/models.py:996 core/models.py:996
|
||||
msgid "Document favorites"
|
||||
msgstr "文档收藏夹"
|
||||
|
||||
#: build/lib/core/models.py:1004 core/models.py:1004
|
||||
#: build/lib/core/models.py:1002 core/models.py:1002
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "该文档已被同一用户的收藏关系实例关联。"
|
||||
|
||||
#: build/lib/core/models.py:1026 core/models.py:1026
|
||||
#: build/lib/core/models.py:1024 core/models.py:1024
|
||||
msgid "Document/user relation"
|
||||
msgstr "文档/用户关系"
|
||||
|
||||
#: build/lib/core/models.py:1027 core/models.py:1027
|
||||
#: build/lib/core/models.py:1025 core/models.py:1025
|
||||
msgid "Document/user relations"
|
||||
msgstr "文档/用户关系集"
|
||||
|
||||
#: build/lib/core/models.py:1033 core/models.py:1033
|
||||
#: build/lib/core/models.py:1031 core/models.py:1031
|
||||
msgid "This user is already in this document."
|
||||
msgstr "该用户已在此文档中。"
|
||||
|
||||
#: build/lib/core/models.py:1039 core/models.py:1039
|
||||
#: build/lib/core/models.py:1037 core/models.py:1037
|
||||
msgid "This team is already in this document."
|
||||
msgstr "该团队已在此文档中。"
|
||||
|
||||
#: build/lib/core/models.py:1045 build/lib/core/models.py:1370
|
||||
#: core/models.py:1045 core/models.py:1370
|
||||
#: build/lib/core/models.py:1043 build/lib/core/models.py:1368
|
||||
#: core/models.py:1043 core/models.py:1368
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "必须设置用户或团队之一,不能同时设置两者。"
|
||||
|
||||
#: build/lib/core/models.py:1191 core/models.py:1191
|
||||
#: build/lib/core/models.py:1189 core/models.py:1189
|
||||
msgid "Document ask for access"
|
||||
msgstr "文档需要访问权限"
|
||||
|
||||
#: build/lib/core/models.py:1192 core/models.py:1192
|
||||
#: build/lib/core/models.py:1190 core/models.py:1190
|
||||
msgid "Document ask for accesses"
|
||||
msgstr "文档需要访问权限"
|
||||
|
||||
#: build/lib/core/models.py:1198 core/models.py:1198
|
||||
#: build/lib/core/models.py:1196 core/models.py:1196
|
||||
msgid "This user has already asked for access to this document."
|
||||
msgstr "用户已申请该文档的访问权限。"
|
||||
|
||||
#: build/lib/core/models.py:1263 core/models.py:1263
|
||||
#: build/lib/core/models.py:1261 core/models.py:1261
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to a document!"
|
||||
msgstr "{name} 申请访问文档!"
|
||||
|
||||
#: build/lib/core/models.py:1267 core/models.py:1267
|
||||
#: build/lib/core/models.py:1265 core/models.py:1265
|
||||
#, python-brace-format
|
||||
msgid "{name} would like access to the following document:"
|
||||
msgstr "{name} 申请访问以下文档:"
|
||||
|
||||
#: build/lib/core/models.py:1273 core/models.py:1273
|
||||
#: build/lib/core/models.py:1271 core/models.py:1271
|
||||
#, python-brace-format
|
||||
msgid "{name} is asking for access to the document: {title}"
|
||||
msgstr "{name}申请文档:{title}的访问权限"
|
||||
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
#: build/lib/core/models.py:1283 core/models.py:1283
|
||||
msgid "description"
|
||||
msgstr "说明"
|
||||
|
||||
#: build/lib/core/models.py:1286 core/models.py:1286
|
||||
#: build/lib/core/models.py:1284 core/models.py:1284
|
||||
msgid "code"
|
||||
msgstr "代码"
|
||||
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
#: build/lib/core/models.py:1285 core/models.py:1285
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
#: build/lib/core/models.py:1287 core/models.py:1287
|
||||
msgid "public"
|
||||
msgstr "公开"
|
||||
|
||||
#: build/lib/core/models.py:1291 core/models.py:1291
|
||||
#: build/lib/core/models.py:1289 core/models.py:1289
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "该模板是否公开供任何人使用。"
|
||||
|
||||
#: build/lib/core/models.py:1297 core/models.py:1297
|
||||
#: build/lib/core/models.py:1295 core/models.py:1295
|
||||
msgid "Template"
|
||||
msgstr "模板"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1296 core/models.py:1296
|
||||
msgid "Templates"
|
||||
msgstr "模板"
|
||||
|
||||
#: build/lib/core/models.py:1351 core/models.py:1351
|
||||
#: build/lib/core/models.py:1349 core/models.py:1349
|
||||
msgid "Template/user relation"
|
||||
msgstr "模板/用户关系"
|
||||
|
||||
#: build/lib/core/models.py:1352 core/models.py:1352
|
||||
#: build/lib/core/models.py:1350 core/models.py:1350
|
||||
msgid "Template/user relations"
|
||||
msgstr "模板/用户关系集"
|
||||
|
||||
#: build/lib/core/models.py:1358 core/models.py:1358
|
||||
#: build/lib/core/models.py:1356 core/models.py:1356
|
||||
msgid "This user is already in this template."
|
||||
msgstr "该用户已在此模板中。"
|
||||
|
||||
#: build/lib/core/models.py:1364 core/models.py:1364
|
||||
#: build/lib/core/models.py:1362 core/models.py:1362
|
||||
msgid "This team is already in this template."
|
||||
msgstr "该团队已在此模板中。"
|
||||
|
||||
#: build/lib/core/models.py:1441 core/models.py:1441
|
||||
#: build/lib/core/models.py:1439 core/models.py:1439
|
||||
msgid "email address"
|
||||
msgstr "电子邮件地址"
|
||||
|
||||
#: build/lib/core/models.py:1460 core/models.py:1460
|
||||
#: build/lib/core/models.py:1458 core/models.py:1458
|
||||
msgid "Document invitation"
|
||||
msgstr "文档邀请"
|
||||
|
||||
#: build/lib/core/models.py:1461 core/models.py:1461
|
||||
#: build/lib/core/models.py:1459 core/models.py:1459
|
||||
msgid "Document invitations"
|
||||
msgstr "文档邀请"
|
||||
|
||||
#: build/lib/core/models.py:1481 core/models.py:1481
|
||||
#: build/lib/core/models.py:1479 core/models.py:1479
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "此电子邮件已经与现有注册用户关联。"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "impress"
|
||||
version = "3.9.0"
|
||||
version = "3.8.2"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
@@ -25,42 +25,42 @@ license = { file = "LICENSE" }
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"beautifulsoup4==4.14.2",
|
||||
"boto3==1.40.59",
|
||||
"Brotli==1.2.0",
|
||||
"beautifulsoup4==4.13.4",
|
||||
"boto3==1.39.4",
|
||||
"Brotli==1.1.0",
|
||||
"celery[redis]==5.5.3",
|
||||
"django-configurations==2.5.1",
|
||||
"django-cors-headers==4.9.0",
|
||||
"django-cors-headers==4.7.0",
|
||||
"django-countries==7.6.1",
|
||||
"django-csp==4.0",
|
||||
"django-filter==25.2",
|
||||
"django-lasuite[all]==0.0.16",
|
||||
"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.8",
|
||||
"django==5.2.7",
|
||||
"django-treebeard==4.7.1",
|
||||
"djangorestframework==3.16.1",
|
||||
"djangorestframework==3.16.0",
|
||||
"drf_spectacular==0.28.0",
|
||||
"dockerflow==2024.4.2",
|
||||
"easy_thumbnails==2.10.1",
|
||||
"easy_thumbnails==2.10",
|
||||
"factory_boy==3.3.3",
|
||||
"gunicorn==23.0.0",
|
||||
"jsonschema==4.25.1",
|
||||
"lxml==6.0.2",
|
||||
"markdown==3.9",
|
||||
"jsonschema==4.24.0",
|
||||
"lxml==6.0.0",
|
||||
"markdown==3.8.2",
|
||||
"mozilla-django-oidc==4.0.1",
|
||||
"nested-multipart-parser==1.6.0",
|
||||
"openai==2.6.1",
|
||||
"psycopg[binary]==3.2.12",
|
||||
"pycrdt==0.12.42",
|
||||
"nested-multipart-parser==1.5.0",
|
||||
"openai==1.95.0",
|
||||
"psycopg[binary]==3.2.9",
|
||||
"pycrdt==0.12.25",
|
||||
"PyJWT==2.10.1",
|
||||
"python-magic==0.4.27",
|
||||
"redis<6.0.0",
|
||||
"requests==2.32.5",
|
||||
"sentry-sdk==2.42.1",
|
||||
"whitenoise==6.11.0",
|
||||
"requests==2.32.4",
|
||||
"sentry-sdk==2.32.0",
|
||||
"whitenoise==6.9.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
@@ -73,21 +73,21 @@ dependencies = [
|
||||
dev = [
|
||||
"django-extensions==4.1",
|
||||
"django-test-migrations==1.5.0",
|
||||
"drf-spectacular-sidecar==2025.10.1",
|
||||
"freezegun==1.5.5",
|
||||
"drf-spectacular-sidecar==2025.7.1",
|
||||
"freezegun==1.5.2",
|
||||
"ipdb==0.13.13",
|
||||
"ipython==9.6.0",
|
||||
"pyfakefs==5.10.0",
|
||||
"ipython==9.4.0",
|
||||
"pyfakefs==5.9.1",
|
||||
"pylint-django==2.6.1",
|
||||
"pylint<4.0.0",
|
||||
"pytest-cov==7.0.0",
|
||||
"pylint==3.3.7",
|
||||
"pytest-cov==6.2.1",
|
||||
"pytest-django==4.11.1",
|
||||
"pytest==8.4.2",
|
||||
"pytest==8.4.1",
|
||||
"pytest-icdiff==0.9",
|
||||
"pytest-xdist==3.8.0",
|
||||
"responses==0.25.8",
|
||||
"ruff==0.14.2",
|
||||
"types-requests==2.32.4.20250913",
|
||||
"responses==0.25.7",
|
||||
"ruff==0.12.2",
|
||||
"types-requests==2.32.4.20250611",
|
||||
]
|
||||
|
||||
[tool.setuptools]
|
||||
|
||||
@@ -494,7 +494,7 @@ test.describe('Doc Editor', () => {
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
status: requestCount > 1 ? 'ready' : 'processing',
|
||||
status: requestCount ? 'ready' : 'processing',
|
||||
file: '/anything.html',
|
||||
},
|
||||
});
|
||||
@@ -518,12 +518,6 @@ test.describe('Doc Editor', () => {
|
||||
await fileChooser.setFiles(path.join(__dirname, 'assets/test.html'));
|
||||
|
||||
await expect(editor.getByText('Analyzing file...')).toBeVisible();
|
||||
|
||||
// To be sure the retry happens even after a page reload
|
||||
await page.reload();
|
||||
|
||||
await expect(editor.getByText('Analyzing file...')).toBeVisible();
|
||||
|
||||
// The retry takes a few seconds
|
||||
await expect(editor.getByText('test.html')).toBeVisible({
|
||||
timeout: 7000,
|
||||
|
||||
@@ -2,11 +2,12 @@ import path from 'path';
|
||||
|
||||
import { expect, test } from '@playwright/test';
|
||||
import cs from 'convert-stream';
|
||||
import { PDFParse } from 'pdf-parse';
|
||||
import { pdf } from 'pdf-parse';
|
||||
|
||||
import {
|
||||
TestLanguage,
|
||||
createDoc,
|
||||
randomName,
|
||||
verifyDocName,
|
||||
waitForLanguageSwitch,
|
||||
} from './utils-common';
|
||||
@@ -85,16 +86,11 @@ test.describe('Doc Export', () => {
|
||||
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
|
||||
|
||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||
const pdfParse = new PDFParse({ data: pdfBuffer });
|
||||
const pdfInfo = await pdfParse.getInfo();
|
||||
const pdfText = await pdfParse.getText();
|
||||
const pdfData = await pdf(pdfBuffer);
|
||||
|
||||
expect(pdfInfo.total).toBe(2);
|
||||
expect(pdfText.pages).toStrictEqual([
|
||||
{ text: 'Hello', num: 1 },
|
||||
{ text: 'World', num: 2 },
|
||||
]);
|
||||
expect(pdfInfo?.info.Title).toBe(randomDoc);
|
||||
expect(pdfData.total).toBe(2);
|
||||
expect(pdfData.text).toContain('Hello\n\nWorld\n\n'); // This is the doc text
|
||||
expect(pdfData.info?.Title).toBe(randomDoc);
|
||||
});
|
||||
|
||||
test('it exports the doc to docx', async ({ page, browserName }) => {
|
||||
@@ -223,10 +219,10 @@ test.describe('Doc Export', () => {
|
||||
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
|
||||
|
||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||
const pdfExport = await pdf(pdfBuffer);
|
||||
const pdfText = pdfExport.text;
|
||||
|
||||
const pdfParse = new PDFParse({ data: pdfBuffer });
|
||||
const pdfText = await pdfParse.getText();
|
||||
expect(pdfText.text).toContain('Hello World');
|
||||
expect(pdfText).toContain('Hello World');
|
||||
});
|
||||
|
||||
test('it exports the doc with quotes', async ({ page, browserName }) => {
|
||||
@@ -269,9 +265,9 @@ test.describe('Doc Export', () => {
|
||||
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
|
||||
|
||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||
const pdfParse = new PDFParse({ data: pdfBuffer });
|
||||
const pdfText = await pdfParse.getText();
|
||||
expect(pdfText.text).toContain('Hello World');
|
||||
const pdfData = await pdf(pdfBuffer);
|
||||
|
||||
expect(pdfData.text).toContain('Hello World'); // This is the pdf text
|
||||
});
|
||||
|
||||
test('it exports the doc with multi columns', async ({
|
||||
@@ -324,33 +320,46 @@ test.describe('Doc Export', () => {
|
||||
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
|
||||
|
||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||
const pdfParse = new PDFParse({ data: pdfBuffer });
|
||||
const pdfText = await pdfParse.getText();
|
||||
expect(pdfText.text).toContain('Column 1');
|
||||
expect(pdfText.text).toContain('Column 2');
|
||||
expect(pdfText.text).toContain('Column 3');
|
||||
const pdfData = await pdf(pdfBuffer);
|
||||
expect(pdfData.text).toContain('Column 1');
|
||||
expect(pdfData.text).toContain('Column 2');
|
||||
expect(pdfData.text).toContain('Column 3');
|
||||
});
|
||||
|
||||
test('it injects the correct language attribute into PDF export', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
const [randomDocFrench] = await createDoc(
|
||||
page,
|
||||
'doc-language-export-french',
|
||||
browserName,
|
||||
1,
|
||||
);
|
||||
|
||||
await waitForLanguageSwitch(page, TestLanguage.French);
|
||||
|
||||
// Wait for the page to be ready after language switch
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
||||
await writeInEditor({
|
||||
page,
|
||||
text: 'Contenu de test pour export en français',
|
||||
});
|
||||
const header = page.locator('header').first();
|
||||
await header.locator('h1').getByText('Docs').click();
|
||||
|
||||
const randomDocFrench = randomName(
|
||||
'doc-language-export-french',
|
||||
browserName,
|
||||
1,
|
||||
)[0];
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Nouveau doc',
|
||||
})
|
||||
.click();
|
||||
|
||||
const input = page.getByRole('textbox', { name: 'Titre du document' });
|
||||
await expect(input).toBeVisible();
|
||||
await expect(input).toHaveText('', { timeout: 10000 });
|
||||
await input.click();
|
||||
await input.fill(randomDocFrench);
|
||||
await input.blur();
|
||||
|
||||
const editor = page.locator('.ProseMirror.bn-editor');
|
||||
await editor.click();
|
||||
await editor.fill('Contenu de test pour export en français');
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
@@ -438,8 +447,8 @@ test.describe('Doc Export', () => {
|
||||
expect(download.suggestedFilename()).toBe(`${docChild}.pdf`);
|
||||
|
||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||
const pdfParse = new PDFParse({ data: pdfBuffer });
|
||||
const pdfText = await pdfParse.getText();
|
||||
expect(pdfText.text).toContain(randomDoc);
|
||||
const pdfData = await pdf(pdfBuffer);
|
||||
|
||||
expect(pdfData.text).toContain(randomDoc);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { createDoc, getGridRow, verifyDocName } from './utils-common';
|
||||
import { addNewMember, connectOtherUserToDoc } from './utils-share';
|
||||
import { createDoc, getGridRow } from './utils-common';
|
||||
|
||||
type SmallDoc = {
|
||||
id: string;
|
||||
@@ -12,7 +11,7 @@ test.describe('Documents Grid mobile', () => {
|
||||
test.use({ viewport: { width: 500, height: 1200 } });
|
||||
|
||||
test('it checks the grid when mobile', async ({ page }) => {
|
||||
await page.route(/.*\/documents\/.*/, async (route) => {
|
||||
await page.route('**/documents/**', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET') && request.url().includes('page=')) {
|
||||
await route.fulfill({
|
||||
@@ -134,8 +133,6 @@ test.describe('Document grid item options', () => {
|
||||
test('it deletes the document', async ({ page, browserName }) => {
|
||||
const [docTitle] = await createDoc(page, `delete doc`, browserName);
|
||||
|
||||
await verifyDocName(page, docTitle);
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
await expect(page.getByText(docTitle)).toBeVisible();
|
||||
@@ -164,7 +161,7 @@ test.describe('Document grid item options', () => {
|
||||
test("it checks if the delete option is disabled if we don't have the destroy capability", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.route(/.*\/api\/v1.0\/documents\/\?page=1/, async (route) => {
|
||||
await page.route('*/**/api/v1.0/documents/?page=1', async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
results: [
|
||||
@@ -195,68 +192,90 @@ test.describe('Document grid item options', () => {
|
||||
});
|
||||
await page.goto('/');
|
||||
|
||||
const button = page
|
||||
.getByTestId(`docs-grid-actions-button-mocked-document-id`)
|
||||
.first();
|
||||
const button = page.getByTestId(
|
||||
`docs-grid-actions-button-mocked-document-id`,
|
||||
);
|
||||
await expect(button).toBeVisible();
|
||||
await button.click();
|
||||
const removeButton = page
|
||||
.getByTestId(`docs-grid-actions-remove-mocked-document-id`)
|
||||
.first();
|
||||
const removeButton = page.getByTestId(
|
||||
`docs-grid-actions-remove-mocked-document-id`,
|
||||
);
|
||||
await expect(removeButton).toBeVisible();
|
||||
await removeButton.isDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Documents filters', () => {
|
||||
test('it checks the left panel filters', async ({ page, browserName }) => {
|
||||
test('it checks the prebuild left panel filters', async ({ page }) => {
|
||||
void page.goto('/');
|
||||
|
||||
// Create my doc
|
||||
const [docName] = await createDoc(page, 'my-doc', browserName, 1);
|
||||
await verifyDocName(page, docName);
|
||||
|
||||
// Another user create a doc and share it with me
|
||||
const { cleanup, otherPage, otherBrowserName } =
|
||||
await connectOtherUserToDoc({
|
||||
browserName,
|
||||
docUrl: '/',
|
||||
});
|
||||
|
||||
const [docShareName] = await createDoc(
|
||||
otherPage,
|
||||
'my-share-doc',
|
||||
otherBrowserName,
|
||||
1,
|
||||
);
|
||||
|
||||
await verifyDocName(otherPage, docShareName);
|
||||
|
||||
await otherPage.getByRole('button', { name: 'Share' }).click();
|
||||
|
||||
await addNewMember(otherPage, 0, 'Editor', browserName);
|
||||
|
||||
// Let's check the filters
|
||||
await page.getByRole('button', { name: 'Back to homepage' }).click();
|
||||
|
||||
const row = await getGridRow(page, docName);
|
||||
const rowShare = await getGridRow(page, docShareName);
|
||||
|
||||
// All Docs
|
||||
await expect(row).toBeVisible();
|
||||
await expect(rowShare).toBeVisible();
|
||||
const response = await page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().endsWith('documents/?page=1') &&
|
||||
response.status() === 200,
|
||||
);
|
||||
const result = await response.json();
|
||||
const allCount = result.count as number;
|
||||
await expect(page.getByTestId('grid-loader')).toBeHidden();
|
||||
|
||||
// My Docs
|
||||
await page.getByRole('link', { name: 'My docs' }).click();
|
||||
await expect(row).toBeVisible();
|
||||
await expect(rowShare).toBeHidden();
|
||||
const allDocs = page.getByLabel('All docs');
|
||||
const myDocs = page.getByLabel('My docs');
|
||||
const sharedWithMe = page.getByLabel('Shared with me');
|
||||
|
||||
// Initial state
|
||||
await expect(allDocs).toBeVisible();
|
||||
await expect(allDocs).toHaveAttribute('aria-current', 'page');
|
||||
|
||||
await expect(myDocs).toBeVisible();
|
||||
await expect(myDocs).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||
await expect(myDocs).not.toHaveAttribute('aria-current');
|
||||
|
||||
await expect(sharedWithMe).toBeVisible();
|
||||
await expect(sharedWithMe).toHaveCSS(
|
||||
'background-color',
|
||||
'rgba(0, 0, 0, 0)',
|
||||
);
|
||||
await expect(sharedWithMe).not.toHaveAttribute('aria-current');
|
||||
|
||||
await allDocs.click();
|
||||
|
||||
await page.waitForURL('**/?target=all_docs');
|
||||
|
||||
let url = new URL(page.url());
|
||||
let target = url.searchParams.get('target');
|
||||
expect(target).toBe('all_docs');
|
||||
|
||||
// My docs
|
||||
await myDocs.click();
|
||||
url = new URL(page.url());
|
||||
target = url.searchParams.get('target');
|
||||
expect(target).toBe('my_docs');
|
||||
const responseMyDocs = await page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().endsWith('documents/?page=1&is_creator_me=true') &&
|
||||
response.status() === 200,
|
||||
);
|
||||
const resultMyDocs = await responseMyDocs.json();
|
||||
const countMyDocs = resultMyDocs.count as number;
|
||||
await expect(page.getByTestId('grid-loader')).toBeHidden();
|
||||
expect(countMyDocs).toBeLessThanOrEqual(allCount);
|
||||
|
||||
// Shared with me
|
||||
await page.getByRole('link', { name: 'Shared with me' }).click();
|
||||
await expect(row).toBeHidden();
|
||||
await expect(rowShare).toBeVisible();
|
||||
|
||||
await cleanup();
|
||||
await sharedWithMe.click();
|
||||
url = new URL(page.url());
|
||||
target = url.searchParams.get('target');
|
||||
expect(target).toBe('shared_with_me');
|
||||
const responseSharedWithMe = await page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('documents/?page=1&is_creator_me=false') &&
|
||||
response.status() === 200,
|
||||
);
|
||||
const resultSharedWithMe = await responseSharedWithMe.json();
|
||||
const countSharedWithMe = resultSharedWithMe.count as number;
|
||||
await expect(page.getByTestId('grid-loader')).toBeHidden();
|
||||
expect(countSharedWithMe).toBeLessThanOrEqual(allCount);
|
||||
expect(countSharedWithMe + countMyDocs).toEqual(allCount);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -68,18 +68,9 @@ test.describe('Doc Header', () => {
|
||||
await createDoc(page, 'doc-update-emoji', browserName, 1);
|
||||
|
||||
const emojiPicker = page.locator('.--docs--doc-title').getByRole('button');
|
||||
const optionMenu = page.getByLabel('Open the document options');
|
||||
const addEmojiMenuItem = page.getByRole('menuitem', { name: 'Add emoji' });
|
||||
const removeEmojiMenuItem = page.getByRole('menuitem', {
|
||||
name: 'Remove emoji',
|
||||
});
|
||||
|
||||
// Top parent should not have emoji picker
|
||||
await expect(emojiPicker).toBeHidden();
|
||||
await optionMenu.click();
|
||||
await expect(addEmojiMenuItem).toBeHidden();
|
||||
await expect(removeEmojiMenuItem).toBeHidden();
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
const { name: docChild } = await createRootSubPage(
|
||||
page,
|
||||
@@ -89,23 +80,13 @@ test.describe('Doc Header', () => {
|
||||
|
||||
await verifyDocName(page, docChild);
|
||||
|
||||
// Emoji picker should be hidden initially
|
||||
await expect(emojiPicker).toBeHidden();
|
||||
|
||||
// Add emoji
|
||||
await optionMenu.click();
|
||||
await expect(removeEmojiMenuItem).toBeHidden();
|
||||
await addEmojiMenuItem.click();
|
||||
await expect(emojiPicker).toHaveText('📄');
|
||||
|
||||
// Change emoji
|
||||
await expect(emojiPicker).toBeVisible();
|
||||
await emojiPicker.click({
|
||||
delay: 100,
|
||||
});
|
||||
await page.getByRole('button', { name: '😀' }).first().click();
|
||||
await expect(emojiPicker).toHaveText('😀');
|
||||
|
||||
// Update title
|
||||
const docTitle = page.getByRole('textbox', { name: 'Document title' });
|
||||
await docTitle.fill('Hello Emoji World');
|
||||
await docTitle.blur();
|
||||
@@ -114,12 +95,6 @@ test.describe('Doc Header', () => {
|
||||
// Check the tree
|
||||
const row = await getTreeRow(page, 'Hello Emoji World');
|
||||
await expect(row.getByText('😀')).toBeVisible();
|
||||
|
||||
// Remove emoji
|
||||
await optionMenu.click();
|
||||
await expect(addEmojiMenuItem).toBeHidden();
|
||||
await removeEmojiMenuItem.click();
|
||||
await expect(emojiPicker).toBeHidden();
|
||||
});
|
||||
|
||||
test('it deletes the doc', async ({ page, browserName }) => {
|
||||
|
||||
@@ -31,7 +31,7 @@ test.describe('Document list members', () => {
|
||||
return cleanUrl.split('/').pop() || '';
|
||||
})();
|
||||
|
||||
await page.route(/.*\/documents\/.*\/accesses\//, async (route) => {
|
||||
await page.route('**/documents/**/accesses/', async (route) => {
|
||||
const request = route.request();
|
||||
const url = new URL(request.url());
|
||||
const pageId = url.searchParams.get('page') ?? '1';
|
||||
|
||||
@@ -119,10 +119,6 @@ test.describe('Doc Trashbin', () => {
|
||||
await row.getByText(subDocName).click();
|
||||
await verifyDocName(page, subDocName);
|
||||
|
||||
await expect(
|
||||
page.locator('.--docs--editor-container.--docs--doc-deleted'),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(page.getByLabel('Alert deleted document')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Share' })).toBeDisabled();
|
||||
await expect(page.locator('.bn-editor')).toHaveAttribute(
|
||||
|
||||
@@ -352,7 +352,7 @@ test.describe('Doc Tree', () => {
|
||||
await page.getByRole('menuitem', { name: 'Remove emoji' }).click();
|
||||
|
||||
await expect(row.getByText('😀')).toBeHidden();
|
||||
await expect(titleEmojiPicker).toBeHidden();
|
||||
await expect(titleEmojiPicker).not.toHaveText('😀');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
keyCloakSignIn,
|
||||
verifyDocName,
|
||||
} from './utils-common';
|
||||
import { getEditor, writeInEditor } from './utils-editor';
|
||||
import { writeInEditor } from './utils-editor';
|
||||
import { addNewMember, connectOtherUserToDoc } from './utils-share';
|
||||
import { createRootSubPage } from './utils-sub-pages';
|
||||
|
||||
@@ -182,14 +182,15 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
});
|
||||
|
||||
test.describe('Doc Visibility: Public', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
|
||||
test('It checks a public doc in read only mode', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(
|
||||
page,
|
||||
'Public read only',
|
||||
@@ -199,8 +200,6 @@ test.describe('Doc Visibility: Public', () => {
|
||||
|
||||
await verifyDocName(page, docTitle);
|
||||
|
||||
await writeInEditor({ page, text: 'Hello Public Viewonly' });
|
||||
|
||||
await page.getByRole('button', { name: 'Share' }).click();
|
||||
const selectVisibility = page.getByTestId('doc-visibility');
|
||||
await selectVisibility.click();
|
||||
@@ -242,67 +241,49 @@ test.describe('Doc Visibility: Public', () => {
|
||||
await expect(page.getByTestId('search-docs-button')).toBeVisible();
|
||||
await expect(page.getByTestId('new-doc-button')).toBeVisible();
|
||||
|
||||
const docUrl = page.url();
|
||||
const urlDoc = page.url();
|
||||
|
||||
const { otherPage, cleanup } = await connectOtherUserToDoc({
|
||||
browserName,
|
||||
docUrl,
|
||||
withoutSignIn: true,
|
||||
});
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Logout',
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(otherPage.locator('h2').getByText(docTitle)).toBeVisible();
|
||||
await expect(otherPage.getByTestId('search-docs-button')).toBeHidden();
|
||||
await expect(otherPage.getByTestId('new-doc-button')).toBeHidden();
|
||||
await expect(
|
||||
otherPage.getByRole('button', { name: 'Share' }),
|
||||
).toBeVisible();
|
||||
const card = otherPage.getByLabel('It is the card information');
|
||||
await expectLoginPage(page);
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
await expect(page.locator('h2').getByText(docTitle)).toBeVisible();
|
||||
await expect(page.getByTestId('search-docs-button')).toBeHidden();
|
||||
await expect(page.getByTestId('new-doc-button')).toBeHidden();
|
||||
await expect(page.getByRole('button', { name: 'Share' })).toBeVisible();
|
||||
const card = page.getByLabel('It is the card information');
|
||||
await expect(card).toBeVisible();
|
||||
await expect(card.getByText('Reader')).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Share' }).click();
|
||||
await expect(
|
||||
otherPage.locator('.--docs--editor-container.--docs--doc-readonly'),
|
||||
).toBeVisible();
|
||||
|
||||
const otherEditor = await getEditor({ page: otherPage });
|
||||
await expect(otherEditor).toHaveAttribute('contenteditable', 'false');
|
||||
await expect(otherEditor.getByText('Hello Public Viewonly')).toBeVisible();
|
||||
|
||||
// Cursor and selection of the anonymous user are not visible
|
||||
await otherEditor.getByText('Hello Public').selectText();
|
||||
await expect(
|
||||
page.locator('.collaboration-cursor-custom__base'),
|
||||
).toBeHidden();
|
||||
await expect(page.locator('.ProseMirror-yjs-selection')).toBeHidden();
|
||||
|
||||
// Can still see changes made by others
|
||||
await writeInEditor({ page, text: 'Can you see it ?' });
|
||||
await expect(otherEditor.getByText('Can you see it ?')).toBeVisible();
|
||||
|
||||
await otherPage.getByRole('button', { name: 'Share' }).click();
|
||||
await expect(
|
||||
otherPage.getByText(
|
||||
page.getByText(
|
||||
'You can view this document but need additional access to see its members or modify settings.',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
otherPage.getByRole('button', { name: 'Request access' }),
|
||||
page.getByRole('button', { name: 'Request access' }),
|
||||
).toBeHidden();
|
||||
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
test('It checks a public doc in editable mode', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(page, 'Public editable', browserName, 1);
|
||||
|
||||
await verifyDocName(page, docTitle);
|
||||
|
||||
await writeInEditor({ page, text: 'Hello Public Editable' });
|
||||
|
||||
await page.getByRole('button', { name: 'Share' }).click();
|
||||
const selectVisibility = page.getByTestId('doc-visibility');
|
||||
await selectVisibility.click();
|
||||
@@ -336,47 +317,20 @@ test.describe('Doc Visibility: Public', () => {
|
||||
cardContainer.getByText('Public document', { exact: true }),
|
||||
).toBeVisible();
|
||||
|
||||
const docUrl = page.url();
|
||||
const urlDoc = page.url();
|
||||
|
||||
const { otherPage, cleanup } = await connectOtherUserToDoc({
|
||||
browserName,
|
||||
docUrl,
|
||||
withoutSignIn: true,
|
||||
docTitle,
|
||||
});
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Logout',
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(otherPage.getByTestId('search-docs-button')).toBeHidden();
|
||||
await expect(otherPage.getByTestId('new-doc-button')).toBeHidden();
|
||||
await expectLoginPage(page);
|
||||
|
||||
const otherEditor = await getEditor({ page: otherPage });
|
||||
await expect(otherEditor).toHaveAttribute('contenteditable', 'true');
|
||||
await expect(otherEditor.getByText('Hello Public Editable')).toBeVisible();
|
||||
await page.goto(urlDoc);
|
||||
|
||||
// We can see the collaboration cursor of the anonymous user
|
||||
await otherEditor.getByText('Hello Public').selectText();
|
||||
await expect(
|
||||
page.locator('.collaboration-cursor-custom__base').getByText('Anonymous'),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
otherPage.getByRole('button', { name: 'Share' }),
|
||||
).toBeVisible();
|
||||
const card = otherPage.getByLabel('It is the card information');
|
||||
await expect(card).toBeVisible();
|
||||
await expect(card.getByText('Editor')).toBeVisible();
|
||||
|
||||
await otherPage.getByRole('button', { name: 'Share' }).click();
|
||||
await expect(
|
||||
otherPage.getByText(
|
||||
'You can view this document but need additional access to see its members or modify settings.',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
otherPage.getByRole('button', { name: 'Request access' }),
|
||||
).toBeHidden();
|
||||
|
||||
await cleanup();
|
||||
await verifyDocName(page, docTitle);
|
||||
await expect(page.getByRole('button', { name: 'Share' })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
37
src/frontend/apps/e2e/__tests__/app-impress/types/pdf-parse.d.ts
vendored
Normal file
37
src/frontend/apps/e2e/__tests__/app-impress/types/pdf-parse.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Type definitions for pdf-parse library
|
||||
* The library doesn't export complete type definitions for the parsed PDF data
|
||||
*/
|
||||
|
||||
declare module 'pdf-parse' {
|
||||
export interface PdfInfo {
|
||||
Title?: string;
|
||||
Author?: string;
|
||||
Subject?: string;
|
||||
Keywords?: string;
|
||||
Creator?: string;
|
||||
Producer?: string;
|
||||
CreationDate?: string;
|
||||
ModDate?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface PdfData {
|
||||
/** Total number of pages */
|
||||
numpages: number;
|
||||
/** Alias for numpages */
|
||||
total?: number;
|
||||
/** Extracted text content from the PDF */
|
||||
text: string;
|
||||
/** PDF metadata information */
|
||||
info?: PdfInfo;
|
||||
/** PDF metadata (alternative structure) */
|
||||
metadata?: unknown;
|
||||
/** PDF version */
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export function pdf(buffer: Buffer): Promise<PdfData>;
|
||||
|
||||
export default pdf;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export const overrideConfig = async (
|
||||
page: Page,
|
||||
newConfig: { [_K in keyof typeof CONFIG]?: unknown },
|
||||
) =>
|
||||
await page.route(/.*\/api\/v1.0\/config\/.*/, async (route) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
@@ -204,7 +204,7 @@ export const waitForResponseCreateDoc = (page: Page) => {
|
||||
};
|
||||
|
||||
export const mockedDocument = async (page: Page, data: object) => {
|
||||
await page.route(/\**\/documents\/\**/, async (route) => {
|
||||
await page.route('**/documents/**/', async (route) => {
|
||||
const request = route.request();
|
||||
if (
|
||||
request.method().includes('GET') &&
|
||||
@@ -256,7 +256,7 @@ export const mockedDocument = async (page: Page, data: object) => {
|
||||
};
|
||||
|
||||
export const mockedListDocs = async (page: Page, data: object[] = []) => {
|
||||
await page.route(/\**\/documents\/\**/, async (route) => {
|
||||
await page.route('**/documents/**/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET') && request.url().includes('page=')) {
|
||||
await route.fulfill({
|
||||
@@ -277,7 +277,6 @@ export const expectLoginPage = async (page: Page) =>
|
||||
).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
// language helper
|
||||
export const TestLanguage = {
|
||||
English: {
|
||||
@@ -301,7 +300,7 @@ export async function waitForLanguageSwitch(
|
||||
page: Page,
|
||||
lang: TestLanguageValue,
|
||||
) {
|
||||
await page.route(/\**\/api\/v1.0\/users\/\**/, async (route, request) => {
|
||||
await page.route('**/api/v1.0/users/**', async (route, request) => {
|
||||
if (request.method().includes('PATCH')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
|
||||
@@ -118,16 +118,12 @@ export const connectOtherUserToDoc = async ({
|
||||
await otherPage.goto(docUrl);
|
||||
|
||||
if (!withoutSignIn) {
|
||||
const loginFromApp = otherPage
|
||||
await otherPage
|
||||
.getByRole('main', { name: 'Main content' })
|
||||
.getByLabel('Login');
|
||||
const loginFromHome = otherPage.getByRole('button', {
|
||||
name: 'Start Writing',
|
||||
});
|
||||
|
||||
await loginFromApp.or(loginFromHome).first().click({
|
||||
timeout: 15000,
|
||||
});
|
||||
.getByLabel('Login')
|
||||
.click({
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
await keyCloakSignIn(otherPage, otherBrowserName, false);
|
||||
}
|
||||
@@ -163,7 +159,7 @@ export const mockedInvitations = async (page: Page, json?: object) => {
|
||||
...json,
|
||||
},
|
||||
];
|
||||
await page.route(/.*\/invitations\/.*/, async (route) => {
|
||||
await page.route('**/invitations/**/', async (route) => {
|
||||
const request = route.request();
|
||||
if (
|
||||
request.method().includes('GET') &&
|
||||
@@ -184,7 +180,7 @@ export const mockedInvitations = async (page: Page, json?: object) => {
|
||||
});
|
||||
|
||||
await page.route(
|
||||
/.*\/invitations\/120ec765-43af-4602-83eb-7f4e1224548a\/.*/,
|
||||
'**/invitations/120ec765-43af-4602-83eb-7f4e1224548a/**/',
|
||||
async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('DELETE')) {
|
||||
@@ -199,7 +195,7 @@ export const mockedInvitations = async (page: Page, json?: object) => {
|
||||
};
|
||||
|
||||
export const mockedAccesses = async (page: Page, json?: object) => {
|
||||
await page.route(/.*\/accesses\/.*/, async (route) => {
|
||||
await page.route('**/accesses/**/', async (route) => {
|
||||
const request = route.request();
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-e2e",
|
||||
"version": "3.9.0",
|
||||
"version": "3.8.2",
|
||||
"repository": "https://github.com/suitenumerique/docs",
|
||||
"author": "DINUM",
|
||||
"license": "MIT",
|
||||
@@ -15,7 +15,7 @@
|
||||
"test:ui::chromium": "yarn test:ui --project=chromium"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.56.1",
|
||||
"@playwright/test": "1.55.1",
|
||||
"@types/node": "*",
|
||||
"@types/pdf-parse": "1.1.5",
|
||||
"eslint-plugin-docs": "*",
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"convert-stream": "1.0.2",
|
||||
"pdf-parse": "2.4.5"
|
||||
"pdf-parse": "2.1.7"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-impress",
|
||||
"version": "3.9.0",
|
||||
"version": "3.8.2",
|
||||
"repository": "https://github.com/suitenumerique/docs",
|
||||
"author": "DINUM",
|
||||
"license": "MIT",
|
||||
@@ -31,38 +31,38 @@
|
||||
"@emoji-mart/data": "1.2.1",
|
||||
"@emoji-mart/react": "1.1.1",
|
||||
"@fontsource-variable/inter": "5.2.8",
|
||||
"@fontsource-variable/material-symbols-outlined": "5.2.28",
|
||||
"@fontsource-variable/material-symbols-outlined": "5.2.25",
|
||||
"@fontsource/material-icons": "5.2.7",
|
||||
"@gouvfr-lasuite/integration": "1.0.3",
|
||||
"@gouvfr-lasuite/ui-kit": "0.16.2",
|
||||
"@hocuspocus/provider": "3.4.0",
|
||||
"@mantine/core": "8.3.6",
|
||||
"@mantine/hooks": "8.3.6",
|
||||
"@hocuspocus/provider": "3.3.0",
|
||||
"@mantine/core": "8.3.4",
|
||||
"@mantine/hooks": "8.3.4",
|
||||
"@openfun/cunningham-react": "3.2.3",
|
||||
"@react-pdf/renderer": "4.3.1",
|
||||
"@sentry/nextjs": "10.22.0",
|
||||
"@tanstack/react-query": "5.90.6",
|
||||
"@tiptap/extensions": "3.10.1",
|
||||
"@sentry/nextjs": "10.17.0",
|
||||
"@tanstack/react-query": "5.90.2",
|
||||
"@tiptap/extensions": "3.4.4",
|
||||
"canvg": "4.0.3",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"crisp-sdk-web": "1.0.26",
|
||||
"crisp-sdk-web": "1.0.25",
|
||||
"docx": "*",
|
||||
"emoji-datasource-apple": "16.0.0",
|
||||
"emoji-mart": "5.6.0",
|
||||
"emoji-regex": "10.6.0",
|
||||
"i18next": "25.6.0",
|
||||
"emoji-regex": "10.5.0",
|
||||
"i18next": "25.5.3",
|
||||
"i18next-browser-languagedetector": "8.2.0",
|
||||
"idb": "8.0.3",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.7.2",
|
||||
"next": "15.5.4",
|
||||
"posthog-js": "1.284.0",
|
||||
"posthog-js": "1.271.0",
|
||||
"react": "*",
|
||||
"react-aria-components": "1.13.0",
|
||||
"react-dom": "*",
|
||||
"react-i18next": "16.2.3",
|
||||
"react-intersection-observer": "10.0.0",
|
||||
"react-i18next": "16.0.0",
|
||||
"react-intersection-observer": "9.16.0",
|
||||
"react-resizable-panels": "3.0.6",
|
||||
"react-select": "5.10.2",
|
||||
"styled-components": "6.1.19",
|
||||
@@ -83,13 +83,13 @@
|
||||
"@types/node": "*",
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"@vitejs/plugin-react": "5.1.0",
|
||||
"@vitejs/plugin-react": "5.0.4",
|
||||
"copy-webpack-plugin": "13.0.1",
|
||||
"cross-env": "10.1.0",
|
||||
"dotenv": "17.2.3",
|
||||
"eslint-plugin-docs": "*",
|
||||
"fetch-mock": "9.11.0",
|
||||
"jsdom": "27.1.0",
|
||||
"jsdom": "27.0.0",
|
||||
"node-fetch": "2.7.0",
|
||||
"prettier": "3.6.2",
|
||||
"stylelint": "16.25.0",
|
||||
@@ -97,8 +97,8 @@
|
||||
"stylelint-prettier": "5.0.3",
|
||||
"typescript": "*",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "4.0.6",
|
||||
"webpack": "5.102.1",
|
||||
"vitest": "3.2.4",
|
||||
"webpack": "5.102.0",
|
||||
"workbox-webpack-plugin": "7.1.0"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
|
||||
@@ -31,7 +31,7 @@ const StyledButton = styled(Button)<StyledButtonProps>`
|
||||
font-weight: 500;
|
||||
font-size: 0.938rem;
|
||||
padding: 0;
|
||||
border-radius: 4px;
|
||||
${({ $css }) => $css};
|
||||
&:hover {
|
||||
background-color: var(
|
||||
--c--components--button--primary-text--background--color-hover
|
||||
@@ -41,7 +41,6 @@ const StyledButton = styled(Button)<StyledButtonProps>`
|
||||
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-400);
|
||||
border-radius: 4px;
|
||||
}
|
||||
${({ $css }) => $css};
|
||||
`;
|
||||
|
||||
export interface DropButtonProps {
|
||||
|
||||
@@ -13,7 +13,7 @@ export const Icon = ({
|
||||
iconName,
|
||||
disabled,
|
||||
variant = 'outlined',
|
||||
$variation = 'text',
|
||||
$variation,
|
||||
...textProps
|
||||
}: IconProps) => {
|
||||
const hasLabel = 'aria-label' in textProps || 'aria-labelledby' in textProps;
|
||||
@@ -41,19 +41,15 @@ type IconOptionsProps = TextType & {
|
||||
isHorizontal?: boolean;
|
||||
};
|
||||
|
||||
export const IconOptions = ({
|
||||
isHorizontal,
|
||||
$css,
|
||||
...props
|
||||
}: IconOptionsProps) => {
|
||||
export const IconOptions = ({ isHorizontal, ...props }: IconOptionsProps) => {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
iconName={isHorizontal ? 'more_horiz' : 'more_vert'}
|
||||
$css={css`
|
||||
user-select: none;
|
||||
${$css}
|
||||
${props.$css}
|
||||
`}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -44,11 +44,6 @@
|
||||
contain: content;
|
||||
}
|
||||
|
||||
.c__button--medium {
|
||||
min-height: var(--c--components--button--medium-height);
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal
|
||||
*/
|
||||
|
||||
@@ -44,7 +44,7 @@ export function useAuthQuery(
|
||||
staleTime: 1000 * 60 * 15, // 15 minutes
|
||||
retry: (failureCount, error) => {
|
||||
// we assume that a 401 means the user is not logged in
|
||||
if (error.status === 401) {
|
||||
if (error.status == 401) {
|
||||
return false;
|
||||
}
|
||||
return failureCount < DEFAULT_QUERY_RETRY;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { APIError, errorCauses } from '@/api';
|
||||
import { sleep } from '@/utils';
|
||||
|
||||
interface CheckDocMediaStatusResponse {
|
||||
file?: string;
|
||||
@@ -26,28 +25,3 @@ export const checkDocMediaStatus = async ({
|
||||
|
||||
return response.json() as Promise<CheckDocMediaStatusResponse>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Upload file can be analyzed on the server side,
|
||||
* we had this function to wait for the analysis to be done
|
||||
* before returning the file url. It will keep the loader
|
||||
* on the upload button until the analysis is done.
|
||||
* @param url
|
||||
* @returns Promise<CheckDocMediaStatusResponse> status_code
|
||||
* @description Waits for the upload to be analyzed by checking the status of the file.
|
||||
*/
|
||||
export const loopCheckDocMediaStatus = async (
|
||||
url: string,
|
||||
): Promise<CheckDocMediaStatusResponse> => {
|
||||
const SLEEP_TIME = 5000;
|
||||
const response = await checkDocMediaStatus({
|
||||
urlMedia: url,
|
||||
});
|
||||
|
||||
if (response.status === 'ready') {
|
||||
return response;
|
||||
} else {
|
||||
await sleep(SLEEP_TIME);
|
||||
return await loopCheckDocMediaStatus(url);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,12 +12,16 @@ import { BlockNoteView } from '@blocknote/mantine';
|
||||
import '@blocknote/mantine/style.css';
|
||||
import { useCreateBlockNote } from '@blocknote/react';
|
||||
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { Box, TextErrors } from '@/components';
|
||||
import { Doc, useProviderStore } from '@/docs/doc-management';
|
||||
import {
|
||||
Doc,
|
||||
useIsCollaborativeEditable,
|
||||
useProviderStore,
|
||||
} from '@/docs/doc-management';
|
||||
import { useAuth } from '@/features/auth';
|
||||
|
||||
import {
|
||||
@@ -80,21 +84,26 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
const { setEditor } = useEditorStore();
|
||||
const { t } = useTranslation();
|
||||
const { isSynced: isConnectedToCollabServer } = useProviderStore();
|
||||
const refEditorContainer = useRef<HTMLDivElement>(null);
|
||||
|
||||
useSaveDoc(doc.id, provider.document, isConnectedToCollabServer);
|
||||
const { isEditable, isLoading } = useIsCollaborativeEditable(doc);
|
||||
const readOnly = !doc.abilities.partial_update || !isEditable || isLoading;
|
||||
const isDeletedDoc = !!doc.deleted_at;
|
||||
|
||||
useSaveDoc(doc.id, provider.document, !readOnly, isConnectedToCollabServer);
|
||||
const { i18n } = useTranslation();
|
||||
const lang = i18n.resolvedLanguage;
|
||||
|
||||
const { uploadFile, errorAttachment } = useUploadFile(doc.id);
|
||||
|
||||
const collabName = user?.full_name || user?.email || t('Anonymous');
|
||||
const collabName = readOnly
|
||||
? 'Reader'
|
||||
: user?.full_name || user?.email || t('Anonymous');
|
||||
const showCursorLabels: 'always' | 'activity' | (string & {}) = 'activity';
|
||||
|
||||
const editor: DocsBlockNoteEditor = useCreateBlockNote(
|
||||
{
|
||||
collaboration: {
|
||||
provider: provider,
|
||||
provider,
|
||||
fragment: provider.document.getXmlFragment('document-store'),
|
||||
user: {
|
||||
name: collabName,
|
||||
@@ -108,6 +117,10 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
renderCursor: (user: { color: string; name: string }) => {
|
||||
const cursorElement = document.createElement('span');
|
||||
|
||||
if (user.name === 'Reader') {
|
||||
return cursorElement;
|
||||
}
|
||||
|
||||
cursorElement.classList.add('collaboration-cursor-custom__base');
|
||||
const caretElement = document.createElement('span');
|
||||
caretElement.classList.add('collaboration-cursor-custom__caret');
|
||||
@@ -156,9 +169,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
);
|
||||
|
||||
useHeadings(editor);
|
||||
|
||||
useShortcuts(editor, refEditorContainer.current);
|
||||
|
||||
useShortcuts(editor);
|
||||
useUploadStatus(editor);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -170,7 +181,12 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
}, [setEditor, editor]);
|
||||
|
||||
return (
|
||||
<Box ref={refEditorContainer} $css={cssEditor}>
|
||||
<Box
|
||||
$padding={{ top: 'md' }}
|
||||
$background="white"
|
||||
$css={cssEditor(readOnly, isDeletedDoc)}
|
||||
className="--docs--editor-container"
|
||||
>
|
||||
{errorAttachment && (
|
||||
<Box $margin={{ bottom: 'big', top: 'none', horizontal: 'large' }}>
|
||||
<TextErrors
|
||||
@@ -185,6 +201,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
editor={editor}
|
||||
formattingToolbar={false}
|
||||
slashMenu={false}
|
||||
editable={!readOnly}
|
||||
theme="light"
|
||||
>
|
||||
<BlockNoteSuggestionMenu />
|
||||
@@ -194,12 +211,14 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface BlockNoteReaderProps {
|
||||
interface BlockNoteEditorVersionProps {
|
||||
initialContent: Y.XmlFragment;
|
||||
}
|
||||
|
||||
export const BlockNoteReader = ({ initialContent }: BlockNoteReaderProps) => {
|
||||
const { setEditor } = useEditorStore();
|
||||
export const BlockNoteEditorVersion = ({
|
||||
initialContent,
|
||||
}: BlockNoteEditorVersionProps) => {
|
||||
const readOnly = true;
|
||||
const editor = useCreateBlockNote(
|
||||
{
|
||||
collaboration: {
|
||||
@@ -215,25 +234,9 @@ export const BlockNoteReader = ({ initialContent }: BlockNoteReaderProps) => {
|
||||
[initialContent],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setEditor(editor);
|
||||
|
||||
return () => {
|
||||
setEditor(undefined);
|
||||
};
|
||||
}, [setEditor, editor]);
|
||||
|
||||
useHeadings(editor);
|
||||
|
||||
return (
|
||||
<Box $css={cssEditor}>
|
||||
<BlockNoteView
|
||||
editor={editor}
|
||||
editable={false}
|
||||
theme="light"
|
||||
formattingToolbar={false}
|
||||
slashMenu={false}
|
||||
/>
|
||||
<Box $css={cssEditor(readOnly, true)} className="--docs--editor-container">
|
||||
<BlockNoteView editor={editor} editable={!readOnly} theme="light" />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,87 +1,32 @@
|
||||
import clsx from 'clsx';
|
||||
import { useEffect } from 'react';
|
||||
import { Loader } from '@openfun/cunningham-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { css } from 'styled-components';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { Box, Loading } from '@/components';
|
||||
import { DocHeader } from '@/docs/doc-header/';
|
||||
import { Box, Loading, Text, TextErrors } from '@/components';
|
||||
import { DocHeader, DocVersionHeader } from '@/docs/doc-header/';
|
||||
import {
|
||||
Doc,
|
||||
useIsCollaborativeEditable,
|
||||
base64ToBlocknoteXmlFragment,
|
||||
useProviderStore,
|
||||
} from '@/docs/doc-management';
|
||||
import { TableContent } from '@/docs/doc-table-content/';
|
||||
import { Versions, useDocVersion } from '@/docs/doc-versioning/';
|
||||
import { useSkeletonStore } from '@/features/skeletons';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import { BlockNoteEditor, BlockNoteReader } from './BlockNoteEditor';
|
||||
|
||||
interface DocEditorContainerProps {
|
||||
docHeader: React.ReactNode;
|
||||
docEditor: React.ReactNode;
|
||||
isDeletedDoc: boolean;
|
||||
readOnly: boolean;
|
||||
}
|
||||
|
||||
export const DocEditorContainer = ({
|
||||
docHeader,
|
||||
docEditor,
|
||||
isDeletedDoc,
|
||||
readOnly,
|
||||
}: DocEditorContainerProps) => {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
$maxWidth="868px"
|
||||
$width="100%"
|
||||
$height="100%"
|
||||
className="--docs--doc-editor"
|
||||
>
|
||||
<Box
|
||||
$padding={{ horizontal: isDesktop ? '54px' : 'base' }}
|
||||
className="--docs--doc-editor-header"
|
||||
>
|
||||
{docHeader}
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
$direction="row"
|
||||
$width="100%"
|
||||
$css="overflow-x: clip; flex: 1;"
|
||||
$position="relative"
|
||||
className="--docs--doc-editor-content"
|
||||
>
|
||||
<Box $css="flex:1;" $position="relative" $width="100%">
|
||||
<Box
|
||||
$padding={{ top: 'md', bottom: '2rem' }}
|
||||
$background="white"
|
||||
className={clsx('--docs--editor-container', {
|
||||
'--docs--doc-readonly': readOnly,
|
||||
'--docs--doc-deleted': isDeletedDoc,
|
||||
})}
|
||||
$height="100%"
|
||||
>
|
||||
{docEditor}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
import { BlockNoteEditor, BlockNoteEditorVersion } from './BlockNoteEditor';
|
||||
|
||||
interface DocEditorProps {
|
||||
doc: Doc;
|
||||
versionId?: Versions['version_id'];
|
||||
}
|
||||
|
||||
export const DocEditor = ({ doc }: DocEditorProps) => {
|
||||
export const DocEditor = ({ doc, versionId }: DocEditorProps) => {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const isVersion = !!versionId && typeof versionId === 'string';
|
||||
const { provider, isReady } = useProviderStore();
|
||||
const { isEditable, isLoading } = useIsCollaborativeEditable(doc);
|
||||
const isDeletedDoc = !!doc.deleted_at;
|
||||
const readOnly =
|
||||
!doc.abilities.partial_update || !isEditable || isLoading || isDeletedDoc;
|
||||
const { setIsSkeletonVisible } = useSkeletonStore();
|
||||
const isProviderReady = isReady && provider;
|
||||
|
||||
@@ -97,7 +42,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{isDesktop && (
|
||||
{isDesktop && !isVersion && (
|
||||
<Box
|
||||
$position="absolute"
|
||||
$css={css`
|
||||
@@ -108,22 +53,102 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
|
||||
<TableContent />
|
||||
</Box>
|
||||
)}
|
||||
<DocEditorContainer
|
||||
docHeader={<DocHeader doc={doc} />}
|
||||
docEditor={
|
||||
readOnly ? (
|
||||
<BlockNoteReader
|
||||
initialContent={provider.document.getXmlFragment(
|
||||
'document-store',
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<BlockNoteEditor doc={doc} provider={provider} />
|
||||
)
|
||||
}
|
||||
isDeletedDoc={isDeletedDoc}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
<Box
|
||||
$maxWidth="868px"
|
||||
$width="100%"
|
||||
$height="100%"
|
||||
className="--docs--doc-editor"
|
||||
>
|
||||
<Box
|
||||
$padding={{ horizontal: isDesktop ? '54px' : 'base' }}
|
||||
className="--docs--doc-editor-header"
|
||||
>
|
||||
{isVersion ? <DocVersionHeader /> : <DocHeader doc={doc} />}
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
$direction="row"
|
||||
$width="100%"
|
||||
$css="overflow-x: clip; flex: 1;"
|
||||
$position="relative"
|
||||
className="--docs--doc-editor-content"
|
||||
>
|
||||
<Box $css="flex:1;" $position="relative" $width="100%">
|
||||
{isVersion ? (
|
||||
<DocVersionEditor docId={doc.id} versionId={versionId} />
|
||||
) : (
|
||||
<BlockNoteEditor doc={doc} provider={provider} />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface DocVersionEditorProps {
|
||||
docId: Doc['id'];
|
||||
versionId: Versions['version_id'];
|
||||
}
|
||||
|
||||
export const DocVersionEditor = ({
|
||||
docId,
|
||||
versionId,
|
||||
}: DocVersionEditorProps) => {
|
||||
const {
|
||||
data: version,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useDocVersion({
|
||||
docId,
|
||||
versionId,
|
||||
});
|
||||
|
||||
const { replace } = useRouter();
|
||||
const [initialContent, setInitialContent] = useState<Y.XmlFragment>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!version?.content) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInitialContent(base64ToBlocknoteXmlFragment(version.content));
|
||||
}, [version?.content]);
|
||||
|
||||
if (isError && error) {
|
||||
if (error.status === 404) {
|
||||
void replace(`/404`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box $margin="large" className="--docs--doc-version-editor-error">
|
||||
<TextErrors
|
||||
causes={error.cause}
|
||||
icon={
|
||||
error.status === 502 ? (
|
||||
<Text
|
||||
className="material-icons"
|
||||
$theme="danger"
|
||||
aria-hidden={true}
|
||||
>
|
||||
wifi_off
|
||||
</Text>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading || !version || !initialContent) {
|
||||
return (
|
||||
<Box $align="center" $justify="center" $height="100%">
|
||||
<Loader />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return <BlockNoteEditorVersion initialContent={initialContent} />;
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ type CreatePDFBlockConfig = BlockConfig<
|
||||
|
||||
interface PdfBlockComponentProps {
|
||||
block: BlockNoDefaults<
|
||||
Record<'pdf', CreatePDFBlockConfig>,
|
||||
Record<'callout', CreatePDFBlockConfig>,
|
||||
InlineContentSchema,
|
||||
StyleSchema
|
||||
>;
|
||||
|
||||
@@ -1,146 +1,34 @@
|
||||
import {
|
||||
BlockConfig,
|
||||
BlockNoDefaults,
|
||||
BlockNoteEditor,
|
||||
InlineContentSchema,
|
||||
StyleSchema,
|
||||
} from '@blocknote/core';
|
||||
import { createReactBlockSpec } from '@blocknote/react';
|
||||
import { t } from 'i18next';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
import { useMediaUrl } from '@/core';
|
||||
|
||||
import { loopCheckDocMediaStatus } from '../../api';
|
||||
import Loader from '../../assets/loader.svg';
|
||||
import Warning from '../../assets/warning.svg';
|
||||
|
||||
type UploadLoaderPropSchema = {
|
||||
readonly information: { readonly default: '' };
|
||||
readonly type: {
|
||||
readonly default: 'loading';
|
||||
readonly values: readonly ['loading', 'warning'];
|
||||
};
|
||||
readonly blockUploadName: { readonly default: '' };
|
||||
readonly blockUploadShowPreview: { readonly default: true };
|
||||
readonly blockUploadType: {
|
||||
readonly default: '';
|
||||
};
|
||||
readonly blockUploadUrl: { readonly default: '' };
|
||||
};
|
||||
|
||||
type UploadLoaderBlockConfig = BlockConfig<
|
||||
'uploadLoader',
|
||||
UploadLoaderPropSchema,
|
||||
'none'
|
||||
>;
|
||||
|
||||
type UploadLoaderBlockType = BlockNoDefaults<
|
||||
Record<'uploadLoader', UploadLoaderBlockConfig>,
|
||||
InlineContentSchema,
|
||||
StyleSchema
|
||||
>;
|
||||
|
||||
type UploadLoaderEditor = BlockNoteEditor<
|
||||
Record<'uploadLoader', UploadLoaderBlockConfig>,
|
||||
InlineContentSchema,
|
||||
StyleSchema
|
||||
>;
|
||||
|
||||
interface UploadLoaderBlockComponentProps {
|
||||
block: UploadLoaderBlockType;
|
||||
editor: UploadLoaderEditor;
|
||||
contentRef: (node: HTMLElement | null) => void;
|
||||
}
|
||||
|
||||
const UploadLoaderBlockComponent = ({
|
||||
block,
|
||||
editor,
|
||||
}: UploadLoaderBlockComponentProps) => {
|
||||
const mediaUrl = useMediaUrl();
|
||||
|
||||
useEffect(() => {
|
||||
if (!block.props.blockUploadUrl || block.props.type !== 'loading') {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = block.props.blockUploadUrl;
|
||||
|
||||
loopCheckDocMediaStatus(url)
|
||||
.then((response) => {
|
||||
// Replace the loading block with the resource block (image, audio, video, pdf ...)
|
||||
try {
|
||||
editor.replaceBlocks(
|
||||
[block.id],
|
||||
[
|
||||
{
|
||||
type: block.props.blockUploadType,
|
||||
props: {
|
||||
url: `${mediaUrl}${response.file}`,
|
||||
showPreview: block.props.blockUploadShowPreview,
|
||||
name: block.props.blockUploadName,
|
||||
caption: '',
|
||||
backgroundColor: 'default',
|
||||
textAlignment: 'left',
|
||||
},
|
||||
} as never,
|
||||
],
|
||||
);
|
||||
} catch {
|
||||
/* During collaboration, another user might have updated the block */
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error analyzing file:', error);
|
||||
|
||||
try {
|
||||
editor.updateBlock(block.id, {
|
||||
type: 'uploadLoader',
|
||||
props: {
|
||||
type: 'warning',
|
||||
information: t(
|
||||
'The antivirus has detected an anomaly in your file.',
|
||||
),
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
/* During collaboration, another user might have updated the block */
|
||||
}
|
||||
});
|
||||
}, [block, editor, mediaUrl]);
|
||||
|
||||
return (
|
||||
<Box className="bn-visual-media-wrapper" $direction="row" $gap="0.5rem">
|
||||
{block.props.type === 'warning' ? (
|
||||
<Warning />
|
||||
) : (
|
||||
<Loader style={{ animation: 'spin 1.5s linear infinite' }} />
|
||||
)}
|
||||
<Text>{block.props.information}</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const UploadLoaderBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'uploadLoader',
|
||||
propSchema: {
|
||||
information: { default: '' },
|
||||
information: { default: '' as const },
|
||||
type: {
|
||||
default: 'loading',
|
||||
values: ['loading', 'warning'],
|
||||
default: 'loading' as const,
|
||||
values: ['loading', 'warning'] as const,
|
||||
},
|
||||
blockUploadName: { default: '' },
|
||||
blockUploadShowPreview: { default: true },
|
||||
blockUploadType: {
|
||||
default: '',
|
||||
},
|
||||
blockUploadUrl: { default: '' },
|
||||
},
|
||||
content: 'none',
|
||||
},
|
||||
{
|
||||
render: (props) => <UploadLoaderBlockComponent {...props} />,
|
||||
render: ({ block }) => {
|
||||
return (
|
||||
<Box className="bn-visual-media-wrapper" $direction="row" $gap="0.5rem">
|
||||
{block.props.type === 'warning' ? (
|
||||
<Warning />
|
||||
) : (
|
||||
<Loader style={{ animation: 'spin 1.5s linear infinite' }} />
|
||||
)}
|
||||
<Text>{block.props.information}</Text>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -29,9 +29,6 @@ export const InterlinkingLinkInlineContent = createReactInlineContentSpec(
|
||||
render: ({ inlineContent, updateInlineContent }) => {
|
||||
const { data: doc } = useDoc({ id: inlineContent.props.docId });
|
||||
|
||||
/**
|
||||
* Update the content title if the referenced doc title changes
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (doc?.title && doc.title !== inlineContent.props.title) {
|
||||
updateInlineContent({
|
||||
@@ -42,15 +39,7 @@ export const InterlinkingLinkInlineContent = createReactInlineContentSpec(
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ⚠️ When doing collaborative editing, doc?.title might be out of sync
|
||||
* causing an infinite loop of updates.
|
||||
* To prevent this, we only run this effect when doc?.title changes,
|
||||
* not when inlineContent.props.title changes.
|
||||
*/
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [doc?.title]);
|
||||
}, [inlineContent.props, doc?.title, updateInlineContent]);
|
||||
|
||||
return <LinkSelected {...inlineContent.props} />;
|
||||
},
|
||||
@@ -77,7 +66,7 @@ const LinkSelected = ({ url, title }: LinkSelectedProps) => {
|
||||
onClick={handleClick}
|
||||
draggable="false"
|
||||
$css={css`
|
||||
display: contents;
|
||||
display: inline;
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
& svg {
|
||||
@@ -89,10 +78,6 @@ const LinkSelected = ({ url, title }: LinkSelectedProps) => {
|
||||
background-color: ${colorsTokens['greyscale-100']};
|
||||
}
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
.--docs--doc-deleted & {
|
||||
pointer-events: none;
|
||||
}
|
||||
`}
|
||||
>
|
||||
{emoji ? (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './BlockNoteEditor';
|
||||
export * from './DocEditor';
|
||||
export * from './EmojiPicker';
|
||||
export * from './custom-blocks/';
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('useSaveDoc', () => {
|
||||
|
||||
const addEventListenerSpy = vi.spyOn(window, 'addEventListener');
|
||||
|
||||
renderHook(() => useSaveDoc(docId, yDoc, true), {
|
||||
renderHook(() => useSaveDoc(docId, yDoc, true, true), {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
@@ -62,6 +62,37 @@ describe('useSaveDoc', () => {
|
||||
addEventListenerSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should not save when canSave is false', () => {
|
||||
vi.useFakeTimers();
|
||||
const yDoc = new Y.Doc();
|
||||
const docId = 'test-doc-id';
|
||||
|
||||
fetchMock.patch('http://test.jest/api/v1.0/documents/test-doc-id/', {
|
||||
body: JSON.stringify({
|
||||
id: 'test-doc-id',
|
||||
content: 'test-content',
|
||||
title: 'test-title',
|
||||
}),
|
||||
});
|
||||
|
||||
renderHook(() => useSaveDoc(docId, yDoc, false, true), {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
// Trigger a local update
|
||||
yDoc.getMap('test').set('key', 'value');
|
||||
|
||||
// Advance timers to trigger the save interval
|
||||
vi.advanceTimersByTime(61000);
|
||||
});
|
||||
|
||||
// Since canSave is false, no API call should be made
|
||||
expect(fetchMock.calls().length).toBe(0);
|
||||
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it('should save when there are local changes', async () => {
|
||||
vi.useFakeTimers();
|
||||
const yDoc = new Y.Doc();
|
||||
@@ -75,7 +106,7 @@ describe('useSaveDoc', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
renderHook(() => useSaveDoc(docId, yDoc, true), {
|
||||
renderHook(() => useSaveDoc(docId, yDoc, true, true), {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
@@ -112,7 +143,7 @@ describe('useSaveDoc', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
renderHook(() => useSaveDoc(docId, yDoc, true), {
|
||||
renderHook(() => useSaveDoc(docId, yDoc, true, true), {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
@@ -132,7 +163,7 @@ describe('useSaveDoc', () => {
|
||||
const docId = 'test-doc-id';
|
||||
const removeEventListenerSpy = vi.spyOn(window, 'removeEventListener');
|
||||
|
||||
const { unmount } = renderHook(() => useSaveDoc(docId, yDoc, true), {
|
||||
const { unmount } = renderHook(() => useSaveDoc(docId, yDoc, true, true), {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
|
||||
@@ -9,13 +9,12 @@ export const useHeadings = (editor: DocsBlockNoteEditor) => {
|
||||
useEffect(() => {
|
||||
setHeadings(editor);
|
||||
|
||||
const unsubscribe = editor?.onChange(() => {
|
||||
editor?.onChange(() => {
|
||||
setHeadings(editor);
|
||||
});
|
||||
|
||||
return () => {
|
||||
resetHeadings();
|
||||
unsubscribe();
|
||||
};
|
||||
}, [editor, resetHeadings, setHeadings]);
|
||||
};
|
||||
|
||||
@@ -13,10 +13,11 @@ const SAVE_INTERVAL = 60000;
|
||||
export const useSaveDoc = (
|
||||
docId: string,
|
||||
yDoc: Y.Doc,
|
||||
canSave: boolean,
|
||||
isConnectedToCollabServer: boolean,
|
||||
) => {
|
||||
const { mutate: updateDoc } = useUpdateDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC_VERSIONS],
|
||||
listInvalideQueries: [KEY_LIST_DOC_VERSIONS],
|
||||
onSuccess: () => {
|
||||
setIsLocalChange(false);
|
||||
},
|
||||
@@ -46,7 +47,7 @@ export const useSaveDoc = (
|
||||
}, [yDoc]);
|
||||
|
||||
const saveDoc = useCallback(() => {
|
||||
if (!isLocalChange) {
|
||||
if (!canSave || !isLocalChange) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,7 +58,14 @@ export const useSaveDoc = (
|
||||
});
|
||||
|
||||
return true;
|
||||
}, [isLocalChange, updateDoc, docId, yDoc, isConnectedToCollabServer]);
|
||||
}, [
|
||||
canSave,
|
||||
isLocalChange,
|
||||
updateDoc,
|
||||
docId,
|
||||
yDoc,
|
||||
isConnectedToCollabServer,
|
||||
]);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
@@ -2,10 +2,7 @@ import { useEffect } from 'react';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
|
||||
export const useShortcuts = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
el: HTMLDivElement | null,
|
||||
) => {
|
||||
export const useShortcuts = (editor: DocsBlockNoteEditor) => {
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === '@' && editor?.isFocused()) {
|
||||
@@ -32,14 +29,11 @@ export const useShortcuts = (
|
||||
}
|
||||
};
|
||||
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
el.addEventListener('keydown', handleKeyDown);
|
||||
// Attach the event listener to the document instead of the window
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
return () => {
|
||||
el.removeEventListener('keydown', handleKeyDown);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [editor, el]);
|
||||
}, [editor]);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,36 @@
|
||||
import { captureException } from '@sentry/nextjs';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { backendUrl } from '@/api';
|
||||
import { useMediaUrl } from '@/core/config';
|
||||
import { sleep } from '@/utils';
|
||||
|
||||
import { useCreateDocAttachment } from '../api';
|
||||
import { checkDocMediaStatus, useCreateDocAttachment } from '../api';
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
|
||||
/**
|
||||
* Upload file can be analyzed on the server side,
|
||||
* we had this function to wait for the analysis to be done
|
||||
* before returning the file url. It will keep the loader
|
||||
* on the upload button until the analysis is done.
|
||||
* @param url
|
||||
* @returns Promise<CheckDocMediaStatusResponse> status_code
|
||||
* @description Waits for the upload to be analyzed by checking the status of the file.
|
||||
*/
|
||||
const loopCheckDocMediaStatus = async (url: string) => {
|
||||
const SLEEP_TIME = 5000;
|
||||
const response = await checkDocMediaStatus({
|
||||
urlMedia: url,
|
||||
});
|
||||
|
||||
if (response.status === 'ready') {
|
||||
return response;
|
||||
} else {
|
||||
await sleep(SLEEP_TIME);
|
||||
return await loopCheckDocMediaStatus(url);
|
||||
}
|
||||
};
|
||||
|
||||
export const useUploadFile = (docId: string) => {
|
||||
const {
|
||||
mutateAsync: createDocAttachment,
|
||||
@@ -39,9 +63,94 @@ export const useUploadFile = (docId: string) => {
|
||||
export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
|
||||
const ANALYZE_URL = 'media-check';
|
||||
const { t } = useTranslation();
|
||||
const mediaUrl = useMediaUrl();
|
||||
const timeoutIds = useRef<Record<string, NodeJS.Timeout>>({});
|
||||
|
||||
const blockAnalyzeProcess = useCallback(
|
||||
(editor: DocsBlockNoteEditor, blockId: string, url: string) => {
|
||||
if (timeoutIds.current[url]) {
|
||||
clearTimeout(timeoutIds.current[url]);
|
||||
}
|
||||
|
||||
// Delay to let the time to the dom to be rendered
|
||||
const timoutId = setTimeout(() => {
|
||||
// Replace the resource block by a loading block
|
||||
const { insertedBlocks, removedBlocks } = editor.replaceBlocks(
|
||||
[blockId],
|
||||
[
|
||||
{
|
||||
type: 'uploadLoader',
|
||||
props: {
|
||||
information: t('Analyzing file...'),
|
||||
type: 'loading',
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
loopCheckDocMediaStatus(url)
|
||||
.then((response) => {
|
||||
if (insertedBlocks.length === 0 || removedBlocks.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const loadingBlockId = insertedBlocks[0].id;
|
||||
const removedBlock = removedBlocks[0];
|
||||
|
||||
removedBlock.props = {
|
||||
...removedBlock.props,
|
||||
url: `${mediaUrl}${response.file}`,
|
||||
};
|
||||
|
||||
// Replace the loading block with the resource block (image, audio, video, pdf ...)
|
||||
editor.replaceBlocks([loadingBlockId], [removedBlock]);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error analyzing file:', error);
|
||||
|
||||
const loadingBlock = insertedBlocks[0];
|
||||
|
||||
if (!loadingBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingBlock.props = {
|
||||
...loadingBlock.props,
|
||||
type: 'warning',
|
||||
information: t(
|
||||
'The antivirus has detected an anomaly in your file.',
|
||||
),
|
||||
};
|
||||
|
||||
editor.updateBlock(loadingBlock.id, loadingBlock);
|
||||
});
|
||||
}, 250);
|
||||
|
||||
timeoutIds.current[url] = timoutId;
|
||||
},
|
||||
[t, mediaUrl],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = editor.onChange((_, context) => {
|
||||
const blocksAnalyze = editor?.document.filter(
|
||||
(block) => 'url' in block.props && block.props.url.includes(ANALYZE_URL),
|
||||
);
|
||||
|
||||
if (!blocksAnalyze?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
blocksAnalyze.forEach((block) => {
|
||||
if (!('url' in block.props)) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockAnalyzeProcess(editor, block.id, block.props.url);
|
||||
});
|
||||
}, [blockAnalyzeProcess, editor]);
|
||||
|
||||
useEffect(() => {
|
||||
editor.onChange((_, context) => {
|
||||
const blocksChanges = context.getChanges();
|
||||
|
||||
if (!blocksChanges.length) {
|
||||
@@ -60,49 +169,11 @@ export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const blockUploadUrl = blockChanges.block.props.url;
|
||||
const blockUploadType = blockChanges.block.type;
|
||||
const blockUploadName = blockChanges.block.props.name;
|
||||
const blockUploadShowPreview =
|
||||
('showPreview' in blockChanges.block.props &&
|
||||
blockChanges.block.props.showPreview) ||
|
||||
false;
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
// Replace the resource block by a uploadLoader block
|
||||
// to show analyzing status
|
||||
try {
|
||||
editor.replaceBlocks(
|
||||
[blockChanges.block.id],
|
||||
[
|
||||
{
|
||||
type: 'uploadLoader',
|
||||
props: {
|
||||
information: t('Analyzing file...'),
|
||||
type: 'loading',
|
||||
blockUploadName,
|
||||
blockUploadType,
|
||||
blockUploadUrl,
|
||||
blockUploadShowPreview,
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
} catch (error) {
|
||||
captureException(error, {
|
||||
extra: { info: 'Error replacing block for upload loader' },
|
||||
});
|
||||
}
|
||||
}, 250);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeoutId);
|
||||
unsubscribe();
|
||||
};
|
||||
blockAnalyzeProcess(
|
||||
editor,
|
||||
blockChanges.block.id,
|
||||
blockChanges.block.props.url,
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [editor, t]);
|
||||
}, [blockAnalyzeProcess, mediaUrl, editor, t]);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { css } from 'styled-components';
|
||||
|
||||
export const cssEditor = css`
|
||||
export const cssEditor = (readonly: boolean, isDeletedDoc: boolean) => css`
|
||||
&,
|
||||
& > .bn-container,
|
||||
& .ProseMirror {
|
||||
height: 100%;
|
||||
}
|
||||
padding-bottom: 2rem;
|
||||
|
||||
& .ProseMirror {
|
||||
/**
|
||||
* WCAG Accessibility contrast fixes for BlockNote editor
|
||||
*/
|
||||
@@ -132,6 +131,13 @@ export const cssEditor = css`
|
||||
.bn-block-outer:not([data-prev-depth-changed]):before {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
${isDeletedDoc &&
|
||||
`
|
||||
.node-interlinkingLinkInline button {
|
||||
pointer-events: none;
|
||||
}
|
||||
`}
|
||||
}
|
||||
|
||||
& .bn-editor {
|
||||
@@ -181,10 +187,8 @@ export const cssEditor = css`
|
||||
}
|
||||
|
||||
@media screen and (width <= 560px) {
|
||||
.--docs--doc-readonly & .bn-editor {
|
||||
padding-left: 10px;
|
||||
}
|
||||
& .bn-editor {
|
||||
${readonly && `padding-left: 10px;`}
|
||||
padding-right: 10px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='1'] {
|
||||
|
||||
@@ -76,7 +76,7 @@ export const BoutonShare = ({
|
||||
|
||||
return (
|
||||
<Button
|
||||
color="primary-text"
|
||||
color="tertiary-text"
|
||||
onClick={open}
|
||||
size="medium"
|
||||
disabled={isDisabled}
|
||||
|
||||
@@ -55,16 +55,8 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
const { emoji } = getEmojiAndTitle(doc.title ?? '');
|
||||
|
||||
if (!emoji) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={t('Edit document emoji')}
|
||||
aria-hidden={true}
|
||||
placement="top"
|
||||
>
|
||||
<Tooltip content={t('Document emoji')} aria-hidden={true} placement="top">
|
||||
<Box
|
||||
$css={css`
|
||||
padding: 4px;
|
||||
@@ -78,17 +70,11 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
|
||||
`}
|
||||
>
|
||||
<DocIcon
|
||||
buttonProps={{
|
||||
$width: '32px',
|
||||
$height: '32px',
|
||||
$justify: 'space-between',
|
||||
$align: 'center',
|
||||
}}
|
||||
withEmojiPicker={doc.abilities.partial_update}
|
||||
docId={doc.id}
|
||||
title={doc.title}
|
||||
emoji={emoji}
|
||||
$size="23px"
|
||||
$size="25px"
|
||||
defaultIcon={
|
||||
<SimpleFileIcon
|
||||
width="25px"
|
||||
@@ -108,6 +94,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { isTopRoot } = useDocUtils(doc);
|
||||
const { untitledDocument } = useTrans();
|
||||
const { emoji, titleWithoutEmoji } = getEmojiAndTitle(doc.title ?? '');
|
||||
@@ -152,9 +139,19 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
|
||||
className="--docs--doc-title"
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$gap="4px"
|
||||
$gap={spacingsTokens['xs']}
|
||||
$minHeight="40px"
|
||||
>
|
||||
{isTopRoot && (
|
||||
<SimpleFileIcon
|
||||
width="25px"
|
||||
height="25px"
|
||||
aria-hidden="true"
|
||||
aria-label={t('Simple document icon')}
|
||||
color={colorsTokens['primary-500']}
|
||||
style={{ flexShrink: '0' }}
|
||||
/>
|
||||
)}
|
||||
{!isTopRoot && <DocTitleEmojiPicker doc={doc} />}
|
||||
|
||||
<Tooltip content={t('Rename')} aria-hidden={true} placement="top">
|
||||
|
||||
@@ -60,7 +60,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
const selectHistoryModal = useModal();
|
||||
const modalShare = useModal();
|
||||
|
||||
const { isSmallMobile, isMobile } = useResponsiveStore();
|
||||
const { isSmallMobile, isDesktop } = useResponsiveStore();
|
||||
const copyDocLink = useCopyDocLink(doc.id);
|
||||
const { mutate: duplicateDoc } = useDuplicateDoc({
|
||||
onSuccess: (data) => {
|
||||
@@ -69,10 +69,10 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
});
|
||||
const { isFeatureFlagActivated } = useAnalytics();
|
||||
const removeFavoriteDoc = useDeleteFavoriteDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
const makeFavoriteDoc = useCreateFavoriteDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -90,20 +90,28 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
const { updateDocEmoji } = useDocTitleUpdate();
|
||||
|
||||
const options: DropdownMenuOption[] = [
|
||||
{
|
||||
label: t('Share'),
|
||||
icon: 'group',
|
||||
callback: modalShare.open,
|
||||
show: isSmallMobile,
|
||||
},
|
||||
{
|
||||
label: t('Export'),
|
||||
icon: 'download',
|
||||
callback: () => {
|
||||
setIsModalExportOpen(true);
|
||||
},
|
||||
show: !!ModalExport && isSmallMobile,
|
||||
},
|
||||
...(isSmallMobile
|
||||
? [
|
||||
{
|
||||
label: t('Share'),
|
||||
icon: 'group',
|
||||
callback: modalShare.open,
|
||||
},
|
||||
{
|
||||
label: t('Export'),
|
||||
icon: 'download',
|
||||
callback: () => {
|
||||
setIsModalExportOpen(true);
|
||||
},
|
||||
show: !!ModalExport,
|
||||
},
|
||||
{
|
||||
label: t('Copy link'),
|
||||
icon: 'add_link',
|
||||
callback: copyDocLink,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: doc.is_favorite ? t('Unpin') : t('Pin'),
|
||||
icon: 'push_pin',
|
||||
@@ -116,6 +124,17 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
},
|
||||
testId: `docs-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`,
|
||||
},
|
||||
...(emoji && doc.abilities.partial_update && !isTopRoot
|
||||
? [
|
||||
{
|
||||
label: t('Remove emoji'),
|
||||
icon: 'emoji_emotions',
|
||||
callback: () => {
|
||||
updateDocEmoji(doc.id, doc.title ?? '', '');
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: t('Version history'),
|
||||
icon: 'history',
|
||||
@@ -123,31 +142,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
callback: () => {
|
||||
selectHistoryModal.open();
|
||||
},
|
||||
show: !isMobile,
|
||||
showSeparator: isTopRoot ? true : false,
|
||||
},
|
||||
{
|
||||
label: t('Remove emoji'),
|
||||
icon: 'emoji_emotions',
|
||||
callback: () => {
|
||||
updateDocEmoji(doc.id, doc.title ?? '', '');
|
||||
},
|
||||
showSeparator: true,
|
||||
show: !!emoji && doc.abilities.partial_update && !isTopRoot,
|
||||
},
|
||||
{
|
||||
label: t('Add emoji'),
|
||||
icon: 'emoji_emotions',
|
||||
callback: () => {
|
||||
updateDocEmoji(doc.id, doc.title ?? '', '📄');
|
||||
},
|
||||
showSeparator: true,
|
||||
show: !emoji && doc.abilities.partial_update && !isTopRoot,
|
||||
},
|
||||
{
|
||||
label: t('Copy link'),
|
||||
icon: 'add_link',
|
||||
callback: copyDocLink,
|
||||
show: isDesktop,
|
||||
},
|
||||
{
|
||||
label: t('Copy as {{format}}', { format: 'Markdown' }),
|
||||
@@ -163,7 +158,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
void copyCurrentEditorToClipboard('html');
|
||||
},
|
||||
show: isFeatureFlagActivated('CopyAsHTML'),
|
||||
showSeparator: true,
|
||||
},
|
||||
{
|
||||
label: t('Duplicate'),
|
||||
@@ -176,7 +170,6 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
canSave: doc.abilities.partial_update,
|
||||
});
|
||||
},
|
||||
showSeparator: true,
|
||||
},
|
||||
{
|
||||
label: isChild ? t('Delete sub-document') : t('Delete document'),
|
||||
@@ -231,22 +224,25 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
aria-label={t('Export the document')}
|
||||
/>
|
||||
)}
|
||||
<DropdownMenu
|
||||
options={options}
|
||||
label={t('Open the document options')}
|
||||
buttonCss={css`
|
||||
padding: ${spacingsTokens['xs']};
|
||||
&:hover {
|
||||
background-color: ${colorsTokens['greyscale-100']};
|
||||
}
|
||||
${isSmallMobile
|
||||
? css`
|
||||
border: 1px solid ${colorsTokens['greyscale-300']};
|
||||
`
|
||||
: ''}
|
||||
`}
|
||||
>
|
||||
<IconOptions aria-hidden="true" isHorizontal $theme="primary" />
|
||||
<DropdownMenu options={options} label={t('Open the document options')}>
|
||||
<IconOptions
|
||||
aria-hidden="true"
|
||||
isHorizontal
|
||||
$theme="primary"
|
||||
$padding={{ all: 'xs' }}
|
||||
$css={css`
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
background-color: ${colorsTokens['greyscale-100']};
|
||||
}
|
||||
${isSmallMobile
|
||||
? css`
|
||||
padding: 10px;
|
||||
border: 1px solid ${colorsTokens['greyscale-300']};
|
||||
`
|
||||
: ''}
|
||||
`}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, HorizontalSeparator } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { DocTitleText } from '@/docs/doc-header';
|
||||
|
||||
import { DocTitleText } from './DocTitle';
|
||||
|
||||
export const DocVersionHeader = () => {
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from './DocHeader';
|
||||
export * from './DocTitle';
|
||||
export * from './DocVersionHeader';
|
||||
|
||||
@@ -10,16 +10,13 @@ import {
|
||||
getEmojiAndTitle,
|
||||
} from '../utils';
|
||||
|
||||
vi.mock('yjs', () => {
|
||||
class MockDoc {
|
||||
getXmlFragment = vi.fn().mockReturnValue('mocked-xml-fragment');
|
||||
}
|
||||
|
||||
return {
|
||||
Doc: MockDoc,
|
||||
applyUpdate: vi.fn(),
|
||||
};
|
||||
});
|
||||
// Mock Y.js
|
||||
vi.mock('yjs', () => ({
|
||||
Doc: vi.fn().mockImplementation(() => ({
|
||||
getXmlFragment: vi.fn().mockReturnValue('mocked-xml-fragment'),
|
||||
})),
|
||||
applyUpdate: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('doc-management utils', () => {
|
||||
beforeEach(() => {
|
||||
@@ -29,30 +26,45 @@ describe('doc-management utils', () => {
|
||||
describe('base64ToYDoc', () => {
|
||||
it('should convert base64 string to Y.Doc', () => {
|
||||
const base64String = 'dGVzdA=='; // "test" in base64
|
||||
const mockYDoc = { getXmlFragment: vi.fn() };
|
||||
|
||||
(Y.Doc as any).mockReturnValue(mockYDoc);
|
||||
|
||||
const result = base64ToYDoc(base64String);
|
||||
|
||||
expect(result).toBeInstanceOf(Y.Doc);
|
||||
expect(Y.applyUpdate).toHaveBeenCalledWith(result, expect.any(Buffer));
|
||||
expect(Y.Doc).toHaveBeenCalled();
|
||||
expect(Y.applyUpdate).toHaveBeenCalledWith(mockYDoc, expect.any(Buffer));
|
||||
expect(result).toBe(mockYDoc);
|
||||
});
|
||||
|
||||
it('should handle empty base64 string', () => {
|
||||
const base64String = '';
|
||||
const mockYDoc = { getXmlFragment: vi.fn() };
|
||||
|
||||
(Y.Doc as any).mockReturnValue(mockYDoc);
|
||||
|
||||
const result = base64ToYDoc(base64String);
|
||||
|
||||
expect(result).toBeInstanceOf(Y.Doc);
|
||||
expect(Y.applyUpdate).toHaveBeenCalledWith(result, expect.any(Buffer));
|
||||
expect(Y.Doc).toHaveBeenCalled();
|
||||
expect(Y.applyUpdate).toHaveBeenCalledWith(mockYDoc, expect.any(Buffer));
|
||||
expect(result).toBe(mockYDoc);
|
||||
});
|
||||
});
|
||||
|
||||
describe('base64ToBlocknoteXmlFragment', () => {
|
||||
it('should convert base64 to Blocknote XML fragment', () => {
|
||||
const base64String = 'dGVzdA==';
|
||||
const mockYDoc = {
|
||||
getXmlFragment: vi.fn().mockReturnValue('mocked-xml-fragment'),
|
||||
};
|
||||
|
||||
(Y.Doc as any).mockReturnValue(mockYDoc);
|
||||
|
||||
const result = base64ToBlocknoteXmlFragment(base64String);
|
||||
|
||||
expect(Y.applyUpdate).toHaveBeenCalled();
|
||||
expect(Y.Doc).toHaveBeenCalled();
|
||||
expect(Y.applyUpdate).toHaveBeenCalledWith(mockYDoc, expect.any(Buffer));
|
||||
expect(mockYDoc.getXmlFragment).toHaveBeenCalledWith('document-store');
|
||||
expect(result).toBe('mocked-xml-fragment');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,18 +21,18 @@ export const createFavoriteDoc = async ({ id }: CreateFavoriteDocParams) => {
|
||||
|
||||
interface CreateFavoriteDocProps {
|
||||
onSuccess?: () => void;
|
||||
listInvalidQueries?: string[];
|
||||
listInvalideQueries?: string[];
|
||||
}
|
||||
|
||||
export function useCreateFavoriteDoc({
|
||||
onSuccess,
|
||||
listInvalidQueries,
|
||||
listInvalideQueries,
|
||||
}: CreateFavoriteDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, APIError, CreateFavoriteDocParams>({
|
||||
mutationFn: createFavoriteDoc,
|
||||
onSuccess: () => {
|
||||
listInvalidQueries?.forEach((queryKey) => {
|
||||
listInvalideQueries?.forEach((queryKey) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
|
||||
@@ -21,18 +21,18 @@ export const deleteFavoriteDoc = async ({ id }: DeleteFavoriteDocParams) => {
|
||||
|
||||
interface DeleteFavoriteDocProps {
|
||||
onSuccess?: () => void;
|
||||
listInvalidQueries?: string[];
|
||||
listInvalideQueries?: string[];
|
||||
}
|
||||
|
||||
export function useDeleteFavoriteDoc({
|
||||
onSuccess,
|
||||
listInvalidQueries,
|
||||
listInvalideQueries,
|
||||
}: DeleteFavoriteDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, APIError, DeleteFavoriteDocParams>({
|
||||
mutationFn: deleteFavoriteDoc,
|
||||
onSuccess: () => {
|
||||
listInvalidQueries?.forEach((queryKey) => {
|
||||
listInvalideQueries?.forEach((queryKey) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ export function useDuplicateDoc(options?: DuplicateDocOptions) {
|
||||
const { provider } = useProviderStore();
|
||||
|
||||
const { mutateAsync: updateDoc } = useUpdateDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC_VERSIONS],
|
||||
listInvalideQueries: [KEY_LIST_DOC_VERSIONS],
|
||||
});
|
||||
|
||||
return useMutation<DuplicateDocResponse, APIError, DuplicateDocParams>({
|
||||
|
||||
@@ -34,7 +34,7 @@ export const updateDoc = async ({
|
||||
};
|
||||
|
||||
type UseUpdateDoc = UseMutationOptions<Doc, APIError, Partial<Doc>> & {
|
||||
listInvalidQueries?: string[];
|
||||
listInvalideQueries?: string[];
|
||||
};
|
||||
|
||||
export function useUpdateDoc(queryConfig?: UseUpdateDoc) {
|
||||
@@ -43,7 +43,7 @@ export function useUpdateDoc(queryConfig?: UseUpdateDoc) {
|
||||
mutationFn: updateDoc,
|
||||
...queryConfig,
|
||||
onSuccess: (data, variables, onMutateResult, context) => {
|
||||
queryConfig?.listInvalidQueries?.forEach((queryKey) => {
|
||||
queryConfig?.listInvalideQueries?.forEach((queryKey) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { MouseEvent, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { BoxButton, BoxButtonType, Text, TextType } from '@/components';
|
||||
import { BoxButton, Icon, TextType } from '@/components';
|
||||
import { EmojiPicker, emojidata } from '@/docs/doc-editor/';
|
||||
|
||||
import { useDocTitleUpdate } from '../hooks/useDocTitleUpdate';
|
||||
|
||||
type DocIconProps = TextType & {
|
||||
buttonProps?: BoxButtonType;
|
||||
emoji?: string | null;
|
||||
defaultIcon: React.ReactNode;
|
||||
docId?: string;
|
||||
@@ -17,7 +16,6 @@ type DocIconProps = TextType & {
|
||||
};
|
||||
|
||||
export const DocIcon = ({
|
||||
buttonProps,
|
||||
emoji,
|
||||
defaultIcon,
|
||||
$size = 'sm',
|
||||
@@ -83,13 +81,13 @@ export const DocIcon = ({
|
||||
ref={iconRef}
|
||||
onClick={toggleEmojiPicker}
|
||||
color="tertiary-text"
|
||||
{...buttonProps}
|
||||
>
|
||||
{!emoji ? (
|
||||
defaultIcon
|
||||
) : (
|
||||
<Text
|
||||
<Icon
|
||||
{...textProps}
|
||||
iconName={emoji}
|
||||
$size={$size}
|
||||
$variation={$variation}
|
||||
$weight={$weight}
|
||||
@@ -97,7 +95,7 @@ export const DocIcon = ({
|
||||
data-testid="doc-emoji-icon"
|
||||
>
|
||||
{emoji}
|
||||
</Text>
|
||||
</Icon>
|
||||
)}
|
||||
</BoxButton>
|
||||
{openEmojiPicker &&
|
||||
|
||||
@@ -20,7 +20,7 @@ export const useDocTitleUpdate = (options?: UseDocUpdateOptions) => {
|
||||
const treeContext = useTreeContext<Doc>();
|
||||
|
||||
const { mutate: updateDoc, ...mutationResult } = useUpdateDoc({
|
||||
listInvalidQueries: [KEY_DOC, KEY_LIST_DOC],
|
||||
listInvalideQueries: [KEY_DOC, KEY_LIST_DOC],
|
||||
onSuccess: (updatedDoc) => {
|
||||
// Broadcast to every user connected to the document
|
||||
broadcast(`${KEY_DOC}-${updatedDoc.id}`);
|
||||
|
||||
@@ -31,12 +31,12 @@ export const updateDocLink = async ({
|
||||
|
||||
interface UpdateDocLinkProps {
|
||||
onSuccess?: (data: Doc) => void;
|
||||
listInvalidQueries?: string[];
|
||||
listInvalideQueries?: string[];
|
||||
}
|
||||
|
||||
export function useUpdateDocLink({
|
||||
onSuccess,
|
||||
listInvalidQueries,
|
||||
listInvalideQueries,
|
||||
}: UpdateDocLinkProps = {}) {
|
||||
const queryClient = useQueryClient();
|
||||
const { toast } = useToastProvider();
|
||||
@@ -45,7 +45,7 @@ export function useUpdateDocLink({
|
||||
return useMutation<Doc, APIError, UpdateDocLinkParams>({
|
||||
mutationFn: updateDocLink,
|
||||
onSuccess: (data) => {
|
||||
listInvalidQueries?.forEach((queryKey) => {
|
||||
listInvalideQueries?.forEach((queryKey) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ export const DocDesynchronized = ({ doc }: DocDesynchronizedProps) => {
|
||||
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
|
||||
|
||||
const { mutate: updateDocLink } = useUpdateDocLink({
|
||||
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -48,7 +48,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
|
||||
: linkReachChoices[docLinkReach].descriptionEdit;
|
||||
|
||||
const { mutate: updateDocLink } = useUpdateDocLink({
|
||||
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
|
||||
const linkReachOptions: DropdownMenuOption[] = useMemo(() => {
|
||||
@@ -147,11 +147,6 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
|
||||
arrowCss={css`
|
||||
color: ${colorsTokens['primary-800']} !important;
|
||||
`}
|
||||
buttonCss={css`
|
||||
&:hover {
|
||||
background-color: unset;
|
||||
}
|
||||
`}
|
||||
disabled={!canManage}
|
||||
showArrow={true}
|
||||
topMessage={
|
||||
@@ -189,11 +184,6 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
|
||||
<Box $direction="row" $align="center" $gap={spacingsTokens['3xs']}>
|
||||
<DropdownMenu
|
||||
testId="doc-access-mode"
|
||||
buttonCss={css`
|
||||
&:hover {
|
||||
background-color: unset;
|
||||
}
|
||||
`}
|
||||
disabled={!canManage}
|
||||
showArrow={true}
|
||||
options={linkRoleOptions}
|
||||
@@ -206,7 +196,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
|
||||
}
|
||||
label={t('Document access mode')}
|
||||
>
|
||||
<Text $weight="initial" $variation="600" $theme="primary">
|
||||
<Text $weight="initial" $variation="600">
|
||||
{linkModeTranslations[docLinkRole]}
|
||||
</Text>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -149,14 +149,6 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
|
||||
`}
|
||||
>
|
||||
<TreeViewItem {...props} onClick={handleActivate}>
|
||||
<DocIcon
|
||||
emoji={emoji}
|
||||
withEmojiPicker={doc.abilities.partial_update}
|
||||
defaultIcon={<SubPageIcon color={colorsTokens['primary-400']} />}
|
||||
$size="sm"
|
||||
docId={doc.id}
|
||||
title={doc.title}
|
||||
/>
|
||||
<BoxButton
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -174,6 +166,17 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
|
||||
min-width: 0;
|
||||
`}
|
||||
>
|
||||
<Box>
|
||||
<DocIcon
|
||||
emoji={emoji}
|
||||
withEmojiPicker={doc.abilities.partial_update}
|
||||
defaultIcon={<SubPageIcon color={colorsTokens['primary-400']} />}
|
||||
$size="sm"
|
||||
docId={doc.id}
|
||||
title={doc.title}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { Loader } from '@openfun/cunningham-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { Box, Text, TextErrors } from '@/components';
|
||||
import { BlockNoteReader, DocEditorContainer } from '@/docs/doc-editor/';
|
||||
import { Doc, base64ToBlocknoteXmlFragment } from '@/docs/doc-management';
|
||||
import { Versions, useDocVersion } from '@/docs/doc-versioning/';
|
||||
|
||||
import { DocVersionHeader } from './DocVersionHeader';
|
||||
|
||||
interface DocVersionEditorProps {
|
||||
docId: Doc['id'];
|
||||
versionId: Versions['version_id'];
|
||||
}
|
||||
|
||||
export const DocVersionEditor = ({
|
||||
docId,
|
||||
versionId,
|
||||
}: DocVersionEditorProps) => {
|
||||
const {
|
||||
data: version,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useDocVersion({
|
||||
docId,
|
||||
versionId,
|
||||
});
|
||||
|
||||
const { replace } = useRouter();
|
||||
const [initialContent, setInitialContent] = useState<Y.XmlFragment>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!version?.content) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInitialContent(base64ToBlocknoteXmlFragment(version.content));
|
||||
}, [version?.content]);
|
||||
|
||||
if (isError && error) {
|
||||
if (error.status === 404) {
|
||||
void replace(`/404`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box $margin="large" className="--docs--doc-version-editor-error">
|
||||
<TextErrors
|
||||
causes={error.cause}
|
||||
icon={
|
||||
error.status === 502 ? (
|
||||
<Text
|
||||
className="material-icons"
|
||||
$theme="danger"
|
||||
aria-hidden={true}
|
||||
>
|
||||
wifi_off
|
||||
</Text>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading || !version || !initialContent) {
|
||||
return (
|
||||
<Box $align="center" $justify="center" $height="100%">
|
||||
<Loader />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DocEditorContainer
|
||||
docHeader={<DocVersionHeader />}
|
||||
docEditor={<BlockNoteReader initialContent={initialContent} />}
|
||||
isDeletedDoc={false}
|
||||
readOnly={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -42,7 +42,7 @@ export const ModalConfirmationVersion = ({
|
||||
const { push } = useRouter();
|
||||
const { provider } = useProviderStore();
|
||||
const { mutate: updateDoc } = useUpdateDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC_VERSIONS],
|
||||
listInvalideQueries: [KEY_LIST_DOC_VERSIONS],
|
||||
onSuccess: () => {
|
||||
const onDisplaySuccess = () => {
|
||||
toast(t('Version restored successfully'), VariantType.SUCCESS);
|
||||
|
||||
@@ -4,11 +4,11 @@ import { useTranslation } from 'react-i18next';
|
||||
import { createGlobalStyle, css } from 'styled-components';
|
||||
|
||||
import { Box, ButtonCloseModal, Text } from '@/components';
|
||||
import { DocEditor } from '@/docs/doc-editor';
|
||||
import { Doc } from '@/docs/doc-management';
|
||||
|
||||
import { Versions } from '../types';
|
||||
|
||||
import { DocVersionEditor } from './DocVersionEditor';
|
||||
import { ModalConfirmationVersion } from './ModalConfirmationVersion';
|
||||
import { VersionList } from './VersionList';
|
||||
|
||||
@@ -81,10 +81,7 @@ export const ModalSelectVersion = ({
|
||||
$align="center"
|
||||
>
|
||||
{selectedVersionId && (
|
||||
<DocVersionEditor
|
||||
docId={doc.id}
|
||||
versionId={selectedVersionId}
|
||||
/>
|
||||
<DocEditor doc={doc} versionId={selectedVersionId} />
|
||||
)}
|
||||
{!selectedVersionId && (
|
||||
<Box $align="center" $justify="center" $height="100%">
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
|
||||
import { Doc, KEY_LIST_DOC } from '../../doc-management';
|
||||
|
||||
export const importDoc = async (file: File): Promise<Doc> => {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
|
||||
const response = await fetchAPI(`documents/`, {
|
||||
method: 'POST',
|
||||
body: form,
|
||||
withoutContentType: true,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError('Failed to import the doc', await errorCauses(response));
|
||||
}
|
||||
|
||||
return response.json() as Promise<Doc>;
|
||||
};
|
||||
|
||||
interface ImportDocProps {
|
||||
onSuccess?: (data: Doc) => void;
|
||||
onError?: (error: APIError) => void;
|
||||
}
|
||||
|
||||
export function useImportDoc({ onSuccess, onError }: ImportDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Doc, APIError, File>({
|
||||
mutationFn: importDoc,
|
||||
onSuccess: (data) => {
|
||||
void queryClient.resetQueries({
|
||||
queryKey: [KEY_LIST_DOC],
|
||||
});
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError: (error) => {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { InView } from 'react-intersection-observer';
|
||||
import { css } from 'styled-components';
|
||||
@@ -9,7 +9,6 @@ import { DocDefaultFilter, useInfiniteDocs } from '@/docs/doc-management';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import { useInfiniteDocsTrashbin } from '../api';
|
||||
import { useImportDoc } from '../api/useImportDoc';
|
||||
import { useResponsiveDocGrid } from '../hooks/useResponsiveDocGrid';
|
||||
|
||||
import {
|
||||
@@ -28,7 +27,6 @@ export const DocsGrid = ({
|
||||
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { flexLeft, flexRight } = useResponsiveDocGrid();
|
||||
const importInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -77,33 +75,6 @@ export const DocsGrid = ({
|
||||
title = t('All docs');
|
||||
}
|
||||
|
||||
const resetImportInput = () => {
|
||||
if (!importInputRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
importInputRef.current.value = '';
|
||||
};
|
||||
|
||||
const { mutate: importDoc } = useImportDoc({
|
||||
onSuccess: resetImportInput,
|
||||
onError: resetImportInput,
|
||||
});
|
||||
|
||||
const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
console.log(event);
|
||||
|
||||
if (!event.target.files || event.target.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const file = event.target.files[0];
|
||||
|
||||
console.log(file);
|
||||
|
||||
importDoc(file);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
$position="relative"
|
||||
@@ -136,14 +107,6 @@ export const DocsGrid = ({
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
<input
|
||||
type="file"
|
||||
name="doc"
|
||||
accept=".md,.docx"
|
||||
onChange={handleImport}
|
||||
ref={importInputRef}
|
||||
></input>
|
||||
|
||||
{!hasDocs && !loading && (
|
||||
<Box $padding={{ vertical: 'sm' }} $align="center" $justify="center">
|
||||
<Text $size="sm" $variation="600" $weight="700">
|
||||
|
||||
@@ -27,10 +27,10 @@ export const DocsGridActions = ({
|
||||
const { mutate: duplicateDoc } = useDuplicateDoc();
|
||||
|
||||
const removeFavoriteDoc = useDeleteFavoriteDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC],
|
||||
listInvalideQueries: [KEY_LIST_DOC],
|
||||
});
|
||||
const makeFavoriteDoc = useCreateFavoriteDoc({
|
||||
listInvalidQueries: [KEY_LIST_DOC],
|
||||
listInvalideQueries: [KEY_LIST_DOC],
|
||||
});
|
||||
|
||||
const options: DropdownMenuOption[] = [
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('DocsGridItemDate', () => {
|
||||
rendered: '5 days ago',
|
||||
},
|
||||
{
|
||||
updated_at: DateTime.now().minus({ days: 35 }).toISO(),
|
||||
updated_at: DateTime.now().minus({ days: 30 }).toISO(),
|
||||
rendered: '1 month ago',
|
||||
},
|
||||
].forEach(({ updated_at, rendered }) => {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"Actions for {{title}}": "Oberezhioù evit {{title}}",
|
||||
"Add": "Ouzhpennañ",
|
||||
"Add a callout block": "Ouzhpennañ ur bloc'had kemenn-son",
|
||||
"Add a horizontal line": "Ouzhpennañ ul linenn a-blaen",
|
||||
"Administrator": "Merour",
|
||||
"All docs": "An holl restroù",
|
||||
"An uncompromising writing experience.": "Un doare skrivañ hep treuzvarc'had.",
|
||||
@@ -57,6 +58,7 @@
|
||||
"Delete": "Dilemel",
|
||||
"Delete a doc": "Dilemel un doc",
|
||||
"Delete document": "Dilemel ar restr",
|
||||
"Divider": "Skejer",
|
||||
"Doc visibility card": "Kartenn gweled ar restr",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Logo Docs",
|
||||
@@ -68,6 +70,7 @@
|
||||
"Document access mode": "Doare moned ar restr",
|
||||
"Document accessible to any connected person": "Restr a c'hall bezañ tizhet gant ne vern piv a vefe kevreet",
|
||||
"Document duplicated successfully!": "Restr eilet gant berzh!",
|
||||
"Document emoji": "Emoju ar restr",
|
||||
"Document owner": "Perc'henn ar restr",
|
||||
"Document role text": "Testenn rol ar restr",
|
||||
"Document sections": "Kevrennoù ar restr",
|
||||
@@ -173,6 +176,7 @@
|
||||
"Reader": "Lenner",
|
||||
"Reading": "Lenn hepken",
|
||||
"Remove access": "Dilemel ar moned",
|
||||
"Remove emoji": "Dilemel ar emoju",
|
||||
"Rename": "Adenvel",
|
||||
"Rephrase": "Adformulenniñ",
|
||||
"Request access": "Goulenn mont e-barzh",
|
||||
@@ -252,6 +256,7 @@
|
||||
"Accessible to anyone": "Für alle zugänglich",
|
||||
"Accessible to authenticated users": "Für authentifizierte Benutzer zugänglich",
|
||||
"Add": "Hinzufügen",
|
||||
"Add a horizontal line": "Waagerechte Linie einfügen",
|
||||
"Administrator": "Administrator",
|
||||
"All docs": "Alle Dokumente",
|
||||
"An uncompromising writing experience.": "Ein kompromissloses Schreiberlebnis.",
|
||||
@@ -282,6 +287,7 @@
|
||||
"Delete": "Löschen",
|
||||
"Delete a doc": "Dokument löschen",
|
||||
"Delete document": "Dokument löschen",
|
||||
"Divider": "Trenner",
|
||||
"Doc visibility card": "Dokumenten-Sichtbarkeitskarte",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Docs-Logo",
|
||||
@@ -289,9 +295,10 @@
|
||||
"Docs makes real-time collaboration simple. Invite collaborators - public officials or external partners - with one click to see their changes live, while maintaining precise access control for data security.": "Docs macht die Zusammenarbeit in Echtzeit einfach. Laden Sie Mitarbeiter — Beamte oder externe Partner — mit einem Klick ein, um ihre Änderungen live zu sehen und dabei die genaue Zugangskontrolle zwecks Datensicherheit beizubehalten.",
|
||||
"Docs offers an intuitive writing experience. Its minimalist interface favors content over layout, while offering the essentials: media import, offline mode and keyboard shortcuts for greater efficiency.": "Docs bietet ein intuitives Schreiberlebnis. Seine minimalistische Oberfläche bevorzugt Inhalte über Layout, bietet aber das Wesentliche: Medien-Import, Offline-Modus und Tastaturkürzel für mehr Effizienz.",
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Dank Unterseiten, leistungsstarker Suche und der Möglichkeit, wichtige Dokumente zu fixieren, verwandelt Docs Ihre Dokumente in Wissensdatenbanken.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs: Ihr neuer Begleiter für eine effiziente, intuitive und sichere Zusammenarbeit bei Dokumenten.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Pages: Ihr neuer Begleiter für eine effiziente, intuitive und sichere Zusammenarbeit bei Dokumenten.",
|
||||
"Document accessible to any connected person": "Dokument für jeden angemeldeten Benutzer zugänglich",
|
||||
"Document duplicated successfully!": "Dokument erfolgreich dupliziert!",
|
||||
"Document emoji": "Dokument-Emoji",
|
||||
"Document owner": "Besitzer des Dokuments",
|
||||
"Docx": "Docx",
|
||||
"Download": "Herunterladen",
|
||||
@@ -344,7 +351,7 @@
|
||||
"Move to my docs": "In \"Meine Dokumente\" verschieben",
|
||||
"My docs": "Meine Dokumente",
|
||||
"Name": "Name",
|
||||
"New doc": "Neues Dok",
|
||||
"New doc": "Neues Dokument",
|
||||
"No active search": "Keine aktive Suche",
|
||||
"No document found": "Kein Dokument gefunden",
|
||||
"No documents found": "Keine Dokumente gefunden",
|
||||
@@ -374,6 +381,7 @@
|
||||
"Reader": "Leser",
|
||||
"Reading": "Lesen",
|
||||
"Remove access": "Zugriff entziehen",
|
||||
"Remove emoji": "Emoji entfernen",
|
||||
"Rename": "Umbenennen",
|
||||
"Rephrase": "Umformulieren",
|
||||
"Request access": "Zugriff anfragen",
|
||||
@@ -454,6 +462,7 @@
|
||||
"Accessible to authenticated users": "Accesible a usuarios autenticados",
|
||||
"Add": "Añadir",
|
||||
"Add a callout block": "Añadir un bloque destacado",
|
||||
"Add a horizontal line": "Añadir una línea horizontal",
|
||||
"Administrator": "Administrador",
|
||||
"All docs": "Todos los documentos",
|
||||
"An uncompromising writing experience.": "Una experiencia de escritura sin compromisos.",
|
||||
@@ -481,6 +490,7 @@
|
||||
"Delete": "Eliminar",
|
||||
"Delete a doc": "Eliminar un documento",
|
||||
"Delete document": "Borrar documento",
|
||||
"Divider": "Separador",
|
||||
"Doc visibility card": "Accesos al documento",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Logo de Docs",
|
||||
@@ -490,6 +500,7 @@
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Docs transforma sus documentos en bases de conocimiento gracias a las subpáginas, una potente herramienta de búsqueda y la capacidad de marcar como favorito sus documentos más importantes.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs: su nuevo compañero para colaborar en documentos de forma eficiente, intuitiva y segura.",
|
||||
"Document accessible to any connected person": "Documento accesible a cualquier persona conectada",
|
||||
"Document emoji": "Emoji del documento",
|
||||
"Document owner": "Propietario del documento",
|
||||
"Docx": "Docx",
|
||||
"Download": "Descargar",
|
||||
@@ -532,7 +543,7 @@
|
||||
"More docs": "Más documentos",
|
||||
"My docs": "Mis documentos",
|
||||
"Name": "Nombre",
|
||||
"New doc": "Nuevo doc",
|
||||
"New doc": "Nuevo documento",
|
||||
"No active search": "Ninguna búsqueda activa",
|
||||
"No document found": "No se ha encontrado ningún documento",
|
||||
"No documents found": "No se han encontrado documentos",
|
||||
@@ -559,6 +570,7 @@
|
||||
"Quick search input": "Entrada de búsqueda rápida",
|
||||
"Reader": "Lector",
|
||||
"Reading": "Lectura",
|
||||
"Remove emoji": "Eliminar emoji",
|
||||
"Rename": "Cambiar el nombre",
|
||||
"Rephrase": "Reformular",
|
||||
"Request access": "Solicitar acceso",
|
||||
@@ -625,8 +637,7 @@
|
||||
"Add": "Ajouter",
|
||||
"Add PDF": "Ajouter un PDF",
|
||||
"Add a callout block": "Ajouter un bloc d'alerte",
|
||||
"Add a sub page": "Ajouter une sous-page",
|
||||
"Add emoji": "Ajouter une émoticône",
|
||||
"Add a horizontal line": "Ajouter une ligne horizontale",
|
||||
"Administrator": "Administrateur",
|
||||
"Alert deleted document": "Alerte de document supprimé",
|
||||
"All docs": "Tous les documents",
|
||||
@@ -676,6 +687,7 @@
|
||||
"Delete a doc": "Supprimer un doc",
|
||||
"Delete document": "Supprimer le document",
|
||||
"Delete sub-document": "Supprimer le sous-document",
|
||||
"Divider": "Séparateur",
|
||||
"Doc visibility card": "Carte de visibilité du doc",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Logo Docs",
|
||||
@@ -688,6 +700,7 @@
|
||||
"Document accessible to any connected person": "Document accessible à toute personne connectée",
|
||||
"Document deleted": "Document supprimé",
|
||||
"Document duplicated successfully!": "Document dupliqué avec succès !",
|
||||
"Document emoji": "Emoji du document",
|
||||
"Document owner": "Propriétaire du document",
|
||||
"Document role text": "Texte du rôle du document",
|
||||
"Document sections": "Sections du document",
|
||||
@@ -701,7 +714,6 @@
|
||||
"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",
|
||||
"Edit document emoji": "Modifier l'émoticône du document",
|
||||
"Editing": "Édition",
|
||||
"Editor": "Éditeur",
|
||||
"Editor unavailable": "Éditeur indisponible",
|
||||
@@ -763,7 +775,7 @@
|
||||
"My docs": "Mes documents",
|
||||
"Name": "Nom",
|
||||
"New doc": "Nouveau doc",
|
||||
"New sub-doc": "Nouveau sous-doc",
|
||||
"New sub-doc": "Nouveau sous-document",
|
||||
"No active search": "Aucune recherche active",
|
||||
"No document found": "Aucun document trouvé",
|
||||
"No documents found": "Aucun document trouvé",
|
||||
@@ -773,6 +785,7 @@
|
||||
"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 document {{title}}": "Ouvrir le document {{title}}",
|
||||
"Open document: {{title}}": "Ouvrir le document : {{title}}",
|
||||
"Open invitation actions menu": "Menu des actions d'ouverture d'une invitation",
|
||||
@@ -800,7 +813,7 @@
|
||||
"Reader": "Lecteur",
|
||||
"Reading": "Lecture seule",
|
||||
"Remove access": "Supprimer l'accès",
|
||||
"Remove emoji": "Supprimer les emojis",
|
||||
"Remove emoji": "Supprimer l'emoji",
|
||||
"Rename": "Renommer",
|
||||
"Rephrase": "Reformuler",
|
||||
"Request access": "Demander l'accès",
|
||||
@@ -830,7 +843,6 @@
|
||||
"Shared with {{count}} users_other": "Partagé entre {{count}} utilisateurs",
|
||||
"Show more": "Voir plus",
|
||||
"Simple and secure collaboration.": "Une collaboration simple et sécurisée.",
|
||||
"Simple document icon": "Icône simple du document",
|
||||
"Something bad happens, please retry.": "Une erreur inattendue s'est produite, veuillez réessayer.",
|
||||
"Start Writing": "Commencer à écrire",
|
||||
"Summarize": "Résumer",
|
||||
@@ -857,7 +869,6 @@
|
||||
"Untitled document": "Document sans titre",
|
||||
"Updated": "Mise à jour",
|
||||
"Updated at": "Mise à jour le",
|
||||
"Upload PDF": "Téléverser un PDF",
|
||||
"Use as prompt": "Utiliser comme un prompt",
|
||||
"Version history": "Historique des versions",
|
||||
"Version restored successfully": "Version restaurée avec succès",
|
||||
@@ -895,6 +906,7 @@
|
||||
"Accessible to anyone": "Accessibile a chiunque",
|
||||
"Accessible to authenticated users": "Accessibile agli utenti autenticati",
|
||||
"Add": "Aggiungi",
|
||||
"Add a horizontal line": "Aggiungi una linea orizzontale",
|
||||
"Administrator": "Amministratore",
|
||||
"All docs": "Tutti i documenti",
|
||||
"Anonymous": "Anonimo",
|
||||
@@ -926,6 +938,7 @@
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Docs trasforma i tuoi documenti in piattaforme di conoscenza grazie alle sotto-pagine, alla ricerca potente e alla capacità di fissare i tuoi documenti importanti.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs: Il tuo nuovo compagno di collaborare sui documenti in modo efficiente, intuitivo e sicuro.",
|
||||
"Document accessible to any connected person": "Documento accessibile a qualsiasi persona collegata",
|
||||
"Document emoji": "Emoji del documento",
|
||||
"Document owner": "Proprietario del documento",
|
||||
"Docx": "Docx",
|
||||
"Download": "Scarica",
|
||||
@@ -962,7 +975,7 @@
|
||||
"More docs": "Altri documenti",
|
||||
"My docs": "I miei documenti",
|
||||
"Name": "Nome",
|
||||
"New doc": "Nuovo doc",
|
||||
"New doc": "Nuovo documento",
|
||||
"No active search": "Nessuna ricerca attiva",
|
||||
"No document found": "Nessun documento trovato",
|
||||
"No documents found": "Nessun documento trovato",
|
||||
@@ -986,6 +999,7 @@
|
||||
"Public document": "Documento pubblico",
|
||||
"Reader": "Lettore",
|
||||
"Reading": "Leggendo",
|
||||
"Remove emoji": "Rimuovi emoji",
|
||||
"Rename": "Rinomina",
|
||||
"Rephrase": "Riformula",
|
||||
"Restore": "Ripristina",
|
||||
@@ -1031,55 +1045,51 @@
|
||||
"translation": {
|
||||
"\"{{email}}\" is already invited to the document.": "{{email}} is al uitgenodigd voor dit document.",
|
||||
"\"{{email}}\" is already member of the document.": "{{email}} is al lid van dit document",
|
||||
"401 Unauthorized": "401 Ongeautoriseerd",
|
||||
"401 Unauthorized": "401 Onbevoegd",
|
||||
"A new way to organize knowledge.": "Een nieuwe manier om kennis te organiseren.",
|
||||
"AI Actions": "AI Actie",
|
||||
"AI seems busy! Please try again.": "AI is bezig! Probeer het later opnieuw.",
|
||||
"AI seems busy! Please try again.": "AI is druk! Probeer het later opnieuw.",
|
||||
"Access Denied - Error 403": "Toegang geweigerd - Fout 403",
|
||||
"Access Requests": "Toegangsverzoeken",
|
||||
"Access request sent successfully.": "Toegangsverzoek is succesvol verzonden.",
|
||||
"Accessible to anyone": "Toegankelijk voor iedereen",
|
||||
"Accessible to authenticated users": "Toegankelijk voor ingelogde gebruikers",
|
||||
"Accessible to authenticated users": "Toegankelijk voor geauthentiseerde gebruikers",
|
||||
"Actions for {{title}}": "Acties voor {{title}}",
|
||||
"Add": "Voeg toe",
|
||||
"Add PDF": "PDF toevoegen",
|
||||
"Add a callout block": "Voeg een opmerking toe",
|
||||
"Add a sub page": "Voeg subpagina toe",
|
||||
"Add emoji": "Emoji toevoegen",
|
||||
"Add a callout block": "Voeg een toelichting toe",
|
||||
"Add a horizontal line": "Voeg horizontale lijn toe",
|
||||
"Administrator": "Administrator",
|
||||
"Alert deleted document": "Melding verwijderd document",
|
||||
"All docs": "Alle documenten",
|
||||
"An error occurred while restoring the document: {{error}}": "Er is een fout opgetreden tijdens het herstellen van het document: {{error}}",
|
||||
"An uncompromising writing experience.": "Een compromisloze schrijfervaring.",
|
||||
"An uncompromising writing experience.": "Een compromisloze schrijvingservaring.",
|
||||
"Analyzing file...": "Bestand analyseren...",
|
||||
"Anonymous": "Anoniem",
|
||||
"Anyone with the link can edit the document": "Iedereen met de link kan het document bewerken",
|
||||
"Anyone with the link can edit the document if they are logged in": "Iedereen met deze link kan het document bewerken, mits ze ingelogd zijn",
|
||||
"Anyone with the link can edit the document if they are logged in": "Iedereen met deze link kan het document bewerken als ze ingelogd zijn",
|
||||
"Anyone with the link can see the document": "Iedereen met de link kan het document bekijken",
|
||||
"Anyone with the link can view the document if they are logged in": "Iedereen met deze link kan het document zien, mits ze ingelogd zijn",
|
||||
"Anyone with the link can view the document if they are logged in": "Iedereen met deze link kan het document zien als ze ingelogd zijn",
|
||||
"Approve": "Goedkeuren",
|
||||
"As this is a sub-document, please request access to the parent document to enable these features.": "Aangezien dit een subdocument is, vraag om toegang tot het bovenliggende document om deze functies in te schakelen.",
|
||||
"Available soon": "Binnenkort beschikbaar",
|
||||
"Back to homepage": "Terug naar startpagina",
|
||||
"Banner image": "Banner afbeelding",
|
||||
"Beautify": "Maak mooier",
|
||||
"By moving this document to <strong>{{targetDocumentTitle}}</strong>, it will lose its current access rights and inherit the permissions of that document. <strong>This access change cannot be undone.</strong>": "Door dit document te verplaatsen naar <strong>{{targetDocumentTitle}}</strong>, zal het document zijn huidige toegangsrechten verliezen en erft de machtigingen van dat document. <strong>Deze toegangswijziging kan niet ongedaan worden gemaakt.</strong>",
|
||||
"Callout": "Opmerking",
|
||||
"By moving this document to <strong>{{targetDocumentTitle}}</strong>, it will lose its current access rights and inherit the permissions of that document. <strong>This access change cannot be undone.</strong>": "Door dit document te verplaatsen naar <strong>{{targetDocumentTitle}}</strong>, zal het zijn huidige toegangsrechten en erft de machtigingen van dat document. <strong>Deze toegangswijziging kan niet ongedaan worden gemaakt.</strong>",
|
||||
"Callout": "Toelichting",
|
||||
"Can't load this page, please check your internet connection.": "Kan deze pagina niet laden. Controleer je internetverbinding.",
|
||||
"Cancel": "Annuleren",
|
||||
"Cancel": "Breek af",
|
||||
"Cancel the deletion": "Verwijderen annuleren",
|
||||
"Cancel the download": "Annuleer de download",
|
||||
"Close the access request modal": "Sluit het toegangsverzoek venster",
|
||||
"Close the delete modal": "Sluit het verwijder venster",
|
||||
"Close the download modal": "Sluit het downloadvenster",
|
||||
"Close the search modal": "Sluit het zoekvenster",
|
||||
"Close the share modal": "Sluit het deelvenster",
|
||||
"Close the version history modal": "Sluit versie geschiedenis venster",
|
||||
"Collaborate": "Samenwerken",
|
||||
"Collaborate and write in real time, without layout constraints.": "Samenwerken en schrijven in realtime, zonder lay-outbeperkingen.",
|
||||
"Collaborative writing, Simplified.": "Gezamenlijk schrijven, Vereenvoudigd.",
|
||||
"Confirm": "Bevestigen",
|
||||
"Connected": "Ingelogd",
|
||||
"Collaborate and write in real time, without layout constraints.": "Samenwerken en schrijven in realtime, zonder lay-out beperkingen.",
|
||||
"Collaborative writing, Simplified.": "Vereenvoudigd samenwerkend",
|
||||
"Confirm": "Bevestig",
|
||||
"Connected": "Verbonden",
|
||||
"Content modal to explain why the user cannot edit": "Content modal om uit te leggen waarom de gebruiker niet kan bewerken",
|
||||
"Content modal to export the document": "Content venster om document te exporteren",
|
||||
"Convert Markdown": "Converteer naar Markdown formaat",
|
||||
@@ -1088,31 +1098,29 @@
|
||||
"Copy link": "Kopieer link",
|
||||
"Correct": "Correct",
|
||||
"Create a new sub-doc": "Maak een nieuw subdocument",
|
||||
"Current doc": "Huidig document",
|
||||
"Days remaining": "Dagen resterend",
|
||||
"Days remaining:": "Dagen resterend:",
|
||||
"Current doc": "Huidige document",
|
||||
"Delete": "Verwijder",
|
||||
"Delete a doc": "Verwijder een document",
|
||||
"Delete document": "Verwijder document",
|
||||
"Delete sub-document": "Verwijder subdocument",
|
||||
"Doc visibility card": "Document zichtbaarheid kaart",
|
||||
"Divider": "Scheidingslijn",
|
||||
"Doc visibility card": "Docs zichtbaarheid kaart",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Docs logo",
|
||||
"Docs is already available, log in to use it now.": "Docs is beschikbaar, log in om het te gebruiken.",
|
||||
"Docs makes real-time collaboration simple. Invite collaborators - public officials or external partners - with one click to see their changes live, while maintaining precise access control for data security.": "Docs maakt real-time samenwerking eenvoudig. Nodig medewerkers - ambtenaren of externe partners - uit met één klik om hun veranderingen live te zien, terwijl de toegangscontrole voor de gegevensbeveiliging wordt gehandhaafd.",
|
||||
"Docs offers an intuitive writing experience. Its minimalist interface favors content over layout, while offering the essentials: media import, offline mode and keyboard shortcuts for greater efficiency.": "Docs biedt een intuïtieve schrijfervaring. De minimalistische interface geeft voorrang aan de inhoud boven de lay-out, terwijl essentiële zaken worden aangeboden: importeren van media, offline-modus en sneltoetsen voor grotere efficiëntie.",
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Documentatie transformeert uw documenten in een kennisbank, dankzij subpagina's, krachtig zoeken en de mogelijkheid om uw belangrijke documenten vast te zetten.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs: Je nieuwe partner om efficiënt, intuïtief en veilig samen te werken aan documenten.",
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Documentatie transformeert uw documenten in een kennisbasis, dankzij subpagina's, krachtig zoeken en de mogelijkheid om uw belangrijke documenten te pinnen.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs: Je nieuwe metgezel om efficiënt, intuïtief en veilig samen te werken aan documenten.",
|
||||
"Document access mode": "Document toegangsmodus",
|
||||
"Document accessible to any connected person": "Document is toegankelijk voor ieder ingelogde persoon",
|
||||
"Document deleted": "Document verwijderd",
|
||||
"Document accessible to any connected person": "Document is toegankelijk voor ieder verbonden persoon",
|
||||
"Document emoji": "Document emoji",
|
||||
"Document duplicated successfully!": "Document met succes gedupliceerd!",
|
||||
"Document owner": "Document eigenaar",
|
||||
"Document role text": "Document roluitleg",
|
||||
"Document sections": "Document secties",
|
||||
"Document title": "Documenttitel",
|
||||
"Document role text": "Document roltekst",
|
||||
"Document sections": "Document gedeelten",
|
||||
"Document title": "Titel van het document",
|
||||
"Document tree": "Boomstructuur document",
|
||||
"Document visibility": "Document toegankelijkheid",
|
||||
"Document visibility": "Document zichtbaarheid",
|
||||
"Documents grid": "Documenten overzicht",
|
||||
"Docx": "Docx",
|
||||
"Download": "Download",
|
||||
@@ -1120,60 +1128,58 @@
|
||||
"Download your document in a .docx or .pdf format.": "Download jouw document in .docx of .pdf formaat.",
|
||||
"Drag and drop status": "Drag & drop status",
|
||||
"Duplicate": "Dupliceer",
|
||||
"Edit document emoji": "Bewerk document emoji",
|
||||
"Editing": "Bewerken",
|
||||
"Editor": "Redacteur",
|
||||
"Editor unavailable": "Editor niet beschikbaar",
|
||||
"Embed a PDF file": "PDF bestand invoegen",
|
||||
"Editor": "Bewerker",
|
||||
"Editor unavailable": "Editor onbereikbaar",
|
||||
"Embed a PDF file": "PDF-bestand insluiten",
|
||||
"Emojify": "Maak met emoji's",
|
||||
"Empty template": "Leeg sjabloon",
|
||||
"Empty template": "Lege template",
|
||||
"Error during delete invitation": "Fout bij verwijderen uitnodiging",
|
||||
"Error during update invitation": "Fout tijdens bijwerken uitnodiging",
|
||||
"Error during update invitation": "Fout bij updaten uitnodiging",
|
||||
"Error while deleting invitation": "Fout bij verwijderen uitnodiging",
|
||||
"Error while removing the request.": "Fout bij het verwijderen van het verzoek.",
|
||||
"Error while updating the member role.": "Fout tijdens het bijwerken van de rol van de gebruiker.",
|
||||
"Error while updating the member role.": "Fout bij het bijwerken van de rol van de gebruiker.",
|
||||
"Export": "Exporteer",
|
||||
"Export the document": "Exporteer het document",
|
||||
"Failed to add the member in the document.": "Het toevoegen van het lid aan het document is mislukt.",
|
||||
"Failed to copy link": "Koppeling kopiëren mislukt",
|
||||
"Failed to copy to clipboard": "Kopiëren naar klembord mislukt",
|
||||
"Export the document": "Deel dit document",
|
||||
"Failed to add the member in the document.": "Toevoegen van het lid in het document is mislukt.",
|
||||
"Failed to copy link": "Link kopiëren gefaald",
|
||||
"Failed to copy to clipboard": "Kopiëren naar klembord misluk",
|
||||
"Failed to create the invitation for {{email}}.": "Aanmaken uitnodiging voor {{email}} is mislukt.",
|
||||
"Failed to duplicate the document...": "Het dupliceren van het document is mislukt...",
|
||||
"Flexible export.": "Flexibele export.",
|
||||
"Format": "Formaat",
|
||||
"Govs ❤️ Open Source.": "Govs ❤️ Open Source.",
|
||||
"History": "Geschiedenis",
|
||||
"Home": "Startscherm",
|
||||
"Home": "Thuis",
|
||||
"I understand": "Ik begrijp het",
|
||||
"If a member is editing, his works can be lost.": "Als een gebruiker aan het bewerken is, kan zijn werk verloren gaan.",
|
||||
"If you wish to be able to co-edit in real-time, contact your Information Systems Security Manager about allowing WebSockets.": "Als u in real-time wilt kunnen samenwerken, neem dan contact op met uw de beheerder over het toestaan van WebSockets.",
|
||||
"If you wish to be able to co-edit in real-time, contact your Information Systems Security Manager about allowing WebSockets.": "Als u in real-time wilt kunnen medebewerken, neem dan contact op met uw Information Systems Security Manager over het toestaan van WebSockets.",
|
||||
"Illustration": "Illustratie",
|
||||
"Image 403": "Afbeelding 403",
|
||||
"Image: {{title}}": "Afbeelding: {{title}}",
|
||||
"Insufficient access rights to view the document.": "Onvoldoende toegangsrechten om het document te bekijken.",
|
||||
"Insufficient access rights to view the document.": "Onvoldoende toegangsrechten om het document te zien.",
|
||||
"Invite": "Uitnodigen",
|
||||
"It is the card information about the document.": "Het is een informatie kaart over het document.",
|
||||
"It is the document title": "Het is de titel van het document",
|
||||
"It is the document title": "Dit is de titel",
|
||||
"It seems that the page you are looking for does not exist or cannot be displayed correctly.": "Het lijkt erop dat de pagina die u zoekt niet bestaat of niet correct kan worden weergegeven.",
|
||||
"Language": "Taal",
|
||||
"Last update: {{update}}": "Laatst bijgewerkt: {{update}}",
|
||||
"Last update: {{update}}": "Laatste update: {{update}}",
|
||||
"Learn more": "Meer informatie",
|
||||
"Link Copied !": "Link gekopieerd!",
|
||||
"Link Copied !": "Link gekopieerd",
|
||||
"Link a doc": "Koppel een document",
|
||||
"Link settings": "Linkinstellingen",
|
||||
"Link this doc to another doc": "Dit document aan een ander document koppelen",
|
||||
"Link this doc to another doc": "Dit document aan een andere document koppelen",
|
||||
"Links": "Links",
|
||||
"List invitation card": "Uitnodigingskaart weergeven",
|
||||
"List members card": "Gebruikerslijst kaart",
|
||||
"List request access card": "Kaart voor de lijst van toegangsverzoeken",
|
||||
"List search user result card": "Gebruikersresultaten weergeven op zoekkaart",
|
||||
"List invitation card": "Uitnodiging lijst kaart",
|
||||
"List members card": "Gebruikers lijst kaart",
|
||||
"List request access card": "Toegangskaart voor lijstverzoeken",
|
||||
"Load more": "Laad meer",
|
||||
"Log in to access the document.": "Log in om toegang tot het document te krijgen.",
|
||||
"Login": "Inloggen",
|
||||
"Logo": "Logo",
|
||||
"Logout": "Uitloggen",
|
||||
"Main content": "Hoofdinhoud",
|
||||
"Modal confirmation to download the attachment": "Bevestiging om bijlage te downloaden",
|
||||
"Modal confirmation to download the attachment": "Venster bevestiging om bijlage te downloaden",
|
||||
"More docs": "Meer documenten",
|
||||
"More options": "Meer opties",
|
||||
"Move": "Verplaats",
|
||||
@@ -1181,25 +1187,25 @@
|
||||
"Move to my docs": "Verplaatsen naar mijn documenten",
|
||||
"My docs": "Mijn documenten",
|
||||
"Name": "Naam",
|
||||
"New doc": "Nieuwe doc",
|
||||
"New doc": "Nieuw document",
|
||||
"New sub-doc": "Nieuw subdocument",
|
||||
"No active search": "Geen actieve zoekactie",
|
||||
"No document found": "Geen documenten gevonden",
|
||||
"No documents found": "Geen documenten gevonden",
|
||||
"No text selected": "Geen tekst geselecteerd",
|
||||
"No versions": "Geen versies",
|
||||
"OK": "OK",
|
||||
"Offline ?!": "Offline?!",
|
||||
"OK": "Ok",
|
||||
"Offline ?!": "Offline ?!",
|
||||
"Only invited people can access": "Alleen uitgenodigde gebruikers hebben toegang",
|
||||
"Open Source": "Open Source",
|
||||
"Open document actions menu": "Open document actie menu",
|
||||
"Open document {{title}}": "Open document {{title}}",
|
||||
"Open document: {{title}}": "Open document: {{title}}",
|
||||
"Open invitation actions menu": "Open uitnodigingsactiemenu",
|
||||
"Open document: {{title}}": "Open document {{title}}",
|
||||
"Open invitation actions menu": "Open uitnodiging actie menu",
|
||||
"Open root document": "Open hoofddocument",
|
||||
"Open the document options": "Open document opties",
|
||||
"Open the header menu": "Open het hoofdmenu",
|
||||
"Open the menu of actions for the document: {{title}}": "Open het menu van acties voor het document: {{title}}",
|
||||
"Open the sharing settings for the document": "Open de instellingen voor delen van het document",
|
||||
"Organize": "Organiseer",
|
||||
"Others are editing this document. Unfortunately your network blocks WebSockets, the technology enabling real-time co-editing.": "Anderen bewerken dit document. Helaas blokkeert uw netwerk WebSockets, de technologie voor real-time co-editing.",
|
||||
"Others are editing. Your network prevent changes.": "Anderen zijn aan het bewerken. Uw netwerk voorkomt wijzigingen.",
|
||||
@@ -1207,7 +1213,7 @@
|
||||
"PDF": "PDF",
|
||||
"Page Not Found - Error 404": "Pagina niet gevonden - Fout 404",
|
||||
"Pending invitations": "Openstaande uitnodigingen",
|
||||
"People with access via the parent document": "Gebruikers met toegang via het bovenliggend document",
|
||||
"People with access via the parent document": "Mensen met toegang via het bovenliggend document",
|
||||
"Pin": "Vastzetten",
|
||||
"Pinned documents": "Vastgepinde documenten",
|
||||
"Please download it only if it comes from a trusted source.": "Alleen downloaden als het van een vertrouwde bron komt.",
|
||||
@@ -1220,28 +1226,27 @@
|
||||
"Reading": "Lezen",
|
||||
"Remove access": "Toegang verwijderen",
|
||||
"Remove emoji": "Emoji verwijderen",
|
||||
"Rename": "Hernoem",
|
||||
"Rename": "Hernoemen",
|
||||
"Rephrase": "Herschrijf",
|
||||
"Request access": "Toegang aanvragen",
|
||||
"Reset": "Herstellen",
|
||||
"Reset": "Resetten",
|
||||
"Restore": "Herstel",
|
||||
"Root document {{title}}": "Hoofddocument {{title}}",
|
||||
"Search": "Zoeken",
|
||||
"Search by title": "Zoek op titel",
|
||||
"Search docs": "Zoek documenten",
|
||||
"Search modal": "Zoekvenster",
|
||||
"Search modal": "Zoek modal",
|
||||
"Search results": "Zoekresultaten",
|
||||
"Search user result": "Zoekresultaten",
|
||||
"Search user result": "Zoek resultaat",
|
||||
"Select a doc": "Selecteer een document",
|
||||
"Select a document": "Selecteer een document",
|
||||
"Select a version on the right to restore": "Selecteer een versie aan de rechterzijde om te herstellen",
|
||||
"Select a version on the right to restore": "Selecteer een versie rechts om te herstellen",
|
||||
"Select language": "Selecteer taal",
|
||||
"Share": "Deel",
|
||||
"Share button": "Deelknop",
|
||||
"Share modal content": "Deel venster inhoud",
|
||||
"Share the document": "Deel dit document",
|
||||
"Share with {{count}} users_many": "Gedeeld met {{count}} gebruikers",
|
||||
"Share with {{count}} users_one": "Gedeeld met {{count}} gebruiker",
|
||||
"Share with {{count}} users_one": "Delen met {{count}} gebruiker",
|
||||
"Share with {{count}} users_other": "Gedeeld met {{count}} gebruikers",
|
||||
"Shared with me": "Gedeeld met mij",
|
||||
"Shared with {{count}} users_many": "Gedeeld met {{count}} gebruikers",
|
||||
@@ -1249,62 +1254,56 @@
|
||||
"Shared with {{count}} users_other": "Gedeeld met {{count}} gebruikers",
|
||||
"Show more": "Toon meer",
|
||||
"Simple and secure collaboration.": "Eenvoudige en veilige samenwerking.",
|
||||
"Simple document icon": "Eenvoudig documentpictogram",
|
||||
"Something bad happens, please retry.": "Een fout heeft plaatsgevonden, probeer het opnieuw.",
|
||||
"Start Writing": "Begin met schrijven",
|
||||
"Summarize": "Vat samen",
|
||||
"Summary": "Samenvatting",
|
||||
"Template": "Sjabloon",
|
||||
"The antivirus has detected an anomaly in your file.": "Antivirus heeft een afwijking in uw bestand ontdekt.",
|
||||
"Template": "Template",
|
||||
"The antivirus has detected an anomaly in your file.": "Antivirus heeft een anomalie in uw bestand ontdekt.",
|
||||
"The document has been deleted.": "Het document is verwijderd",
|
||||
"The document has been restored.": "Het document is hersteld.",
|
||||
"The document visibility has been updated.": "De toegang van het document is bijgewerkt.",
|
||||
"The document visibility has been updated.": "De zichtbaarheid van het document is bijgewerkt",
|
||||
"The export failed": "Het exporteren is mislukt",
|
||||
"The link sharing rules differ from the parent document": "De regels voor het delen via een link verschillen van het bovenliggende document",
|
||||
"This document and <strong>any sub-documents</strong> will be placed in the trashbin. You can restore it within {{days}} days.": "Dit document en <strong>alle sub-documenten</strong> zullen in de prullenbak worden geplaatst. Je kunt het binnen {{days}} dagen herstellen.",
|
||||
"This document will be placed in the trashbin. You can restore it within {{days}} days.": "Dit document zal worden geplaatst in de prullenbak. U kunt het herstellen binnen {{days}} dagen.",
|
||||
"The link sharing rules differ from the parent document": "De link delen regels verschillen van het bovenliggende document",
|
||||
"This file is flagged as unsafe.": "Het bestand is gemarkeerd als onveilig.",
|
||||
"This means you can't edit until others leave.": "Dit betekent dat je niet kunt bewerken totdat anderen weggaan.",
|
||||
"This user has access inherited from a parent page.": "Deze gebruiker heeft toegang gekregen vanuit een bovenliggend document.",
|
||||
"To facilitate the circulation of documents, Docs allows you to export your content to the most common formats: PDF, Word or OpenDocument.": "Om het circuleren van documenten te vergemakkelijken, kan Docs je inhoud exporteren naar de meest voorkomende formaten: PDF, Word of OpenDocument.",
|
||||
"This user has access inherited from a parent page.": "Deze gebruiker heeft toegang overgenomen van de bovenliggende pagina.",
|
||||
"To facilitate the circulation of documents, Docs allows you to export your content to the most common formats: PDF, Word or OpenDocument.": "Om het circuleren van documenten te vergemakkelijken, kunt Docs je inhoud exporteren naar de meest voorkomende formaten: PDF, Word of OpenDocument.",
|
||||
"Too many requests. Please wait 60 seconds.": "Te veel verzoeken. Wacht 60 seconden.",
|
||||
"Trashbin": "Prullenbak",
|
||||
"Type a name or email": "Type een naam of email",
|
||||
"Type the name of a document": "Vul de naam van een document in",
|
||||
"Unnamed document": "Naamloos document",
|
||||
"Unpin": "Losmaken",
|
||||
"Untitled document": "Naamloos document",
|
||||
"Updated": "Bijgewerkt",
|
||||
"Updated at": "Bijgewerkt op",
|
||||
"Upload PDF": "PDF uploaden",
|
||||
"Updated at": "Geüpdate op",
|
||||
"Use as prompt": "Gebruik als prompt",
|
||||
"Version history": "Versiegeschiedenis",
|
||||
"Version restored successfully": "Versie succesvol hersteld",
|
||||
"Version history": "Versie historie",
|
||||
"Version restored successfully": "Versie teruggezet",
|
||||
"Warning": "Waarschuwing",
|
||||
"Why you can't edit the document?": "Waarom kunt u het document niet bewerken?",
|
||||
"Write": "Schrijf",
|
||||
"You are the sole owner of this group, make another member the group owner before you can change your own role or be removed from your document.": "U bent de enige eigenaar van deze groep, maak een ander lid de groepseigenaar voordat u uw eigen rol kunt wijzigen of kan worden verwijderd van het document.",
|
||||
"You can view this document but need additional access to see its members or modify settings.": "U kunt dit document bekijken, maar u heeft extra toegang nodig om de leden te kunnen bekijken of de instellingen aan te passen.",
|
||||
"You can view this document but need additional access to see its members or modify settings.": "U kunt dit document bekijken maar u heeft extra toegang nodig om de delen te kunnen bekijken of de instellingen aan te passen.",
|
||||
"You cannot restrict access to a subpage relative to its parent page.": "U kunt de toegang niet beperken tot een subpagina met betrekking tot de bovenliggende pagina.",
|
||||
"You must be at least the administrator of the target document": "U moet tenminste beheerder zijn van het doeldocument",
|
||||
"You must be the owner to move the document": "U moet de eigenaar zijn om het document te verplaatsen",
|
||||
"You're currently viewing a sub-document. To gain access, please request permission from the main document.": "U bekijkt momenteel een subdocument. Om toegang te krijgen, vraagt u toestemming voor het hoofddocument.",
|
||||
"Your access request for this document is pending.": "Uw toegangsverzoek voor dit document is in behandeling.",
|
||||
"You're currently viewing a sub-document. To gain access, please request permission from the main document.": "U bekijkt momenteel een subdocument. Om toegang te krijgen, vraagt u toestemming van het hoofddocument.",
|
||||
"Your access request for this document is pending.": "Uw verzoek om toegang tot dit document is in behandeling.",
|
||||
"Your current document will revert to this version.": "Uw huidige document wordt teruggezet naar deze versie.",
|
||||
"Your {{format}} was downloaded succesfully": "Jouw {{format}} is succesvol gedownload",
|
||||
"days_many": "dagen",
|
||||
"days_one": "dag",
|
||||
"days_other": "dagen",
|
||||
"document": "document",
|
||||
"embed": "invoegen",
|
||||
"embed": "insluiten",
|
||||
"file": "bestand",
|
||||
"home-content-open-source-part1": "Docs is gebouwd op <2>Django Rest Framework</2> en <6>Next.js</6>. We gebruiken ook <9>Yjs</9> en <13>BlockNote.js</13>, twee projecten die we met trots sponsoren.",
|
||||
"home-content-open-source-part2": "U kunt Docs eenvoudig zelf hosten (zie onze <2>installatiedocumentatie</2>).<br/>Docs gebruikt een <7>licentie</7> (MIT) die is afgestemd op innovatie en ondernemingen.<br/>Bijdragen zijn welkom (zie onze routekaart <13>hier</13>).",
|
||||
"home-content-open-source-part3": "Docs is het resultaat van een gezamenlijke inspanning geleid door de Franse 🇫🇷🥖 <1>(DINUM)</1> en Duitse 🇩🇪🥨 <5>(ZenDiS)</5> overheden.",
|
||||
"pdf": "pdf"
|
||||
"pdf": "PDF"
|
||||
}
|
||||
},
|
||||
"pt": {
|
||||
"translation": {
|
||||
"Remove emoji": "Remover emoji"
|
||||
}
|
||||
},
|
||||
"pt": { "translation": {} },
|
||||
"ru": {
|
||||
"translation": {
|
||||
"\"{{email}}\" is already invited to the document.": "\"{{email}}\" уже имеет приглашение для этого документа.",
|
||||
@@ -1322,7 +1321,7 @@
|
||||
"Add": "Добавить",
|
||||
"Add PDF": "Добавить PDF-файл",
|
||||
"Add a callout block": "Добавить блок выноски",
|
||||
"Add a sub page": "Добавить вложенную страницу",
|
||||
"Add a horizontal line": "Добавить горизонтальную линию",
|
||||
"Administrator": "Администратор",
|
||||
"Alert deleted document": "Оповещение об удалённом документе",
|
||||
"All docs": "Все документы",
|
||||
@@ -1372,6 +1371,7 @@
|
||||
"Delete a doc": "Удалить документ",
|
||||
"Delete document": "Удаление документа",
|
||||
"Delete sub-document": "Удалить вложенный документ",
|
||||
"Divider": "Разделитель",
|
||||
"Doc visibility card": "Карта видимости документа",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Логотип Docs",
|
||||
@@ -1384,6 +1384,7 @@
|
||||
"Document accessible to any connected person": "Документ доступен всем, кто присоединится",
|
||||
"Document deleted": "Документ удалён",
|
||||
"Document duplicated successfully!": "Документ успешно дублирован!",
|
||||
"Document emoji": "Эмодзи документа",
|
||||
"Document owner": "Владелец документа",
|
||||
"Document role text": "Текст роли документа",
|
||||
"Document sections": "Разделы документа",
|
||||
@@ -1468,6 +1469,7 @@
|
||||
"Offline ?!": "Не в сети?!",
|
||||
"Only invited people can access": "Имеют доступ только приглашенные люди",
|
||||
"Open Source": "Open Source",
|
||||
"Open document actions menu": "Меню действий открытия документа",
|
||||
"Open document {{title}}": "Открыть документ {{title}}",
|
||||
"Open document: {{title}}": "Открыть документ: {{title}}",
|
||||
"Open invitation actions menu": "Меню действий открытия приглашения",
|
||||
@@ -1525,7 +1527,6 @@
|
||||
"Shared with {{count}} users_other": "Поделились с пользователями: {{count}}",
|
||||
"Show more": "Показать ещё",
|
||||
"Simple and secure collaboration.": "Простое и безопасное сотрудничество.",
|
||||
"Simple document icon": "Простой значок документа",
|
||||
"Something bad happens, please retry.": "Что-то пошло не так, повторите попытку.",
|
||||
"Start Writing": "Начать писать",
|
||||
"Summarize": "Обобщить",
|
||||
@@ -1552,7 +1553,6 @@
|
||||
"Untitled document": "Безымянный документ",
|
||||
"Updated": "Обновлено",
|
||||
"Updated at": "Обновлено",
|
||||
"Upload PDF": "Выгрузить PDF",
|
||||
"Use as prompt": "Использовать как запрос",
|
||||
"Version history": "История версий",
|
||||
"Version restored successfully": "Версия успешно восстановлена",
|
||||
@@ -1583,6 +1583,7 @@
|
||||
"sl": {
|
||||
"translation": {
|
||||
"Load more": "Naloži več",
|
||||
"Remove emoji": "Odstrani emoji",
|
||||
"Untitled document": "Dokument brez naslova"
|
||||
}
|
||||
},
|
||||
@@ -1590,11 +1591,13 @@
|
||||
"translation": {
|
||||
"AI Actions": "AI-åtgärder",
|
||||
"AI seems busy! Please try again.": "AI verkar upptagen! Försök igen.",
|
||||
"Add a horizontal line": "Lägg till en horisontell linje",
|
||||
"Anonymous": "Anonym",
|
||||
"Beautify": "Försköna",
|
||||
"Cancel": "Avbryt",
|
||||
"Convert Markdown": "Konvertera Markdown",
|
||||
"Correct": "Korrekt",
|
||||
"Divider": "Avskiljare",
|
||||
"Download": "Ladda ner",
|
||||
"Download anyway": "Ladda ner ändå",
|
||||
"Emojify": "Emojify",
|
||||
@@ -1614,12 +1617,14 @@
|
||||
"This file is flagged as unsafe.": "Denna fil är flaggad som osäker.",
|
||||
"Too many requests. Please wait 60 seconds.": "För många förfrågningar. Vänligen vänta 60 sekunder.",
|
||||
"Use as prompt": "Använd som prompt",
|
||||
"Warning": "Varning"
|
||||
"Warning": "Varning",
|
||||
"Remove emoji": "Ta bort emoji"
|
||||
}
|
||||
},
|
||||
"tr": {
|
||||
"translation": {
|
||||
"AI Actions": "Yapay Zeka Eylemleri",
|
||||
"Add a horizontal line": "Yatay çizgi ekle",
|
||||
"Administrator": "Yönetici",
|
||||
"Anonymous": "Anonim",
|
||||
"Available soon": "Çok yakında!",
|
||||
@@ -1636,9 +1641,11 @@
|
||||
"Delete": "Sil",
|
||||
"Delete a doc": "Bir belgeyi silin",
|
||||
"Delete document": "Belgeyi sil",
|
||||
"Divider": "Ayırıcı",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Docs logosu",
|
||||
"Document accessible to any connected person": "Bağlanan herhangi bir kişi tarafından erişilebilen belge",
|
||||
"Document emoji": "Belge emojisi",
|
||||
"Docx": "Docx",
|
||||
"Download": "İndir",
|
||||
"Download anyway": "Yine de indir",
|
||||
@@ -1682,7 +1689,8 @@
|
||||
"Version history": "Sürüm geçmişi",
|
||||
"Warning": "Uyarı",
|
||||
"Write": "Yaz",
|
||||
"Your {{format}} was downloaded succesfully": "{{format}} indirildi"
|
||||
"Your {{format}} was downloaded succesfully": "{{format}} indirildi",
|
||||
"Remove emoji": "Emoji kaldır"
|
||||
}
|
||||
},
|
||||
"uk": {
|
||||
@@ -1702,7 +1710,7 @@
|
||||
"Add": "Додати",
|
||||
"Add PDF": "Додати файл PDF",
|
||||
"Add a callout block": "Додати блок винесення",
|
||||
"Add a sub page": "Додати вкладену сторінку",
|
||||
"Add a horizontal line": "Додати горизонтальну лінію",
|
||||
"Administrator": "Адміністратор",
|
||||
"Alert deleted document": "Сповіщення про видалений документ",
|
||||
"All docs": "Всі документи",
|
||||
@@ -1752,6 +1760,7 @@
|
||||
"Delete a doc": "Видалити документ",
|
||||
"Delete document": "Видалення документу",
|
||||
"Delete sub-document": "Видалити вкладений документ",
|
||||
"Divider": "Роздільник",
|
||||
"Doc visibility card": "Картка видимості документу",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Логотип Docs",
|
||||
@@ -1764,6 +1773,7 @@
|
||||
"Document accessible to any connected person": "Документ, доступний для будь-якої особи, що приєдналася",
|
||||
"Document deleted": "Документ видалено",
|
||||
"Document duplicated successfully!": "Документ успішно продубльовано!",
|
||||
"Document emoji": "Емодзі документа",
|
||||
"Document owner": "Власник документа",
|
||||
"Document role text": "Текст ролі документа",
|
||||
"Document sections": "Розділи документу",
|
||||
@@ -1848,6 +1858,7 @@
|
||||
"Offline ?!": "Не в мережі?!",
|
||||
"Only invited people can access": "Лише запрошені люди можуть мати доступ",
|
||||
"Open Source": "Open Source",
|
||||
"Open document actions menu": "Меню дій відкриття документу",
|
||||
"Open document {{title}}": "Відкрити документ {{title}}",
|
||||
"Open document: {{title}}": "Відкрити документ: {{title}}",
|
||||
"Open invitation actions menu": "Меню дій відкриття запрошення",
|
||||
@@ -1875,7 +1886,7 @@
|
||||
"Reader": "Читач",
|
||||
"Reading": "Читання",
|
||||
"Remove access": "Вилучити доступ",
|
||||
"Remove emoji": "Прибрати емодзі",
|
||||
"Remove emoji": "Видалити емодзі",
|
||||
"Rename": "Перейменувати",
|
||||
"Rephrase": "Перефразувати",
|
||||
"Request access": "Запит доступу",
|
||||
@@ -1905,7 +1916,6 @@
|
||||
"Shared with {{count}} users_other": "Поділилися з користувачами: {{count}}",
|
||||
"Show more": "Показати більше",
|
||||
"Simple and secure collaboration.": "Проста та безпечна співпраця.",
|
||||
"Simple document icon": "Проста піктограма документа",
|
||||
"Something bad happens, please retry.": "Сталася помилка, спробуйте ще раз.",
|
||||
"Start Writing": "Почати писати",
|
||||
"Summarize": "Підсумувати",
|
||||
@@ -1932,7 +1942,6 @@
|
||||
"Untitled document": "Документ без назви",
|
||||
"Updated": "Оновлено",
|
||||
"Updated at": "Оновлено",
|
||||
"Upload PDF": "Вивантажити PDF",
|
||||
"Use as prompt": "Використати як запит",
|
||||
"Version history": "Історія версій",
|
||||
"Version restored successfully": "Версія успішно відновлена",
|
||||
@@ -1972,6 +1981,7 @@
|
||||
"Accessible to authenticated users": "对授权用户开放",
|
||||
"Add": "新增",
|
||||
"Add a callout block": "增加一个标注模块",
|
||||
"Add a horizontal line": "添加水平线",
|
||||
"Administrator": "管理员",
|
||||
"All docs": "所有文档",
|
||||
"An uncompromising writing experience.": "极致的写作体验。",
|
||||
@@ -2004,6 +2014,7 @@
|
||||
"Delete": "删除",
|
||||
"Delete a doc": "删除文档",
|
||||
"Delete document": "删除文档",
|
||||
"Divider": "分割线",
|
||||
"Doc visibility card": "文档可见列表",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Docs 徽标",
|
||||
@@ -2013,6 +2024,7 @@
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Docs 通过子页面、强大的搜索功能以及固定重要文档的能力,将您的文档转化为知识库。",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs 为您提供高效、直观且安全的文档协作解决方案。",
|
||||
"Document accessible to any connected person": "任何来访的人都可以访问文档",
|
||||
"Document emoji": "文档表情符号",
|
||||
"Document owner": "文档所有者",
|
||||
"Document title": "文档标题",
|
||||
"Docx": "Doc",
|
||||
@@ -2089,6 +2101,7 @@
|
||||
"Quick search input": "快速搜索",
|
||||
"Reader": "阅读者",
|
||||
"Reading": "阅读中",
|
||||
"Remove emoji": "移除表情符号",
|
||||
"Rename": "重命名",
|
||||
"Rephrase": "改写",
|
||||
"Reset": "重置",
|
||||
|
||||
@@ -176,7 +176,10 @@ const DocPage = ({ id }: DocProps) => {
|
||||
|
||||
if (error.status === 401) {
|
||||
if (authenticated) {
|
||||
queryClient.setQueryData([KEY_AUTH], null);
|
||||
queryClient.setQueryData([KEY_AUTH], {
|
||||
user: null,
|
||||
authenticated: false,
|
||||
});
|
||||
}
|
||||
setAuthUrl();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress",
|
||||
"version": "3.9.0",
|
||||
"version": "3.8.2",
|
||||
"private": true,
|
||||
"repository": "https://github.com/suitenumerique/docs",
|
||||
"author": "DINUM",
|
||||
@@ -31,13 +31,13 @@
|
||||
"server:test": "yarn COLLABORATION_SERVER run test"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "24.10.0",
|
||||
"@types/react": "19.2.2",
|
||||
"@types/react-dom": "19.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "8.46.2",
|
||||
"@typescript-eslint/parser": "8.46.2",
|
||||
"@types/node": "22.18.8",
|
||||
"@types/react": "19.2.0",
|
||||
"@types/react-dom": "19.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.45.0",
|
||||
"@typescript-eslint/parser": "8.45.0",
|
||||
"docx": "9.5.0",
|
||||
"eslint": "9.39.0",
|
||||
"eslint": "9.37.0",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"typescript": "5.9.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eslint-plugin-docs",
|
||||
"version": "3.9.0",
|
||||
"version": "3.8.2",
|
||||
"repository": "https://github.com/suitenumerique/docs",
|
||||
"author": "DINUM",
|
||||
"license": "MIT",
|
||||
@@ -18,19 +18,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "15.5.4",
|
||||
"@tanstack/eslint-plugin-query": "5.91.2",
|
||||
"@tanstack/eslint-plugin-query": "5.91.0",
|
||||
"@typescript-eslint/eslint-plugin": "*",
|
||||
"@typescript-eslint/parser": "*",
|
||||
"@vitest/eslint-plugin": "1.4.0",
|
||||
"@vitest/eslint-plugin": "1.3.16",
|
||||
"eslint-config-next": "15.5.4",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-jest": "29.0.1",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-playwright": "2.3.0",
|
||||
"eslint-plugin-playwright": "2.2.2",
|
||||
"eslint-plugin-prettier": "5.5.4",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-testing-library": "7.13.3",
|
||||
"eslint-plugin-testing-library": "7.11.0",
|
||||
"prettier": "3.6.2"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "packages-i18n",
|
||||
"version": "3.9.0",
|
||||
"version": "3.8.2",
|
||||
"repository": "https://github.com/suitenumerique/docs",
|
||||
"author": "DINUM",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"i18next-parser": "9.3.0",
|
||||
"jest": "30.2.0",
|
||||
"ts-jest": "29.4.5",
|
||||
"ts-jest": "29.4.4",
|
||||
"typescript": "*",
|
||||
"yargs": "18.0.0"
|
||||
},
|
||||
|
||||
@@ -69,7 +69,7 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer wrong-api-key`)
|
||||
.set('authorization', 'wrong-api-key')
|
||||
.set('content-type', 'application/json');
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
@@ -99,7 +99,7 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'application/json');
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
@@ -114,7 +114,7 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'application/json')
|
||||
.send('');
|
||||
|
||||
@@ -129,10 +129,9 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'image/png')
|
||||
.send('randomdata');
|
||||
|
||||
expect(response.status).toBe(415);
|
||||
expect(response.body).toStrictEqual({ error: 'Unsupported Content-Type' });
|
||||
});
|
||||
@@ -142,73 +141,38 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'text/markdown')
|
||||
.set('accept', 'image/png')
|
||||
.send('# Header');
|
||||
|
||||
expect(response.status).toBe(406);
|
||||
expect(response.body).toStrictEqual({ error: 'Unsupported format' });
|
||||
});
|
||||
|
||||
test('POST /api/convert BlockNote to Markdown', async () => {
|
||||
const app = initApp();
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('content-type', 'application/vnd.blocknote+json')
|
||||
.set('accept', 'text/markdown')
|
||||
.send(expectedBlocks);
|
||||
test.each([[apiKey], [`Bearer ${apiKey}`]])(
|
||||
'POST /api/convert with correct content with Authorization: %s',
|
||||
async (authHeader) => {
|
||||
const app = initApp();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe(
|
||||
'text/markdown; charset=utf-8',
|
||||
);
|
||||
expect(typeof response.text).toBe('string');
|
||||
expect(response.text.trim()).toBe(expectedMarkdown);
|
||||
});
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('Origin', origin)
|
||||
.set('Authorization', authHeader)
|
||||
.set('content-type', 'text/markdown')
|
||||
.set('accept', 'application/vnd.yjs.doc')
|
||||
.send(expectedMarkdown);
|
||||
|
||||
test('POST /api/convert BlockNote to Yjs', async () => {
|
||||
const app = initApp();
|
||||
const editor = ServerBlockNoteEditor.create();
|
||||
const blocks = await editor.tryParseMarkdownToBlocks(expectedMarkdown);
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('content-type', 'application/vnd.blocknote+json')
|
||||
.set('accept', 'application/vnd.yjs.doc')
|
||||
.send(blocks)
|
||||
.responseType('blob');
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toBeInstanceOf(Buffer);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe('application/vnd.yjs.doc');
|
||||
const editor = ServerBlockNoteEditor.create();
|
||||
const doc = new Y.Doc();
|
||||
Y.applyUpdate(doc, response.body);
|
||||
const blocks = editor.yDocToBlocks(doc, 'document-store');
|
||||
|
||||
// Decode the Yjs response and verify it contains the correct blocks
|
||||
const responseBuffer = Buffer.from(response.body as Buffer);
|
||||
const ydoc = new Y.Doc();
|
||||
Y.applyUpdate(ydoc, responseBuffer);
|
||||
const decodedBlocks = editor.yDocToBlocks(ydoc, 'document-store');
|
||||
|
||||
expect(decodedBlocks).toStrictEqual(expectedBlocks);
|
||||
});
|
||||
|
||||
test('POST /api/convert BlockNote to HTML', async () => {
|
||||
const app = initApp();
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('content-type', 'application/vnd.blocknote+json')
|
||||
.set('accept', 'text/html')
|
||||
.send(expectedBlocks);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe('text/html; charset=utf-8');
|
||||
expect(typeof response.text).toBe('string');
|
||||
expect(response.text).toBe(expectedHTML);
|
||||
});
|
||||
expect(blocks).toStrictEqual(expectedBlocks);
|
||||
},
|
||||
);
|
||||
|
||||
test('POST /api/convert Yjs to HTML', async () => {
|
||||
const app = initApp();
|
||||
@@ -219,11 +183,10 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'application/vnd.yjs.doc')
|
||||
.set('accept', 'text/html')
|
||||
.send(Buffer.from(yjsUpdate));
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe('text/html; charset=utf-8');
|
||||
expect(typeof response.text).toBe('string');
|
||||
@@ -239,11 +202,10 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'application/vnd.yjs.doc')
|
||||
.set('accept', 'text/markdown')
|
||||
.send(Buffer.from(yjsUpdate));
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe(
|
||||
'text/markdown; charset=utf-8',
|
||||
@@ -261,16 +223,15 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'application/vnd.yjs.doc')
|
||||
.set('accept', 'application/json')
|
||||
.send(Buffer.from(yjsUpdate));
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe(
|
||||
'application/json; charset=utf-8',
|
||||
);
|
||||
expect(response.body).toBeInstanceOf(Array);
|
||||
expect(Array.isArray(response.body)).toBe(true);
|
||||
expect(response.body).toStrictEqual(expectedBlocks);
|
||||
});
|
||||
|
||||
@@ -279,16 +240,15 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'text/markdown')
|
||||
.set('accept', 'application/json')
|
||||
.send(expectedMarkdown);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.header['content-type']).toBe(
|
||||
'application/json; charset=utf-8',
|
||||
);
|
||||
expect(response.body).toBeInstanceOf(Array);
|
||||
expect(Array.isArray(response.body)).toBe(true);
|
||||
expect(response.body).toStrictEqual(expectedBlocks);
|
||||
});
|
||||
|
||||
@@ -297,12 +257,11 @@ describe('Server Tests', () => {
|
||||
const response = await request(app)
|
||||
.post('/api/convert')
|
||||
.set('origin', origin)
|
||||
.set('authorization', `Bearer ${apiKey}`)
|
||||
.set('authorization', apiKey)
|
||||
.set('content-type', 'application/vnd.yjs.doc')
|
||||
.set('accept', 'application/json')
|
||||
.send(Buffer.from('notvalidyjs'));
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body).toStrictEqual({ error: 'Invalid content' });
|
||||
expect(response.body).toStrictEqual({ error: 'Invalid Yjs content' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
import { v1 as uuidv1, v4 as uuidv4 } from 'uuid';
|
||||
import {
|
||||
afterAll,
|
||||
afterEach,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
test,
|
||||
@@ -45,8 +45,7 @@ import { hocuspocusServer, initApp } from '@/servers';
|
||||
describe('Server Tests', () => {
|
||||
let server: Server;
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
@@ -204,12 +203,11 @@ describe('Server Tests', () => {
|
||||
test('WebSocket connection fails if user can not access document', () => {
|
||||
const { promise, done } = promiseDone();
|
||||
|
||||
const room = uuidv4();
|
||||
|
||||
const fetchDocumentMock = vi
|
||||
.spyOn(CollaborationBackend, 'fetchDocument')
|
||||
.mockRejectedValue(new Error('some error'));
|
||||
|
||||
const room = uuidv4();
|
||||
const wsHocus = new HocuspocusProviderWebsocket({
|
||||
url: `ws://localhost:${portWS}/?room=${room}`,
|
||||
WebSocketPolyfill: WebSocket,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server-y-provider",
|
||||
"version": "3.9.0",
|
||||
"version": "3.8.2",
|
||||
"description": "Y.js provider for docs",
|
||||
"repository": "https://github.com/suitenumerique/docs",
|
||||
"license": "MIT",
|
||||
@@ -17,11 +17,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocknote/server-util": "0.41.1",
|
||||
"@hocuspocus/server": "3.4.0",
|
||||
"@sentry/node": "10.22.0",
|
||||
"@sentry/profiling-node": "10.22.0",
|
||||
"@hocuspocus/server": "3.3.0",
|
||||
"@sentry/node": "10.17.0",
|
||||
"@sentry/profiling-node": "10.17.0",
|
||||
"@tiptap/extensions": "*",
|
||||
"axios": "1.13.1",
|
||||
"axios": "1.12.2",
|
||||
"cors": "2.8.5",
|
||||
"express": "5.1.0",
|
||||
"express-ws": "5.0.2",
|
||||
@@ -31,10 +31,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocknote/core": "0.41.1",
|
||||
"@hocuspocus/provider": "3.4.0",
|
||||
"@hocuspocus/provider": "3.3.0",
|
||||
"@types/cors": "2.8.19",
|
||||
"@types/express": "5.0.5",
|
||||
"@types/express-ws": "3.0.6",
|
||||
"@types/express": "5.0.3",
|
||||
"@types/express-ws": "3.0.5",
|
||||
"@types/node": "*",
|
||||
"@types/supertest": "6.0.3",
|
||||
"@types/ws": "8.18.1",
|
||||
@@ -45,7 +45,7 @@
|
||||
"ts-node": "10.9.2",
|
||||
"tsc-alias": "1.8.16",
|
||||
"typescript": "*",
|
||||
"vitest": "4.0.6",
|
||||
"vitest": "3.2.4",
|
||||
"vitest-mock-extended": "3.1.0",
|
||||
"ws": "8.18.3"
|
||||
},
|
||||
|
||||
@@ -14,115 +14,27 @@ interface ErrorResponse {
|
||||
error: string;
|
||||
}
|
||||
|
||||
type ConversionResponseBody = Uint8Array | string | object | ErrorResponse;
|
||||
|
||||
interface InputReader {
|
||||
supportedContentTypes: string[];
|
||||
read(data: Buffer): Promise<PartialBlock[]>;
|
||||
}
|
||||
|
||||
interface OutputWriter {
|
||||
supportedContentTypes: string[];
|
||||
write(blocks: PartialBlock[]): Promise<ConversionResponseBody>;
|
||||
}
|
||||
|
||||
const editor = ServerBlockNoteEditor.create<
|
||||
DefaultBlockSchema,
|
||||
DefaultInlineContentSchema,
|
||||
DefaultStyleSchema
|
||||
>();
|
||||
|
||||
const ContentTypes = {
|
||||
XMarkdown: 'text/x-markdown',
|
||||
Markdown: 'text/markdown',
|
||||
YJS: 'application/vnd.yjs.doc',
|
||||
FormUrlEncoded: 'application/x-www-form-urlencoded',
|
||||
OctetStream: 'application/octet-stream',
|
||||
HTML: 'text/html',
|
||||
BlockNote: 'application/vnd.blocknote+json',
|
||||
JSON: 'application/json',
|
||||
} as const;
|
||||
|
||||
const createYDocument = (blocks: PartialBlock[]) =>
|
||||
editor.blocksToYDoc(blocks, 'document-store');
|
||||
|
||||
const readers: InputReader[] = [
|
||||
{
|
||||
// application/x-www-form-urlencoded is interpreted as Markdown for backward compatibility
|
||||
supportedContentTypes: [
|
||||
ContentTypes.Markdown,
|
||||
ContentTypes.XMarkdown,
|
||||
ContentTypes.FormUrlEncoded,
|
||||
],
|
||||
read: (data) => editor.tryParseMarkdownToBlocks(data.toString()),
|
||||
},
|
||||
{
|
||||
supportedContentTypes: [ContentTypes.YJS, ContentTypes.OctetStream],
|
||||
read: async (data) => {
|
||||
const ydoc = new Y.Doc();
|
||||
Y.applyUpdate(ydoc, data);
|
||||
return editor.yDocToBlocks(ydoc, 'document-store') as PartialBlock[];
|
||||
},
|
||||
},
|
||||
{
|
||||
supportedContentTypes: [ContentTypes.BlockNote],
|
||||
read: async (data) => JSON.parse(data.toString()),
|
||||
},
|
||||
];
|
||||
|
||||
const writers: OutputWriter[] = [
|
||||
{
|
||||
supportedContentTypes: [ContentTypes.BlockNote, ContentTypes.JSON],
|
||||
write: async (blocks) => blocks,
|
||||
},
|
||||
{
|
||||
supportedContentTypes: [ContentTypes.YJS, ContentTypes.OctetStream],
|
||||
write: async (blocks) => Y.encodeStateAsUpdate(createYDocument(blocks)),
|
||||
},
|
||||
{
|
||||
supportedContentTypes: [ContentTypes.Markdown, ContentTypes.XMarkdown],
|
||||
write: (blocks) => editor.blocksToMarkdownLossy(blocks),
|
||||
},
|
||||
{
|
||||
supportedContentTypes: [ContentTypes.HTML],
|
||||
write: (blocks) => editor.blocksToHTMLLossy(blocks),
|
||||
},
|
||||
];
|
||||
|
||||
const normalizeContentType = (value: string) => value.split(';')[0];
|
||||
|
||||
export const convertHandler = async (
|
||||
req: Request<object, Uint8Array | ErrorResponse, Buffer, object>,
|
||||
res: Response<ConversionResponseBody>,
|
||||
res: Response<Uint8Array | string | object | ErrorResponse>,
|
||||
) => {
|
||||
if (!req.body || req.body.length === 0) {
|
||||
res.status(400).json({ error: 'Invalid request: missing content' });
|
||||
return;
|
||||
}
|
||||
|
||||
const contentType = normalizeContentType(
|
||||
req.header('content-type') || ContentTypes.Markdown,
|
||||
);
|
||||
|
||||
const reader = readers.find((reader) =>
|
||||
reader.supportedContentTypes.includes(contentType),
|
||||
);
|
||||
|
||||
if (!reader) {
|
||||
res.status(415).json({ error: 'Unsupported Content-Type' });
|
||||
return;
|
||||
}
|
||||
|
||||
const accept = normalizeContentType(req.header('accept') || ContentTypes.YJS);
|
||||
|
||||
const writer = writers.find((writer) =>
|
||||
writer.supportedContentTypes.includes(accept),
|
||||
);
|
||||
|
||||
if (!writer) {
|
||||
res.status(406).json({ error: 'Unsupported format' });
|
||||
return;
|
||||
}
|
||||
const contentType = (req.header('content-type') || 'text/markdown').split(
|
||||
';',
|
||||
)[0];
|
||||
const accept = (req.header('accept') || 'application/vnd.yjs.doc').split(
|
||||
';',
|
||||
)[0];
|
||||
|
||||
let blocks:
|
||||
| PartialBlock<
|
||||
@@ -132,23 +44,63 @@ export const convertHandler = async (
|
||||
>[]
|
||||
| null = null;
|
||||
try {
|
||||
try {
|
||||
blocks = await reader.read(req.body);
|
||||
} catch (e) {
|
||||
logger('Invalid content:', e);
|
||||
res.status(400).json({ error: 'Invalid content' });
|
||||
// First, convert from the input format to blocks
|
||||
// application/x-www-form-urlencoded is interpreted as Markdown for backward compatibility
|
||||
if (
|
||||
contentType === 'text/markdown' ||
|
||||
contentType === 'application/x-www-form-urlencoded'
|
||||
) {
|
||||
blocks = await editor.tryParseMarkdownToBlocks(req.body.toString());
|
||||
} else if (
|
||||
contentType === 'application/vnd.yjs.doc' ||
|
||||
contentType === 'application/octet-stream'
|
||||
) {
|
||||
try {
|
||||
const ydoc = new Y.Doc();
|
||||
Y.applyUpdate(ydoc, req.body);
|
||||
blocks = editor.yDocToBlocks(ydoc, 'document-store') as PartialBlock[];
|
||||
} catch (e) {
|
||||
logger('Invalid Yjs content:', e);
|
||||
res.status(400).json({ error: 'Invalid Yjs content' });
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
res.status(415).json({ error: 'Unsupported Content-Type' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blocks || blocks.length === 0) {
|
||||
res.status(500).json({ error: 'No valid blocks were generated' });
|
||||
return;
|
||||
}
|
||||
|
||||
res
|
||||
.status(200)
|
||||
.setHeader('content-type', accept)
|
||||
.send(await writer.write(blocks));
|
||||
// Then, convert from blocks to the output format
|
||||
if (accept === 'application/json') {
|
||||
res.status(200).json(blocks);
|
||||
} else {
|
||||
const yDocument = editor.blocksToYDoc(blocks, 'document-store');
|
||||
|
||||
if (
|
||||
accept === 'application/vnd.yjs.doc' ||
|
||||
accept === 'application/octet-stream'
|
||||
) {
|
||||
res
|
||||
.status(200)
|
||||
.setHeader('content-type', 'application/octet-stream')
|
||||
.send(Y.encodeStateAsUpdate(yDocument));
|
||||
} else if (accept === 'text/markdown') {
|
||||
res
|
||||
.status(200)
|
||||
.setHeader('content-type', 'text/markdown')
|
||||
.send(await editor.blocksToMarkdownLossy(blocks));
|
||||
} else if (accept === 'text/html') {
|
||||
res
|
||||
.status(200)
|
||||
.setHeader('content-type', 'text/html')
|
||||
.send(await editor.blocksToHTMLLossy(blocks));
|
||||
} else {
|
||||
res.status(406).json({ error: 'Unsupported format' });
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger('conversion failed:', e);
|
||||
res.status(500).json({ error: 'An error occurred' });
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
environments:
|
||||
dev:
|
||||
values:
|
||||
- version: 3.9.0
|
||||
- version: 3.8.2
|
||||
feature:
|
||||
values:
|
||||
- version: 3.9.0
|
||||
- version: 3.8.2
|
||||
feature: ci
|
||||
domain: example.com
|
||||
imageTag: demo
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
type: application
|
||||
name: docs
|
||||
version: 3.9.0
|
||||
version: 3.8.2
|
||||
appVersion: latest
|
||||
|
||||
@@ -166,14 +166,6 @@ Requires top level scope
|
||||
{{ include "impress.fullname" . }}-y-provider
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Full name for the docSpecApi
|
||||
|
||||
Requires top level scope
|
||||
*/}}
|
||||
{{- define "impress.docSpecApi.fullname" -}}
|
||||
{{ include "impress.fullname" . }}-docspec-api
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Full name for the Celery Worker
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
{{- $envVars := include "impress.common.env" (list . .Values.docSpecApi) -}}
|
||||
{{- $fullName := include "impress.docSpecApi.fullname" . -}}
|
||||
{{- $component := "docspec" -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
{{- with .Values.backend.dpAnnotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.docSpecApi.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.docSpecApi.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
|
||||
spec:
|
||||
{{- if $.Values.image.credentials }}
|
||||
imagePullSecrets:
|
||||
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
|
||||
{{- end}}
|
||||
{{- if .Values.docSpecApi.serviceAccountName }}
|
||||
serviceAccountName: {{ .Values.docSpecApi.serviceAccountName }}
|
||||
{{- end }}
|
||||
shareProcessNamespace: {{ .Values.docSpecApi.shareProcessNamespace }}
|
||||
containers:
|
||||
{{- with .Values.docSpecApi.sidecars }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ (.Values.docSpecApi.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.docSpecApi.image | default dict).tag | default .Values.image.tag }}"
|
||||
imagePullPolicy: {{ (.Values.docSpecApi.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
|
||||
{{- with .Values.yPrdocspecovider.command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.docSpecApi.args }}
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
env:
|
||||
{{- if $envVars}}
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.docSpecApi.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.docSpecApi.service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- if .Values.docSpecApi.probes.liveness }}
|
||||
livenessProbe:
|
||||
{{- include "impress.probes.abstract" (merge .Values.docSpecApi.probes.liveness (dict "targetPort" .Values.docSpecApi.service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.docSpecApi.probes.readiness }}
|
||||
readinessProbe:
|
||||
{{- include "impress.probes.abstract" (merge .Values.docSpecApi.probes.readiness (dict "targetPort" .Values.docSpecApi.service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.docSpecApi.probes.startup }}
|
||||
startupProbe:
|
||||
{{- include "impress.probes.abstract" (merge .Values.docSpecApi.probes.startup (dict "targetPort" .Values.docSpecApi.service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.docSpecApi.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
subPath: content
|
||||
{{- end }}
|
||||
{{- range $name, $volume := .Values.docSpecApi.persistence }}
|
||||
- name: "{{ $name }}"
|
||||
mountPath: "{{ $volume.mountPath }}"
|
||||
{{- end }}
|
||||
{{- range .Values.docSpecApi.extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
subPath: {{ .subPath | default "" }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
{{- with .Values.docSpecApi.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.docSpecApi.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.docSpecApi.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
|
||||
{{- end }}
|
||||
{{- range $name, $volume := .Values.docSpecApi.persistence }}
|
||||
- name: "{{ $name }}"
|
||||
{{- if eq $volume.type "emptyDir" }}
|
||||
emptyDir: {}
|
||||
{{- else }}
|
||||
persistentVolumeClaim:
|
||||
claimName: "{{ $fullName }}-{{ $name }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range .Values.docSpecApi.extraVolumes }}
|
||||
- name: {{ .name }}
|
||||
{{- if .existingClaim }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .existingClaim }}
|
||||
{{- else if .hostPath }}
|
||||
hostPath:
|
||||
{{ toYaml .hostPath | nindent 12 }}
|
||||
{{- else if .csi }}
|
||||
csi:
|
||||
{{- toYaml .csi | nindent 12 }}
|
||||
{{- else if .configMap }}
|
||||
configMap:
|
||||
{{- toYaml .configMap | nindent 12 }}
|
||||
{{- else if .emptyDir }}
|
||||
emptyDir:
|
||||
{{- toYaml .emptyDir | nindent 12 }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if .Values.docSpecApi.pdb.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
spec:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
{{ end }}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user