mirror of
https://github.com/docmost/docmost.git
synced 2026-05-10 08:23:05 +08:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 371c796afd | |||
| 65f048e6c4 | |||
| da61d464b2 | |||
| 8eb8de6df7 | |||
| 10d922eb71 | |||
| ab4605c4ad | |||
| a95f3d254d | |||
| 5451efaf5d | |||
| 4ee65525c9 | |||
| d39ba67834 | |||
| 253c9a5d88 | |||
| cdf00a96a9 | |||
| 73b726c7a8 | |||
| d9d6a8e2ae | |||
| 3602860979 | |||
| 537e45bc11 | |||
| 79b79348ba | |||
| b44d6e3138 | |||
| cdd9c5cf66 | |||
| c866c07219 | |||
| 6638ca806c | |||
| adc2341029 | |||
| 27ebcd248f | |||
| 366b8fbdc1 | |||
| 44cba3c581 | |||
| 23c5bf6b66 | |||
| a6b49f49bd | |||
| 24a9403f09 | |||
| e8323708d7 | |||
| b9d28223d9 | |||
| 57ca56744d | |||
| f45c6bead3 | |||
| e02cdf6d59 | |||
| 0f6d0fb440 | |||
| 7025e3c947 | |||
| 53a803383b | |||
| 1d5b5a3002 | |||
| 08a9df37ef | |||
| 63be9a58c1 | |||
| bdc369fce0 | |||
| 696aa430f4 | |||
| ed9d85ca95 | |||
| d992abf8d8 | |||
| 149bcc14f1 | |||
| 8ed4f4b7aa | |||
| fd0200331c | |||
| 44ab6e5485 | |||
| 505d7923db | |||
| 3112709d03 | |||
| 8c9d0389f4 | |||
| afafc8451f | |||
| 0a4bbd5d30 | |||
| c802222562 | |||
| be2d93877a | |||
| 34da8d3fb4 | |||
| f55bd21b08 | |||
| f6f9cc14df | |||
| 1790ee8f6f | |||
| 58840da7f4 | |||
| db77b31782 | |||
| 77ba4facb1 | |||
| 6fa08e487e | |||
| 979e8faeee | |||
| 1839418430 | |||
| 94461e90a3 | |||
| 58aa02340e | |||
| 592e6a39e8 | |||
| 56526c6c1c | |||
| 6f9387b8b4 | |||
| aa2ca3ef91 | |||
| 21848b91bf | |||
| 989231d818 | |||
| d50986453b | |||
| 2c21af4e91 | |||
| 574f687335 | |||
| 9956a98d1f | |||
| 14fd3eb956 |
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} ist verfügbar",
|
||||
"Default page edit mode": "Standard-Bearbeitungsmodus für Seiten",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Wählen Sie Ihren bevorzugten Seitenbearbeitungsmodus. Vermeiden Sie versehentliche Bearbeitungen.",
|
||||
"Choose {{format}} file": "{{format}}-Datei auswählen",
|
||||
"Reading": "Lesen",
|
||||
"Delete member": "Mitglied löschen",
|
||||
"Member deleted successfully": "Mitglied erfolgreich gelöscht",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "Bild überschreitet das Limit von 10 MB.",
|
||||
"Image removed successfully": "Bild erfolgreich entfernt",
|
||||
"API key": "API-Schlüssel",
|
||||
"API key created successfully": "API-Schlüssel erfolgreich erstellt",
|
||||
"API keys": "API-Schlüssel",
|
||||
"API management": "API-Verwaltung",
|
||||
"Are you sure you want to revoke this API key": "Sind Sie sicher, dass Sie diesen API-Schlüssel widerrufen möchten?",
|
||||
"Create API Key": "API-Schlüssel erstellen",
|
||||
"Custom expiration date": "Benutzerdefiniertes Ablaufdatum",
|
||||
"Enter a descriptive token name": "Geben Sie einen beschreibenden Token-Namen ein",
|
||||
"Expiration": "Ablauf",
|
||||
"Expired": "Abgelaufen",
|
||||
"Expires": "Läuft ab",
|
||||
"I've saved my API key": "Ich habe meinen API-Schlüssel gespeichert",
|
||||
"Last use": "Zuletzt verwendet",
|
||||
"No API keys found": "Keine API-Schlüssel gefunden",
|
||||
"No expiration": "Kein Ablauf",
|
||||
"Revoke API key": "API-Schlüssel widerrufen",
|
||||
"Revoked successfully": "Erfolgreich widerrufen",
|
||||
"Select expiration date": "Ablaufdatum wählen",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Diese Aktion kann nicht rückgängig gemacht werden. Alle Anwendungen, die diesen API-Schlüssel verwenden, werden nicht mehr funktionieren.",
|
||||
"Update API key": "API-Schlüssel aktualisieren",
|
||||
"Update": "Aktualisieren",
|
||||
"Update {{credential}}": "{{credential}} aktualisieren",
|
||||
"Manage API keys for all users in the workspace": "Verwalten Sie API-Schlüssel für alle Benutzer im Arbeitsbereich",
|
||||
"Restrict API key creation to admins": "API-Schlüsselerstellung auf Administratoren beschränken",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Nur Administratoren und Eigentümer können neue API-Schlüssel erstellen. Bestehende Mitgliederschlüssel funktionieren weiterhin.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Letzte 7 Tage",
|
||||
"Previous 30 days": "Letzte 30 Tage",
|
||||
"Search chats...": "Chats durchsuchen...",
|
||||
"Search chats": "Chats durchsuchen",
|
||||
"Ask anything... Use @ to mention pages": "Frag etwas ... Verwende @, um Seiten zu erwähnen",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Starten Sie einen neuen Chat, damit er hier angezeigt wird.",
|
||||
"Summarize this page": "Diese Seite zusammenfassen",
|
||||
"Toggle AI Chat": "KI-Chat umschalten",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Versuchen Sie einen anderen Suchbegriff.",
|
||||
"Try again": "Erneut versuchen",
|
||||
"Untitled chat": "Chat ohne Titel",
|
||||
"What can I help you with?": "Womit kann ich Ihnen helfen?"
|
||||
"What can I help you with?": "Womit kann ich Ihnen helfen?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Sind Sie sicher, dass Sie diese(n) {{credential}} widerrufen möchten?",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Stellen Sie Benutzer und Gruppen automatisch über SCIM von Ihrem Identitätsanbieter bereit.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Konfigurieren Sie Ihren Identitätsanbieter mit dieser URL, um Benutzer und Gruppen bereitzustellen.",
|
||||
"Create {{credential}}": "{{credential}} erstellen",
|
||||
"{{credential}} created": "{{credential}} erstellt",
|
||||
"{{credential}} created successfully": "{{credential}} erfolgreich erstellt",
|
||||
"Created by": "Erstellt von",
|
||||
"Custom": "Benutzerdefiniert",
|
||||
"Enable SCIM": "SCIM aktivieren",
|
||||
"Enter a descriptive name": "Geben Sie einen beschreibenden Namen ein",
|
||||
"I've saved my {{credential}}": "Ich habe meine(n) {{credential}} gespeichert",
|
||||
"Important": "Wichtig",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Stellen Sie sicher, dass Sie Ihre(n) {{credential}} jetzt kopieren. Sie können sie/ihn später nicht erneut anzeigen!",
|
||||
"Never": "Nie",
|
||||
"Revoke {{credential}}": "{{credential}} widerrufen",
|
||||
"SCIM endpoint URL": "SCIM-Endpunkt-URL",
|
||||
"SCIM provisioning": "SCIM-Bereitstellung",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM hat Vorrang vor der SSO-Gruppensynchronisierung, solange es aktiviert ist.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Sie haben die maximale Anzahl von {{max}} SCIM-Token erreicht. Löschen Sie ein vorhandenes Token, um ein neues zu erstellen.",
|
||||
"SCIM token": "SCIM-Token",
|
||||
"SCIM tokens": "SCIM-Token",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Diese Aktion kann nicht rückgängig gemacht werden. Ihr Identitätsanbieter wird die Synchronisierung sofort beenden.",
|
||||
"Toggle SCIM provisioning": "SCIM-Bereitstellung umschalten",
|
||||
"Token": "Token",
|
||||
"Page menu": "Seitenmenü",
|
||||
"Expand": "Erweitern",
|
||||
"Collapse": "Reduzieren",
|
||||
"Comment menu": "Kommentarmenü",
|
||||
"Group menu": "Gruppenmenü",
|
||||
"Show hidden breadcrumbs": "Ausgeblendete Breadcrumbs anzeigen",
|
||||
"Breadcrumbs": "Navigationspfade",
|
||||
"Page actions": "Seitenaktionen",
|
||||
"Pick emoji": "Emoji auswählen",
|
||||
"Template menu": "Vorlagenmenü",
|
||||
"Chat menu": "Chatmenü",
|
||||
"API key menu": "API-Schlüssel-Menü",
|
||||
"Jump to comment selection": "Zur Kommentarauswahl springen",
|
||||
"Slash commands": "Slash-Befehle",
|
||||
"Mention suggestions": "Erwähnungsvorschläge",
|
||||
"Link suggestions": "Linkvorschläge",
|
||||
"Diagram editor": "Diagrammeditor",
|
||||
"Add comment": "Kommentar hinzufügen",
|
||||
"Find and replace": "Suchen und ersetzen",
|
||||
"Main navigation": "Hauptnavigation",
|
||||
"Space navigation": "Bereichsnavigation",
|
||||
"Settings navigation": "Einstellungsnavigation",
|
||||
"AI navigation": "KI-Navigation",
|
||||
"Breadcrumb": "Navigationspfad",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -970,5 +970,18 @@
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo"
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} está disponible",
|
||||
"Default page edit mode": "Modo de edición predeterminado de la página",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Elige tu modo de edición de página preferido. Evita ediciones accidentales.",
|
||||
"Choose {{format}} file": "Elegir archivo {{format}}",
|
||||
"Reading": "Lectura",
|
||||
"Delete member": "Eliminar miembro",
|
||||
"Member deleted successfully": "Miembro eliminado correctamente",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "La imagen excede del límite de 10 MB",
|
||||
"Image removed successfully": "Imagen eliminada correctamente",
|
||||
"API key": "Clave API",
|
||||
"API key created successfully": "Clave API creada correctamente",
|
||||
"API keys": "Claves API",
|
||||
"API management": "Gestión de API",
|
||||
"Are you sure you want to revoke this API key": "¿Está seguro de que desea revocar esta clave API? ",
|
||||
"Create API Key": "Crear clave API",
|
||||
"Custom expiration date": "Fecha de vencimiento personalizada",
|
||||
"Enter a descriptive token name": "Introduce un nombre descriptivo del token",
|
||||
"Expiration": "Vencimiento",
|
||||
"Expired": "Vencido",
|
||||
"Expires": "Vence",
|
||||
"I've saved my API key": "He guardado mi clave API",
|
||||
"Last use": "Último uso",
|
||||
"No API keys found": "No se han encontrado claves API",
|
||||
"No expiration": "Sin vencimiento",
|
||||
"Revoke API key": "Revocar clave API",
|
||||
"Revoked successfully": "Revocada correctamente",
|
||||
"Select expiration date": "Seleccionar fecha de vencimiento",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Esta acción no se puede deshacer. Las aplicaciones que utilicen esta clave API dejarán de funcionar.",
|
||||
"Update API key": "Actualizar clave API",
|
||||
"Update": "Actualizar",
|
||||
"Update {{credential}}": "Actualizar {{credential}}",
|
||||
"Manage API keys for all users in the workspace": "Gestionar claves API para todos los usuarios en el espacio de trabajo",
|
||||
"Restrict API key creation to admins": "Restringir la creación de claves API a administradores",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Solo los administradores y propietarios pueden crear nuevas claves API. Las claves de miembros existentes seguirán funcionando.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Últimos 7 días",
|
||||
"Previous 30 days": "Últimos 30 días",
|
||||
"Search chats...": "Buscar chats...",
|
||||
"Search chats": "Buscar chats",
|
||||
"Ask anything... Use @ to mention pages": "Pregunta lo que sea... Usa @ para mencionar páginas",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Inicia un nuevo chat para verlo aquí.",
|
||||
"Summarize this page": "Resumir esta página",
|
||||
"Toggle AI Chat": "Alternar chat de IA",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Prueba con otro término de búsqueda.",
|
||||
"Try again": "Intentar de nuevo",
|
||||
"Untitled chat": "Chat sin título",
|
||||
"What can I help you with?": "¿En qué puedo ayudarte?"
|
||||
"What can I help you with?": "¿En qué puedo ayudarte?",
|
||||
"Are you sure you want to revoke this {{credential}}": "¿Está seguro de que desea revocar esta {{credential}}?",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Aprovisione automáticamente usuarios y grupos desde su proveedor de identidad mediante SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Configure su proveedor de identidad con esta URL para aprovisionar usuarios y grupos.",
|
||||
"Create {{credential}}": "Crear {{credential}}",
|
||||
"{{credential}} created": "{{credential}} creada",
|
||||
"{{credential}} created successfully": "{{credential}} creada con éxito",
|
||||
"Created by": "Creado por",
|
||||
"Custom": "Personalizado",
|
||||
"Enable SCIM": "Habilitar SCIM",
|
||||
"Enter a descriptive name": "Introduzca un nombre descriptivo",
|
||||
"I've saved my {{credential}}": "He guardado mi {{credential}}",
|
||||
"Important": "Importante",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Asegúrese de copiar su {{credential}} ahora. ¡No podrá volver a verla!",
|
||||
"Never": "Nunca",
|
||||
"Revoke {{credential}}": "Revocar {{credential}}",
|
||||
"SCIM endpoint URL": "URL del endpoint de SCIM",
|
||||
"SCIM provisioning": "Aprovisionamiento SCIM",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM tiene prioridad sobre la sincronización de grupos de SSO mientras esté habilitado.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Ha alcanzado el máximo de {{max}} tokens SCIM. Elimine un token existente para crear uno nuevo.",
|
||||
"SCIM token": "Token SCIM",
|
||||
"SCIM tokens": "Tokens SCIM",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Esta acción no se puede deshacer. Su proveedor de identidad dejará de sincronizarse inmediatamente.",
|
||||
"Toggle SCIM provisioning": "Activar o desactivar el aprovisionamiento SCIM",
|
||||
"Token": "Token",
|
||||
"Page menu": "Menú de la página",
|
||||
"Expand": "Expandir",
|
||||
"Collapse": "Contraer",
|
||||
"Comment menu": "Menú de comentarios",
|
||||
"Group menu": "Menú del grupo",
|
||||
"Show hidden breadcrumbs": "Mostrar rutas de navegación ocultas",
|
||||
"Breadcrumbs": "Rutas de navegación",
|
||||
"Page actions": "Acciones de la página",
|
||||
"Pick emoji": "Elegir emoji",
|
||||
"Template menu": "Menú de plantillas",
|
||||
"Chat menu": "Menú del chat",
|
||||
"API key menu": "Menú de la clave API",
|
||||
"Jump to comment selection": "Ir a la selección de comentarios",
|
||||
"Slash commands": "Comandos de barra",
|
||||
"Mention suggestions": "Sugerencias de menciones",
|
||||
"Link suggestions": "Sugerencias de enlaces",
|
||||
"Diagram editor": "Editor de diagramas",
|
||||
"Add comment": "Agregar comentario",
|
||||
"Find and replace": "Buscar y reemplazar",
|
||||
"Main navigation": "Navegación principal",
|
||||
"Space navigation": "Navegación del espacio",
|
||||
"Settings navigation": "Navegación de configuración",
|
||||
"AI navigation": "Navegación de IA",
|
||||
"Breadcrumb": "Ruta de navegación",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} est disponible",
|
||||
"Default page edit mode": "Mode d’édition par défaut de la page",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Choisissez votre mode d'édition de page préféré. Évitez les modifications accidentelles.",
|
||||
"Choose {{format}} file": "Choisir un fichier {{format}}",
|
||||
"Reading": "Lecture",
|
||||
"Delete member": "Supprimer le membre",
|
||||
"Member deleted successfully": "Membre supprimé avec succès",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "L'image dépasse la limite de 10 Mo.",
|
||||
"Image removed successfully": "Image supprimée avec succès",
|
||||
"API key": "Clé API",
|
||||
"API key created successfully": "Clé API créée avec succès",
|
||||
"API keys": "Clés API",
|
||||
"API management": "Gestion des API",
|
||||
"Are you sure you want to revoke this API key": "Êtes-vous sûr de vouloir révoquer cette clé API",
|
||||
"Create API Key": "Créer une clé API",
|
||||
"Custom expiration date": "Date d'expiration personnalisée",
|
||||
"Enter a descriptive token name": "Entrez un nom descriptif pour le jeton",
|
||||
"Expiration": "Expiration",
|
||||
"Expired": "Expiré(e)",
|
||||
"Expires": "Expire",
|
||||
"I've saved my API key": "J'ai enregistré ma clé API",
|
||||
"Last use": "Dernière utilisation",
|
||||
"No API keys found": "Aucune clé API trouvée",
|
||||
"No expiration": "Pas d'expiration",
|
||||
"Revoke API key": "Révoquer la clé API",
|
||||
"Revoked successfully": "Révoqué(e) avec succès",
|
||||
"Select expiration date": "Sélectionnez la date d'expiration",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Cette action ne peut pas être annulée. Toutes les applications utilisant cette clé API cesseront de fonctionner.",
|
||||
"Update API key": "Mettre à jour la clé API",
|
||||
"Update": "Mettre à jour",
|
||||
"Update {{credential}}": "Mettre à jour {{credential}}",
|
||||
"Manage API keys for all users in the workspace": "Gérer les clés API pour tous les utilisateurs dans l'espace de travail",
|
||||
"Restrict API key creation to admins": "Restreindre la création de clés API aux administrateurs",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Seuls les administrateurs et les propriétaires peuvent créer de nouvelles clés API. Les clés des membres existants continueront de fonctionner.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "7 derniers jours",
|
||||
"Previous 30 days": "30 derniers jours",
|
||||
"Search chats...": "Rechercher des discussions...",
|
||||
"Search chats": "Rechercher des discussions",
|
||||
"Ask anything... Use @ to mention pages": "Demandez n’importe quoi… Utilisez @ pour mentionner des pages",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Commencez une nouvelle discussion pour la voir ici.",
|
||||
"Summarize this page": "Résumer cette page",
|
||||
"Toggle AI Chat": "Basculer le chat IA",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Essayez un autre terme de recherche.",
|
||||
"Try again": "Réessayer",
|
||||
"Untitled chat": "Discussion sans titre",
|
||||
"What can I help you with?": "Que puis-je faire pour vous aider ?"
|
||||
"What can I help you with?": "Que puis-je faire pour vous aider ?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Êtes-vous sûr de vouloir révoquer ce/cette {{credential}}",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Provisionnez automatiquement les utilisateurs et les groupes depuis votre fournisseur d’identité via SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Configurez votre fournisseur d’identité avec cette URL pour provisionner les utilisateurs et les groupes.",
|
||||
"Create {{credential}}": "Créer {{credential}}",
|
||||
"{{credential}} created": "{{credential}} créé",
|
||||
"{{credential}} created successfully": "{{credential}} créé avec succès",
|
||||
"Created by": "Créé par",
|
||||
"Custom": "Personnalisé",
|
||||
"Enable SCIM": "Activer SCIM",
|
||||
"Enter a descriptive name": "Saisissez un nom descriptif",
|
||||
"I've saved my {{credential}}": "J’ai enregistré mon/ma {{credential}}",
|
||||
"Important": "Important",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Assurez-vous de copier votre {{credential}} maintenant. Vous ne pourrez plus le/la voir ensuite !",
|
||||
"Never": "Jamais",
|
||||
"Revoke {{credential}}": "Révoquer {{credential}}",
|
||||
"SCIM endpoint URL": "URL du point de terminaison SCIM",
|
||||
"SCIM provisioning": "Provisionnement SCIM",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM a priorité sur la synchronisation des groupes SSO lorsqu’il est activé.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Vous avez atteint le maximum de {{max}} jetons SCIM. Supprimez un jeton existant pour en créer un nouveau.",
|
||||
"SCIM token": "Jeton SCIM",
|
||||
"SCIM tokens": "Jetons SCIM",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Cette action est irréversible. Votre fournisseur d’identité cessera immédiatement la synchronisation.",
|
||||
"Toggle SCIM provisioning": "Activer/désactiver le provisionnement SCIM",
|
||||
"Token": "Jeton",
|
||||
"Page menu": "Menu de la page",
|
||||
"Expand": "Développer",
|
||||
"Collapse": "Réduire",
|
||||
"Comment menu": "Menu du commentaire",
|
||||
"Group menu": "Menu du groupe",
|
||||
"Show hidden breadcrumbs": "Afficher les fils d’Ariane masqués",
|
||||
"Breadcrumbs": "Fils d’Ariane",
|
||||
"Page actions": "Actions de la page",
|
||||
"Pick emoji": "Choisir un emoji",
|
||||
"Template menu": "Menu du modèle",
|
||||
"Chat menu": "Menu du chat",
|
||||
"API key menu": "Menu de la clé API",
|
||||
"Jump to comment selection": "Aller à la sélection de commentaires",
|
||||
"Slash commands": "Commandes slash",
|
||||
"Mention suggestions": "Suggestions de mention",
|
||||
"Link suggestions": "Suggestions de liens",
|
||||
"Diagram editor": "Éditeur de diagrammes",
|
||||
"Add comment": "Ajouter un commentaire",
|
||||
"Find and replace": "Rechercher et remplacer",
|
||||
"Main navigation": "Navigation principale",
|
||||
"Space navigation": "Navigation de l’espace",
|
||||
"Settings navigation": "Navigation des paramètres",
|
||||
"AI navigation": "Navigation IA",
|
||||
"Breadcrumb": "Fil d’Ariane",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} è disponibile",
|
||||
"Default page edit mode": "Modalità di modifica predefinita della pagina",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Scegli la tua modalità di modifica della pagina preferita. Evita modifiche accidentali.",
|
||||
"Choose {{format}} file": "Scegli file {{format}}",
|
||||
"Reading": "Lettura",
|
||||
"Delete member": "Elimina membro",
|
||||
"Member deleted successfully": "Membro eliminato con successo",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "L'immagine supera il limite di 10MB.",
|
||||
"Image removed successfully": "Immagine rimossa con successo",
|
||||
"API key": "Chiave API",
|
||||
"API key created successfully": "Chiave API creata con successo",
|
||||
"API keys": "Chiavi API",
|
||||
"API management": "Gestione API",
|
||||
"Are you sure you want to revoke this API key": "Sei sicuro di voler revocare questa chiave API",
|
||||
"Create API Key": "Crea Chiave API",
|
||||
"Custom expiration date": "Data di scadenza personalizzata",
|
||||
"Enter a descriptive token name": "Inserisci un nome descrittivo del token",
|
||||
"Expiration": "Scadenza",
|
||||
"Expired": "Scaduto",
|
||||
"Expires": "Scade",
|
||||
"I've saved my API key": "Ho salvato la mia chiave API",
|
||||
"Last use": "Ultimo utilizzo",
|
||||
"No API keys found": "Nessuna chiave API trovata",
|
||||
"No expiration": "Nessuna scadenza",
|
||||
"Revoke API key": "Revoca chiave API",
|
||||
"Revoked successfully": "Revocata con successo",
|
||||
"Select expiration date": "Seleziona la data di scadenza",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Questa azione non può essere annullata. Qualsiasi applicazione che utilizza questa chiave API smetterà di funzionare.",
|
||||
"Update API key": "Aggiorna chiave API",
|
||||
"Update": "Aggiorna",
|
||||
"Update {{credential}}": "Aggiorna {{credential}}",
|
||||
"Manage API keys for all users in the workspace": "Gestisci le chiavi API per tutti gli utenti nell'area di lavoro",
|
||||
"Restrict API key creation to admins": "Limita la creazione delle chiavi API agli amministratori",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Solo gli amministratori e i proprietari possono creare nuove chiavi API. Le chiavi dei membri esistenti continueranno a funzionare.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Ultimi 7 giorni",
|
||||
"Previous 30 days": "Ultimi 30 giorni",
|
||||
"Search chats...": "Cerca nelle chat...",
|
||||
"Search chats": "Cerca nelle chat",
|
||||
"Ask anything... Use @ to mention pages": "Chiedi qualsiasi cosa... Usa @ per menzionare le pagine",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Avvia una nuova chat per vederla qui.",
|
||||
"Summarize this page": "Riassumi questa pagina",
|
||||
"Toggle AI Chat": "Attiva/disattiva Chat IA",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Prova un termine di ricerca diverso.",
|
||||
"Try again": "Riprova",
|
||||
"Untitled chat": "Chat senza titolo",
|
||||
"What can I help you with?": "Con cosa posso aiutarti?"
|
||||
"What can I help you with?": "Con cosa posso aiutarti?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Sei sicuro di voler revocare questa {{credential}}",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Esegui automaticamente il provisioning di utenti e gruppi dal tuo provider di identità tramite SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Configura il tuo provider di identità con questo URL per eseguire il provisioning di utenti e gruppi.",
|
||||
"Create {{credential}}": "Crea {{credential}}",
|
||||
"{{credential}} created": "{{credential}} creata",
|
||||
"{{credential}} created successfully": "{{credential}} creata con successo",
|
||||
"Created by": "Creata da",
|
||||
"Custom": "Personalizzato",
|
||||
"Enable SCIM": "Abilita SCIM",
|
||||
"Enter a descriptive name": "Inserisci un nome descrittivo",
|
||||
"I've saved my {{credential}}": "Ho salvato la mia {{credential}}",
|
||||
"Important": "Importante",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Assicurati di copiare subito la tua {{credential}}. Non potrai più visualizzarla!",
|
||||
"Never": "Mai",
|
||||
"Revoke {{credential}}": "Revoca {{credential}}",
|
||||
"SCIM endpoint URL": "URL dell'endpoint SCIM",
|
||||
"SCIM provisioning": "Provisioning SCIM",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM ha la precedenza sulla sincronizzazione dei gruppi SSO quando è abilitato.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Hai raggiunto il numero massimo di {{max}} token SCIM. Elimina un token esistente per crearne uno nuovo.",
|
||||
"SCIM token": "Token SCIM",
|
||||
"SCIM tokens": "Token SCIM",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Questa azione non può essere annullata. Il tuo provider di identità smetterà di sincronizzarsi immediatamente.",
|
||||
"Toggle SCIM provisioning": "Attiva/disattiva il provisioning SCIM",
|
||||
"Token": "Token",
|
||||
"Page menu": "Menu della pagina",
|
||||
"Expand": "Espandi",
|
||||
"Collapse": "Comprimi",
|
||||
"Comment menu": "Menu dei commenti",
|
||||
"Group menu": "Menu del gruppo",
|
||||
"Show hidden breadcrumbs": "Mostra breadcrumb nascosti",
|
||||
"Breadcrumbs": "Breadcrumb",
|
||||
"Page actions": "Azioni della pagina",
|
||||
"Pick emoji": "Scegli emoji",
|
||||
"Template menu": "Menu del modello",
|
||||
"Chat menu": "Menu della chat",
|
||||
"API key menu": "Menu della chiave API",
|
||||
"Jump to comment selection": "Vai alla selezione dei commenti",
|
||||
"Slash commands": "Comandi slash",
|
||||
"Mention suggestions": "Suggerimenti di menzione",
|
||||
"Link suggestions": "Suggerimenti di link",
|
||||
"Diagram editor": "Editor di diagrammi",
|
||||
"Add comment": "Aggiungi commento",
|
||||
"Find and replace": "Trova e sostituisci",
|
||||
"Main navigation": "Navigazione principale",
|
||||
"Space navigation": "Navigazione dello spazio",
|
||||
"Settings navigation": "Navigazione delle impostazioni",
|
||||
"AI navigation": "Navigazione AI",
|
||||
"Breadcrumb": "Percorso di navigazione",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} が利用可能です",
|
||||
"Default page edit mode": "デフォルトのページ編集モード",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "お好みのページ編集モードを選択してください(誤編集を防止します)",
|
||||
"Choose {{format}} file": "{{format}} ファイルを選択",
|
||||
"Reading": "閲覧",
|
||||
"Delete member": "メンバーを削除",
|
||||
"Member deleted successfully": "メンバーが正常に削除されました",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "画像が10MBの制限を超えています",
|
||||
"Image removed successfully": "画像を削除しました",
|
||||
"API key": "APIキー",
|
||||
"API key created successfully": "APIキーを作成しました",
|
||||
"API keys": "APIキー",
|
||||
"API management": "API管理",
|
||||
"Are you sure you want to revoke this API key": "このAPIキーを無効にしてもよろしいですか",
|
||||
"Create API Key": "APIキーを作成",
|
||||
"Custom expiration date": "カスタム有効期限",
|
||||
"Enter a descriptive token name": "説明的なトークン名を入力してください",
|
||||
"Expiration": "有効期限",
|
||||
"Expired": "期限切れ",
|
||||
"Expires": "期限が切れます",
|
||||
"I've saved my API key": "APIキーを保存しました",
|
||||
"Last use": "最終使用",
|
||||
"No API keys found": "APIキーが見つかりません",
|
||||
"No expiration": "期限なし",
|
||||
"Revoke API key": "APIキーを無効にする",
|
||||
"Revoked successfully": "無効にしました",
|
||||
"Select expiration date": "有効期限を選択してください",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "この操作は取り消せません。このAPIキーを使用しているアプリケーションは動作しなくなります",
|
||||
"Update API key": "APIキーを更新",
|
||||
"Update": "更新",
|
||||
"Update {{credential}}": "{{credential}}を更新",
|
||||
"Manage API keys for all users in the workspace": "ワークスペース内のすべてのユーザーのAPIキーを管理",
|
||||
"Restrict API key creation to admins": "APIキーの作成を管理者のみに制限する",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "新しいAPIキーを作成できるのは管理者とオーナーのみです。既存のメンバーキーは引き続き有効です。",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "過去 7 日間",
|
||||
"Previous 30 days": "過去 30 日間",
|
||||
"Search chats...": "チャットを検索...",
|
||||
"Search chats": "チャットを検索",
|
||||
"Ask anything... Use @ to mention pages": "何でも質問してください… @ を使ってページにメンションできます",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "ここに表示するには新しいチャットを開始してください。",
|
||||
"Summarize this page": "このページを要約",
|
||||
"Toggle AI Chat": "AI チャットを切り替え",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "別の検索語を試してください。",
|
||||
"Try again": "再試行",
|
||||
"Untitled chat": "無題のチャット",
|
||||
"What can I help you with?": "何をお手伝いしましょうか?"
|
||||
"What can I help you with?": "何をお手伝いしましょうか?",
|
||||
"Are you sure you want to revoke this {{credential}}": "この{{credential}}を無効にしてもよろしいですか",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "SCIM を介して、ID プロバイダーからユーザーとグループを自動的にプロビジョニングします。",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "この URL を使用して ID プロバイダーを設定し、ユーザーとグループをプロビジョニングします。",
|
||||
"Create {{credential}}": "{{credential}}を作成",
|
||||
"{{credential}} created": "{{credential}}を作成しました",
|
||||
"{{credential}} created successfully": "{{credential}}を正常に作成しました",
|
||||
"Created by": "作成者",
|
||||
"Custom": "カスタム",
|
||||
"Enable SCIM": "SCIM を有効にする",
|
||||
"Enter a descriptive name": "説明的な名前を入力してください",
|
||||
"I've saved my {{credential}}": "{{credential}}を保存しました",
|
||||
"Important": "重要",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "今すぐ {{credential}} をコピーしてください。後でもう一度表示することはできません!",
|
||||
"Never": "なし",
|
||||
"Revoke {{credential}}": "{{credential}}を無効にする",
|
||||
"SCIM endpoint URL": "SCIM エンドポイント URL",
|
||||
"SCIM provisioning": "SCIM プロビジョニング",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "有効になっている間は、SCIM が SSO グループ同期より優先されます。",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "SCIM トークンの上限 {{max}} に達しました。新しいトークンを作成するには、既存のトークンを削除してください。",
|
||||
"SCIM token": "SCIM トークン",
|
||||
"SCIM tokens": "SCIM トークン",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "この操作は元に戻せません。ID プロバイダーは直ちに同期を停止します。",
|
||||
"Toggle SCIM provisioning": "SCIM プロビジョニングを切り替える",
|
||||
"Token": "トークン",
|
||||
"Page menu": "ページメニュー",
|
||||
"Expand": "展開",
|
||||
"Collapse": "折りたたむ",
|
||||
"Comment menu": "コメントメニュー",
|
||||
"Group menu": "グループメニュー",
|
||||
"Show hidden breadcrumbs": "非表示のパンくずリストを表示",
|
||||
"Breadcrumbs": "パンくずリスト",
|
||||
"Page actions": "ページアクション",
|
||||
"Pick emoji": "絵文字を選択",
|
||||
"Template menu": "テンプレートメニュー",
|
||||
"Chat menu": "チャットメニュー",
|
||||
"API key menu": "API キーメニュー",
|
||||
"Jump to comment selection": "コメント選択に移動",
|
||||
"Slash commands": "スラッシュコマンド",
|
||||
"Mention suggestions": "メンション候補",
|
||||
"Link suggestions": "リンク候補",
|
||||
"Diagram editor": "ダイアグラムエディター",
|
||||
"Add comment": "コメントを追加",
|
||||
"Find and replace": "検索と置換",
|
||||
"Main navigation": "メインナビゲーション",
|
||||
"Space navigation": "スペースナビゲーション",
|
||||
"Settings navigation": "設定ナビゲーション",
|
||||
"AI navigation": "AI ナビゲーション",
|
||||
"Breadcrumb": "パンくずリスト",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} 버전을 사용할 수 있습니다",
|
||||
"Default page edit mode": "기본 페이지 편집 모드",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "선호하는 페이지 편집 모드를 선택하세요. 실수로 인한 편집을 방지하세요.",
|
||||
"Choose {{format}} file": "{{format}} 파일 선택",
|
||||
"Reading": "읽기",
|
||||
"Delete member": "멤버 삭제",
|
||||
"Member deleted successfully": "멤버가 성공적으로 삭제되었습니다",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "이미지가 10MB 용량 제한을 초과합니다.",
|
||||
"Image removed successfully": "이미지가 성공적으로 제거되었습니다",
|
||||
"API key": "API 키",
|
||||
"API key created successfully": "API 키 생성 완료",
|
||||
"API keys": "API 키",
|
||||
"API management": "API 관리",
|
||||
"Are you sure you want to revoke this API key": "이 API 키를 취소하시겠습니까?",
|
||||
"Create API Key": "API 키 생성",
|
||||
"Custom expiration date": "사용자 정의 만료일",
|
||||
"Enter a descriptive token name": "토큰 이름을 입력하세요",
|
||||
"Expiration": "만료",
|
||||
"Expired": "만료됨",
|
||||
"Expires": "만료일",
|
||||
"I've saved my API key": "API 키를 저장했습니다",
|
||||
"Last use": "최근 사용",
|
||||
"No API keys found": "API 키를 찾을 수 없습니다",
|
||||
"No expiration": "유효기간 없음",
|
||||
"Revoke API key": "API 키 취소",
|
||||
"Revoked successfully": "성공적으로 취소되었습니다",
|
||||
"Select expiration date": "만료일 선택",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "이 작업은 되돌릴 수 없습니다. 이 API 키를 사용하는 모든 응용 프로그램이 작동을 멈출 것입니다.",
|
||||
"Update API key": "API 키 갱신",
|
||||
"Update": "업데이트",
|
||||
"Update {{credential}}": "{{credential}} 업데이트",
|
||||
"Manage API keys for all users in the workspace": "워크스페이스 내 모든 사용자의 API 키 관리",
|
||||
"Restrict API key creation to admins": "API 키 생성 권한을 관리자에게만 제한합니다",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "새로운 API 키는 관리자와 소유자만 생성할 수 있습니다. 기존 멤버 키는 계속 사용할 수 있습니다.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "지난 7일",
|
||||
"Previous 30 days": "지난 30일",
|
||||
"Search chats...": "채팅 검색...",
|
||||
"Search chats": "채팅 검색",
|
||||
"Ask anything... Use @ to mention pages": "무엇이든 물어보세요... 페이지를 언급하려면 @를 사용하세요",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "여기에 표시하려면 새 채팅을 시작하세요.",
|
||||
"Summarize this page": "이 페이지 요약",
|
||||
"Toggle AI Chat": "AI 채팅 전환",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "다른 검색어를 사용해 보세요.",
|
||||
"Try again": "다시 시도",
|
||||
"Untitled chat": "제목 없는 채팅",
|
||||
"What can I help you with?": "무엇을 도와드릴까요?"
|
||||
"What can I help you with?": "무엇을 도와드릴까요?",
|
||||
"Are you sure you want to revoke this {{credential}}": "이 {{credential}}을 취소하시겠습니까?",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "SCIM을 통해 ID 공급자에서 사용자와 그룹을 자동으로 프로비저닝합니다.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "사용자와 그룹을 프로비저닝할 수 있도록 이 URL로 ID 공급자를 구성하세요.",
|
||||
"Create {{credential}}": "{{credential}} 만들기",
|
||||
"{{credential}} created": "{{credential}} 생성됨",
|
||||
"{{credential}} created successfully": "{{credential}} 생성 완료",
|
||||
"Created by": "생성한 사람",
|
||||
"Custom": "사용자 지정",
|
||||
"Enable SCIM": "SCIM 활성화",
|
||||
"Enter a descriptive name": "설명적인 이름을 입력하세요",
|
||||
"I've saved my {{credential}}": "내 {{credential}}를 저장했습니다",
|
||||
"Important": "중요",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "지금 {{credential}}를 복사해 두세요. 다시는 볼 수 없습니다!",
|
||||
"Never": "안 함",
|
||||
"Revoke {{credential}}": "{{credential}} 취소",
|
||||
"SCIM endpoint URL": "SCIM 엔드포인트 URL",
|
||||
"SCIM provisioning": "SCIM 프로비저닝",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM이 활성화되어 있는 동안에는 SSO 그룹 동기화보다 SCIM이 우선 적용됩니다.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "SCIM 토큰은 최대 {{max}}개까지 만들 수 있습니다. 새 토큰을 만들려면 기존 토큰을 삭제하세요.",
|
||||
"SCIM token": "SCIM 토큰",
|
||||
"SCIM tokens": "SCIM 토큰",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "이 작업은 되돌릴 수 없습니다. ID 공급자가 즉시 동기화를 중지합니다.",
|
||||
"Toggle SCIM provisioning": "SCIM 프로비저닝 전환",
|
||||
"Token": "토큰",
|
||||
"Page menu": "페이지 메뉴",
|
||||
"Expand": "펼치기",
|
||||
"Collapse": "접기",
|
||||
"Comment menu": "댓글 메뉴",
|
||||
"Group menu": "그룹 메뉴",
|
||||
"Show hidden breadcrumbs": "숨겨진 이동 경로 표시",
|
||||
"Breadcrumbs": "이동 경로",
|
||||
"Page actions": "페이지 작업",
|
||||
"Pick emoji": "이모지 선택",
|
||||
"Template menu": "템플릿 메뉴",
|
||||
"Chat menu": "채팅 메뉴",
|
||||
"API key menu": "API 키 메뉴",
|
||||
"Jump to comment selection": "댓글 선택으로 이동",
|
||||
"Slash commands": "슬래시 명령어",
|
||||
"Mention suggestions": "멘션 추천",
|
||||
"Link suggestions": "링크 추천",
|
||||
"Diagram editor": "다이어그램 편집기",
|
||||
"Add comment": "댓글 추가",
|
||||
"Find and replace": "찾기 및 바꾸기",
|
||||
"Main navigation": "기본 탐색",
|
||||
"Space navigation": "스페이스 탐색",
|
||||
"Settings navigation": "설정 탐색",
|
||||
"AI navigation": "AI 탐색",
|
||||
"Breadcrumb": "이동 경로",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} is beschikbaar",
|
||||
"Default page edit mode": "Standaard bewerkingsmodus voor pagina",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Kies uw voorkeurs bewerkmodus voor pagina's. Vermijd per ongeluk bewerken.",
|
||||
"Choose {{format}} file": "Kies {{format}}-bestand",
|
||||
"Reading": "Lezen",
|
||||
"Delete member": "Lid verwijderen",
|
||||
"Member deleted successfully": "Lid succesvol verwijderd",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "Afbeelding overschrijdt de limiet van 10MB.",
|
||||
"Image removed successfully": "Afbeelding succesvol verwijderd",
|
||||
"API key": "API-sleutel",
|
||||
"API key created successfully": "API-sleutel succesvol aangemaakt",
|
||||
"API keys": "API-sleutels",
|
||||
"API management": "API-beheer",
|
||||
"Are you sure you want to revoke this API key": "Weet u zeker dat u deze API-sleutel wilt intrekken",
|
||||
"Create API Key": "API-sleutel aanmaken",
|
||||
"Custom expiration date": "Aangepaste vervaldatum",
|
||||
"Enter a descriptive token name": "Voer een beschrijvende tokennaam in",
|
||||
"Expiration": "Vervaldatum",
|
||||
"Expired": "Verlopen",
|
||||
"Expires": "Verloopt",
|
||||
"I've saved my API key": "Ik heb mijn API-sleutel opgeslagen",
|
||||
"Last use": "Laatst gebruikt",
|
||||
"No API keys found": "Geen API-sleutels gevonden",
|
||||
"No expiration": "Geen vervaldatum",
|
||||
"Revoke API key": "API-sleutel intrekken",
|
||||
"Revoked successfully": "Succesvol ingetrokken",
|
||||
"Select expiration date": "Selecteer vervaldatum",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Deze actie kan niet ongedaan worden gemaakt. Alle toepassingen die deze API-sleutel gebruiken, zullen niet meer werken.",
|
||||
"Update API key": "API-sleutel bijwerken",
|
||||
"Update": "Bijwerken",
|
||||
"Update {{credential}}": "{{credential}} bijwerken",
|
||||
"Manage API keys for all users in the workspace": "Beheer API-sleutels voor alle gebruikers in de werkruimte",
|
||||
"Restrict API key creation to admins": "Beperk het aanmaken van API-sleutels tot beheerders.",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Alleen beheerders en eigenaren kunnen nieuwe API-sleutels aanmaken. Bestaande leden-sleutels blijven werken.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Afgelopen 7 dagen",
|
||||
"Previous 30 days": "Afgelopen 30 dagen",
|
||||
"Search chats...": "Chats zoeken...",
|
||||
"Search chats": "Chats zoeken",
|
||||
"Ask anything... Use @ to mention pages": "Vraag iets... Gebruik @ om pagina's te vermelden",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Start een nieuwe chat om die hier te zien.",
|
||||
"Summarize this page": "Vat deze pagina samen",
|
||||
"Toggle AI Chat": "AI-chat in-/uitschakelen",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Probeer een andere zoekterm.",
|
||||
"Try again": "Probeer opnieuw",
|
||||
"Untitled chat": "Chat zonder titel",
|
||||
"What can I help you with?": "Waar kan ik je mee helpen?"
|
||||
"What can I help you with?": "Waar kan ik je mee helpen?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Weet u zeker dat u deze {{credential}} wilt intrekken",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Voorzie gebruikers en groepen automatisch vanuit uw identiteitsprovider via SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Configureer uw identiteitsprovider met deze URL om gebruikers en groepen te provisioneren.",
|
||||
"Create {{credential}}": "{{credential}} maken",
|
||||
"{{credential}} created": "{{credential}} aangemaakt",
|
||||
"{{credential}} created successfully": "{{credential}} succesvol aangemaakt",
|
||||
"Created by": "Aangemaakt door",
|
||||
"Custom": "Aangepast",
|
||||
"Enable SCIM": "SCIM inschakelen",
|
||||
"Enter a descriptive name": "Voer een beschrijvende naam in",
|
||||
"I've saved my {{credential}}": "Ik heb mijn {{credential}} opgeslagen",
|
||||
"Important": "Belangrijk",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Zorg ervoor dat u uw {{credential}} nu kopieert. U kunt deze niet meer bekijken!",
|
||||
"Never": "Nooit",
|
||||
"Revoke {{credential}}": "{{credential}} intrekken",
|
||||
"SCIM endpoint URL": "SCIM-eindpunt-URL",
|
||||
"SCIM provisioning": "SCIM-provisioning",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM heeft voorrang op SSO-groepssynchronisatie zolang het is ingeschakeld.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "U heeft het maximum van {{max}} SCIM-tokens bereikt. Verwijder een bestaand token om een nieuw token aan te maken.",
|
||||
"SCIM token": "SCIM-token",
|
||||
"SCIM tokens": "SCIM-tokens",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Deze actie kan niet ongedaan worden gemaakt. Uw identiteitsprovider stopt onmiddellijk met synchroniseren.",
|
||||
"Toggle SCIM provisioning": "SCIM-provisioning in-/uitschakelen",
|
||||
"Token": "Token",
|
||||
"Page menu": "Paginamenu",
|
||||
"Expand": "Uitvouwen",
|
||||
"Collapse": "Samenvouwen",
|
||||
"Comment menu": "Reactiemenu",
|
||||
"Group menu": "Groepsmenu",
|
||||
"Show hidden breadcrumbs": "Verborgen broodkruimels weergeven",
|
||||
"Breadcrumbs": "Broodkruimels",
|
||||
"Page actions": "Pagina-acties",
|
||||
"Pick emoji": "Emoji kiezen",
|
||||
"Template menu": "Sjabloonmenu",
|
||||
"Chat menu": "Chatmenu",
|
||||
"API key menu": "API-sleutelmenu",
|
||||
"Jump to comment selection": "Naar reactieselectie springen",
|
||||
"Slash commands": "Slash-opdrachten",
|
||||
"Mention suggestions": "Vermeldingssuggesties",
|
||||
"Link suggestions": "Linksuggesties",
|
||||
"Diagram editor": "Diagrameditor",
|
||||
"Add comment": "Reactie toevoegen",
|
||||
"Find and replace": "Zoeken en vervangen",
|
||||
"Main navigation": "Hoofdnavigatie",
|
||||
"Space navigation": "Ruimtenavigatie",
|
||||
"Settings navigation": "Instellingennavigatie",
|
||||
"AI navigation": "AI-navigatie",
|
||||
"Breadcrumb": "Broodkruimel",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} está disponível",
|
||||
"Default page edit mode": "Modo padrão de edição da página",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Escolha o modo de edição de página preferido. Evite edições acidentais.",
|
||||
"Choose {{format}} file": "Escolher arquivo {{format}}",
|
||||
"Reading": "Leitura",
|
||||
"Delete member": "Excluir membro",
|
||||
"Member deleted successfully": "Membro excluído com sucesso",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "A imagem excede o limite de 10MB.",
|
||||
"Image removed successfully": "Imagem removida com sucesso",
|
||||
"API key": "Chave API",
|
||||
"API key created successfully": "Chave API criada com sucesso",
|
||||
"API keys": "Chaves API",
|
||||
"API management": "Gestão de API",
|
||||
"Are you sure you want to revoke this API key": "Tem certeza de que deseja revogar esta chave API",
|
||||
"Create API Key": "Criar Chave API",
|
||||
"Custom expiration date": "Data de expiração personalizada",
|
||||
"Enter a descriptive token name": "Insira um nome descritivo para o token",
|
||||
"Expiration": "Expiração",
|
||||
"Expired": "Expirado",
|
||||
"Expires": "Expira",
|
||||
"I've saved my API key": "Salvei minha chave API",
|
||||
"Last use": "Último uso",
|
||||
"No API keys found": "Nenhuma chave API encontrada",
|
||||
"No expiration": "Sem expiração",
|
||||
"Revoke API key": "Revogar chave API",
|
||||
"Revoked successfully": "Revogada com sucesso",
|
||||
"Select expiration date": "Selecionar data de expiração",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Esta ação não pode ser desfeita. Qualquer aplicação usando esta chave API deixará de funcionar.",
|
||||
"Update API key": "Atualizar chave API",
|
||||
"Update": "Atualizar",
|
||||
"Update {{credential}}": "Atualizar {{credential}}",
|
||||
"Manage API keys for all users in the workspace": "Gerenciar chaves API para todos os usuários no espaço de trabalho",
|
||||
"Restrict API key creation to admins": "Restringir a criação de chave de API aos administradores",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Somente administradores e proprietários podem criar novas chaves de API. As chaves de membros já existentes continuarão funcionando.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Últimos 7 dias",
|
||||
"Previous 30 days": "Últimos 30 dias",
|
||||
"Search chats...": "Pesquisar chats...",
|
||||
"Search chats": "Pesquisar chats",
|
||||
"Ask anything... Use @ to mention pages": "Pergunte qualquer coisa... Use @ para mencionar páginas",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Inicie um novo chat para vê-lo aqui.",
|
||||
"Summarize this page": "Resumir esta página",
|
||||
"Toggle AI Chat": "Alternar chat com IA",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Tente um termo de pesquisa diferente.",
|
||||
"Try again": "Tentar novamente",
|
||||
"Untitled chat": "Chat sem título",
|
||||
"What can I help you with?": "Com o que posso ajudar você?"
|
||||
"What can I help you with?": "Com o que posso ajudar você?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Tem certeza de que deseja revogar esta {{credential}}",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Provisione automaticamente usuários e grupos do seu provedor de identidade via SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Configure seu provedor de identidade com esta URL para provisionar usuários e grupos.",
|
||||
"Create {{credential}}": "Criar {{credential}}",
|
||||
"{{credential}} created": "{{credential}} criada",
|
||||
"{{credential}} created successfully": "{{credential}} criada com sucesso",
|
||||
"Created by": "Criado por",
|
||||
"Custom": "Personalizado",
|
||||
"Enable SCIM": "Ativar SCIM",
|
||||
"Enter a descriptive name": "Insira um nome descritivo",
|
||||
"I've saved my {{credential}}": "Salvei minha {{credential}}",
|
||||
"Important": "Importante",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Copie sua {{credential}} agora. Você não poderá vê-la novamente!",
|
||||
"Never": "Nunca",
|
||||
"Revoke {{credential}}": "Revogar {{credential}}",
|
||||
"SCIM endpoint URL": "URL do endpoint SCIM",
|
||||
"SCIM provisioning": "Provisionamento SCIM",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "O SCIM tem precedência sobre a sincronização de grupos por SSO enquanto estiver ativado.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Você atingiu o máximo de {{max}} tokens SCIM. Exclua um token existente para criar um novo.",
|
||||
"SCIM token": "Token SCIM",
|
||||
"SCIM tokens": "Tokens SCIM",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Esta ação não pode ser desfeita. Seu provedor de identidade deixará de sincronizar imediatamente.",
|
||||
"Toggle SCIM provisioning": "Alternar provisionamento SCIM",
|
||||
"Token": "Token",
|
||||
"Page menu": "Menu da página",
|
||||
"Expand": "Expandir",
|
||||
"Collapse": "Recolher",
|
||||
"Comment menu": "Menu de comentários",
|
||||
"Group menu": "Menu do grupo",
|
||||
"Show hidden breadcrumbs": "Mostrar breadcrumbs ocultos",
|
||||
"Breadcrumbs": "Trilhas de navegação",
|
||||
"Page actions": "Ações da página",
|
||||
"Pick emoji": "Escolher emoji",
|
||||
"Template menu": "Menu do modelo",
|
||||
"Chat menu": "Menu do chat",
|
||||
"API key menu": "Menu da chave de API",
|
||||
"Jump to comment selection": "Ir para a seleção de comentários",
|
||||
"Slash commands": "Comandos de barra",
|
||||
"Mention suggestions": "Sugestões de menção",
|
||||
"Link suggestions": "Sugestões de links",
|
||||
"Diagram editor": "Editor de diagramas",
|
||||
"Add comment": "Adicionar comentário",
|
||||
"Find and replace": "Localizar e substituir",
|
||||
"Main navigation": "Navegação principal",
|
||||
"Space navigation": "Navegação do espaço",
|
||||
"Settings navigation": "Navegação de configurações",
|
||||
"AI navigation": "Navegação de IA",
|
||||
"Breadcrumb": "Trilha de navegação",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "Доступна версия {{latestVersion}}",
|
||||
"Default page edit mode": "Режим редактирования страницы по умолчанию",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Выберите предпочитаемый режим редактирования страницы. Избегайте случайных изменений.",
|
||||
"Choose {{format}} file": "Выберите файл {{format}}",
|
||||
"Reading": "Чтение",
|
||||
"Delete member": "Удалить участника",
|
||||
"Member deleted successfully": "Участник успешно удалён",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "Изображение превышает предел 10MB.",
|
||||
"Image removed successfully": "Изображение успешно удалено",
|
||||
"API key": "API ключ",
|
||||
"API key created successfully": "API ключ успешно создан",
|
||||
"API keys": "API ключи",
|
||||
"API management": "Управление API",
|
||||
"Are you sure you want to revoke this API key": "Вы уверены, что хотите отозвать этот API ключ",
|
||||
"Create API Key": "Создать API ключ",
|
||||
"Custom expiration date": "Пользовательская дата срока действия",
|
||||
"Enter a descriptive token name": "Введите понятное имя токена",
|
||||
"Expiration": "Срок действия",
|
||||
"Expired": "Истек",
|
||||
"Expires": "Истекает",
|
||||
"I've saved my API key": "Я сохранил мой API ключ",
|
||||
"Last use": "Последнее использование",
|
||||
"No API keys found": "API ключи не найдены",
|
||||
"No expiration": "Не истекает",
|
||||
"Revoke API key": "Отозвать API ключ",
|
||||
"Revoked successfully": "Отозван успешно",
|
||||
"Select expiration date": "Выберете срок действия",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Это действие необратимо. Любые приложения, использующие этот API ключ, перестанут работать.",
|
||||
"Update API key": "Обновить API ключ",
|
||||
"Update": "Обновить",
|
||||
"Update {{credential}}": "Обновить {{credential}}",
|
||||
"Manage API keys for all users in the workspace": "Управлять API ключами для всех пользователей в рабочей области",
|
||||
"Restrict API key creation to admins": "Ограничить создание API-ключей только администраторами.",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Только администраторы и владельцы могут создавать новые API-ключи. Существующие ключи участников продолжат работать.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Предыдущие 7 дней",
|
||||
"Previous 30 days": "Предыдущие 30 дней",
|
||||
"Search chats...": "Поиск чатов...",
|
||||
"Search chats": "Поиск чатов",
|
||||
"Ask anything... Use @ to mention pages": "Спросите что угодно... Используйте @, чтобы упомянуть страницы",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Добро пожаловать в {{name}}",
|
||||
"Add files": "Добавить файлы",
|
||||
"Mention a page": "Упомянуть страницу",
|
||||
"Start a new chat to see it here.": "Начните новый чат, чтобы увидеть его здесь.",
|
||||
"Summarize this page": "Суммировать эту страницу",
|
||||
"Toggle AI Chat": "Переключить чат с ИИ",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Попробуйте другой поисковый запрос.",
|
||||
"Try again": "Попробовать снова",
|
||||
"Untitled chat": "Чат без названия",
|
||||
"What can I help you with?": "Чем я могу вам помочь?"
|
||||
"What can I help you with?": "Чем я могу вам помочь?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Вы уверены, что хотите отозвать этот {{credential}}",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Автоматически предоставляйте доступ пользователям и группам из вашего провайдера удостоверений через SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Настройте ваш провайдер удостоверений с этим URL для предоставления доступа пользователям и группам.",
|
||||
"Create {{credential}}": "Создать {{credential}}",
|
||||
"{{credential}} created": "{{credential}} создан",
|
||||
"{{credential}} created successfully": "{{credential}} успешно создан",
|
||||
"Created by": "Создан",
|
||||
"Custom": "Пользовательский",
|
||||
"Enable SCIM": "Включить SCIM",
|
||||
"Enter a descriptive name": "Введите понятное имя",
|
||||
"I've saved my {{credential}}": "Я сохранил свой {{credential}}",
|
||||
"Important": "Важно",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Обязательно скопируйте ваш {{credential}} сейчас. Позже вы не сможете увидеть его снова!",
|
||||
"Never": "Никогда",
|
||||
"Revoke {{credential}}": "Отозвать {{credential}}",
|
||||
"SCIM endpoint URL": "URL конечной точки SCIM",
|
||||
"SCIM provisioning": "SCIM-подготовка учетных записей",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "Пока SCIM включен, он имеет приоритет над синхронизацией групп через SSO.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Вы достигли максимального количества токенов SCIM: {{max}}. Удалите существующий токен, чтобы создать новый.",
|
||||
"SCIM token": "Токен SCIM",
|
||||
"SCIM tokens": "Токены SCIM",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Это действие нельзя отменить. Ваш провайдер удостоверений немедленно прекратит синхронизацию.",
|
||||
"Toggle SCIM provisioning": "Переключить подготовку учетных записей SCIM",
|
||||
"Token": "Токен",
|
||||
"Page menu": "Меню страницы",
|
||||
"Expand": "Развернуть",
|
||||
"Collapse": "Свернуть",
|
||||
"Comment menu": "Меню комментария",
|
||||
"Group menu": "Меню группы",
|
||||
"Show hidden breadcrumbs": "Показать скрытые хлебные крошки",
|
||||
"Breadcrumbs": "Хлебные крошки",
|
||||
"Page actions": "Действия со страницей",
|
||||
"Pick emoji": "Выбрать эмодзи",
|
||||
"Template menu": "Меню шаблона",
|
||||
"Chat menu": "Меню чата",
|
||||
"API key menu": "Меню API-ключа",
|
||||
"Jump to comment selection": "Перейти к выбору комментария",
|
||||
"Slash commands": "Команды со слешем",
|
||||
"Mention suggestions": "Подсказки упоминаний",
|
||||
"Link suggestions": "Подсказки ссылок",
|
||||
"Diagram editor": "Редактор диаграмм",
|
||||
"Add comment": "Добавить комментарий",
|
||||
"Find and replace": "Найти и заменить",
|
||||
"Main navigation": "Основная навигация",
|
||||
"Space navigation": "Навигация по пространству",
|
||||
"Settings navigation": "Навигация по настройкам",
|
||||
"AI navigation": "Навигация ИИ",
|
||||
"Breadcrumb": "Хлебная крошка",
|
||||
"Synced block": "Синхронизированный блок",
|
||||
"Create a block that stays in sync across pages.": "Создайте блок, который будет синхронизироваться между страницами.",
|
||||
"Editing original": "Редактирование оригинала",
|
||||
"Copy synced block": "Скопировать синхронизированный блок",
|
||||
"Unsync": "Не синхронизировать",
|
||||
"Delete synced block": "Удалить синхронизированный блок",
|
||||
"Synced to {{count}} other page_one": "Синхронизировано с {{count}} с другой страницей",
|
||||
"Synced to {{count}} other page_other": "Синхронизировано с {{count}} с другими страницами",
|
||||
"ORIGINAL": "ОРИГИНАЛ",
|
||||
"THIS PAGE": "ЭТА СТРАНИЦА",
|
||||
"No pages": "Нет страниц",
|
||||
"The original synced block no longer exists": "Исходный синхронизированный блок больше не существует",
|
||||
"You don't have access to this synced block": "У вас нет доступа к этому синхронизированному блоку",
|
||||
"Failed to load this synced block": "Не удалось загрузить этот синхронизированный блок",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Подстрочный",
|
||||
"Superscript": "Надстрочный",
|
||||
"Inline code": "Встроенный код",
|
||||
"Insert media": "Вставить медиа",
|
||||
"Mention": "Упоминание",
|
||||
"Emoji": "Эмодзи",
|
||||
"Columns": "Столбцы",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Диаграммы",
|
||||
"Advanced": "Дополнительно",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Очистить форматирование",
|
||||
"Code block": "Блок кода",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Зачеркивание",
|
||||
"Undo": "Отменить",
|
||||
"Redo": "Повторить",
|
||||
"Backlinks": "Обратные ссылки",
|
||||
"Last updated by": "Последний изменивший",
|
||||
"Last updated": "Последнее обновление",
|
||||
"Stats": "Статистика",
|
||||
"Word count": "Количество слов",
|
||||
"Characters": "Символы",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "На эту страницу пока что нет ссылок.",
|
||||
"This page doesn't link to other pages yet.": "Эта страница пока не содержит ссылок на другие страницы.",
|
||||
"Verified until {{date}}": "Подтверждено до: {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "Доступна версія {{latestVersion}}",
|
||||
"Default page edit mode": "Режим редагування сторінки за замовчуванням",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Виберіть бажаний режим редагування сторінки. Уникайте випадкових редагувань.",
|
||||
"Choose {{format}} file": "Виберіть файл {{format}}",
|
||||
"Reading": "Читання",
|
||||
"Delete member": "Видалити учасника",
|
||||
"Member deleted successfully": "Учасника успішно видалено",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "Зображення має займати менше, ніж 10 МБ.",
|
||||
"Image removed successfully": "Зображення видалено",
|
||||
"API key": "Ключ API",
|
||||
"API key created successfully": "Ключ API успішно створено",
|
||||
"API keys": "Ключі API",
|
||||
"API management": "Управління API",
|
||||
"Are you sure you want to revoke this API key": "Ви впевнені, що хочете відкликати цей ключ API",
|
||||
"Create API Key": "Створити ключ API",
|
||||
"Custom expiration date": "Користувацька дата закінчення",
|
||||
"Enter a descriptive token name": "Введіть описову назву токена",
|
||||
"Expiration": "Термін дії",
|
||||
"Expired": "Закінчився",
|
||||
"Expires": "Закінчується",
|
||||
"I've saved my API key": "Я зберіг свій ключ API",
|
||||
"Last use": "Останнє використання",
|
||||
"No API keys found": "Ключі API не знайдено",
|
||||
"No expiration": "Без терміну дії",
|
||||
"Revoke API key": "Відкликати ключ API",
|
||||
"Revoked successfully": "Успішно відкликано",
|
||||
"Select expiration date": "Виберіть дату закінчення",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Цю дію не можна скасувати. Будь-які додатки, що використовують цей ключ API, перестануть працювати.",
|
||||
"Update API key": "Оновити ключ API",
|
||||
"Update": "Оновити",
|
||||
"Update {{credential}}": "Оновити {{credential}}",
|
||||
"Manage API keys for all users in the workspace": "Керувати ключами API для всіх користувачів у робочій області",
|
||||
"Restrict API key creation to admins": "Обмежити створення API-ключів лише для адміністраторів",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Тільки адміністратори та власники можуть створювати нові API-ключі. Існуючі ключі учасників і надалі працюватимуть.",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "Попередні 7 днів",
|
||||
"Previous 30 days": "Попередні 30 днів",
|
||||
"Search chats...": "Шукати чати...",
|
||||
"Search chats": "Шукати чати",
|
||||
"Ask anything... Use @ to mention pages": "Запитайте будь-що... Використовуйте @, щоб згадувати сторінки",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "Почніть новий чат, щоб побачити його тут.",
|
||||
"Summarize this page": "Підсумувати цю сторінку",
|
||||
"Toggle AI Chat": "Перемкнути AI-чат",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "Спробуйте інший пошуковий запит.",
|
||||
"Try again": "Спробувати ще раз",
|
||||
"Untitled chat": "Чат без назви",
|
||||
"What can I help you with?": "Чим я можу вам допомогти?"
|
||||
"What can I help you with?": "Чим я можу вам допомогти?",
|
||||
"Are you sure you want to revoke this {{credential}}": "Ви впевнені, що хочете відкликати цей {{credential}}",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "Автоматично надавайте користувачів і групи від вашого постачальника ідентифікації через SCIM.",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "Налаштуйте свого постачальника ідентифікації за допомогою цієї URL-адреси для надання користувачів і груп.",
|
||||
"Create {{credential}}": "Створити {{credential}}",
|
||||
"{{credential}} created": "{{credential}} створено",
|
||||
"{{credential}} created successfully": "{{credential}} успішно створено",
|
||||
"Created by": "Створено",
|
||||
"Custom": "Користувацький",
|
||||
"Enable SCIM": "Увімкнути SCIM",
|
||||
"Enter a descriptive name": "Введіть описову назву",
|
||||
"I've saved my {{credential}}": "Я зберіг(ла) свій {{credential}}",
|
||||
"Important": "Важливо",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "Обов’язково скопіюйте свій {{credential}} зараз. Ви більше не зможете побачити його знову!",
|
||||
"Never": "Ніколи",
|
||||
"Revoke {{credential}}": "Відкликати {{credential}}",
|
||||
"SCIM endpoint URL": "URL-адреса кінцевої точки SCIM",
|
||||
"SCIM provisioning": "Надання SCIM",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "SCIM має пріоритет над синхронізацією груп SSO, коли його ввімкнено.",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "Ви досягли максимальної кількості токенів SCIM: {{max}}. Видаліть наявний токен, щоб створити новий.",
|
||||
"SCIM token": "Токен SCIM",
|
||||
"SCIM tokens": "Токени SCIM",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "Цю дію не можна скасувати. Ваш постачальник ідентифікації негайно припинить синхронізацію.",
|
||||
"Toggle SCIM provisioning": "Перемкнути надання SCIM",
|
||||
"Token": "Токен",
|
||||
"Page menu": "Меню сторінки",
|
||||
"Expand": "Розгорнути",
|
||||
"Collapse": "Згорнути",
|
||||
"Comment menu": "Меню коментаря",
|
||||
"Group menu": "Меню групи",
|
||||
"Show hidden breadcrumbs": "Показати приховані \"хлібні крихти\"",
|
||||
"Breadcrumbs": "\"Хлібні крихти\"",
|
||||
"Page actions": "Дії сторінки",
|
||||
"Pick emoji": "Вибрати емодзі",
|
||||
"Template menu": "Меню шаблону",
|
||||
"Chat menu": "Меню чату",
|
||||
"API key menu": "Меню ключа API",
|
||||
"Jump to comment selection": "Перейти до вибору коментаря",
|
||||
"Slash commands": "Слеш-команди",
|
||||
"Mention suggestions": "Підказки згадок",
|
||||
"Link suggestions": "Підказки посилань",
|
||||
"Diagram editor": "Редактор діаграм",
|
||||
"Add comment": "Додати коментар",
|
||||
"Find and replace": "Знайти й замінити",
|
||||
"Main navigation": "Основна навігація",
|
||||
"Space navigation": "Навігація простору",
|
||||
"Settings navigation": "Навігація налаштувань",
|
||||
"AI navigation": "Навігація AI",
|
||||
"Breadcrumb": "Хлібна крихта",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@
|
||||
"{{latestVersion}} is available": "{{latestVersion}} 可用",
|
||||
"Default page edit mode": "默认页面编辑模式",
|
||||
"Choose your preferred page edit mode. Avoid accidental edits.": "选择您偏好的页面编辑模式。避免意外编辑。",
|
||||
"Choose {{format}} file": "选择 {{format}} 文件",
|
||||
"Reading": "阅读",
|
||||
"Delete member": "删除成员",
|
||||
"Member deleted successfully": "成员删除成功",
|
||||
@@ -608,25 +609,21 @@
|
||||
"Image exceeds 10MB limit.": "图片超过10MB限制。",
|
||||
"Image removed successfully": "图片删除成功",
|
||||
"API key": "API密钥",
|
||||
"API key created successfully": "API密钥创建成功",
|
||||
"API keys": "API密钥",
|
||||
"API management": "API管理",
|
||||
"Are you sure you want to revoke this API key": "确定要撤销此API密钥吗",
|
||||
"Create API Key": "创建API密钥",
|
||||
"Custom expiration date": "自定义到期日期",
|
||||
"Enter a descriptive token name": "输入描述性令牌名称",
|
||||
"Expiration": "到期",
|
||||
"Expired": "已过期",
|
||||
"Expires": "到期",
|
||||
"I've saved my API key": "我已保存我的API密钥",
|
||||
"Last use": "上次使用",
|
||||
"No API keys found": "找不到API密钥",
|
||||
"No expiration": "无到期",
|
||||
"Revoke API key": "撤销API密钥",
|
||||
"Revoked successfully": "撤销成功",
|
||||
"Select expiration date": "选择到期日期",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "此操作无法撤销。使用此API密钥的任何应用程序将停止工作。",
|
||||
"Update API key": "更新API密钥",
|
||||
"Update": "更新",
|
||||
"Update {{credential}}": "更新{{credential}}",
|
||||
"Manage API keys for all users in the workspace": "管理工作空间中所有用户的API密钥",
|
||||
"Restrict API key creation to admins": "仅限管理员创建 API 密钥。",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "只有管理员和所有者可以创建新的 API 密钥。现有成员密钥将继续有效。",
|
||||
@@ -873,6 +870,12 @@
|
||||
"Previous 7 days": "前 7 天",
|
||||
"Previous 30 days": "前 30 天",
|
||||
"Search chats...": "搜索聊天...",
|
||||
"Search chats": "搜索聊天",
|
||||
"Ask anything... Use @ to mention pages": "询问任何内容……使用 @ 提及页面",
|
||||
"Ask anything or search your workspace": "Ask anything or search your workspace",
|
||||
"Welcome to {{name}}": "Welcome to {{name}}",
|
||||
"Add files": "Add files",
|
||||
"Mention a page": "Mention a page",
|
||||
"Start a new chat to see it here.": "开始新的聊天后会显示在这里。",
|
||||
"Summarize this page": "总结此页面",
|
||||
"Toggle AI Chat": "切换 AI 聊天",
|
||||
@@ -880,5 +883,105 @@
|
||||
"Try a different search term.": "请尝试其他搜索词。",
|
||||
"Try again": "重试",
|
||||
"Untitled chat": "未命名聊天",
|
||||
"What can I help you with?": "我能帮您做什么?"
|
||||
"What can I help you with?": "我能帮您做什么?",
|
||||
"Are you sure you want to revoke this {{credential}}": "确定要撤销此{{credential}}吗",
|
||||
"Automatically provision users and groups from your identity provider via SCIM.": "通过 SCIM 从您的身份提供商自动预配用户和群组。",
|
||||
"Configure your identity provider with this URL to provision users and groups.": "使用此 URL 配置您的身份提供商以预配用户和群组。",
|
||||
"Create {{credential}}": "创建{{credential}}",
|
||||
"{{credential}} created": "已创建{{credential}}",
|
||||
"{{credential}} created successfully": "已成功创建{{credential}}",
|
||||
"Created by": "创建者",
|
||||
"Custom": "自定义",
|
||||
"Enable SCIM": "启用 SCIM",
|
||||
"Enter a descriptive name": "输入描述性名称",
|
||||
"I've saved my {{credential}}": "我已保存我的{{credential}}",
|
||||
"Important": "重要",
|
||||
"Make sure to copy your {{credential}} now. You won't be able to see it again!": "请务必立即复制您的{{credential}}。之后您将无法再次查看!",
|
||||
"Never": "从不",
|
||||
"Revoke {{credential}}": "撤销{{credential}}",
|
||||
"SCIM endpoint URL": "SCIM 端点 URL",
|
||||
"SCIM provisioning": "SCIM 预配",
|
||||
"SCIM takes precedence over SSO group sync while enabled.": "启用后,SCIM 的优先级高于 SSO 群组同步。",
|
||||
"You have reached the maximum of {{max}} SCIM tokens. Delete an existing token to create a new one.": "您已达到 {{max}} 个 SCIM 令牌的上限。请删除一个现有令牌以创建新令牌。",
|
||||
"SCIM token": "SCIM 令牌",
|
||||
"SCIM tokens": "SCIM 令牌",
|
||||
"This action cannot be undone. Your identity provider will stop syncing immediately.": "此操作无法撤销。您的身份提供商将立即停止同步。",
|
||||
"Toggle SCIM provisioning": "切换 SCIM 预配",
|
||||
"Token": "令牌",
|
||||
"Page menu": "页面菜单",
|
||||
"Expand": "展开",
|
||||
"Collapse": "折叠",
|
||||
"Comment menu": "评论菜单",
|
||||
"Group menu": "群组菜单",
|
||||
"Show hidden breadcrumbs": "显示隐藏的面包屑",
|
||||
"Breadcrumbs": "面包屑",
|
||||
"Page actions": "页面操作",
|
||||
"Pick emoji": "选择表情符号",
|
||||
"Template menu": "模板菜单",
|
||||
"Chat menu": "聊天菜单",
|
||||
"API key menu": "API 密钥菜单",
|
||||
"Jump to comment selection": "跳转到评论选择",
|
||||
"Slash commands": "斜杠命令",
|
||||
"Mention suggestions": "提及建议",
|
||||
"Link suggestions": "链接建议",
|
||||
"Diagram editor": "图表编辑器",
|
||||
"Add comment": "添加评论",
|
||||
"Find and replace": "查找和替换",
|
||||
"Main navigation": "主导航",
|
||||
"Space navigation": "空间导航",
|
||||
"Settings navigation": "设置导航",
|
||||
"AI navigation": "AI 导航",
|
||||
"Breadcrumb": "面包屑",
|
||||
"Synced block": "Synced block",
|
||||
"Create a block that stays in sync across pages.": "Create a block that stays in sync across pages.",
|
||||
"Editing original": "Editing original",
|
||||
"Copy synced block": "Copy synced block",
|
||||
"Unsync": "Unsync",
|
||||
"Delete synced block": "Delete synced block",
|
||||
"Synced to {{count}} other page_one": "Synced to {{count}} other page",
|
||||
"Synced to {{count}} other page_other": "Synced to {{count}} other pages",
|
||||
"ORIGINAL": "ORIGINAL",
|
||||
"THIS PAGE": "THIS PAGE",
|
||||
"No pages": "No pages",
|
||||
"The original synced block no longer exists": "The original synced block no longer exists",
|
||||
"You don't have access to this synced block": "You don't have access to this synced block",
|
||||
"Failed to load this synced block": "Failed to load this synced block",
|
||||
"Fixed editor toolbar": "Fixed editor toolbar",
|
||||
"Show a formatting toolbar above the editor with quick access to common actions.": "Show a formatting toolbar above the editor with quick access to common actions.",
|
||||
"Toggle fixed editor toolbar": "Toggle fixed editor toolbar",
|
||||
"Normal text": "Normal text",
|
||||
"More inline formatting": "More inline formatting",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Inline code": "Inline code",
|
||||
"Insert media": "Insert media",
|
||||
"Mention": "Mention",
|
||||
"Emoji": "Emoji",
|
||||
"Columns": "Columns",
|
||||
"More inserts": "More inserts",
|
||||
"Embeds": "Embeds",
|
||||
"Diagrams": "Diagrams",
|
||||
"Advanced": "Advanced",
|
||||
"Utility": "Utility",
|
||||
"Decrease indent": "Decrease indent",
|
||||
"Increase indent": "Increase indent",
|
||||
"Clear formatting": "Clear formatting",
|
||||
"Code block": "Code block",
|
||||
"Experimental": "Experimental",
|
||||
"Strikethrough": "Strikethrough",
|
||||
"Undo": "Undo",
|
||||
"Redo": "Redo",
|
||||
"Backlinks": "Backlinks",
|
||||
"Last updated by": "Last updated by",
|
||||
"Last updated": "Last updated",
|
||||
"Stats": "Stats",
|
||||
"Word count": "Word count",
|
||||
"Characters": "Characters",
|
||||
"Incoming links": "Incoming links",
|
||||
"Outgoing links": "Outgoing links",
|
||||
"Incoming links ({{count}})": "Incoming links ({{count}})",
|
||||
"Outgoing links ({{count}})": "Outgoing links ({{count}})",
|
||||
"No pages link here yet.": "No pages link here yet.",
|
||||
"This page doesn't link to other pages yet.": "This page doesn't link to other pages yet.",
|
||||
"Verified until {{date}}": "Verified until {{date}}"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { TableOfContents } from "@/features/editor/components/table-of-contents/
|
||||
import { useAtomValue } from "jotai";
|
||||
import { pageEditorAtom } from "@/features/editor/atoms/editor-atoms.ts";
|
||||
import AsideChatPanel from "@/ee/ai-chat/components/aside-chat-panel";
|
||||
import { PageDetailsAside } from "@/features/page-details/components/page-details-aside.tsx";
|
||||
|
||||
export default function Aside() {
|
||||
const [{ tab }] = useAtom(asideStateAtom);
|
||||
@@ -30,6 +31,10 @@ export default function Aside() {
|
||||
component = <AsideChatPanel />;
|
||||
title = "AI Chat";
|
||||
break;
|
||||
case "details":
|
||||
component = <PageDetailsAside />;
|
||||
title = "Details";
|
||||
break;
|
||||
default:
|
||||
component = null;
|
||||
title = null;
|
||||
|
||||
@@ -147,7 +147,9 @@ export default function GlobalAppShell({
|
||||
? t("Table of contents")
|
||||
: asideTab === "chat"
|
||||
? t("AI Chat")
|
||||
: undefined
|
||||
: asideTab === "details"
|
||||
? t("Details")
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Aside />
|
||||
|
||||
@@ -10,6 +10,7 @@ export const desktopSidebarAtom = atomWithWebStorage<boolean>(
|
||||
|
||||
export const desktopAsideAtom = atom<boolean>(false);
|
||||
|
||||
// Valid `tab` values: "" | "comments" | "toc" | "chat" | "details"
|
||||
type AsideStateType = {
|
||||
tab: string;
|
||||
isAsideOpen: boolean;
|
||||
|
||||
@@ -118,10 +118,20 @@ export function PageVerificationBadge({
|
||||
|
||||
if (status === "none" && readOnly) return null;
|
||||
|
||||
const tooltipLabel =
|
||||
status === "verified" && verificationInfo?.expiresAt
|
||||
? t("Verified until {{date}}", {
|
||||
date: new Date(verificationInfo.expiresAt).toLocaleDateString(
|
||||
undefined,
|
||||
{ month: "long", day: "numeric", year: "numeric" },
|
||||
),
|
||||
})
|
||||
: getStatusLabel(status, t);
|
||||
|
||||
return (
|
||||
<>
|
||||
{status !== "none" ? (
|
||||
<Tooltip label={getStatusLabel(status, t)} withArrow openDelay={250}>
|
||||
<Tooltip label={tooltipLabel} withArrow openDelay={250}>
|
||||
<Group
|
||||
gap={4}
|
||||
onClick={open}
|
||||
|
||||
@@ -3,14 +3,17 @@ import React from "react";
|
||||
import { TitleEditor } from "@/features/editor/title-editor";
|
||||
import PageEditor from "@/features/editor/page-editor";
|
||||
import {
|
||||
ActionIcon,
|
||||
Container,
|
||||
Divider,
|
||||
Group,
|
||||
Popover,
|
||||
Stack,
|
||||
Text,
|
||||
Tooltip,
|
||||
UnstyledButton,
|
||||
} from "@mantine/core";
|
||||
import { IconInfoCircle } from "@tabler/icons-react";
|
||||
import { useAtom } from "jotai";
|
||||
import { userAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
@@ -19,6 +22,8 @@ import { useTranslation } from "react-i18next";
|
||||
import { IContributor } from "@/features/page/types/page.types.ts";
|
||||
import { FixedToolbar } from "@/features/editor/components/fixed-toolbar/fixed-toolbar";
|
||||
import { PageEditMode } from "@/features/user/types/user.types.ts";
|
||||
import useToggleAside from "@/hooks/use-toggle-aside.tsx";
|
||||
import clsx from "clsx";
|
||||
|
||||
const MemoizedTitleEditor = React.memo(TitleEditor);
|
||||
const MemoizedPageEditor = React.memo(PageEditor);
|
||||
@@ -101,6 +106,7 @@ function PageByline({
|
||||
readOnly,
|
||||
}: PageBylineProps) {
|
||||
const { t } = useTranslation();
|
||||
const toggleAside = useToggleAside();
|
||||
|
||||
const otherContributors = (contributors ?? []).filter(
|
||||
(c) => c.id !== creator?.id,
|
||||
@@ -110,8 +116,8 @@ function PageByline({
|
||||
<Group
|
||||
gap="sm"
|
||||
mb="md"
|
||||
className="print-hide"
|
||||
style={{ marginTop: "-0.5em", paddingLeft: "3rem" }}
|
||||
className={clsx("print-hide", classes.byline)}
|
||||
style={{ marginTop: "-0.5em" }}
|
||||
>
|
||||
{creator && (
|
||||
<Popover position="bottom-start" shadow="md" width={280} withArrow>
|
||||
@@ -173,6 +179,17 @@ function PageByline({
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
)}
|
||||
<Tooltip label={t("Details")} withArrow openDelay={250}>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
aria-label={t("Details")}
|
||||
onClick={() => toggleAside("details")}
|
||||
>
|
||||
<IconInfoCircle size={20} stroke={1.5} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
|
||||
<PageVerificationBadge readOnly={readOnly} />
|
||||
</Group>
|
||||
);
|
||||
|
||||
@@ -9,3 +9,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.byline {
|
||||
padding-left: 3rem;
|
||||
|
||||
@media (max-width: $mantine-breakpoint-sm) {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
@media print {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Group,
|
||||
Loader,
|
||||
Stack,
|
||||
Text,
|
||||
UnstyledButton,
|
||||
} from "@mantine/core";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useBacklinksQuery } from "@/features/page-details/queries/backlinks-query.ts";
|
||||
import {
|
||||
BacklinkDirection,
|
||||
IBacklinkPageItem,
|
||||
} from "@/features/page-details/types/backlink.types.ts";
|
||||
import { buildPageUrl } from "@/features/page/page.utils.ts";
|
||||
import { getPageIcon } from "@/lib";
|
||||
|
||||
interface BacklinksListProps {
|
||||
pageId: string;
|
||||
direction: BacklinkDirection;
|
||||
enabled: boolean;
|
||||
onItemClick: () => void;
|
||||
}
|
||||
|
||||
export function BacklinksList({
|
||||
pageId,
|
||||
direction,
|
||||
enabled,
|
||||
onItemClick,
|
||||
}: BacklinksListProps) {
|
||||
const { t } = useTranslation();
|
||||
const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
||||
useBacklinksQuery(pageId, direction, enabled);
|
||||
|
||||
if (!enabled) return null;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Center py="sm">
|
||||
<Loader size="sm" />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
const items: IBacklinkPageItem[] =
|
||||
data?.pages.flatMap((page) => page.items) ?? [];
|
||||
|
||||
if (items.length === 0) {
|
||||
return (
|
||||
<Text c="dimmed" size="sm" py="md">
|
||||
{direction === "incoming"
|
||||
? t("No pages link here yet.")
|
||||
: t("This page doesn't link to other pages yet.")}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
const handleClick = (e: React.MouseEvent) => {
|
||||
if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) {
|
||||
return;
|
||||
}
|
||||
onItemClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack gap={4}>
|
||||
{items.map((item) => (
|
||||
<UnstyledButton
|
||||
key={item.id}
|
||||
component={Link}
|
||||
to={
|
||||
item.space?.slug
|
||||
? buildPageUrl(
|
||||
item.space.slug,
|
||||
item.slugId,
|
||||
item.title ?? undefined,
|
||||
)
|
||||
: "#"
|
||||
}
|
||||
onClick={handleClick}
|
||||
style={{ padding: "8px 4px", borderRadius: 4, userSelect: "none" }}
|
||||
>
|
||||
<Group gap="xs" wrap="nowrap">
|
||||
{getPageIcon(item.icon ?? "")}
|
||||
<Stack gap={0} style={{ flex: 1, minWidth: 0 }}>
|
||||
<Text size="sm" fw={500} lineClamp={1}>
|
||||
{item.title || t("Untitled")}
|
||||
</Text>
|
||||
{item.space?.name && (
|
||||
<Text size="xs" c="dimmed" lineClamp={1}>
|
||||
{item.space.name}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
))}
|
||||
{hasNextPage && (
|
||||
<Button
|
||||
variant="subtle"
|
||||
size="xs"
|
||||
loading={isFetchingNextPage}
|
||||
onClick={() => fetchNextPage()}
|
||||
mt="xs"
|
||||
>
|
||||
{t("Load more")}
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Modal, Stack, Text } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useBacklinksCountQuery } from "@/features/page-details/queries/backlinks-query.ts";
|
||||
import { BacklinksList } from "./backlinks-list";
|
||||
|
||||
interface BacklinksModalProps {
|
||||
pageId: string;
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function BacklinksModal({
|
||||
pageId,
|
||||
opened,
|
||||
onClose,
|
||||
}: BacklinksModalProps) {
|
||||
const { t } = useTranslation();
|
||||
const { data: counts } = useBacklinksCountQuery(pageId);
|
||||
|
||||
return (
|
||||
<Modal.Root opened={opened} onClose={onClose} size={640} yOffset="10vh">
|
||||
<Modal.Overlay />
|
||||
<Modal.Content>
|
||||
<Modal.Header>
|
||||
<Modal.Title fw={500}>{t("Backlinks")}</Modal.Title>
|
||||
<Modal.CloseButton />
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<Stack gap="lg">
|
||||
<Stack gap="xs">
|
||||
<Text size="sm" fw={500} c="dimmed">
|
||||
{t("Incoming links ({{count}})", {
|
||||
count: counts?.incoming ?? 0,
|
||||
})}
|
||||
</Text>
|
||||
<BacklinksList
|
||||
pageId={pageId}
|
||||
direction="incoming"
|
||||
enabled={opened}
|
||||
onItemClick={onClose}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Stack gap="xs">
|
||||
<Text size="sm" fw={500} c="dimmed">
|
||||
{t("Outgoing links ({{count}})", {
|
||||
count: counts?.outgoing ?? 0,
|
||||
})}
|
||||
</Text>
|
||||
<BacklinksList
|
||||
pageId={pageId}
|
||||
direction="outgoing"
|
||||
enabled={opened}
|
||||
onItemClick={onClose}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Modal.Body>
|
||||
</Modal.Content>
|
||||
</Modal.Root>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
import {
|
||||
Divider,
|
||||
Group,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
UnstyledButton,
|
||||
} from "@mantine/core";
|
||||
import { IconChevronRight } from "@tabler/icons-react";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { extractPageSlugId } from "@/lib";
|
||||
import { usePageQuery } from "@/features/page/queries/page-query.ts";
|
||||
import { pageEditorAtom } from "@/features/editor/atoms/editor-atoms.ts";
|
||||
import { useBacklinksCountQuery } from "@/features/page-details/queries/backlinks-query.ts";
|
||||
import { BacklinksModal } from "./backlinks-modal";
|
||||
import { formattedDate, timeAgo } from "@/lib/time.ts";
|
||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||
|
||||
export function PageDetailsAside() {
|
||||
const { pageSlug } = useParams();
|
||||
const { data: page } = usePageQuery({
|
||||
pageId: extractPageSlugId(pageSlug),
|
||||
});
|
||||
const pageEditor = useAtomValue(pageEditorAtom);
|
||||
const { data: counts, isLoading: countsLoading } = useBacklinksCountQuery(page?.id);
|
||||
const [modalOpened, { open: openModal, close: closeModal }] =
|
||||
useDisclosure(false);
|
||||
|
||||
if (!page) return null;
|
||||
|
||||
const wordCount: number =
|
||||
pageEditor?.storage?.characterCount?.words?.() ?? 0;
|
||||
const characterCount: number =
|
||||
pageEditor?.storage?.characterCount?.characters?.() ?? 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack gap="md">
|
||||
<PeopleSection
|
||||
creator={page.creator}
|
||||
lastUpdatedBy={page.lastUpdatedBy}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
<StatsSection
|
||||
wordCount={wordCount}
|
||||
characterCount={characterCount}
|
||||
createdAt={page.createdAt}
|
||||
updatedAt={page.updatedAt}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
<BacklinksSection
|
||||
incomingCount={counts?.incoming ?? 0}
|
||||
outgoingCount={counts?.outgoing ?? 0}
|
||||
isLoading={countsLoading}
|
||||
onClick={openModal}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<BacklinksModal
|
||||
pageId={page.id}
|
||||
opened={modalOpened}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function PeopleSection({
|
||||
creator,
|
||||
lastUpdatedBy,
|
||||
}: {
|
||||
creator: { id: string; name: string; avatarUrl: string } | null;
|
||||
lastUpdatedBy: { id: string; name: string; avatarUrl: string } | null;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Stack gap="xs">
|
||||
<PersonRow label={t("Created by")} person={creator} />
|
||||
<PersonRow label={t("Last updated by")} person={lastUpdatedBy} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
function PersonRow({
|
||||
label,
|
||||
person,
|
||||
}: {
|
||||
label: string;
|
||||
person: { id: string; name: string; avatarUrl: string } | null;
|
||||
}) {
|
||||
return (
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Text size="sm" c="dimmed">
|
||||
{label}
|
||||
</Text>
|
||||
{person ? (
|
||||
<Group gap={6} wrap="nowrap">
|
||||
<CustomAvatar
|
||||
avatarUrl={person.avatarUrl}
|
||||
name={person.name}
|
||||
size={20}
|
||||
radius="xl"
|
||||
/>
|
||||
<Text size="sm" lineClamp={1}>
|
||||
{person.name}
|
||||
</Text>
|
||||
</Group>
|
||||
) : (
|
||||
<Text size="sm" c="dimmed">
|
||||
—
|
||||
</Text>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
function StatsSection({
|
||||
wordCount,
|
||||
characterCount,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
}: {
|
||||
wordCount: number;
|
||||
characterCount: number;
|
||||
createdAt: Date | string;
|
||||
updatedAt: Date | string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Stack gap="xs">
|
||||
<Text size="xs" fw={500} c="dimmed">
|
||||
{t("Stats")}
|
||||
</Text>
|
||||
<StatRow label={t("Word count")} value={String(wordCount)} />
|
||||
<StatRow label={t("Characters")} value={String(characterCount)} />
|
||||
<StatRow
|
||||
label={t("Created")}
|
||||
value={formattedDate(new Date(createdAt))}
|
||||
/>
|
||||
<StatRow
|
||||
label={t("Last updated")}
|
||||
value={timeAgo(new Date(updatedAt))}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
function StatRow({ label, value }: { label: string; value: string }) {
|
||||
return (
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Text size="sm" c="dimmed">
|
||||
{label}
|
||||
</Text>
|
||||
<Text size="sm">{value}</Text>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
function BacklinksSection({
|
||||
incomingCount,
|
||||
outgoingCount,
|
||||
isLoading,
|
||||
onClick,
|
||||
}: {
|
||||
incomingCount: number;
|
||||
outgoingCount: number;
|
||||
isLoading: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Stack gap="xs">
|
||||
<Text size="xs" fw={500} c="dimmed">
|
||||
{t("Backlinks")}
|
||||
</Text>
|
||||
<BacklinksRow
|
||||
label={t("Incoming links")}
|
||||
count={incomingCount}
|
||||
isLoading={isLoading}
|
||||
onClick={onClick}
|
||||
/>
|
||||
<BacklinksRow
|
||||
label={t("Outgoing links")}
|
||||
count={outgoingCount}
|
||||
isLoading={isLoading}
|
||||
onClick={onClick}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
function BacklinksRow({
|
||||
label,
|
||||
count,
|
||||
isLoading,
|
||||
onClick,
|
||||
}: {
|
||||
label: string;
|
||||
count: number;
|
||||
isLoading: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<UnstyledButton
|
||||
onClick={onClick}
|
||||
style={{
|
||||
padding: "4px 4px",
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Text size="sm" c="dimmed">
|
||||
{label}
|
||||
</Text>
|
||||
<Group gap={6} wrap="nowrap">
|
||||
{isLoading ? (
|
||||
<Skeleton height={18} width={20} />
|
||||
) : (
|
||||
<Text size="sm">{count}</Text>
|
||||
)}
|
||||
<IconChevronRight size={16} stroke={2} color="var(--mantine-color-dimmed)" />
|
||||
</Group>
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
getBacklinks,
|
||||
getBacklinksCount,
|
||||
} from "@/features/page-details/services/backlinks-service.ts";
|
||||
import {
|
||||
BacklinkDirection,
|
||||
IBacklinkCount,
|
||||
} from "@/features/page-details/types/backlink.types.ts";
|
||||
|
||||
const BACKLINKS_STALE_TIME = 30 * 1000;
|
||||
const BACKLINKS_PAGE_LIMIT = 100;
|
||||
|
||||
export function useBacklinksCountQuery(pageId: string | undefined) {
|
||||
return useQuery<IBacklinkCount>({
|
||||
queryKey: ["backlinks-count", pageId],
|
||||
queryFn: () => getBacklinksCount(pageId as string),
|
||||
enabled: !!pageId,
|
||||
staleTime: BACKLINKS_STALE_TIME,
|
||||
});
|
||||
}
|
||||
|
||||
export function useBacklinksQuery(
|
||||
pageId: string | undefined,
|
||||
direction: BacklinkDirection,
|
||||
enabled: boolean,
|
||||
) {
|
||||
return useInfiniteQuery({
|
||||
queryKey: ["backlinks", pageId, direction],
|
||||
queryFn: ({ pageParam }) =>
|
||||
getBacklinks({
|
||||
pageId: pageId as string,
|
||||
direction,
|
||||
cursor: pageParam,
|
||||
limit: BACKLINKS_PAGE_LIMIT,
|
||||
}),
|
||||
enabled: enabled && !!pageId,
|
||||
initialPageParam: undefined as string | undefined,
|
||||
getNextPageParam: (lastPage) =>
|
||||
lastPage.meta.hasNextPage
|
||||
? (lastPage.meta.nextCursor ?? undefined)
|
||||
: undefined,
|
||||
staleTime: BACKLINKS_STALE_TIME,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import api from "@/lib/api-client";
|
||||
import { IPagination } from "@/lib/types.ts";
|
||||
import {
|
||||
IBacklinkCount,
|
||||
IBacklinkPageItem,
|
||||
IBacklinksListParams,
|
||||
} from "@/features/page-details/types/backlink.types.ts";
|
||||
|
||||
export async function getBacklinksCount(
|
||||
pageId: string,
|
||||
): Promise<IBacklinkCount> {
|
||||
const req = await api.post<IBacklinkCount>("/pages/backlinks-count", {
|
||||
pageId,
|
||||
});
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function getBacklinks(
|
||||
params: IBacklinksListParams,
|
||||
): Promise<IPagination<IBacklinkPageItem>> {
|
||||
const req = await api.post<IPagination<IBacklinkPageItem>>(
|
||||
"/pages/backlinks",
|
||||
params,
|
||||
);
|
||||
return req.data;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
export type BacklinkDirection = "incoming" | "outgoing";
|
||||
|
||||
export interface IBacklinkCount {
|
||||
incoming: number;
|
||||
outgoing: number;
|
||||
}
|
||||
|
||||
export interface IBacklinkPageItem {
|
||||
id: string;
|
||||
slugId: string;
|
||||
title: string | null;
|
||||
icon: string | null;
|
||||
spaceId: string;
|
||||
space: { id: string; slug: string; name: string } | null;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface IBacklinksListParams {
|
||||
pageId: string;
|
||||
direction: BacklinkDirection;
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { IsIn, IsNotEmpty, IsString } from 'class-validator';
|
||||
import { PageIdDto } from './page.dto';
|
||||
|
||||
export type BacklinkDirection = 'incoming' | 'outgoing';
|
||||
|
||||
export class BacklinksListDto extends PageIdDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@IsIn(['incoming', 'outgoing'])
|
||||
direction: BacklinkDirection;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { PageService } from './services/page.service';
|
||||
import { BacklinkService } from './services/backlink.service';
|
||||
import { PageAccessService } from './page-access/page-access.service';
|
||||
import { CreatePageDto } from './dto/create-page.dto';
|
||||
import { UpdatePageDto } from './dto/update-page.dto';
|
||||
@@ -38,6 +39,7 @@ import { RecentPageDto } from './dto/recent-page.dto';
|
||||
import { CreatedByUserDto } from './dto/created-by-user.dto';
|
||||
import { DuplicatePageDto } from './dto/duplicate-page.dto';
|
||||
import { DeletedPageDto } from './dto/deleted-page.dto';
|
||||
import { BacklinksListDto } from './dto/backlink.dto';
|
||||
import {
|
||||
jsonToHtml,
|
||||
jsonToMarkdown,
|
||||
@@ -58,6 +60,7 @@ export class PageController {
|
||||
private readonly pageHistoryService: PageHistoryService,
|
||||
private readonly spaceAbility: SpaceAbilityFactory,
|
||||
private readonly pageAccessService: PageAccessService,
|
||||
private readonly backlinkService: BacklinkService,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
@@ -96,6 +99,42 @@ export class PageController {
|
||||
return { ...page, permissions };
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('backlinks-count')
|
||||
async getBacklinksCount(
|
||||
@Body() dto: PageIdDto,
|
||||
@AuthUser() user: User,
|
||||
): Promise<{ incoming: number; outgoing: number }> {
|
||||
const page = await this.pageRepo.findById(dto.pageId);
|
||||
if (!page) {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return this.backlinkService.countByPageId(page.id, user.id);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('backlinks')
|
||||
async getBacklinks(
|
||||
@Body() dto: BacklinksListDto,
|
||||
@Body() pagination: PaginationOptions,
|
||||
@AuthUser() user: User,
|
||||
) {
|
||||
const page = await this.pageRepo.findById(dto.pageId);
|
||||
if (!page) {
|
||||
throw new NotFoundException('Page not found');
|
||||
}
|
||||
await this.pageAccessService.validateCanView(page, user);
|
||||
|
||||
return this.backlinkService.findByPageId(
|
||||
page.id,
|
||||
dto.direction,
|
||||
user.id,
|
||||
pagination,
|
||||
);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('create')
|
||||
async create(
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PageService } from './services/page.service';
|
||||
import { PageController } from './page.controller';
|
||||
import { PageHistoryService } from './services/page-history.service';
|
||||
import { TrashCleanupService } from './services/trash-cleanup.service';
|
||||
import { BacklinkService } from './services/backlink.service';
|
||||
import { StorageModule } from '../../integrations/storage/storage.module';
|
||||
import { CollaborationModule } from '../../collaboration/collaboration.module';
|
||||
import { WatcherModule } from '../watcher/watcher.module';
|
||||
@@ -10,8 +11,18 @@ import { TransclusionModule } from './transclusion/transclusion.module';
|
||||
|
||||
@Module({
|
||||
controllers: [PageController],
|
||||
providers: [PageService, PageHistoryService, TrashCleanupService],
|
||||
providers: [
|
||||
PageService,
|
||||
PageHistoryService,
|
||||
TrashCleanupService,
|
||||
BacklinkService,
|
||||
],
|
||||
exports: [PageService, PageHistoryService],
|
||||
imports: [StorageModule, CollaborationModule, WatcherModule, TransclusionModule],
|
||||
imports: [
|
||||
StorageModule,
|
||||
CollaborationModule,
|
||||
WatcherModule,
|
||||
TransclusionModule,
|
||||
],
|
||||
})
|
||||
export class PageModule {}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { BacklinkService } from './backlink.service';
|
||||
import { BacklinkRepo } from '@docmost/db/repos/backlink/backlink.repo';
|
||||
import { PagePermissionRepo } from '@docmost/db/repos/page/page-permission.repo';
|
||||
|
||||
describe('BacklinkService.countByPageId', () => {
|
||||
let service: BacklinkService;
|
||||
let backlinkRepo: jest.Mocked<BacklinkRepo>;
|
||||
let permissionRepo: jest.Mocked<PagePermissionRepo>;
|
||||
|
||||
const pageId = '00000000-0000-0000-0000-000000000001';
|
||||
const userId = '00000000-0000-0000-0000-000000000099';
|
||||
|
||||
beforeEach(async () => {
|
||||
const backlinkRepoMock: jest.Mocked<Partial<BacklinkRepo>> = {
|
||||
findRelatedPageIds: jest.fn(),
|
||||
findPagesByIdsPaginated: jest.fn(),
|
||||
};
|
||||
const permissionRepoMock: jest.Mocked<Partial<PagePermissionRepo>> = {
|
||||
filterAccessiblePageIds: jest.fn(),
|
||||
};
|
||||
|
||||
const module = await Test.createTestingModule({
|
||||
providers: [
|
||||
BacklinkService,
|
||||
{ provide: BacklinkRepo, useValue: backlinkRepoMock },
|
||||
{ provide: PagePermissionRepo, useValue: permissionRepoMock },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get(BacklinkService);
|
||||
backlinkRepo = module.get(BacklinkRepo) as jest.Mocked<BacklinkRepo>;
|
||||
permissionRepo = module.get(
|
||||
PagePermissionRepo,
|
||||
) as jest.Mocked<PagePermissionRepo>;
|
||||
});
|
||||
|
||||
it('returns post-filter counts for both directions', async () => {
|
||||
backlinkRepo.findRelatedPageIds.mockImplementation(async (_id, dir) =>
|
||||
dir === 'incoming' ? ['a', 'b', 'c'] : ['x', 'y'],
|
||||
);
|
||||
permissionRepo.filterAccessiblePageIds.mockImplementation(
|
||||
async ({ pageIds }) =>
|
||||
pageIds.filter((id) => id !== 'b' && id !== 'y'),
|
||||
);
|
||||
|
||||
const result = await service.countByPageId(pageId, userId);
|
||||
|
||||
expect(result).toEqual({ incoming: 2, outgoing: 1 });
|
||||
expect(permissionRepo.filterAccessiblePageIds).toHaveBeenCalledWith({
|
||||
pageIds: ['a', 'b', 'c'],
|
||||
userId,
|
||||
});
|
||||
expect(permissionRepo.filterAccessiblePageIds).toHaveBeenCalledWith({
|
||||
pageIds: ['x', 'y'],
|
||||
userId,
|
||||
});
|
||||
});
|
||||
|
||||
it('skips the permission filter when there are no candidates', async () => {
|
||||
backlinkRepo.findRelatedPageIds.mockResolvedValue([]);
|
||||
permissionRepo.filterAccessiblePageIds.mockResolvedValue([]);
|
||||
|
||||
const result = await service.countByPageId(pageId, userId);
|
||||
|
||||
expect(result).toEqual({ incoming: 0, outgoing: 0 });
|
||||
expect(permissionRepo.filterAccessiblePageIds).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('passes the userId to findRelatedPageIds so the repo can apply space membership filtering', async () => {
|
||||
backlinkRepo.findRelatedPageIds.mockResolvedValue([]);
|
||||
|
||||
await service.countByPageId(pageId, userId);
|
||||
|
||||
expect(backlinkRepo.findRelatedPageIds).toHaveBeenCalledWith(
|
||||
pageId,
|
||||
'incoming',
|
||||
userId,
|
||||
);
|
||||
expect(backlinkRepo.findRelatedPageIds).toHaveBeenCalledWith(
|
||||
pageId,
|
||||
'outgoing',
|
||||
userId,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('BacklinkService.findByPageId', () => {
|
||||
let service: BacklinkService;
|
||||
let backlinkRepo: jest.Mocked<BacklinkRepo>;
|
||||
let permissionRepo: jest.Mocked<PagePermissionRepo>;
|
||||
|
||||
const pageId = '00000000-0000-0000-0000-000000000001';
|
||||
const userId = '00000000-0000-0000-0000-000000000099';
|
||||
|
||||
beforeEach(async () => {
|
||||
const backlinkRepoMock: jest.Mocked<Partial<BacklinkRepo>> = {
|
||||
findRelatedPageIds: jest.fn(),
|
||||
findPagesByIdsPaginated: jest.fn(),
|
||||
};
|
||||
const permissionRepoMock: jest.Mocked<Partial<PagePermissionRepo>> = {
|
||||
filterAccessiblePageIds: jest.fn(),
|
||||
};
|
||||
|
||||
const module = await Test.createTestingModule({
|
||||
providers: [
|
||||
BacklinkService,
|
||||
{ provide: BacklinkRepo, useValue: backlinkRepoMock },
|
||||
{ provide: PagePermissionRepo, useValue: permissionRepoMock },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get(BacklinkService);
|
||||
backlinkRepo = module.get(BacklinkRepo) as jest.Mocked<BacklinkRepo>;
|
||||
permissionRepo = module.get(
|
||||
PagePermissionRepo,
|
||||
) as jest.Mocked<PagePermissionRepo>;
|
||||
});
|
||||
|
||||
it('passes filtered ids through to the paginated repo call', async () => {
|
||||
backlinkRepo.findRelatedPageIds.mockResolvedValue(['a', 'b']);
|
||||
permissionRepo.filterAccessiblePageIds.mockResolvedValue(['a']);
|
||||
backlinkRepo.findPagesByIdsPaginated.mockResolvedValue({
|
||||
items: [],
|
||||
meta: {
|
||||
limit: 20,
|
||||
hasNextPage: false,
|
||||
hasPrevPage: false,
|
||||
nextCursor: null,
|
||||
prevCursor: null,
|
||||
},
|
||||
} as any);
|
||||
|
||||
await service.findByPageId(pageId, 'incoming', userId, { limit: 20 } as any);
|
||||
|
||||
expect(backlinkRepo.findPagesByIdsPaginated).toHaveBeenCalledWith(
|
||||
['a'],
|
||||
expect.objectContaining({ limit: 20 }),
|
||||
);
|
||||
});
|
||||
|
||||
it('hands an empty list to the repo when there are no accessible ids', async () => {
|
||||
backlinkRepo.findRelatedPageIds.mockResolvedValue([]);
|
||||
backlinkRepo.findPagesByIdsPaginated.mockResolvedValue({
|
||||
items: [],
|
||||
meta: {
|
||||
limit: 20,
|
||||
hasNextPage: false,
|
||||
hasPrevPage: false,
|
||||
nextCursor: null,
|
||||
prevCursor: null,
|
||||
},
|
||||
} as any);
|
||||
|
||||
await service.findByPageId(pageId, 'incoming', userId, { limit: 20 } as any);
|
||||
|
||||
expect(backlinkRepo.findPagesByIdsPaginated).toHaveBeenCalledWith(
|
||||
[],
|
||||
expect.objectContaining({ limit: 20 }),
|
||||
);
|
||||
expect(permissionRepo.filterAccessiblePageIds).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BacklinkRepo } from '@docmost/db/repos/backlink/backlink.repo';
|
||||
import { PagePermissionRepo } from '@docmost/db/repos/page/page-permission.repo';
|
||||
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
|
||||
|
||||
export type BacklinkDirection = 'incoming' | 'outgoing';
|
||||
|
||||
@Injectable()
|
||||
export class BacklinkService {
|
||||
constructor(
|
||||
private readonly backlinkRepo: BacklinkRepo,
|
||||
private readonly pagePermissionRepo: PagePermissionRepo,
|
||||
) {}
|
||||
|
||||
async countByPageId(
|
||||
pageId: string,
|
||||
userId: string,
|
||||
): Promise<{ incoming: number; outgoing: number }> {
|
||||
const [incomingIds, outgoingIds] = await Promise.all([
|
||||
this.accessibleRelatedIds(pageId, 'incoming', userId),
|
||||
this.accessibleRelatedIds(pageId, 'outgoing', userId),
|
||||
]);
|
||||
return { incoming: incomingIds.length, outgoing: outgoingIds.length };
|
||||
}
|
||||
|
||||
async findByPageId(
|
||||
pageId: string,
|
||||
direction: BacklinkDirection,
|
||||
userId: string,
|
||||
pagination: PaginationOptions,
|
||||
) {
|
||||
const accessibleIds = await this.accessibleRelatedIds(
|
||||
pageId,
|
||||
direction,
|
||||
userId,
|
||||
);
|
||||
return this.backlinkRepo.findPagesByIdsPaginated(accessibleIds, pagination);
|
||||
}
|
||||
|
||||
private async accessibleRelatedIds(
|
||||
pageId: string,
|
||||
direction: BacklinkDirection,
|
||||
userId: string,
|
||||
): Promise<string[]> {
|
||||
const candidateIds = await this.backlinkRepo.findRelatedPageIds(
|
||||
pageId,
|
||||
direction,
|
||||
userId,
|
||||
);
|
||||
if (candidateIds.length === 0) return [];
|
||||
return this.pagePermissionRepo.filterAccessiblePageIds({
|
||||
pageIds: candidateIds,
|
||||
userId,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,20 @@ import { KyselyDB, KyselyTransaction } from '@docmost/db/types/kysely.types';
|
||||
import { dbOrTx } from '@docmost/db/utils';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
|
||||
import {
|
||||
executeWithCursorPagination,
|
||||
emptyCursorPaginationResult,
|
||||
} from '@docmost/db/pagination/cursor-pagination';
|
||||
import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
|
||||
import { jsonObjectFrom } from 'kysely/helpers/postgres';
|
||||
|
||||
@Injectable()
|
||||
export class BacklinkRepo {
|
||||
constructor(@InjectKysely() private readonly db: KyselyDB) {}
|
||||
constructor(
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
private readonly spaceMemberRepo: SpaceMemberRepo,
|
||||
) {}
|
||||
|
||||
async findById(
|
||||
backlinkId: string,
|
||||
@@ -69,4 +79,84 @@ export class BacklinkRepo {
|
||||
const db = dbOrTx(this.db, trx);
|
||||
await db.deleteFrom('backlinks').where('id', '=', backlinkId).execute();
|
||||
}
|
||||
|
||||
async findRelatedPageIds(
|
||||
pageId: string,
|
||||
direction: 'incoming' | 'outgoing',
|
||||
userId: string,
|
||||
): Promise<string[]> {
|
||||
const userSpaceIds = this.spaceMemberRepo.getUserSpaceIdsQuery(userId);
|
||||
|
||||
if (direction === 'incoming') {
|
||||
const rows = await this.db
|
||||
.selectFrom('backlinks')
|
||||
.innerJoin('pages', 'pages.id', 'backlinks.sourcePageId')
|
||||
.select('backlinks.sourcePageId as relatedId')
|
||||
.where('backlinks.targetPageId', '=', pageId)
|
||||
.where('pages.deletedAt', 'is', null)
|
||||
.where('pages.spaceId', 'in', userSpaceIds)
|
||||
.execute();
|
||||
return rows.map((r) => r.relatedId);
|
||||
}
|
||||
|
||||
const rows = await this.db
|
||||
.selectFrom('backlinks')
|
||||
.innerJoin('pages', 'pages.id', 'backlinks.targetPageId')
|
||||
.select('backlinks.targetPageId as relatedId')
|
||||
.where('backlinks.sourcePageId', '=', pageId)
|
||||
.where('pages.deletedAt', 'is', null)
|
||||
.where('pages.spaceId', 'in', userSpaceIds)
|
||||
.execute();
|
||||
return rows.map((r) => r.relatedId);
|
||||
}
|
||||
|
||||
async findPagesByIdsPaginated(
|
||||
pageIds: string[],
|
||||
pagination: PaginationOptions,
|
||||
) {
|
||||
if (pageIds.length === 0) {
|
||||
return emptyCursorPaginationResult<{
|
||||
id: string;
|
||||
slugId: string;
|
||||
title: string | null;
|
||||
icon: string | null;
|
||||
spaceId: string;
|
||||
updatedAt: Date;
|
||||
space: { id: string; slug: string; name: string } | null;
|
||||
}>(pagination.limit);
|
||||
}
|
||||
|
||||
const query = this.db
|
||||
.selectFrom('pages')
|
||||
.select((eb) => [
|
||||
'pages.id',
|
||||
'pages.slugId',
|
||||
'pages.title',
|
||||
'pages.icon',
|
||||
'pages.spaceId',
|
||||
'pages.updatedAt',
|
||||
jsonObjectFrom(
|
||||
eb
|
||||
.selectFrom('spaces')
|
||||
.select(['spaces.id', 'spaces.slug', 'spaces.name'])
|
||||
.whereRef('spaces.id', '=', 'pages.spaceId'),
|
||||
).as('space'),
|
||||
])
|
||||
.where('pages.deletedAt', 'is', null)
|
||||
.where('pages.id', 'in', pageIds);
|
||||
|
||||
return executeWithCursorPagination(query, {
|
||||
perPage: pagination.limit,
|
||||
cursor: pagination.cursor,
|
||||
beforeCursor: pagination.beforeCursor,
|
||||
fields: [
|
||||
{ expression: 'pages.updatedAt', direction: 'desc', key: 'updatedAt' },
|
||||
{ expression: 'pages.id', direction: 'desc', key: 'id' },
|
||||
],
|
||||
parseCursor: (cursor) => ({
|
||||
updatedAt: new Date(cursor.updatedAt),
|
||||
id: cursor.id,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { TableCell as TiptapTableCell } from "@tiptap/extension-table";
|
||||
export const TableCell = TiptapTableCell.extend({
|
||||
name: "tableCell",
|
||||
content:
|
||||
"(paragraph | heading | bulletList | orderedList | taskList | blockquote | callout | image | video | attachment | mathBlock | details | codeBlock)+",
|
||||
"(paragraph | heading | bulletList | orderedList | taskList | blockquote | callout | image | video | audio | subpages | attachment | mathBlock | details | codeBlock)+",
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { TableHeader as TiptapTableHeader } from "@tiptap/extension-table";
|
||||
export const TableHeader = TiptapTableHeader.extend({
|
||||
name: "tableHeader",
|
||||
content:
|
||||
"(paragraph | heading | bulletList | orderedList | taskList | blockquote | callout | image | video | attachment | mathBlock | details | codeBlock)+",
|
||||
"(paragraph | heading | bulletList | orderedList | taskList | blockquote | callout | image | video | audio | subpages | attachment | mathBlock | details | codeBlock)+",
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user