mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 14:43:06 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 57cc41b2cf | |||
| 9ec688f679 |
+2
-3
@@ -1,6 +1,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.git
|
.git
|
||||||
|
.gitignore
|
||||||
dist
|
dist
|
||||||
/data
|
data
|
||||||
.env*
|
|
||||||
.nx
|
|
||||||
|
|||||||
+1
-10
@@ -43,13 +43,4 @@ POSTMARK_TOKEN=
|
|||||||
# for custom drawio server
|
# for custom drawio server
|
||||||
DRAWIO_URL=
|
DRAWIO_URL=
|
||||||
|
|
||||||
DISABLE_TELEMETRY=false
|
DISABLE_TELEMETRY=false
|
||||||
|
|
||||||
# Enable debug logging in production (default: false)
|
|
||||||
DEBUG_MODE=false
|
|
||||||
|
|
||||||
# Log database queries
|
|
||||||
DEBUG_DB=false
|
|
||||||
|
|
||||||
# Log http requests
|
|
||||||
LOG_HTTP=false
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
name: Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v*'
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'Version tag (e.g. v0.25.3)'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
VERSION: ${{ inputs.version || github.ref_name }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- platform: linux/amd64
|
|
||||||
runner: ubuntu-latest
|
|
||||||
suffix: amd64
|
|
||||||
- platform: linux/arm64
|
|
||||||
runner: ubuntu-24.04-arm
|
|
||||||
suffix: arm64
|
|
||||||
runs-on: ${{ matrix.runner }}
|
|
||||||
steps:
|
|
||||||
- name: Generate token
|
|
||||||
id: app-token
|
|
||||||
uses: actions/create-github-app-token@v1
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.BUILD_APP_ID }}
|
|
||||||
private-key: ${{ secrets.BUILD_APP_PRIVATE_KEY }}
|
|
||||||
owner: ${{ github.repository_owner }}
|
|
||||||
|
|
||||||
- name: Checkout with submodules
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ steps.app-token.outputs.token }}
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push by digest
|
|
||||||
id: build
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: ${{ matrix.platform }}
|
|
||||||
outputs: type=image,name=docmost/docmost,push-by-digest=true,name-canonical=true,push=true
|
|
||||||
cache-from: type=gha,scope=${{ matrix.suffix }}
|
|
||||||
cache-to: type=gha,scope=${{ matrix.suffix }},mode=max
|
|
||||||
|
|
||||||
- name: Export digest
|
|
||||||
run: |
|
|
||||||
mkdir -p /tmp/digests
|
|
||||||
digest="${{ steps.build.outputs.digest }}"
|
|
||||||
touch "/tmp/digests/${digest#sha256:}"
|
|
||||||
|
|
||||||
- name: Upload digest
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: digest-${{ matrix.suffix }}
|
|
||||||
path: /tmp/digests/*
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Strip v prefix
|
|
||||||
id: strip-v
|
|
||||||
run: echo "version=${VERSION#v}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Export Docker image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: ${{ matrix.platform }}
|
|
||||||
push: false
|
|
||||||
tags: |
|
|
||||||
docmost/docmost:latest
|
|
||||||
docmost/docmost:${{ steps.strip-v.outputs.version }}
|
|
||||||
outputs: type=docker,dest=docmost-${{ matrix.suffix }}.docker.tar
|
|
||||||
cache-from: type=gha,scope=${{ matrix.suffix }}
|
|
||||||
|
|
||||||
- name: Compress image
|
|
||||||
run: gzip docmost-${{ matrix.suffix }}.docker.tar
|
|
||||||
|
|
||||||
- name: Upload image archive
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: docker-image-${{ matrix.suffix }}
|
|
||||||
path: docmost-${{ matrix.suffix }}.docker.tar.gz
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
release:
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Download digests
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
pattern: digest-*
|
|
||||||
path: /tmp/digests
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract metadata for tags
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: docmost/docmost
|
|
||||||
tags: |
|
|
||||||
type=semver,pattern={{version}},value=${{ env.VERSION }}
|
|
||||||
type=semver,pattern={{major}}.{{minor}},value=${{ env.VERSION }},enable=${{ !contains(env.VERSION, '-') }}
|
|
||||||
type=raw,value=latest,enable=${{ !contains(env.VERSION, '-') }}
|
|
||||||
|
|
||||||
- name: Create manifest list and push
|
|
||||||
working-directory: /tmp/digests
|
|
||||||
run: |
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
$(printf 'docmost/docmost@sha256:%s ' *)
|
|
||||||
|
|
||||||
- name: Download image archives
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
pattern: docker-image-*
|
|
||||||
path: /tmp/images
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Create GitHub Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.VERSION }}
|
|
||||||
files: |
|
|
||||||
/tmp/images/docmost-amd64.docker.tar.gz
|
|
||||||
/tmp/images/docmost-arm64.docker.tar.gz
|
|
||||||
draft: true
|
|
||||||
+5
-7
@@ -1,22 +1,19 @@
|
|||||||
FROM node:22-slim AS base
|
FROM node:22-alpine AS base
|
||||||
LABEL org.opencontainers.image.source="https://github.com/docmost/docmost"
|
LABEL org.opencontainers.image.source="https://github.com/docmost/docmost"
|
||||||
|
|
||||||
RUN npm install -g pnpm@10.4.0
|
|
||||||
|
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm install -g pnpm@10.4.0
|
||||||
RUN pnpm install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
FROM base AS installer
|
FROM base AS installer
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apk add --no-cache curl bash
|
||||||
&& apt-get install -y --no-install-recommends curl bash \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -32,11 +29,12 @@ COPY --from=builder /app/packages/editor-ext/package.json /app/packages/editor-e
|
|||||||
# Copy root package files
|
# Copy root package files
|
||||||
COPY --from=builder /app/package.json /app/package.json
|
COPY --from=builder /app/package.json /app/package.json
|
||||||
COPY --from=builder /app/pnpm*.yaml /app/
|
COPY --from=builder /app/pnpm*.yaml /app/
|
||||||
COPY --from=builder /app/.npmrc /app/.npmrc
|
|
||||||
|
|
||||||
# Copy patches
|
# Copy patches
|
||||||
COPY --from=builder /app/patches /app/patches
|
COPY --from=builder /app/patches /app/patches
|
||||||
|
|
||||||
|
RUN npm install -g pnpm@10.4.0
|
||||||
|
|
||||||
RUN chown -R node:node /app
|
RUN chown -R node:node /app
|
||||||
|
|
||||||
USER node
|
USER node
|
||||||
|
|||||||
+3
-11
@@ -2,18 +2,10 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" />
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" />
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Docmost</title>
|
<title>Docmost</title>
|
||||||
<meta name="theme-color" content="#1f1f1f" media="(prefers-color-scheme: dark)" />
|
|
||||||
<meta name="theme-color" content="#f6f7f9" media="(prefers-color-scheme: light)" />
|
|
||||||
<link rel="manifest" href="/manifest.json" />
|
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
|
||||||
<meta name="apple-touch-fullscreen" content="yes" />
|
|
||||||
<meta name="apple-mobile-web-app-title" content="Docmost" />
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
||||||
<!--meta-tags-->
|
<!--meta-tags-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
+30
-34
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "client",
|
"name": "client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.70.1",
|
"version": "0.20.4",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
@@ -10,65 +10,61 @@
|
|||||||
"format": "prettier --write \"src/**/*.tsx\" \"src/**/*.ts\""
|
"format": "prettier --write \"src/**/*.tsx\" \"src/**/*.ts\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@casl/ability": "^6.7.2",
|
||||||
"@casl/react": "^4.0.0",
|
"@casl/react": "^4.0.0",
|
||||||
"@docmost/editor-ext": "workspace:*",
|
"@docmost/editor-ext": "workspace:*",
|
||||||
"@emoji-mart/data": "^1.2.1",
|
"@emoji-mart/data": "^1.2.1",
|
||||||
"@emoji-mart/react": "^1.1.1",
|
"@emoji-mart/react": "^1.1.1",
|
||||||
"@excalidraw/excalidraw": "0.18.0-3a5ef40",
|
"@excalidraw/excalidraw": "^0.17.6",
|
||||||
"@mantine/core": "^8.3.14",
|
"@mantine/core": "^7.17.0",
|
||||||
"@mantine/dates": "^8.3.14",
|
"@mantine/form": "^7.17.0",
|
||||||
"@mantine/form": "^8.3.14",
|
"@mantine/hooks": "^7.17.0",
|
||||||
"@mantine/hooks": "^8.3.14",
|
"@mantine/modals": "^7.17.0",
|
||||||
"@mantine/modals": "^8.3.14",
|
"@mantine/notifications": "^7.17.0",
|
||||||
"@mantine/notifications": "^8.3.14",
|
"@mantine/spotlight": "^7.17.0",
|
||||||
"@mantine/spotlight": "^8.3.14",
|
"@tabler/icons-react": "^3.22.0",
|
||||||
"@tabler/icons-react": "^3.36.1",
|
"@tanstack/react-query": "^5.61.4",
|
||||||
"@tanstack/react-query": "^5.90.17",
|
"@tiptap/extension-character-count": "^2.11.5",
|
||||||
"alfaaz": "^1.1.0",
|
"axios": "^1.8.4",
|
||||||
"axios": "^1.13.5",
|
|
||||||
"blueimp-load-image": "^5.16.0",
|
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"emoji-mart": "^5.6.0",
|
"emoji-mart": "^5.6.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"highlightjs-sap-abap": "^0.3.0",
|
"i18next": "^23.14.0",
|
||||||
"i18next": "^23.16.8",
|
"i18next-http-backend": "^2.6.1",
|
||||||
"i18next-http-backend": "^2.7.3",
|
"jotai": "^2.12.1",
|
||||||
"jotai": "^2.16.2",
|
|
||||||
"jotai-optics": "^0.4.0",
|
"jotai-optics": "^0.4.0",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"katex": "0.16.27",
|
"katex": "0.16.21",
|
||||||
"lowlight": "^3.3.0",
|
"lowlight": "^3.2.0",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mermaid": "^11.4.1",
|
||||||
"mermaid": "^11.12.2",
|
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"posthog-js": "1.345.5",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-arborist": "3.4.0",
|
"react-arborist": "3.4.0",
|
||||||
"react-clear-modal": "^2.0.17",
|
"react-clear-modal": "^2.0.11",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-drawio": "^1.0.7",
|
"react-drawio": "^1.0.1",
|
||||||
"react-error-boundary": "^4.1.2",
|
"react-error-boundary": "^4.1.2",
|
||||||
"react-helmet-async": "^2.0.5",
|
"react-helmet-async": "^2.0.5",
|
||||||
"react-i18next": "^15.0.1",
|
"react-i18next": "^15.0.1",
|
||||||
"react-router-dom": "^7.12.0",
|
"react-router-dom": "^7.0.1",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.1",
|
||||||
"socket.io-client": "^4.8.3",
|
"socket.io-client": "^4.8.1",
|
||||||
|
"tippy.js": "^6.3.7",
|
||||||
"tiptap-extension-global-drag-handle": "^0.1.18",
|
"tiptap-extension-global-drag-handle": "^0.1.18",
|
||||||
"zod": "^4.3.6"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.16.0",
|
"@eslint/js": "^9.16.0",
|
||||||
"@tanstack/eslint-plugin-query": "^5.62.1",
|
"@tanstack/eslint-plugin-query": "^5.62.1",
|
||||||
"@types/blueimp-load-image": "^5.16.0",
|
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/katex": "^0.16.7",
|
"@types/katex": "^0.16.7",
|
||||||
"@types/node": "22.19.1",
|
"@types/node": "22.10.0",
|
||||||
"@types/react": "^18.3.12",
|
"@types/react": "^18.3.12",
|
||||||
"@types/react-dom": "^18.3.1",
|
"@types/react-dom": "^18.3.1",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.15.0",
|
||||||
"eslint-plugin-react": "^7.37.2",
|
"eslint-plugin-react": "^7.37.2",
|
||||||
"eslint-plugin-react-hooks": "^5.1.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.16",
|
"eslint-plugin-react-refresh": "^0.4.16",
|
||||||
@@ -80,6 +76,6 @@
|
|||||||
"prettier": "^3.4.1",
|
"prettier": "^3.4.1",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.2",
|
||||||
"typescript-eslint": "^8.17.0",
|
"typescript-eslint": "^8.17.0",
|
||||||
"vite": "^7.2.4"
|
"vite": "^6.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 562 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 509 B |
Binary file not shown.
|
Before Width: | Height: | Size: 881 B |
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Wählen Sie Ihre bevorzugte Benutzersprache.",
|
"Choose your preferred interface language.": "Wählen Sie Ihre bevorzugte Benutzersprache.",
|
||||||
"Choose your preferred page width.": "Wählen Sie Ihre bevorzugte Seitenbreite.",
|
"Choose your preferred page width.": "Wählen Sie Ihre bevorzugte Seitenbreite.",
|
||||||
"Confirm": "Bestätigen",
|
"Confirm": "Bestätigen",
|
||||||
"Copy as Markdown": "Als Markdown kopieren",
|
|
||||||
"Copy link": "Link kopieren",
|
"Copy link": "Link kopieren",
|
||||||
"Create": "Erstellen",
|
"Create": "Erstellen",
|
||||||
"Create group": "Gruppe erstellen",
|
"Create group": "Gruppe erstellen",
|
||||||
@@ -41,9 +40,9 @@
|
|||||||
"Date": "Datum",
|
"Date": "Datum",
|
||||||
"Delete": "Löschen",
|
"Delete": "Löschen",
|
||||||
"Delete group": "Gruppe löschen",
|
"Delete group": "Gruppe löschen",
|
||||||
"Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Sind Sie sicher, dass Sie diese Seite löschen möchten? Dabei werden auch alle Unterseiten und der Seitenverlauf gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",
|
"Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Sind Sie sicher, dass Sie diese Seite löschen möchten? Dadurch werden ihre Unterseiten und die Seitengeschichte gelöscht. Diese Aktion ist unwiderruflich.",
|
||||||
"Description": "Beschreibung",
|
"Description": "Beschreibung",
|
||||||
"Details": "Details",
|
"Details": "Einzelheiten",
|
||||||
"e.g ACME": "z.B. ACME",
|
"e.g ACME": "z.B. ACME",
|
||||||
"e.g ACME Inc": "z.B. ACME Inc.",
|
"e.g ACME Inc": "z.B. ACME Inc.",
|
||||||
"e.g Developers": "z.B. Entwickler",
|
"e.g Developers": "z.B. Entwickler",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "z.B. Bereich für das Produktteam",
|
"e.g Space for product team": "z.B. Bereich für das Produktteam",
|
||||||
"e.g Space for sales team to collaborate": "z.B. Bereich für das Vertriebsteam zur Zusammenarbeit",
|
"e.g Space for sales team to collaborate": "z.B. Bereich für das Vertriebsteam zur Zusammenarbeit",
|
||||||
"Edit": "Bearbeiten",
|
"Edit": "Bearbeiten",
|
||||||
"Read": "Lesen",
|
|
||||||
"Edit group": "Gruppe bearbeiten",
|
"Edit group": "Gruppe bearbeiten",
|
||||||
"Email": "E-Mail",
|
"Email": "E-Mail",
|
||||||
"Enter a strong password": "Geben Sie ein starkes Passwort ein",
|
"Enter a strong password": "Geben Sie ein starkes Passwort ein",
|
||||||
@@ -66,7 +64,7 @@
|
|||||||
"Enter your new preferred email": "Geben Sie Ihre neue bevorzugte E-Mail ein",
|
"Enter your new preferred email": "Geben Sie Ihre neue bevorzugte E-Mail ein",
|
||||||
"Enter your password": "Geben Sie Ihr Passwort ein",
|
"Enter your password": "Geben Sie Ihr Passwort ein",
|
||||||
"Error fetching page data.": "Fehler beim Abrufen der Seitendaten.",
|
"Error fetching page data.": "Fehler beim Abrufen der Seitendaten.",
|
||||||
"Error loading page history.": "Fehler beim Laden des Seitenverlaufs.",
|
"Error loading page history.": "Fehler beim Laden der Seitengeschichte.",
|
||||||
"Export": "Exportieren",
|
"Export": "Exportieren",
|
||||||
"Failed to create page": "Erstellung der Seite fehlgeschlagen",
|
"Failed to create page": "Erstellung der Seite fehlgeschlagen",
|
||||||
"Failed to delete page": "Löschen der Seite fehlgeschlagen",
|
"Failed to delete page": "Löschen der Seite fehlgeschlagen",
|
||||||
@@ -106,7 +104,7 @@
|
|||||||
"Member": "Mitglied",
|
"Member": "Mitglied",
|
||||||
"members": "Mitglieder",
|
"members": "Mitglieder",
|
||||||
"Members": "Mitglieder",
|
"Members": "Mitglieder",
|
||||||
"My preferences": "Meine Voreinstellungen",
|
"My preferences": "Meine Vorlieben",
|
||||||
"My Profile": "Mein Profil",
|
"My Profile": "Mein Profil",
|
||||||
"My profile": "Mein Profil",
|
"My profile": "Mein Profil",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
@@ -114,24 +112,20 @@
|
|||||||
"New page": "Neue Seite",
|
"New page": "Neue Seite",
|
||||||
"New password": "Neues Passwort",
|
"New password": "Neues Passwort",
|
||||||
"No group found": "Keine Gruppe gefunden",
|
"No group found": "Keine Gruppe gefunden",
|
||||||
"No page history saved yet.": "Es wurde noch kein Seitenverlauf gespeichert.",
|
"No page history saved yet.": "Es wurde noch keine Seitengeschichte gespeichert.",
|
||||||
"No pages yet": "Noch keine Seiten",
|
"No pages yet": "Noch keine Seiten",
|
||||||
"No shared pages": "Keine freigegebenen Seiten",
|
|
||||||
"No results found...": "Keine Ergebnisse gefunden...",
|
"No results found...": "Keine Ergebnisse gefunden...",
|
||||||
"No user found": "Kein Benutzer gefunden",
|
"No user found": "Kein Benutzer gefunden",
|
||||||
"Overview": "Überblick",
|
"Overview": "Überblick",
|
||||||
"Owner": "Besitzer",
|
"Owner": "Besitzer",
|
||||||
"page": "Seite",
|
"page": "Seite",
|
||||||
"Page deleted successfully": "Seite erfolgreich gelöscht",
|
"Page deleted successfully": "Seite erfolgreich gelöscht",
|
||||||
"Page history": "Seitenverlauf",
|
"Page history": "Seitengeschichte",
|
||||||
"Select version": "Version auswählen",
|
|
||||||
"Highlight changes": "Änderungen hervorheben",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "Der Seitenimport läuft. Bitte schließen Sie diesen Tab nicht.",
|
"Page import is in progress. Please do not close this tab.": "Der Seitenimport läuft. Bitte schließen Sie diesen Tab nicht.",
|
||||||
"Pages": "Seiten",
|
"Pages": "Seiten",
|
||||||
"pages": "Seiten",
|
"pages": "Seiten",
|
||||||
"Password": "Passwort",
|
"Password": "Passwort",
|
||||||
"Password changed successfully": "Passwort erfolgreich geändert",
|
"Password changed successfully": "Passwort erfolgreich geändert",
|
||||||
"People": "Personen",
|
|
||||||
"Pending": "Ausstehend",
|
"Pending": "Ausstehend",
|
||||||
"Please confirm your action": "Bitte bestätigen Sie Ihre Aktion",
|
"Please confirm your action": "Bitte bestätigen Sie Ihre Aktion",
|
||||||
"Preferences": "Vorlieben",
|
"Preferences": "Vorlieben",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Antworten...",
|
"Reply...": "Antworten...",
|
||||||
"Error loading comments.": "Fehler beim Laden der Kommentare.",
|
"Error loading comments.": "Fehler beim Laden der Kommentare.",
|
||||||
"No comments yet.": "Noch keine Kommentare.",
|
"No comments yet.": "Noch keine Kommentare.",
|
||||||
"No open comments.": "Keine offenen Kommentare.",
|
|
||||||
"No resolved comments.": "Keine gelösten Kommentare.",
|
|
||||||
"Add a comment...": "Kommentar hinzufügen...",
|
|
||||||
"Edit comment": "Kommentar bearbeiten",
|
"Edit comment": "Kommentar bearbeiten",
|
||||||
"Delete comment": "Kommentar löschen",
|
"Delete comment": "Kommentar löschen",
|
||||||
"Are you sure you want to delete this comment?": "Sind Sie sicher, dass Sie diesen Kommentar löschen möchten?",
|
"Are you sure you want to delete this comment?": "Sind Sie sicher, dass Sie diesen Kommentar löschen möchten?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Kommentar erfolgreich gelöscht",
|
"Comment deleted successfully": "Kommentar erfolgreich gelöscht",
|
||||||
"Failed to delete comment": "Löschen des Kommentars fehlgeschlagen",
|
"Failed to delete comment": "Löschen des Kommentars fehlgeschlagen",
|
||||||
"Comment resolved successfully": "Kommentar erfolgreich gelöst",
|
"Comment resolved successfully": "Kommentar erfolgreich gelöst",
|
||||||
"Comment re-opened successfully": "Kommentar erfolgreich wieder geöffnet",
|
|
||||||
"Comment unresolved successfully": "Kommentar erfolgreich ungelöst",
|
|
||||||
"Failed to resolve comment": "Lösen des Kommentars fehlgeschlagen",
|
"Failed to resolve comment": "Lösen des Kommentars fehlgeschlagen",
|
||||||
"Resolve comment": "Kommentar lösen",
|
|
||||||
"Unresolve comment": "Kommentar nicht lösen",
|
|
||||||
"Resolve Comment Thread": "Kommentarthread lösen",
|
|
||||||
"Unresolve Comment Thread": "Kommentarthread nicht lösen",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Sind Sie sicher, dass Sie diesen Kommentarthread lösen möchten? Dies wird als abgeschlossen markiert.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Sind Sie sicher, dass Sie diesen Kommentarthread nicht lösen möchten?",
|
|
||||||
"Resolved": "Gelöst",
|
|
||||||
"No active comments.": "Keine aktiven Kommentare.",
|
|
||||||
"Revoke invitation": "Einladung widerrufen",
|
"Revoke invitation": "Einladung widerrufen",
|
||||||
"Revoke": "Widerrufen",
|
"Revoke": "Widerrufen",
|
||||||
"Don't": "Nicht",
|
"Don't": "Nicht",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Jeder mit diesem Link kann dem Arbeitsbereich beitreten.",
|
"Anyone with this link can join this workspace.": "Jeder mit diesem Link kann dem Arbeitsbereich beitreten.",
|
||||||
"Invite link": "Einladungslink",
|
"Invite link": "Einladungslink",
|
||||||
"Copy": "Kopieren",
|
"Copy": "Kopieren",
|
||||||
"Copy to space": "In Raum kopieren",
|
|
||||||
"Copied": "Kopiert",
|
"Copied": "Kopiert",
|
||||||
"Duplicate": "Duplizieren",
|
|
||||||
"Select a user": "Benutzer auswählen",
|
"Select a user": "Benutzer auswählen",
|
||||||
"Select a group": "Gruppe auswählen",
|
"Select a group": "Gruppe auswählen",
|
||||||
"Export all pages and attachments in this space.": "Alle Seiten und Anhänge in diesem Bereich exportieren.",
|
"Export all pages and attachments in this space.": "Alle Seiten und Anhänge in diesem Bereich exportieren.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Export fehlgeschlagen:",
|
"Export failed:": "Export fehlgeschlagen:",
|
||||||
"export error": "Exportfehler",
|
"export error": "Exportfehler",
|
||||||
"Export page": "Seite exportieren",
|
"Export page": "Seite exportieren",
|
||||||
"Export successful": "Export erfolgreich",
|
|
||||||
"Export space": "Bereich exportieren",
|
"Export space": "Bereich exportieren",
|
||||||
"Export {{type}}": "Exportiere {{type}}",
|
"Export {{type}}": "Exportiere {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "Datei überschreitet das Anhängelimit von {{limit}}",
|
"File exceeds the {{limit}} attachment limit": "Datei überschreitet das Anhängelimit von {{limit}}",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Zeile unten hinzufügen",
|
"Add row below": "Zeile unten hinzufügen",
|
||||||
"Delete table": "Tabelle löschen",
|
"Delete table": "Tabelle löschen",
|
||||||
"Info": "Info",
|
"Info": "Info",
|
||||||
"Note": "Hinweis",
|
|
||||||
"Success": "Erfolg",
|
"Success": "Erfolg",
|
||||||
"Warning": "Warnung",
|
"Warning": "Warnung",
|
||||||
"Danger": "Gefahr",
|
"Danger": "Gefahr",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Laden Sie ein beliebiges Bild von Ihrem Gerät hoch.",
|
"Upload any image from your device.": "Laden Sie ein beliebiges Bild von Ihrem Gerät hoch.",
|
||||||
"Upload any video from your device.": "Laden Sie ein beliebiges Video von Ihrem Gerät hoch.",
|
"Upload any video from your device.": "Laden Sie ein beliebiges Video von Ihrem Gerät hoch.",
|
||||||
"Upload any file from your device.": "Laden Sie eine beliebige Datei von Ihrem Gerät hoch.",
|
"Upload any file from your device.": "Laden Sie eine beliebige Datei von Ihrem Gerät hoch.",
|
||||||
"Uploading {{name}}": "Lade {{name}} hoch",
|
|
||||||
"Uploading file": "Datei wird hochgeladen",
|
|
||||||
"Table": "Tabelle",
|
"Table": "Tabelle",
|
||||||
"Insert a table.": "Tabelle einfügen.",
|
"Insert a table.": "Tabelle einfügen.",
|
||||||
"Insert collapsible block.": "Einklappbaren Block einfügen.",
|
"Insert collapsible block.": "Einklappbaren Block einfügen.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Aktuelles Datum einfügen",
|
"Insert current date": "Aktuelles Datum einfügen",
|
||||||
"Draw and sketch excalidraw diagrams": "Excalidraw-Diagramme zeichnen und skizzieren",
|
"Draw and sketch excalidraw diagrams": "Excalidraw-Diagramme zeichnen und skizzieren",
|
||||||
"Multiple": "Mehrere",
|
"Multiple": "Mehrere",
|
||||||
"Turn into": "In verwandeln",
|
|
||||||
"Text align": "Text ausrichten",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "\"Diese Seite wurde möglicherweise gelöscht, verschoben oder Sie haben keinen Zugriff darauf.\"",
|
|
||||||
"Go to homepage": "Zur Startseite",
|
|
||||||
"Pages you create will show up here.": "\"Die von Ihnen erstellten Seiten werden hier angezeigt.\"",
|
|
||||||
"Heading {{level}}": "Überschrift {{level}}",
|
"Heading {{level}}": "Überschrift {{level}}",
|
||||||
"Toggle title": "Titel umschalten",
|
"Toggle title": "Titel umschalten",
|
||||||
"Write anything. Enter \"/\" for commands": "Schreiben Sie irgendetwas. Geben Sie \"/\" für Befehle ein",
|
"Write anything. Enter \"/\" for commands": "Schreiben Sie irgendetwas. Geben Sie \"/\" für Befehle ein",
|
||||||
"Write...": "\"Schreiben...\"",
|
|
||||||
"Column count": "Spaltenanzahl",
|
|
||||||
"{{count}} Columns": "{count, plural, one {# Spalte} other {# Spalten}}",
|
|
||||||
"Equal columns": "Gleich breite Spalten",
|
|
||||||
"Left sidebar": "Linke Seitenleiste",
|
|
||||||
"Right sidebar": "Rechte Seitenleiste",
|
|
||||||
"Wide center": "Breiter Mittelbereich",
|
|
||||||
"Left wide": "Breiter linker Bereich",
|
|
||||||
"Right wide": "Breiter rechter Bereich",
|
|
||||||
"Names do not match": "Namen stimmen nicht überein",
|
"Names do not match": "Namen stimmen nicht überein",
|
||||||
"Today, {{time}}": "Heute, {{time}}",
|
"Today, {{time}}": "Heute, {{time}}",
|
||||||
"Yesterday, {{time}}": "Gestern, {{time}}",
|
"Yesterday, {{time}}": "Gestern, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Zeichenzahl: {{characterCount}}",
|
"Character count: {{characterCount}}": "Zeichenzahl: {{characterCount}}",
|
||||||
"New update": "Neues Update",
|
"New update": "Neues Update",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} ist verfügbar",
|
"{{latestVersion}} is available": "{{latestVersion}} ist verfügbar",
|
||||||
"Default page edit mode": "Standard-Seitenbearbeitungsmodus",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Wählen Sie Ihren bevorzugten Seitenbearbeitungsmodus. Vermeiden Sie versehentliche Bearbeitungen.",
|
|
||||||
"Reading": "Lesen",
|
|
||||||
"Delete member": "Mitglied löschen",
|
"Delete member": "Mitglied löschen",
|
||||||
"Member deleted successfully": "Mitglied erfolgreich gelöscht",
|
"Member deleted successfully": "Mitglied erfolgreich gelöscht",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Sind Sie sicher, dass Sie dieses Arbeitsbereichsmitglied löschen möchten? Diese Aktion ist unwiderruflich.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Sind Sie sicher, dass Sie dieses Arbeitsbereichsmitglied löschen möchten? Diese Aktion ist unwiderruflich.",
|
||||||
"Deactivate member": "Mitglied deaktivieren",
|
|
||||||
"Activate member": "Mitglied aktivieren",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Sind Sie sicher, dass Sie dieses Mitglied des Arbeitsbereichs deaktivieren möchten? Dieses Mitglied kann danach nicht mehr auf diesen Arbeitsbereich zugreifen.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Sind Sie sicher, dass Sie dieses Mitglied des Arbeitsbereichs aktivieren möchten?",
|
|
||||||
"Deactivate": "Deaktivieren",
|
|
||||||
"Activate": "Aktivieren",
|
|
||||||
"Deactivated": "Deaktiviert",
|
|
||||||
"Move": "Verschieben",
|
"Move": "Verschieben",
|
||||||
"Move page": "Seite verschieben",
|
"Move page": "Seite verschieben",
|
||||||
"Move page to a different space.": "Seite in einen anderen Bereich verschieben.",
|
"Move page to a different space.": "Seite in einen anderen Bereich verschieben.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Öffentlich geteilte Seiten aus Bereichen, in denen Sie Mitglied sind, erscheinen hier",
|
"Publicly shared pages from spaces you are a member of will appear here": "Öffentlich geteilte Seiten aus Bereichen, in denen Sie Mitglied sind, erscheinen hier",
|
||||||
"Share deleted successfully": "Freigabe erfolgreich gelöscht",
|
"Share deleted successfully": "Freigabe erfolgreich gelöscht",
|
||||||
"Share not found": "Freigabe nicht gefunden",
|
"Share not found": "Freigabe nicht gefunden",
|
||||||
"Failed to share page": "Fehler beim Teilen der Seite",
|
"Failed to share page": "Fehler beim Teilen der Seite"
|
||||||
"Disable public sharing": "Öffentliches Teilen deaktivieren",
|
|
||||||
"Prevent members from sharing pages publicly.": "Verhindern Sie, dass Mitglieder Seiten öffentlich teilen.",
|
|
||||||
"Toggle public sharing": "Öffentliches Teilen umschalten",
|
|
||||||
"Toggle space public sharing": "Öffentliches Teilen im Bereich umschalten",
|
|
||||||
"Public sharing is disabled at the workspace level": "Öffentliches Teilen ist auf der Arbeitsbereichsebene deaktiviert",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Verhindern Sie, dass Seiten in diesem Bereich öffentlich geteilt werden.",
|
|
||||||
"Requires an enterprise license": "Erfordert eine Unternehmenslizenz",
|
|
||||||
"Page permissions": "Seitenberechtigungen",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Steuern Sie, wer einzelne Seiten ansehen und bearbeiten kann. Verfügbar mit einer Enterprise-Lizenz.",
|
|
||||||
"Enable public sharing": "Öffentliches Teilen aktivieren",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Sind Sie sicher, dass Sie das öffentliche Teilen aktivieren möchten? Mitglieder können Seiten öffentlich teilen.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Sind Sie sicher, dass Sie das öffentliche Teilen deaktivieren möchten? Alle bestehenden Freigabelinks in diesem Arbeitsbereich werden gelöscht.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Sind Sie sicher, dass Sie das öffentliche Teilen für diesen Bereich aktivieren möchten?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Sind Sie sicher, dass Sie das öffentliche Teilen deaktivieren möchten? Alle bestehenden Freigabelinks in diesem Bereich werden gelöscht.",
|
|
||||||
"Public sharing is disabled": "Öffentliches Teilen ist deaktiviert",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "Das öffentliche Teilen wurde auf der Arbeitsbereichsebene deaktiviert.",
|
|
||||||
"Public sharing has been disabled for this space.": "Das öffentliche Teilen wurde für diesen Bereich deaktiviert.",
|
|
||||||
"Copy page": "Seite kopieren",
|
|
||||||
"Copy page to a different space.": "Seite in einen anderen Bereich kopieren.",
|
|
||||||
"Page copied successfully": "Seite erfolgreich kopiert",
|
|
||||||
"Page duplicated successfully": "Seite erfolgreich dupliziert",
|
|
||||||
"Find": "Finden",
|
|
||||||
"Not found": "Nicht gefunden",
|
|
||||||
"Previous Match (Shift+Enter)": "Vorheriger Treffer (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Nächster Treffer (Enter)",
|
|
||||||
"Match case (Alt+C)": "Groß-/Kleinschreibung beachten (Alt+C)",
|
|
||||||
"Replace": "Ersetzen",
|
|
||||||
"Close (Escape)": "Schließen (Escape)",
|
|
||||||
"Replace (Enter)": "Ersetzen (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Alle ersetzen (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Alle ersetzen",
|
|
||||||
"View all spaces": "Alle Räume anzeigen",
|
|
||||||
"Error": "Fehler",
|
|
||||||
"Failed to disable MFA": "Deaktivierung der MFA fehlgeschlagen",
|
|
||||||
"Disable two-factor authentication": "Zwei-Faktor-Authentifizierung deaktivieren",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Die Deaktivierung der Zwei-Faktor-Authentifizierung macht Ihr Konto weniger sicher. Sie benötigen nur Ihr Passwort, um sich anzumelden.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Bitte geben Sie Ihr Passwort ein, um die Zwei-Faktor-Authentifizierung zu deaktivieren:",
|
|
||||||
"Two-factor authentication has been enabled": "Zwei-Faktor-Authentifizierung wurde aktiviert",
|
|
||||||
"Two-factor authentication has been disabled": "Zwei-Faktor-Authentifizierung wurde deaktiviert",
|
|
||||||
"2-step verification": "2-Schritt-Verifizierung",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Schützen Sie Ihr Konto mit einer zusätzlichen Verifizierungsschicht beim Anmelden.",
|
|
||||||
"Two-factor authentication is active on your account.": "Die Zwei-Faktor-Authentifizierung ist auf Ihrem Konto aktiv.",
|
|
||||||
"Add 2FA method": "2FA-Methode hinzufügen",
|
|
||||||
"Backup codes": "Sicherungscodes",
|
|
||||||
"Disable": "Deaktivieren",
|
|
||||||
"Invalid verification code": "Ungültiger Bestätigungscode",
|
|
||||||
"New backup codes have been generated": "Neue Sicherungscodes wurden generiert",
|
|
||||||
"Failed to regenerate backup codes": "Fehler beim Generieren neuer Sicherungscodes",
|
|
||||||
"About backup codes": "Über Sicherungscodes",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Sicherungscodes können verwendet werden, um auf Ihr Konto zuzugreifen, wenn Sie den Zugang zu Ihrer Authenticator-App verlieren. Jeder Code kann nur einmal verwendet werden.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Sie können jederzeit neue Sicherungscodes generieren. Dies wird alle vorhandenen Codes ungültig machen.",
|
|
||||||
"Confirm password": "Passwort bestätigen",
|
|
||||||
"Generate new backup codes": "Neue Sicherungscodes generieren",
|
|
||||||
"Save your new backup codes": "Speichern Sie Ihre neuen Sicherungscodes",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Speichern Sie diese Codes an einem sicheren Ort. Ihre alten Sicherungscodes sind nicht mehr gültig.",
|
|
||||||
"Your new backup codes": "Ihre neuen Sicherungscodes",
|
|
||||||
"I've saved my backup codes": "Ich habe meine Sicherungscodes gespeichert",
|
|
||||||
"Failed to setup MFA": "Fehler beim Einrichten der MFA",
|
|
||||||
"Setup & Verify": "Einrichten & Überprüfen",
|
|
||||||
"Add to authenticator": "Zum Authenticator hinzufügen",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Scannen Sie diesen QR-Code mit Ihrer Authenticator-App",
|
|
||||||
"Can't scan the code?": "Code kann nicht gescannt werden?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Geben Sie diesen Code manuell in Ihrer Authenticator-App ein:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Geben Sie den 6-stelligen Code aus Ihrem Authenticator ein",
|
|
||||||
"Verify and enable": "Überprüfen und aktivieren",
|
|
||||||
"Failed to generate QR code. Please try again.": "Fehler beim Generieren des QR-Codes. Bitte versuchen Sie es erneut.",
|
|
||||||
"Backup": "Sicherung",
|
|
||||||
"Save codes": "Codes speichern",
|
|
||||||
"Save your backup codes": "Speichern Sie Ihre Sicherungscodes",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Diese Codes können verwendet werden, um auf Ihr Konto zuzugreifen, wenn Sie den Zugang zu Ihrer Authenticator-App verlieren. Jeder Code kann nur einmal verwendet werden.",
|
|
||||||
"Print": "Drucken",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "Zwei-Faktor-Authentifizierung wurde eingerichtet. Bitte melden Sie sich erneut an.",
|
|
||||||
"Two-Factor authentication required": "Zwei-Faktor-Authentifizierung erforderlich",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Ihr Arbeitsbereich erfordert die Zwei-Faktor-Authentifizierung für alle Benutzer",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Um weiterhin auf Ihren Arbeitsbereich zuzugreifen, müssen Sie die Zwei-Faktor-Authentifizierung einrichten. Dies fügt Ihrem Konto eine zusätzliche Sicherheitsebene hinzu.",
|
|
||||||
"Set up two-factor authentication": "Zwei-Faktor-Authentifizierung einrichten",
|
|
||||||
"Cancel and logout": "Abbrechen und abmelden",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Ihr Arbeitsbereich erfordert eine Zwei-Faktor-Authentifizierung. Bitte richten Sie diese ein, um fortzufahren.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Dadurch wird Ihrem Konto eine zusätzliche Sicherheitsebene hinzugefügt, indem ein Bestätigungscode von Ihrer Authenticator-App verlangt wird.",
|
|
||||||
"Password is required": "Passwort erforderlich",
|
|
||||||
"Password must be at least 8 characters": "Passwort muss mindestens 8 Zeichen lang sein",
|
|
||||||
"Please enter a 6-digit code": "Bitte geben Sie einen 6-stelligen Code ein",
|
|
||||||
"Code must be exactly 6 digits": "Code muss genau 6-stellig sein",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Geben Sie den 6-stelligen Code ein, der in Ihrer Authenticator-App zu finden ist",
|
|
||||||
"Need help authenticating?": "Brauchen Sie Hilfe bei der Authentifizierung?",
|
|
||||||
"MFA QR Code": "MFA QR-Code",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Konto erfolgreich erstellt. Bitte melden Sie sich an, um die Zwei-Faktor-Authentifizierung einzurichten.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Passwort erfolgreich zurückgesetzt. Bitte melden Sie sich mit Ihrem neuen Passwort an und führen Sie die Zwei-Faktor-Authentifizierung durch.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Passwort erfolgreich zurückgesetzt. Bitte melden Sie sich mit Ihrem neuen Passwort an, um die Zwei-Faktor-Authentifizierung einzurichten.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "Passwort erfolgreich zurückgesetzt. Bitte melden Sie sich mit Ihrem neuen Passwort an.",
|
|
||||||
"Two-factor authentication": "Zwei-Faktor-Authentifizierung",
|
|
||||||
"Use authenticator app instead": "Stattdessen Authenticator-App verwenden",
|
|
||||||
"Verify backup code": "Sicherungscode überprüfen",
|
|
||||||
"Use backup code": "Sicherungscode verwenden",
|
|
||||||
"Enter one of your backup codes": "Geben Sie einen Ihrer Sicherungscodes ein",
|
|
||||||
"Backup code": "Sicherungscode",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Geben Sie einen Ihrer Sicherungscodes ein. Jeder Sicherungscode kann nur einmal verwendet werden.",
|
|
||||||
"Verify": "Überprüfen",
|
|
||||||
"Trash": "Papierkorb",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "Seiten im Papierkorb werden nach {{count}} Tagen endgültig gelöscht.",
|
|
||||||
"Deleted": "Gelöscht",
|
|
||||||
"No pages in trash": "Keine Seiten im Papierkorb",
|
|
||||||
"Permanently delete page?": "Seite endgültig löschen?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Sind Sie sicher, dass Sie '{{title}}' endgültig löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "'{{title}}' und seine Unterseiten wiederherstellen?",
|
|
||||||
"Move to trash": "In den Papierkorb verschieben",
|
|
||||||
"Move this page to trash?": "Diese Seite in den Papierkorb verschieben?",
|
|
||||||
"Restore page": "Seite wiederherstellen",
|
|
||||||
"Page moved to trash": "Seite in den Papierkorb verschoben",
|
|
||||||
"Page restored successfully": "Seite erfolgreich wiederhergestellt",
|
|
||||||
"Deleted by": "Gelöscht von",
|
|
||||||
"Deleted at": "Gelöscht am",
|
|
||||||
"Preview": "Vorschau",
|
|
||||||
"Subpages": "Unterseiten",
|
|
||||||
"Failed to load subpages": "Fehler beim Laden von Unterseiten",
|
|
||||||
"No subpages": "Keine Unterseiten",
|
|
||||||
"Subpages (Child pages)": "Unterseiten (Untergeordnete Seiten)",
|
|
||||||
"List all subpages of the current page": "Alle Unterseiten der aktuellen Seite auflisten",
|
|
||||||
"Attachments": "Anhänge",
|
|
||||||
"All spaces": "Alle Bereiche",
|
|
||||||
"Unknown": "Unbekannt",
|
|
||||||
"Find a space": "Einen Bereich finden",
|
|
||||||
"Search in all your spaces": "In all deinen Bereichen suchen",
|
|
||||||
"Type": "Art",
|
|
||||||
"Enterprise": "Unternehmen",
|
|
||||||
"Download attachment": "Anhang herunterladen",
|
|
||||||
"Allowed email domains": "Erlaubte E-Mail-Domains",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Nur Benutzer mit E-Mail-Adressen aus diesen Domains können sich über SSO registrieren.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Geben Sie gültige Domainnamen ein, durch Kommas oder Leerzeichen getrennt",
|
|
||||||
"Enforce two-factor authentication": "Erzwingen der Zwei-Faktor-Authentifizierung",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Sobald es erzwungen wird, müssen alle Mitglieder die Zwei-Faktor-Authentifizierung aktivieren, um auf den Arbeitsbereich zugreifen zu können.",
|
|
||||||
"Toggle MFA enforcement": "Umschalten der MFA-Erzwingung",
|
|
||||||
"Display name": "Anzeigename",
|
|
||||||
"Allow signup": "Registrierung erlauben",
|
|
||||||
"Enabled": "Aktiviert",
|
|
||||||
"Advanced Settings": "Erweiterte Einstellungen",
|
|
||||||
"Enable TLS/SSL": "TLS/SSL aktivieren",
|
|
||||||
"Use secure connection to LDAP server": "Sichere Verbindung zum LDAP-Server verwenden",
|
|
||||||
"Group sync": "Gruppensynchronisation",
|
|
||||||
"No SSO providers found.": "Keine SSO-Anbieter gefunden.",
|
|
||||||
"Delete SSO provider": "SSO-Anbieter löschen",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Sind Sie sicher, dass Sie diesen SSO-Anbieter löschen möchten?",
|
|
||||||
"Action": "Aktion",
|
|
||||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}}-Konfiguration",
|
|
||||||
"Icon": "Icon",
|
|
||||||
"Upload image": "Bild hochladen",
|
|
||||||
"Remove image": "Bild entfernen",
|
|
||||||
"Failed to remove image": "Fehler beim Entfernen des Bildes",
|
|
||||||
"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",
|
|
||||||
"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.",
|
|
||||||
"Toggle restrict API keys to admins": "Beschränkung der API-Schlüssel auf Administratoren umschalten",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "Die Erstellung von API-Schlüsseln ist durch Ihren Workspace-Administrator auf Administratoren beschränkt.",
|
|
||||||
"AI settings": "KI-Einstellungen",
|
|
||||||
"AI search": "KI-Suche",
|
|
||||||
"AI Answer": "KI-Antwort",
|
|
||||||
"Ask AI": "KI fragen",
|
|
||||||
"AI is thinking...": "Die KI überlegt...",
|
|
||||||
"Ask a question...": "Fragen stellen...",
|
|
||||||
"AI Answers": "KI-Antworten",
|
|
||||||
"AI-powered search (AI Answers)": "KI-unterstützte Suche (KI-Antworten)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "Die KI-Suche verwendet Vektor-Einbettungen, um semantische Suchfunktionen in Ihrem Arbeitsbereich bereitzustellen.",
|
|
||||||
"Toggle AI search": "KI-Suche umschalten",
|
|
||||||
"Generative AI (Ask AI)": "Generative KI (KI fragen)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Aktivieren Sie die KI-unterstützte Inhaltserstellung im Editor. Ermöglicht Benutzern das Erzeugen, Verbessern, Übersetzen und Transformieren von Text.",
|
|
||||||
"Toggle generative AI": "Generative KI umschalten",
|
|
||||||
"Enterprise feature": "Enterprise-Funktion",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "KI ist nur in der Docmost Enterprise-Edition verfügbar. Kontaktieren Sie sales@docmost.com.",
|
|
||||||
"AI & MCP": "KI & MCP",
|
|
||||||
"AI": "KI",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Model Context Protocol (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Aktivieren Sie den MCP-Server, damit KI-Assistenten und -Tools mit den Inhalten Ihres Arbeitsbereichs interagieren können.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP ist nur in der Docmost Enterprise-Edition verfügbar. Kontaktieren Sie sales@docmost.com.",
|
|
||||||
"MCP documentation": "MCP-Dokumentation",
|
|
||||||
"MCP Server URL": "MCP-Server-URL",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Verwenden Sie Ihren API-Schlüssel zur Authentifizierung. API-Schlüssel können in Ihren Kontoeinstellungen verwaltet werden.",
|
|
||||||
"Supported tools": "Unterstützte Tools",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "In Ihrem Arbeitsbereich ist MCP aktiviert. Verwenden Sie Ihren API-Schlüssel, um KI-Assistenten anzubinden.",
|
|
||||||
"MCP server URL:": "MCP-Server-URL:",
|
|
||||||
"Learn more": "Mehr erfahren",
|
|
||||||
"View the": "Anzeigen",
|
|
||||||
"for usage details.": "für Informationen zur Nutzung.",
|
|
||||||
"for setup instructions.": "für Einrichtungshinweise.",
|
|
||||||
"API documentation": "API-Dokumentation",
|
|
||||||
"Sources": "Quellen",
|
|
||||||
"AI Answers not available for attachments": "KI-Antworten sind für Anhänge nicht verfügbar",
|
|
||||||
"No answer available": "Keine Antwort verfügbar",
|
|
||||||
"Background color": "Hintergrundfarbe",
|
|
||||||
"Highlight color": "Hervorhebungsfarbe",
|
|
||||||
"Remove color": "Farbe entfernen",
|
|
||||||
"Notifications": "Benachrichtigungen",
|
|
||||||
"No notifications": "Keine Benachrichtigungen",
|
|
||||||
"No unread notifications": "Keine ungelesenen Benachrichtigungen",
|
|
||||||
"All notifications": "Alle Benachrichtigungen",
|
|
||||||
"Unread only": "Nur ungelesen",
|
|
||||||
"Mark all as read": "Alle als gelesen markieren",
|
|
||||||
"Mark as read": "Als gelesen markieren",
|
|
||||||
"More options": "Weitere Optionen",
|
|
||||||
"mentioned you in a comment": "hat Sie in einem Kommentar erwähnt",
|
|
||||||
"commented on a page": "hat auf einer Seite kommentiert",
|
|
||||||
"resolved a comment": "hat einen Kommentar gelöst",
|
|
||||||
"mentioned you on a page": "hat Sie auf einer Seite erwähnt",
|
|
||||||
"gave you edit access to a page": "hat Ihnen Bearbeitungsrechte für eine Seite gegeben",
|
|
||||||
"gave you view access to a page": "hat Ihnen Leserechte für eine Seite gewährt",
|
|
||||||
"Today": "Heute",
|
|
||||||
"Yesterday": "Gestern",
|
|
||||||
"This week": "Diese Woche",
|
|
||||||
"Older": "Älter",
|
|
||||||
"Restricted page": "Eingeschränkte Seite",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Eingeschränkte Seiten können nicht öffentlich geteilt werden.",
|
|
||||||
"Restricted by parent": "Eingeschränkt durch die übergeordnete Seite",
|
|
||||||
"Restricted": "Eingeschränkt",
|
|
||||||
"Open": "Offen",
|
|
||||||
"Inherits restrictions from ancestor page": "Erbt Einschränkungen von einer übergeordneten Seite",
|
|
||||||
"Only people listed below can access this page": "Nur die unten aufgeführten Personen können auf diese Seite zugreifen.",
|
|
||||||
"Everyone in this space can access": "Jeder in diesem Bereich kann darauf zugreifen.",
|
|
||||||
"No additional restrictions on this page": "Keine zusätzlichen Einschränkungen auf dieser Seite",
|
|
||||||
"Only specific people can access": "Nur bestimmte Personen können zugreifen",
|
|
||||||
"Use only inherited restrictions": "Nur geerbte Einschränkungen verwenden",
|
|
||||||
"Add restrictions on top of inherited": "Einschränkungen zusätzlich zu den geerbten hinzufügen",
|
|
||||||
"Inherited restriction": "Geerbte Einschränkung",
|
|
||||||
"Access limited by": "Zugriff beschränkt durch",
|
|
||||||
"Restrict access to control who can view and edit this page": "Beschränken Sie den Zugriff, um festzulegen, wer diese Seite ansehen und bearbeiten kann.",
|
|
||||||
"Add additional restrictions specific to this page": "Fügen Sie zusätzliche, für diese Seite spezifische Einschränkungen hinzu.",
|
|
||||||
"Access": "Zugriff",
|
|
||||||
"People with access": "Personen mit Zugriff",
|
|
||||||
"Remove all": "Alle entfernen",
|
|
||||||
"Remove access": "Zugriff entfernen",
|
|
||||||
"Remove all access": "Alle Zugriffsrechte entfernen",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Sind Sie sicher, dass Sie den Zugriff dieses Mitglieds auf die Seite entfernen möchten?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Sind Sie sicher, dass Sie alle spezifischen Zugriffsrechte entfernen möchten? Dadurch wird die Seite für alle in diesem Bereich zugänglich.",
|
|
||||||
"Trash retention": "Aufbewahrungsdauer des Papierkorbs",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Seiten im Papierkorb werden nach Ablauf dieses Zeitraums endgültig gelöscht.",
|
|
||||||
"Trash retention updated": "Aufbewahrungsdauer des Papierkorbs aktualisiert",
|
|
||||||
"Failed to update trash retention": "Aktualisierung der Aufbewahrungsdauer des Papierkorbs fehlgeschlagen",
|
|
||||||
"Removed page restriction": "Seitenbeschränkung entfernt",
|
|
||||||
"Added page permission": "Seitenberechtigung hinzugefügt",
|
|
||||||
"Removed page permission": "Seitenberechtigung entfernt"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Choose your preferred interface language.",
|
"Choose your preferred interface language.": "Choose your preferred interface language.",
|
||||||
"Choose your preferred page width.": "Choose your preferred page width.",
|
"Choose your preferred page width.": "Choose your preferred page width.",
|
||||||
"Confirm": "Confirm",
|
"Confirm": "Confirm",
|
||||||
"Copy as Markdown": "Copy as Markdown",
|
|
||||||
"Copy link": "Copy link",
|
"Copy link": "Copy link",
|
||||||
"Create": "Create",
|
"Create": "Create",
|
||||||
"Create group": "Create group",
|
"Create group": "Create group",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "e.g Space for product team",
|
"e.g Space for product team": "e.g Space for product team",
|
||||||
"e.g Space for sales team to collaborate": "e.g Space for sales team to collaborate",
|
"e.g Space for sales team to collaborate": "e.g Space for sales team to collaborate",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"Read": "Read",
|
|
||||||
"Edit group": "Edit group",
|
"Edit group": "Edit group",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Enter a strong password": "Enter a strong password",
|
"Enter a strong password": "Enter a strong password",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "No group found",
|
"No group found": "No group found",
|
||||||
"No page history saved yet.": "No page history saved yet.",
|
"No page history saved yet.": "No page history saved yet.",
|
||||||
"No pages yet": "No pages yet",
|
"No pages yet": "No pages yet",
|
||||||
"No shared pages": "No shared pages",
|
|
||||||
"No results found...": "No results found...",
|
"No results found...": "No results found...",
|
||||||
"No user found": "No user found",
|
"No user found": "No user found",
|
||||||
"Overview": "Overview",
|
"Overview": "Overview",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "page",
|
"page": "page",
|
||||||
"Page deleted successfully": "Page deleted successfully",
|
"Page deleted successfully": "Page deleted successfully",
|
||||||
"Page history": "Page history",
|
"Page history": "Page history",
|
||||||
"Select version": "Select version",
|
|
||||||
"Highlight changes": "Highlight changes",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "Page import is in progress. Please do not close this tab.",
|
"Page import is in progress. Please do not close this tab.": "Page import is in progress. Please do not close this tab.",
|
||||||
"Pages": "Pages",
|
"Pages": "Pages",
|
||||||
"pages": "pages",
|
"pages": "pages",
|
||||||
"Password": "Password",
|
"Password": "Password",
|
||||||
"Password changed successfully": "Password changed successfully",
|
"Password changed successfully": "Password changed successfully",
|
||||||
"People": "People",
|
|
||||||
"Pending": "Pending",
|
"Pending": "Pending",
|
||||||
"Please confirm your action": "Please confirm your action",
|
"Please confirm your action": "Please confirm your action",
|
||||||
"Preferences": "Preferences",
|
"Preferences": "Preferences",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Reply...",
|
"Reply...": "Reply...",
|
||||||
"Error loading comments.": "Error loading comments.",
|
"Error loading comments.": "Error loading comments.",
|
||||||
"No comments yet.": "No comments yet.",
|
"No comments yet.": "No comments yet.",
|
||||||
"No open comments.": "No open comments.",
|
|
||||||
"No resolved comments.": "No resolved comments.",
|
|
||||||
"Add a comment...": "Add a comment...",
|
|
||||||
"Edit comment": "Edit comment",
|
"Edit comment": "Edit comment",
|
||||||
"Delete comment": "Delete comment",
|
"Delete comment": "Delete comment",
|
||||||
"Are you sure you want to delete this comment?": "Are you sure you want to delete this comment?",
|
"Are you sure you want to delete this comment?": "Are you sure you want to delete this comment?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Comment deleted successfully",
|
"Comment deleted successfully": "Comment deleted successfully",
|
||||||
"Failed to delete comment": "Failed to delete comment",
|
"Failed to delete comment": "Failed to delete comment",
|
||||||
"Comment resolved successfully": "Comment resolved successfully",
|
"Comment resolved successfully": "Comment resolved successfully",
|
||||||
"Comment re-opened successfully": "Comment re-opened successfully",
|
|
||||||
"Comment unresolved successfully": "Comment unresolved successfully",
|
|
||||||
"Failed to resolve comment": "Failed to resolve comment",
|
"Failed to resolve comment": "Failed to resolve comment",
|
||||||
"Resolve comment": "Resolve comment",
|
|
||||||
"Unresolve comment": "Unresolve comment",
|
|
||||||
"Resolve Comment Thread": "Resolve Comment Thread",
|
|
||||||
"Unresolve Comment Thread": "Unresolve Comment Thread",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Are you sure you want to resolve this comment thread? This will mark it as completed.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Are you sure you want to unresolve this comment thread?",
|
|
||||||
"Resolved": "Resolved",
|
|
||||||
"No active comments.": "No active comments.",
|
|
||||||
"Revoke invitation": "Revoke invitation",
|
"Revoke invitation": "Revoke invitation",
|
||||||
"Revoke": "Revoke",
|
"Revoke": "Revoke",
|
||||||
"Don't": "Don't",
|
"Don't": "Don't",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Anyone with this link can join this workspace.",
|
"Anyone with this link can join this workspace.": "Anyone with this link can join this workspace.",
|
||||||
"Invite link": "Invite link",
|
"Invite link": "Invite link",
|
||||||
"Copy": "Copy",
|
"Copy": "Copy",
|
||||||
"Copy to space": "Copy to space",
|
|
||||||
"Copied": "Copied",
|
"Copied": "Copied",
|
||||||
"Duplicate": "Duplicate",
|
|
||||||
"Select a user": "Select a user",
|
"Select a user": "Select a user",
|
||||||
"Select a group": "Select a group",
|
"Select a group": "Select a group",
|
||||||
"Export all pages and attachments in this space.": "Export all pages and attachments in this space.",
|
"Export all pages and attachments in this space.": "Export all pages and attachments in this space.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Export failed:",
|
"Export failed:": "Export failed:",
|
||||||
"export error": "export error",
|
"export error": "export error",
|
||||||
"Export page": "Export page",
|
"Export page": "Export page",
|
||||||
"Export successful": "Export successful",
|
|
||||||
"Export space": "Export space",
|
"Export space": "Export space",
|
||||||
"Export {{type}}": "Export {{type}}",
|
"Export {{type}}": "Export {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "File exceeds the {{limit}} attachment limit",
|
"File exceeds the {{limit}} attachment limit": "File exceeds the {{limit}} attachment limit",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Add row below",
|
"Add row below": "Add row below",
|
||||||
"Delete table": "Delete table",
|
"Delete table": "Delete table",
|
||||||
"Info": "Info",
|
"Info": "Info",
|
||||||
"Note": "Note",
|
|
||||||
"Success": "Success",
|
"Success": "Success",
|
||||||
"Warning": "Warning",
|
"Warning": "Warning",
|
||||||
"Danger": "Danger",
|
"Danger": "Danger",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Upload any image from your device.",
|
"Upload any image from your device.": "Upload any image from your device.",
|
||||||
"Upload any video from your device.": "Upload any video from your device.",
|
"Upload any video from your device.": "Upload any video from your device.",
|
||||||
"Upload any file from your device.": "Upload any file from your device.",
|
"Upload any file from your device.": "Upload any file from your device.",
|
||||||
"Uploading {{name}}": "Uploading {{name}}",
|
|
||||||
"Uploading file": "Uploading file",
|
|
||||||
"Table": "Table",
|
"Table": "Table",
|
||||||
"Insert a table.": "Insert a table.",
|
"Insert a table.": "Insert a table.",
|
||||||
"Insert collapsible block.": "Insert collapsible block.",
|
"Insert collapsible block.": "Insert collapsible block.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Insert current date",
|
"Insert current date": "Insert current date",
|
||||||
"Draw and sketch excalidraw diagrams": "Draw and sketch excalidraw diagrams",
|
"Draw and sketch excalidraw diagrams": "Draw and sketch excalidraw diagrams",
|
||||||
"Multiple": "Multiple",
|
"Multiple": "Multiple",
|
||||||
"Turn into": "Turn into",
|
|
||||||
"Text align": "Text align",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "This page may have been deleted, moved, or you may not have access.",
|
|
||||||
"Go to homepage": "Go to homepage",
|
|
||||||
"Pages you create will show up here.": "Pages you create will show up here.",
|
|
||||||
"Heading {{level}}": "Heading {{level}}",
|
"Heading {{level}}": "Heading {{level}}",
|
||||||
"Toggle title": "Toggle title",
|
"Toggle title": "Toggle title",
|
||||||
"Write anything. Enter \"/\" for commands": "Write anything. Enter \"/\" for commands",
|
"Write anything. Enter \"/\" for commands": "Write anything. Enter \"/\" for commands",
|
||||||
"Write...": "Write...",
|
|
||||||
"Column count": "Column count",
|
|
||||||
"{{count}} Columns": "{{count}} Columns",
|
|
||||||
"Equal columns": "Equal columns",
|
|
||||||
"Left sidebar": "Left sidebar",
|
|
||||||
"Right sidebar": "Right sidebar",
|
|
||||||
"Wide center": "Wide center",
|
|
||||||
"Left wide": "Left wide",
|
|
||||||
"Right wide": "Right wide",
|
|
||||||
"Names do not match": "Names do not match",
|
"Names do not match": "Names do not match",
|
||||||
"Today, {{time}}": "Today, {{time}}",
|
"Today, {{time}}": "Today, {{time}}",
|
||||||
"Yesterday, {{time}}": "Yesterday, {{time}}",
|
"Yesterday, {{time}}": "Yesterday, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Character count: {{characterCount}}",
|
"Character count: {{characterCount}}": "Character count: {{characterCount}}",
|
||||||
"New update": "New update",
|
"New update": "New update",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} is available",
|
"{{latestVersion}} is available": "{{latestVersion}} is available",
|
||||||
"Default page edit mode": "Default page edit mode",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Choose your preferred page edit mode. Avoid accidental edits.",
|
|
||||||
"Reading": "Reading",
|
|
||||||
"Delete member": "Delete member",
|
"Delete member": "Delete member",
|
||||||
"Member deleted successfully": "Member deleted successfully",
|
"Member deleted successfully": "Member deleted successfully",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Are you sure you want to delete this workspace member? This action is irreversible.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Are you sure you want to delete this workspace member? This action is irreversible.",
|
||||||
"Deactivate member": "Deactivate member",
|
|
||||||
"Activate member": "Activate member",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Are you sure you want to activate this workspace member?",
|
|
||||||
"Deactivate": "Deactivate",
|
|
||||||
"Activate": "Activate",
|
|
||||||
"Deactivated": "Deactivated",
|
|
||||||
"Move": "Move",
|
"Move": "Move",
|
||||||
"Move page": "Move page",
|
"Move page": "Move page",
|
||||||
"Move page to a different space.": "Move page to a different space.",
|
"Move page to a different space.": "Move page to a different space.",
|
||||||
@@ -433,265 +384,7 @@
|
|||||||
"Share deleted successfully": "Share deleted successfully",
|
"Share deleted successfully": "Share deleted successfully",
|
||||||
"Share not found": "Share not found",
|
"Share not found": "Share not found",
|
||||||
"Failed to share page": "Failed to share page",
|
"Failed to share page": "Failed to share page",
|
||||||
"Disable public sharing": "Disable public sharing",
|
"Copy page": "Copy page",
|
||||||
"Prevent members from sharing pages publicly.": "Prevent members from sharing pages publicly.",
|
|
||||||
"Toggle public sharing": "Toggle public sharing",
|
|
||||||
"Toggle space public sharing": "Toggle space public sharing",
|
|
||||||
"Public sharing is disabled at the workspace level": "Public sharing is disabled at the workspace level",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Prevent pages in this space from being shared publicly.",
|
|
||||||
"Requires an enterprise license": "Requires an enterprise license",
|
|
||||||
"Page permissions": "Page permissions",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Control who can view and edit individual pages. Available with an enterprise license.",
|
|
||||||
"Enable public sharing": "Enable public sharing",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Are you sure you want to enable public sharing? Members will be able to share pages publicly.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Are you sure you want to enable public sharing for this space?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.",
|
|
||||||
"Public sharing is disabled": "Public sharing is disabled",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "Public sharing has been disabled at the workspace level.",
|
|
||||||
"Public sharing has been disabled for this space.": "Public sharing has been disabled for this space.",
|
|
||||||
"Copy page": "Copy page",
|
|
||||||
"Copy page to a different space.": "Copy page to a different space.",
|
"Copy page to a different space.": "Copy page to a different space.",
|
||||||
"Page copied successfully": "Page copied successfully",
|
"Page copied successfully": "Page copied successfully"
|
||||||
"Page duplicated successfully": "Page duplicated successfully",
|
|
||||||
"Find": "Find",
|
|
||||||
"Not found": "Not found",
|
|
||||||
"Previous Match (Shift+Enter)": "Previous Match (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Next match (Enter)",
|
|
||||||
"Match case (Alt+C)": "Match case (Alt+C)",
|
|
||||||
"Replace": "Replace",
|
|
||||||
"Close (Escape)": "Close (Escape)",
|
|
||||||
"Replace (Enter)": "Replace (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Replace all (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Replace all",
|
|
||||||
"View all spaces": "View all spaces",
|
|
||||||
"Error": "Error",
|
|
||||||
"Failed to disable MFA": "Failed to disable MFA",
|
|
||||||
"Disable two-factor authentication": "Disable two-factor authentication",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Please enter your password to disable two-factor authentication:",
|
|
||||||
"Two-factor authentication has been enabled": "Two-factor authentication has been enabled",
|
|
||||||
"Two-factor authentication has been disabled": "Two-factor authentication has been disabled",
|
|
||||||
"2-step verification": "2-step verification",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Protect your account with an additional verification layer when signing in.",
|
|
||||||
"Two-factor authentication is active on your account.": "Two-factor authentication is active on your account.",
|
|
||||||
"Add 2FA method": "Add 2FA method",
|
|
||||||
"Backup codes": "Backup codes",
|
|
||||||
"Disable": "Disable",
|
|
||||||
"Invalid verification code": "Invalid verification code",
|
|
||||||
"New backup codes have been generated": "New backup codes have been generated",
|
|
||||||
"Failed to regenerate backup codes": "Failed to regenerate backup codes",
|
|
||||||
"About backup codes": "About backup codes",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "You can regenerate new backup codes at any time. This will invalidate all existing codes.",
|
|
||||||
"Confirm password": "Confirm password",
|
|
||||||
"Generate new backup codes": "Generate new backup codes",
|
|
||||||
"Save your new backup codes": "Save your new backup codes",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Make sure to save these codes in a secure place. Your old backup codes are no longer valid.",
|
|
||||||
"Your new backup codes": "Your new backup codes",
|
|
||||||
"I've saved my backup codes": "I've saved my backup codes",
|
|
||||||
"Failed to setup MFA": "Failed to setup MFA",
|
|
||||||
"Setup & Verify": "Setup & Verify",
|
|
||||||
"Add to authenticator": "Add to authenticator",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Scan this QR code with your authenticator app",
|
|
||||||
"Can't scan the code?": "Can't scan the code?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Enter this code manually in your authenticator app:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Enter the 6-digit code from your authenticator",
|
|
||||||
"Verify and enable": "Verify and enable",
|
|
||||||
"Failed to generate QR code. Please try again.": "Failed to generate QR code. Please try again.",
|
|
||||||
"Backup": "Backup",
|
|
||||||
"Save codes": "Save codes",
|
|
||||||
"Save your backup codes": "Save your backup codes",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.",
|
|
||||||
"Print": "Print",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "Two-factor authentication has been set up. Please log in again.",
|
|
||||||
"Two-Factor authentication required": "Two-factor authentication required",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Your workspace requires two-factor authentication for all users",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.",
|
|
||||||
"Set up two-factor authentication": "Set up two-factor authentication",
|
|
||||||
"Cancel and logout": "Cancel and logout",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Your workspace requires two-factor authentication. Please set it up to continue.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "This adds an extra layer of security to your account by requiring a verification code from your authenticator app.",
|
|
||||||
"Password is required": "Password is required",
|
|
||||||
"Password must be at least 8 characters": "Password must be at least 8 characters",
|
|
||||||
"Please enter a 6-digit code": "Please enter a 6-digit code",
|
|
||||||
"Code must be exactly 6 digits": "Code must be exactly 6 digits",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Enter the 6-digit code found in your authenticator app",
|
|
||||||
"Need help authenticating?": "Need help authenticating?",
|
|
||||||
"MFA QR Code": "MFA QR Code",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Account created successfully. Please log in to set up two-factor authentication.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Password reset successful. Please log in with your new password and complete two-factor authentication.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Password reset successful. Please log in with your new password to set up two-factor authentication.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "Password reset was successful. Please log in with your new password.",
|
|
||||||
"Two-factor authentication": "Two-factor authentication",
|
|
||||||
"Use authenticator app instead": "Use authenticator app instead",
|
|
||||||
"Verify backup code": "Verify backup code",
|
|
||||||
"Use backup code": "Use backup code",
|
|
||||||
"Enter one of your backup codes": "Enter one of your backup codes",
|
|
||||||
"Backup code": "Backup code",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Enter one of your backup codes. Each backup code can only be used once.",
|
|
||||||
"Verify": "Verify",
|
|
||||||
"Trash": "Trash",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "Pages in trash will be permanently deleted after {{count}} days.",
|
|
||||||
"Deleted": "Deleted",
|
|
||||||
"No pages in trash": "No pages in trash",
|
|
||||||
"Permanently delete page?": "Permanently delete page?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "Restore '{{title}}' and its sub-pages?",
|
|
||||||
"Move to trash": "Move to trash",
|
|
||||||
"Move this page to trash?": "Move this page to trash?",
|
|
||||||
"Restore page": "Restore page",
|
|
||||||
"Page moved to trash": "Page moved to trash",
|
|
||||||
"Page restored successfully": "Page restored successfully",
|
|
||||||
"Deleted by": "Deleted by",
|
|
||||||
"Deleted at": "Deleted at",
|
|
||||||
"Preview": "Preview",
|
|
||||||
"Subpages": "Subpages",
|
|
||||||
"Failed to load subpages": "Failed to load subpages",
|
|
||||||
"No subpages": "No subpages",
|
|
||||||
"Subpages (Child pages)": "Subpages (Child pages)",
|
|
||||||
"List all subpages of the current page": "List all subpages of the current page",
|
|
||||||
"Attachments": "Attachments",
|
|
||||||
"All spaces": "All spaces",
|
|
||||||
"Unknown": "Unknown",
|
|
||||||
"Find a space": "Find a space",
|
|
||||||
"Search in all your spaces": "Search in all your spaces",
|
|
||||||
"Type": "Type",
|
|
||||||
"Enterprise": "Enterprise",
|
|
||||||
"Download attachment": "Download attachment",
|
|
||||||
"Allowed email domains": "Allowed email domains",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Only users with email addresses from these domains can signup via SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Enter valid domain names separated by comma or space",
|
|
||||||
"Enforce two-factor authentication": "Enforce two-factor authentication",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Once enforced, all members must enable two-factor authentication to access the workspace.",
|
|
||||||
"Toggle MFA enforcement": "Toggle MFA enforcement",
|
|
||||||
"Display name": "Display name",
|
|
||||||
"Allow signup": "Allow signup",
|
|
||||||
"Enabled": "Enabled",
|
|
||||||
"Advanced Settings": "Advanced Settings",
|
|
||||||
"Enable TLS/SSL": "Enable TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Use secure connection to LDAP server",
|
|
||||||
"Group sync": "Group sync",
|
|
||||||
"No SSO providers found.": "No SSO providers found.",
|
|
||||||
"Delete SSO provider": "Delete SSO provider",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Are you sure you want to delete this SSO provider?",
|
|
||||||
"Action": "Action",
|
|
||||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} configuration",
|
|
||||||
"Icon": "Icon",
|
|
||||||
"Upload image": "Upload image",
|
|
||||||
"Remove image": "Remove image",
|
|
||||||
"Failed to remove image": "Failed to remove image",
|
|
||||||
"Image exceeds 10MB limit.": "Image exceeds 10MB limit.",
|
|
||||||
"Image removed successfully": "Image removed successfully",
|
|
||||||
"API key": "API key",
|
|
||||||
"API key created successfully": "API key created successfully",
|
|
||||||
"API keys": "API keys",
|
|
||||||
"API management": "API management",
|
|
||||||
"Are you sure you want to revoke this API key": "Are you sure you want to revoke this API key",
|
|
||||||
"Create API Key": "Create API Key",
|
|
||||||
"Custom expiration date": "Custom expiration date",
|
|
||||||
"Enter a descriptive token name": "Enter a descriptive token name",
|
|
||||||
"Expiration": "Expiration",
|
|
||||||
"Expired": "Expired",
|
|
||||||
"Expires": "Expires",
|
|
||||||
"I've saved my API key": "I've saved my API key",
|
|
||||||
"Last use": "Last Used",
|
|
||||||
"No API keys found": "No API keys found",
|
|
||||||
"No expiration": "No expiration",
|
|
||||||
"Revoke API key": "Revoke API key",
|
|
||||||
"Revoked successfully": "Revoked successfully",
|
|
||||||
"Select expiration date": "Select expiration date",
|
|
||||||
"This action cannot be undone. Any applications using this API key will stop working.": "This action cannot be undone. Any applications using this API key will stop working.",
|
|
||||||
"Update API key": "Update API key",
|
|
||||||
"Manage API keys for all users in the workspace": "Manage API keys for all users in the workspace",
|
|
||||||
"Restrict API key creation to admins": "Restrict API key creation to admins",
|
|
||||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Only admins and owners can create new API keys. Existing member keys will continue to work.",
|
|
||||||
"Toggle restrict API keys to admins": "Toggle restrict API keys to admins",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "API key creation is restricted to admins by your workspace administrator.",
|
|
||||||
"AI settings": "AI settings",
|
|
||||||
"AI search": "AI search",
|
|
||||||
"AI Answer": "AI Answer",
|
|
||||||
"Ask AI": "Ask AI",
|
|
||||||
"AI is thinking...": "AI is thinking...",
|
|
||||||
"Ask a question...": "Ask a question...",
|
|
||||||
"AI Answers": "AI Answers",
|
|
||||||
"AI-powered search (AI Answers)": "AI-powered search (AI Answers)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI search uses vector embeddings to provide semantic search capabilities across your workspace content.",
|
|
||||||
"Toggle AI search": "Toggle AI search",
|
|
||||||
"Generative AI (Ask AI)": "Generative AI (Ask AI)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.",
|
|
||||||
"Toggle generative AI": "Toggle generative AI",
|
|
||||||
"Enterprise feature": "Enterprise feature",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.",
|
|
||||||
"AI & MCP": "AI & MCP",
|
|
||||||
"AI": "AI",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Model Context Protocol (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Enable the MCP server to allow AI assistants and tools to interact with your workspace content.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.",
|
|
||||||
"MCP documentation": "MCP documentation",
|
|
||||||
"MCP Server URL": "MCP Server URL",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Use your API key for authentication. You can manage API keys in your account settings.",
|
|
||||||
"Supported tools": "Supported tools",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "Your workspace has MCP enabled. Use your API key to connect AI assistants.",
|
|
||||||
"MCP server URL:": "MCP server URL:",
|
|
||||||
"Learn more": "Learn more",
|
|
||||||
"View the": "View the",
|
|
||||||
"for usage details.": "for usage details.",
|
|
||||||
"for setup instructions.": "for setup instructions.",
|
|
||||||
"API documentation": "API documentation",
|
|
||||||
"Sources": "Sources",
|
|
||||||
"AI Answers not available for attachments": "AI Answers not available for attachments",
|
|
||||||
"No answer available": "No answer available",
|
|
||||||
"Background color": "Background color",
|
|
||||||
"Highlight color": "Highlight color",
|
|
||||||
"Remove color": "Remove color",
|
|
||||||
"Notifications": "Notifications",
|
|
||||||
"No notifications": "No notifications",
|
|
||||||
"No unread notifications": "No unread notifications",
|
|
||||||
"All notifications": "All notifications",
|
|
||||||
"Unread only": "Unread only",
|
|
||||||
"Mark all as read": "Mark all as read",
|
|
||||||
"Mark as read": "Mark as read",
|
|
||||||
"More options": "More options",
|
|
||||||
"mentioned you in a comment": "mentioned you in a comment",
|
|
||||||
"commented on a page": "commented on a page",
|
|
||||||
"resolved a comment": "resolved a comment",
|
|
||||||
"mentioned you on a page": "mentioned you on a page",
|
|
||||||
"gave you edit access to a page": "gave you edit access to a page",
|
|
||||||
"gave you view access to a page": "gave you view access to a page",
|
|
||||||
"Today": "Today",
|
|
||||||
"Yesterday": "Yesterday",
|
|
||||||
"This week": "This week",
|
|
||||||
"Older": "Older",
|
|
||||||
"Restricted page": "Restricted page",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Restricted pages cannot be shared publicly.",
|
|
||||||
"Restricted by parent": "Restricted by parent",
|
|
||||||
"Restricted": "Restricted",
|
|
||||||
"Open": "Open",
|
|
||||||
"Inherits restrictions from ancestor page": "Inherits restrictions from ancestor page",
|
|
||||||
"Only people listed below can access this page": "Only people listed below can access this page",
|
|
||||||
"Everyone in this space can access": "Everyone in this space can access",
|
|
||||||
"No additional restrictions on this page": "No additional restrictions on this page",
|
|
||||||
"Only specific people can access": "Only specific people can access",
|
|
||||||
"Use only inherited restrictions": "Use only inherited restrictions",
|
|
||||||
"Add restrictions on top of inherited": "Add restrictions on top of inherited",
|
|
||||||
"Inherited restriction": "Inherited restriction",
|
|
||||||
"Access limited by": "Access limited by",
|
|
||||||
"Restrict access to control who can view and edit this page": "Restrict access to control who can view and edit this page",
|
|
||||||
"Add additional restrictions specific to this page": "Add additional restrictions specific to this page",
|
|
||||||
"Access": "Access",
|
|
||||||
"People with access": "People with access",
|
|
||||||
"Remove all": "Remove all",
|
|
||||||
"Remove access": "Remove access",
|
|
||||||
"Remove all access": "Remove all access",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Are you sure you want to remove this member's access to the page?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Are you sure you want to remove all specific access? This will make the page open to everyone in the space.",
|
|
||||||
"Trash retention": "Trash retention",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Pages in trash will be permanently deleted after this period.",
|
|
||||||
"Trash retention updated": "Trash retention updated",
|
|
||||||
"Failed to update trash retention": "Failed to update trash retention",
|
|
||||||
"Removed page restriction": "Removed page restriction",
|
|
||||||
"Added page permission": "Added page permission",
|
|
||||||
"Removed page permission": "Removed page permission"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Elige tu idioma de interfaz preferido.",
|
"Choose your preferred interface language.": "Elige tu idioma de interfaz preferido.",
|
||||||
"Choose your preferred page width.": "Elige el ancho de página que prefieras.",
|
"Choose your preferred page width.": "Elige el ancho de página que prefieras.",
|
||||||
"Confirm": "Confirmar",
|
"Confirm": "Confirmar",
|
||||||
"Copy as Markdown": "Copiar como Markdown",
|
|
||||||
"Copy link": "Copiar enlace",
|
"Copy link": "Copiar enlace",
|
||||||
"Create": "Crear",
|
"Create": "Crear",
|
||||||
"Create group": "Crear grupo",
|
"Create group": "Crear grupo",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "ej: Espacio para el equipo de producto",
|
"e.g Space for product team": "ej: Espacio para el equipo de producto",
|
||||||
"e.g Space for sales team to collaborate": "ej: Espacio para que el equipo de ventas colabore",
|
"e.g Space for sales team to collaborate": "ej: Espacio para que el equipo de ventas colabore",
|
||||||
"Edit": "Editar",
|
"Edit": "Editar",
|
||||||
"Read": "Leer",
|
|
||||||
"Edit group": "Editar grupo",
|
"Edit group": "Editar grupo",
|
||||||
"Email": "Correo electrónico",
|
"Email": "Correo electrónico",
|
||||||
"Enter a strong password": "Introduce una contraseña fuerte",
|
"Enter a strong password": "Introduce una contraseña fuerte",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "No se encontró grupo",
|
"No group found": "No se encontró grupo",
|
||||||
"No page history saved yet.": "No hay historial de la página guardado aún.",
|
"No page history saved yet.": "No hay historial de la página guardado aún.",
|
||||||
"No pages yet": "No hay páginas todavía",
|
"No pages yet": "No hay páginas todavía",
|
||||||
"No shared pages": "No hay páginas compartidas",
|
|
||||||
"No results found...": "No se encontraron resultados...",
|
"No results found...": "No se encontraron resultados...",
|
||||||
"No user found": "No se encontró usuario",
|
"No user found": "No se encontró usuario",
|
||||||
"Overview": "Visión general",
|
"Overview": "Visión general",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "página",
|
"page": "página",
|
||||||
"Page deleted successfully": "Página eliminada con éxito",
|
"Page deleted successfully": "Página eliminada con éxito",
|
||||||
"Page history": "Historial de la página",
|
"Page history": "Historial de la página",
|
||||||
"Select version": "Seleccionar versión",
|
|
||||||
"Highlight changes": "Resaltar cambios",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "La importación de la página está en curso. Por favor, no cierre esta pestaña.",
|
"Page import is in progress. Please do not close this tab.": "La importación de la página está en curso. Por favor, no cierre esta pestaña.",
|
||||||
"Pages": "Páginas",
|
"Pages": "Páginas",
|
||||||
"pages": "páginas",
|
"pages": "páginas",
|
||||||
"Password": "Contraseña",
|
"Password": "Contraseña",
|
||||||
"Password changed successfully": "Contraseña cambiada con éxito",
|
"Password changed successfully": "Contraseña cambiada con éxito",
|
||||||
"People": "Personas",
|
|
||||||
"Pending": "Pendiente",
|
"Pending": "Pendiente",
|
||||||
"Please confirm your action": "Por favor, confirme su acción",
|
"Please confirm your action": "Por favor, confirme su acción",
|
||||||
"Preferences": "Preferencias",
|
"Preferences": "Preferencias",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Responder...",
|
"Reply...": "Responder...",
|
||||||
"Error loading comments.": "Error al cargar comentarios.",
|
"Error loading comments.": "Error al cargar comentarios.",
|
||||||
"No comments yet.": "No hay comentarios todavía.",
|
"No comments yet.": "No hay comentarios todavía.",
|
||||||
"No open comments.": "No hay comentarios abiertos.",
|
|
||||||
"No resolved comments.": "No hay comentarios resueltos.",
|
|
||||||
"Add a comment...": "Agregar un comentario...",
|
|
||||||
"Edit comment": "Editar comentario",
|
"Edit comment": "Editar comentario",
|
||||||
"Delete comment": "Eliminar comentario",
|
"Delete comment": "Eliminar comentario",
|
||||||
"Are you sure you want to delete this comment?": "¿Está seguro de que desea eliminar este comentario?",
|
"Are you sure you want to delete this comment?": "¿Está seguro de que desea eliminar este comentario?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Comentario eliminado con éxito",
|
"Comment deleted successfully": "Comentario eliminado con éxito",
|
||||||
"Failed to delete comment": "No se pudo eliminar el comentario",
|
"Failed to delete comment": "No se pudo eliminar el comentario",
|
||||||
"Comment resolved successfully": "Comentario resuelto con éxito",
|
"Comment resolved successfully": "Comentario resuelto con éxito",
|
||||||
"Comment re-opened successfully": "Comentario reabierto con éxito",
|
|
||||||
"Comment unresolved successfully": "Comentario no resuelto con éxito",
|
|
||||||
"Failed to resolve comment": "No se pudo resolver el comentario",
|
"Failed to resolve comment": "No se pudo resolver el comentario",
|
||||||
"Resolve comment": "Resolver comentario",
|
|
||||||
"Unresolve comment": "No resolver comentario",
|
|
||||||
"Resolve Comment Thread": "Resolver hilo de comentarios",
|
|
||||||
"Unresolve Comment Thread": "No resolver hilo de comentarios",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "¿Está seguro de que desea resolver este hilo de comentarios? Esto lo marcará como completado.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "¿Está seguro de que desea no resolver este hilo de comentarios?",
|
|
||||||
"Resolved": "Resuelto",
|
|
||||||
"No active comments.": "No hay comentarios activos.",
|
|
||||||
"Revoke invitation": "Revocar invitación",
|
"Revoke invitation": "Revocar invitación",
|
||||||
"Revoke": "Revocar",
|
"Revoke": "Revocar",
|
||||||
"Don't": "No",
|
"Don't": "No",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Cualquiera con este enlace puede unirse a este espacio de trabajo.",
|
"Anyone with this link can join this workspace.": "Cualquiera con este enlace puede unirse a este espacio de trabajo.",
|
||||||
"Invite link": "Enlace de invitación",
|
"Invite link": "Enlace de invitación",
|
||||||
"Copy": "Copiar",
|
"Copy": "Copiar",
|
||||||
"Copy to space": "Copiar al espacio",
|
|
||||||
"Copied": "Copiado",
|
"Copied": "Copiado",
|
||||||
"Duplicate": "Duplicar",
|
|
||||||
"Select a user": "Seleccionar un usuario",
|
"Select a user": "Seleccionar un usuario",
|
||||||
"Select a group": "Seleccionar un grupo",
|
"Select a group": "Seleccionar un grupo",
|
||||||
"Export all pages and attachments in this space.": "Exportar todas las páginas y archivos adjuntos en este espacio.",
|
"Export all pages and attachments in this space.": "Exportar todas las páginas y archivos adjuntos en este espacio.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Exportación fallida:",
|
"Export failed:": "Exportación fallida:",
|
||||||
"export error": "error de exportación",
|
"export error": "error de exportación",
|
||||||
"Export page": "Exportar página",
|
"Export page": "Exportar página",
|
||||||
"Export successful": "Exportación exitosa",
|
|
||||||
"Export space": "Exportar espacio",
|
"Export space": "Exportar espacio",
|
||||||
"Export {{type}}": "Exportar {{type}}",
|
"Export {{type}}": "Exportar {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "El archivo supera el límite de {{limit}} adjuntos",
|
"File exceeds the {{limit}} attachment limit": "El archivo supera el límite de {{limit}} adjuntos",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Agregar fila debajo",
|
"Add row below": "Agregar fila debajo",
|
||||||
"Delete table": "Eliminar tabla",
|
"Delete table": "Eliminar tabla",
|
||||||
"Info": "Información",
|
"Info": "Información",
|
||||||
"Note": "Nota",
|
|
||||||
"Success": "Satisfactorio",
|
"Success": "Satisfactorio",
|
||||||
"Warning": "Advertencia",
|
"Warning": "Advertencia",
|
||||||
"Danger": "Peligro",
|
"Danger": "Peligro",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Sube cualquier imagen desde tu dispositivo.",
|
"Upload any image from your device.": "Sube cualquier imagen desde tu dispositivo.",
|
||||||
"Upload any video from your device.": "Sube cualquier video desde tu dispositivo.",
|
"Upload any video from your device.": "Sube cualquier video desde tu dispositivo.",
|
||||||
"Upload any file from your device.": "Sube cualquier archivo desde tu dispositivo.",
|
"Upload any file from your device.": "Sube cualquier archivo desde tu dispositivo.",
|
||||||
"Uploading {{name}}": "Subiendo {{name}}",
|
|
||||||
"Uploading file": "Subiendo archivo",
|
|
||||||
"Table": "Tabla",
|
"Table": "Tabla",
|
||||||
"Insert a table.": "Insertar una tabla.",
|
"Insert a table.": "Insertar una tabla.",
|
||||||
"Insert collapsible block.": "Insertar bloque desplegable.",
|
"Insert collapsible block.": "Insertar bloque desplegable.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Insertar fecha actual",
|
"Insert current date": "Insertar fecha actual",
|
||||||
"Draw and sketch excalidraw diagrams": "Dibujar y esbozar diagramas de Excalidraw",
|
"Draw and sketch excalidraw diagrams": "Dibujar y esbozar diagramas de Excalidraw",
|
||||||
"Multiple": "Múltiple",
|
"Multiple": "Múltiple",
|
||||||
"Turn into": "Convertir en",
|
|
||||||
"Text align": "Alineación del texto",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Es posible que esta página haya sido eliminada, movida o que no tengas acceso.",
|
|
||||||
"Go to homepage": "Ir a la página principal",
|
|
||||||
"Pages you create will show up here.": "Las páginas que crees aparecerán aquí.",
|
|
||||||
"Heading {{level}}": "Encabezado {{level}}",
|
"Heading {{level}}": "Encabezado {{level}}",
|
||||||
"Toggle title": "Alternar título",
|
"Toggle title": "Alternar título",
|
||||||
"Write anything. Enter \"/\" for commands": "Escribe cualquier cosa. Ingresa \"/\" para comandos",
|
"Write anything. Enter \"/\" for commands": "Escribe cualquier cosa. Ingresa \"/\" para comandos",
|
||||||
"Write...": "Escribe...",
|
|
||||||
"Column count": "Número de columnas",
|
|
||||||
"{{count}} Columns": "{count, plural, one {# columna} other {# columnas}}",
|
|
||||||
"Equal columns": "Columnas iguales",
|
|
||||||
"Left sidebar": "Barra lateral izquierda",
|
|
||||||
"Right sidebar": "Barra lateral derecha",
|
|
||||||
"Wide center": "Centro ancho",
|
|
||||||
"Left wide": "Izquierda ancha",
|
|
||||||
"Right wide": "Derecha ancha",
|
|
||||||
"Names do not match": "Los nombres no coinciden",
|
"Names do not match": "Los nombres no coinciden",
|
||||||
"Today, {{time}}": "Hoy, {{time}}",
|
"Today, {{time}}": "Hoy, {{time}}",
|
||||||
"Yesterday, {{time}}": "Ayer, {{time}}",
|
"Yesterday, {{time}}": "Ayer, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Recuento de caracteres: {{characterCount}}",
|
"Character count: {{characterCount}}": "Recuento de caracteres: {{characterCount}}",
|
||||||
"New update": "Nueva actualización",
|
"New update": "Nueva actualización",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} está disponible",
|
"{{latestVersion}} is available": "{{latestVersion}} está disponible",
|
||||||
"Default page edit mode": "Modo de edición de página predeterminado",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Elige tu modo de edición de página preferido. Evita ediciones accidentales.",
|
|
||||||
"Reading": "Leyendo",
|
|
||||||
"Delete member": "Eliminar miembro",
|
"Delete member": "Eliminar miembro",
|
||||||
"Member deleted successfully": "Miembro eliminado con éxito",
|
"Member deleted successfully": "Miembro eliminado con éxito",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "¿Está seguro que desea eliminar este miembro del área de trabajo? Esta acción es irreversible.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "¿Está seguro que desea eliminar este miembro del área de trabajo? Esta acción es irreversible.",
|
||||||
"Deactivate member": "Desactivar miembro",
|
|
||||||
"Activate member": "Activar miembro",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "¿Está seguro de que desea desactivar a este miembro del espacio de trabajo? Ya no podrá acceder a este espacio de trabajo.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "¿Está seguro de que desea activar a este miembro del espacio de trabajo?",
|
|
||||||
"Deactivate": "Desactivar",
|
|
||||||
"Activate": "Activar",
|
|
||||||
"Deactivated": "Desactivado",
|
|
||||||
"Move": "Mover",
|
"Move": "Mover",
|
||||||
"Move page": "Mover página",
|
"Move page": "Mover página",
|
||||||
"Move page to a different space.": "Mover página a un espacio diferente.",
|
"Move page to a different space.": "Mover página a un espacio diferente.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Las páginas compartidas públicamente de los espacios a los que pertenece aparecerán aquí",
|
"Publicly shared pages from spaces you are a member of will appear here": "Las páginas compartidas públicamente de los espacios a los que pertenece aparecerán aquí",
|
||||||
"Share deleted successfully": "Compartición eliminada con éxito",
|
"Share deleted successfully": "Compartición eliminada con éxito",
|
||||||
"Share not found": "Compartición no encontrada",
|
"Share not found": "Compartición no encontrada",
|
||||||
"Failed to share page": "Error al compartir la página",
|
"Failed to share page": "Error al compartir la página"
|
||||||
"Disable public sharing": "Desactivar el uso compartido público",
|
|
||||||
"Prevent members from sharing pages publicly.": "Evitar que los miembros compartan páginas públicamente.",
|
|
||||||
"Toggle public sharing": "Alternar el uso compartido público",
|
|
||||||
"Toggle space public sharing": "Alternar el uso compartido público del espacio",
|
|
||||||
"Public sharing is disabled at the workspace level": "El uso compartido público está desactivado a nivel de espacio de trabajo",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Evitar que las páginas en este espacio se compartan públicamente.",
|
|
||||||
"Requires an enterprise license": "Requiere una licencia empresarial",
|
|
||||||
"Page permissions": "Permisos de la página},{",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Controla quién puede ver y editar páginas individuales. Disponible con una licencia empresarial.",
|
|
||||||
"Enable public sharing": "Activar el uso compartido público",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "¿Está seguro de que desea activar el uso compartido público? Los miembros podrán compartir páginas públicamente.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "¿Está seguro de que desea desactivar el uso compartido público? Todos los enlaces compartidos existentes en este espacio de trabajo se eliminarán.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "¿Está seguro de que desea activar el uso compartido público para este espacio?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "¿Está seguro de que desea desactivar el uso compartido público? Todos los enlaces compartidos existentes en este espacio se eliminarán.",
|
|
||||||
"Public sharing is disabled": "El uso compartido público está desactivado",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "El uso compartido público se ha desactivado a nivel de espacio de trabajo.",
|
|
||||||
"Public sharing has been disabled for this space.": "El uso compartido público se ha desactivado para este espacio.",
|
|
||||||
"Copy page": "Copiar página",
|
|
||||||
"Copy page to a different space.": "Copiar página en otro espacio",
|
|
||||||
"Page copied successfully": "Página copiada exitosamente",
|
|
||||||
"Page duplicated successfully": "Página duplicada con éxito",
|
|
||||||
"Find": "Buscar",
|
|
||||||
"Not found": "No encontrado",
|
|
||||||
"Previous Match (Shift+Enter)": "Coincidencia anterior (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Siguiente coincidencia (Enter)",
|
|
||||||
"Match case (Alt+C)": "Distinguir mayúsculas y minúsculas (Alt+C)",
|
|
||||||
"Replace": "Reemplazar",
|
|
||||||
"Close (Escape)": "Cerrar (Escape)",
|
|
||||||
"Replace (Enter)": "Reemplazar (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Reemplazar todo (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Reemplazar todo",
|
|
||||||
"View all spaces": "Ver todos los espacios",
|
|
||||||
"Error": "Error",
|
|
||||||
"Failed to disable MFA": "No se pudo desactivar MFA",
|
|
||||||
"Disable two-factor authentication": "Desactivar la autenticación de dos factores",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Desactivar la autenticación de dos factores hará que tu cuenta sea menos segura. Solo necesitarás tu contraseña para iniciar sesión.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Por favor ingresa tu contraseña para desactivar la autenticación de dos factores:",
|
|
||||||
"Two-factor authentication has been enabled": "La autenticación de dos factores ha sido activada",
|
|
||||||
"Two-factor authentication has been disabled": "La autenticación de dos factores ha sido desactivada",
|
|
||||||
"2-step verification": "Verificación en 2 pasos",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Protege tu cuenta con una capa adicional de verificación al iniciar sesión.",
|
|
||||||
"Two-factor authentication is active on your account.": "La autenticación de dos factores está activa en tu cuenta.",
|
|
||||||
"Add 2FA method": "Agregar método 2FA",
|
|
||||||
"Backup codes": "Códigos de seguridad",
|
|
||||||
"Disable": "Desactivar",
|
|
||||||
"Invalid verification code": "Código de verificación no válido",
|
|
||||||
"New backup codes have been generated": "Nuevos códigos de seguridad han sido generados",
|
|
||||||
"Failed to regenerate backup codes": "No se pudo regenerar los códigos de seguridad",
|
|
||||||
"About backup codes": "Acerca de los códigos de seguridad",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Los códigos de seguridad pueden usarse para acceder a tu cuenta si pierdes acceso a tu aplicación autenticadora. Cada código solo puede ser usado una vez.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Puedes regenerar nuevos códigos de seguridad en cualquier momento. Esto invalidará todos los códigos existentes.",
|
|
||||||
"Confirm password": "Confirmar contraseña",
|
|
||||||
"Generate new backup codes": "Generar nuevos códigos de seguridad",
|
|
||||||
"Save your new backup codes": "Guarda tus nuevos códigos de seguridad",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Asegúrate de guardar estos códigos en un lugar seguro. Tus viejos códigos de seguridad ya no son válidos.",
|
|
||||||
"Your new backup codes": "Tus nuevos códigos de seguridad",
|
|
||||||
"I've saved my backup codes": "He guardado mis códigos de seguridad",
|
|
||||||
"Failed to setup MFA": "No se pudo configurar MFA",
|
|
||||||
"Setup & Verify": "Configurar y verificar",
|
|
||||||
"Add to authenticator": "Agregar al autenticador",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Escanea este código QR con tu aplicación autenticadora",
|
|
||||||
"Can't scan the code?": "¿No puedes escanear el código?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Introduce este código manualmente en tu aplicación autenticadora:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Introduce el código de 6 dígitos de tu autenticador",
|
|
||||||
"Verify and enable": "Verificar y activar",
|
|
||||||
"Failed to generate QR code. Please try again.": "No se pudo generar el código QR. Por favor, intente de nuevo.",
|
|
||||||
"Backup": "Respaldo",
|
|
||||||
"Save codes": "Guardar códigos",
|
|
||||||
"Save your backup codes": "Guarda tus códigos de seguridad",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Estos códigos pueden usarse para acceder a tu cuenta si pierdes acceso a tu aplicación autenticadora. Cada código solo puede ser usado una vez.",
|
|
||||||
"Print": "Imprimir",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "La autenticación de dos factores ha sido configurada. Por favor, inicie sesión nuevamente.",
|
|
||||||
"Two-Factor authentication required": "Se requiere autenticación de dos factores",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Tu espacio de trabajo requiere autenticación de dos factores para todos los usuarios",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Para continuar accediendo a tu espacio de trabajo, debes configurar la autenticación de dos factores. Esto añade una capa extra de seguridad a tu cuenta.",
|
|
||||||
"Set up two-factor authentication": "Configurar la autenticación de dos factores",
|
|
||||||
"Cancel and logout": "Cancelar y cerrar sesión",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Tu espacio de trabajo requiere autenticación de dos factores. Por favor, configúralo para continuar.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Esto añade una capa extra de seguridad a tu cuenta al requerir un código de verificación de tu aplicación autenticadora.",
|
|
||||||
"Password is required": "Se requiere contraseña",
|
|
||||||
"Password must be at least 8 characters": "La contraseña debe tener al menos 8 caracteres",
|
|
||||||
"Please enter a 6-digit code": "Por favor, introduce un código de 6 dígitos",
|
|
||||||
"Code must be exactly 6 digits": "El código debe ser exactamente de 6 dígitos",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Introduce el código de 6 dígitos que se encuentra en tu aplicación autenticadora",
|
|
||||||
"Need help authenticating?": "¿Necesitas ayuda para autenticar?",
|
|
||||||
"MFA QR Code": "Código QR MFA",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Cuenta creada exitosamente. Por favor, inicie sesión para configurar la autenticación de dos factores.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Restablecimiento de contraseña exitoso. Por favor, inicie sesión con su nueva contraseña y complete la autenticación de dos factores.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Restablecimiento de contraseña exitoso. Por favor, inicie sesión con su nueva contraseña para configurar la autenticación de dos factores.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "El restablecimiento de contraseña fue exitoso. Por favor, inicie sesión con su nueva contraseña.",
|
|
||||||
"Two-factor authentication": "Autenticación de dos factores",
|
|
||||||
"Use authenticator app instead": "Usar la aplicación autenticadora en su lugar",
|
|
||||||
"Verify backup code": "Verificar código de seguridad",
|
|
||||||
"Use backup code": "Usar código de seguridad",
|
|
||||||
"Enter one of your backup codes": "Introduce uno de tus códigos de seguridad",
|
|
||||||
"Backup code": "Código de seguridad",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Introduce uno de tus códigos de seguridad. Cada código de seguridad solo puede ser usado una vez.",
|
|
||||||
"Verify": "Verificar",
|
|
||||||
"Trash": "Papelera",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "{count, plural, one{Las páginas en la papelera se eliminarán permanentemente después de # día.} other{Las páginas en la papelera se eliminarán permanentemente después de # días.}}",
|
|
||||||
"Deleted": "Eliminado",
|
|
||||||
"No pages in trash": "No hay páginas en la papelera",
|
|
||||||
"Permanently delete page?": "¿Eliminar página permanentemente?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "¿Está seguro de que desea eliminar '{{title}}' permanentemente? Esta acción no se puede deshacer.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "¿Restaurar '{{title}}' y sus subpáginas?",
|
|
||||||
"Move to trash": "Mover a la papelera",
|
|
||||||
"Move this page to trash?": "¿Mover esta página a la papelera?",
|
|
||||||
"Restore page": "Restaurar página",
|
|
||||||
"Page moved to trash": "Página movida a la papelera",
|
|
||||||
"Page restored successfully": "Página restaurada con éxito",
|
|
||||||
"Deleted by": "Eliminado por",
|
|
||||||
"Deleted at": "Eliminado en",
|
|
||||||
"Preview": "Vista previa",
|
|
||||||
"Subpages": "Subpáginas",
|
|
||||||
"Failed to load subpages": "Error al cargar subpáginas",
|
|
||||||
"No subpages": "Sin subpáginas",
|
|
||||||
"Subpages (Child pages)": "Subpáginas (Páginas hijas)",
|
|
||||||
"List all subpages of the current page": "Listar todas las subpáginas de la página actual",
|
|
||||||
"Attachments": "Adjuntos",
|
|
||||||
"All spaces": "Todos los espacios",
|
|
||||||
"Unknown": "Desconocido",
|
|
||||||
"Find a space": "Encontrar un espacio",
|
|
||||||
"Search in all your spaces": "Buscar en todos tus espacios",
|
|
||||||
"Type": "Tipo",
|
|
||||||
"Enterprise": "Empresa",
|
|
||||||
"Download attachment": "Descargar adjunto",
|
|
||||||
"Allowed email domains": "Dominios de correo electrónico permitidos",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Solo los usuarios con direcciones de correo electrónico de estos dominios pueden registrarse a través de SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Introduce nombres de dominio válidos separados por coma o espacio",
|
|
||||||
"Enforce two-factor authentication": "Aplicar autenticación de dos factores",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Una vez aplicada, todos los miembros deben habilitar la autenticación de dos factores para acceder al espacio de trabajo.",
|
|
||||||
"Toggle MFA enforcement": "Alternar la aplicación de MFA",
|
|
||||||
"Display name": "Nombre para mostrar",
|
|
||||||
"Allow signup": "Permitir registro",
|
|
||||||
"Enabled": "Habilitado",
|
|
||||||
"Advanced Settings": "Configuración avanzada",
|
|
||||||
"Enable TLS/SSL": "Habilitar TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Usar conexión segura al servidor LDAP",
|
|
||||||
"Group sync": "Sincronización de grupos",
|
|
||||||
"No SSO providers found.": "No se encontraron proveedores de SSO.",
|
|
||||||
"Delete SSO provider": "Eliminar proveedor de SSO",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "¿Está seguro de que desea eliminar este proveedor de SSO?",
|
|
||||||
"Action": "Acción",
|
|
||||||
"{{ssoProviderType}} configuration": "Configuración de {{ssoProviderType}}",
|
|
||||||
"Icon": "Icono",
|
|
||||||
"Upload image": "Subir imagen",
|
|
||||||
"Remove image": "Eliminar imagen",
|
|
||||||
"Failed to remove image": "No se ha podido eliminar la imagen",
|
|
||||||
"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",
|
|
||||||
"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.",
|
|
||||||
"Toggle restrict API keys to admins": "Activar o desactivar la restricción de claves API solo a administradores",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "La creación de claves API está restringida a administradores por el administrador de tu espacio de trabajo.",
|
|
||||||
"AI settings": "Configuración de IA",
|
|
||||||
"AI search": "Búsqueda de IA",
|
|
||||||
"AI Answer": "Respuesta de IA",
|
|
||||||
"Ask AI": "Preguntar a IA",
|
|
||||||
"AI is thinking...": "IA está pensando...",
|
|
||||||
"Ask a question...": "Haz una pregunta...",
|
|
||||||
"AI Answers": "Respuestas de IA",
|
|
||||||
"AI-powered search (AI Answers)": "Búsqueda impulsada por IA (Respuestas de IA)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "La búsqueda de IA utiliza incrustaciones vectoriales para proporcionar capacidades de búsqueda semántica en todo el contenido de su espacio de trabajo.",
|
|
||||||
"Toggle AI search": "Alternar búsqueda de IA",
|
|
||||||
"Generative AI (Ask AI)": "IA generativa (Preguntar a la IA)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Habilitar la generación de contenido impulsada por IA en el editor. Permite a los usuarios generar, mejorar, traducir y transformar texto.",
|
|
||||||
"Toggle generative AI": "Activar IA generativa",
|
|
||||||
"Enterprise feature": "Función empresarial",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "La IA solo está disponible en la edición empresarial de Docmost. Contacte con sales@docmost.com.",
|
|
||||||
"AI & MCP": "IA y MCP",
|
|
||||||
"AI": "IA",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Protocolo de Contexto del Modelo (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Habilite el servidor MCP para permitir que asistentes de IA y herramientas interactúen con el contenido de su espacio de trabajo.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP solo está disponible en la edición empresarial de Docmost. Contacte con sales@docmost.com.",
|
|
||||||
"MCP documentation": "Documentación de MCP",
|
|
||||||
"MCP Server URL": "URL del servidor MCP",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Use su clave API para la autenticación. Puede gestionar las claves API en la configuración de su cuenta.",
|
|
||||||
"Supported tools": "Herramientas compatibles",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "Su espacio de trabajo tiene MCP habilitado. Use su clave API para conectar asistentes de IA.",
|
|
||||||
"MCP server URL:": "URL del servidor MCP:",
|
|
||||||
"Learn more": "Más información",
|
|
||||||
"View the": "Ver la",
|
|
||||||
"for usage details.": "para detalles de uso.",
|
|
||||||
"for setup instructions.": "para instrucciones de configuración.",
|
|
||||||
"API documentation": "Documentación de la API",
|
|
||||||
"Sources": "Fuentes",
|
|
||||||
"AI Answers not available for attachments": "Respuestas de IA no disponibles para archivos adjuntos",
|
|
||||||
"No answer available": "No hay respuesta disponible",
|
|
||||||
"Background color": "Color de fondo",
|
|
||||||
"Highlight color": "Color de resaltado",
|
|
||||||
"Remove color": "Eliminar color",
|
|
||||||
"Notifications": "Notificaciones",
|
|
||||||
"No notifications": "Sin notificaciones",
|
|
||||||
"No unread notifications": "No hay notificaciones no leídas",
|
|
||||||
"All notifications": "Todas las notificaciones",
|
|
||||||
"Unread only": "Solo no leídas",
|
|
||||||
"Mark all as read": "Marcar todo como leído",
|
|
||||||
"Mark as read": "Marcar como leído",
|
|
||||||
"More options": "Más opciones",
|
|
||||||
"mentioned you in a comment": "te mencionó en un comentario",
|
|
||||||
"commented on a page": "comentó en una página",
|
|
||||||
"resolved a comment": "resolvió un comentario",
|
|
||||||
"mentioned you on a page": "te mencionó en una página",
|
|
||||||
"gave you edit access to a page": "Te dio acceso para editar una página.",
|
|
||||||
"gave you view access to a page": "Te dio acceso para ver una página.",
|
|
||||||
"Today": "Hoy",
|
|
||||||
"Yesterday": "Ayer",
|
|
||||||
"This week": "Esta semana",
|
|
||||||
"Older": "Más antiguo",
|
|
||||||
"Restricted page": "Página restringida",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Las páginas restringidas no pueden compartirse públicamente.",
|
|
||||||
"Restricted by parent": "Restringida por la página padre",
|
|
||||||
"Restricted": "Restringida",
|
|
||||||
"Open": "Abierta",
|
|
||||||
"Inherits restrictions from ancestor page": "Hereda las restricciones de una página superior.",
|
|
||||||
"Only people listed below can access this page": "Solo las personas que figuran a continuación pueden acceder a esta página.",
|
|
||||||
"Everyone in this space can access": "Todos en este espacio pueden acceder.",
|
|
||||||
"No additional restrictions on this page": "No hay restricciones adicionales en esta página.",
|
|
||||||
"Only specific people can access": "Solo determinadas personas pueden acceder.",
|
|
||||||
"Use only inherited restrictions": "Usar solo las restricciones heredadas.",
|
|
||||||
"Add restrictions on top of inherited": "Agregar restricciones además de las heredadas.",
|
|
||||||
"Inherited restriction": "Restricción heredada",
|
|
||||||
"Access limited by": "Acceso limitado por",
|
|
||||||
"Restrict access to control who can view and edit this page": "Restringir el acceso para controlar quién puede ver y editar esta página.",
|
|
||||||
"Add additional restrictions specific to this page": "Agregar restricciones adicionales específicas para esta página.",
|
|
||||||
"Access": "Acceso",
|
|
||||||
"People with access": "Personas con acceso",
|
|
||||||
"Remove all": "Eliminar todo",
|
|
||||||
"Remove access": "Eliminar acceso",
|
|
||||||
"Remove all access": "Eliminar todo el acceso",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "¿Está seguro de que desea eliminar el acceso de este miembro a la página?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "¿Está seguro de que desea eliminar todo el acceso específico? Esto hará que la página esté abierta a todos en el espacio.",
|
|
||||||
"Trash retention": "Retención de la papelera",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Las páginas en la papelera se eliminarán permanentemente después de este período.",
|
|
||||||
"Trash retention updated": "Retención de la papelera actualizada",
|
|
||||||
"Failed to update trash retention": "No se pudo actualizar la retención de la papelera.",
|
|
||||||
"Removed page restriction": "Restricción de página eliminada",
|
|
||||||
"Added page permission": "Permiso de página añadido",
|
|
||||||
"Removed page permission": "Permiso de página eliminado"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Choisissez votre langue d'interface préférée.",
|
"Choose your preferred interface language.": "Choisissez votre langue d'interface préférée.",
|
||||||
"Choose your preferred page width.": "Choisissez votre largeur de page préférée.",
|
"Choose your preferred page width.": "Choisissez votre largeur de page préférée.",
|
||||||
"Confirm": "Confirmer",
|
"Confirm": "Confirmer",
|
||||||
"Copy as Markdown": "Copier comme Markdown",
|
|
||||||
"Copy link": "Copier le lien",
|
"Copy link": "Copier le lien",
|
||||||
"Create": "Créer",
|
"Create": "Créer",
|
||||||
"Create group": "Créer groupe",
|
"Create group": "Créer groupe",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "par ex. Espace pour l'équipe produit",
|
"e.g Space for product team": "par ex. Espace pour l'équipe produit",
|
||||||
"e.g Space for sales team to collaborate": "par ex. Espace pour l'équipe de vente pour collaborer",
|
"e.g Space for sales team to collaborate": "par ex. Espace pour l'équipe de vente pour collaborer",
|
||||||
"Edit": "Modifier",
|
"Edit": "Modifier",
|
||||||
"Read": "Lire",
|
|
||||||
"Edit group": "Modifier groupe",
|
"Edit group": "Modifier groupe",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Enter a strong password": "Entrez un mot de passe fort",
|
"Enter a strong password": "Entrez un mot de passe fort",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "Aucun groupe trouvé",
|
"No group found": "Aucun groupe trouvé",
|
||||||
"No page history saved yet.": "Aucun historique de la page enregistré pour l'instant.",
|
"No page history saved yet.": "Aucun historique de la page enregistré pour l'instant.",
|
||||||
"No pages yet": "Aucune page pour l'instant",
|
"No pages yet": "Aucune page pour l'instant",
|
||||||
"No shared pages": "Aucune page partagée",
|
|
||||||
"No results found...": "Aucun résultat trouvé...",
|
"No results found...": "Aucun résultat trouvé...",
|
||||||
"No user found": "Aucun utilisateur trouvé",
|
"No user found": "Aucun utilisateur trouvé",
|
||||||
"Overview": "Vue d'ensemble",
|
"Overview": "Vue d'ensemble",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "page",
|
"page": "page",
|
||||||
"Page deleted successfully": "Page supprimée avec succès",
|
"Page deleted successfully": "Page supprimée avec succès",
|
||||||
"Page history": "Historique de la page",
|
"Page history": "Historique de la page",
|
||||||
"Select version": "Sélectionner la version",
|
|
||||||
"Highlight changes": "Mettre en évidence les changements",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "L'importation de la page est en cours. Veuillez ne pas fermer cet onglet.",
|
"Page import is in progress. Please do not close this tab.": "L'importation de la page est en cours. Veuillez ne pas fermer cet onglet.",
|
||||||
"Pages": "Pages",
|
"Pages": "Pages",
|
||||||
"pages": "pages",
|
"pages": "pages",
|
||||||
"Password": "Mot de passe",
|
"Password": "Mot de passe",
|
||||||
"Password changed successfully": "Mot de passe changé avec succès",
|
"Password changed successfully": "Mot de passe changé avec succès",
|
||||||
"People": "Personnes",
|
|
||||||
"Pending": "En attente",
|
"Pending": "En attente",
|
||||||
"Please confirm your action": "Veuillez confirmer votre action",
|
"Please confirm your action": "Veuillez confirmer votre action",
|
||||||
"Preferences": "Préférences",
|
"Preferences": "Préférences",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Répondre...",
|
"Reply...": "Répondre...",
|
||||||
"Error loading comments.": "Erreur lors du chargement des commentaires.",
|
"Error loading comments.": "Erreur lors du chargement des commentaires.",
|
||||||
"No comments yet.": "Pas de commentaires pour l'instant.",
|
"No comments yet.": "Pas de commentaires pour l'instant.",
|
||||||
"No open comments.": "Aucun commentaire ouvert.",
|
|
||||||
"No resolved comments.": "Aucun commentaire résolu.",
|
|
||||||
"Add a comment...": "Ajouter un commentaire...",
|
|
||||||
"Edit comment": "Modifier le commentaire",
|
"Edit comment": "Modifier le commentaire",
|
||||||
"Delete comment": "Supprimer le commentaire",
|
"Delete comment": "Supprimer le commentaire",
|
||||||
"Are you sure you want to delete this comment?": "Êtes-vous sûr de vouloir supprimer ce commentaire ?",
|
"Are you sure you want to delete this comment?": "Êtes-vous sûr de vouloir supprimer ce commentaire ?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Commentaire supprimé avec succès",
|
"Comment deleted successfully": "Commentaire supprimé avec succès",
|
||||||
"Failed to delete comment": "Échec de la suppression du commentaire",
|
"Failed to delete comment": "Échec de la suppression du commentaire",
|
||||||
"Comment resolved successfully": "Commentaire résolu avec succès",
|
"Comment resolved successfully": "Commentaire résolu avec succès",
|
||||||
"Comment re-opened successfully": "Commentaire rouvert avec succès",
|
|
||||||
"Comment unresolved successfully": "Commentaire non résolu avec succès",
|
|
||||||
"Failed to resolve comment": "Échec de la résolution du commentaire",
|
"Failed to resolve comment": "Échec de la résolution du commentaire",
|
||||||
"Resolve comment": "Résoudre le commentaire",
|
|
||||||
"Unresolve comment": "Désorganiser le commentaire",
|
|
||||||
"Resolve Comment Thread": "Résoudre le fil de commentaires",
|
|
||||||
"Unresolve Comment Thread": "Désorganiser le fil de commentaires",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Êtes-vous sûr de vouloir résoudre ce fil de commentaires ? Cela le marquera comme terminé.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Êtes-vous sûr de vouloir désorganiser ce fil de commentaires ?",
|
|
||||||
"Resolved": "Résolu",
|
|
||||||
"No active comments.": "Aucun commentaire actif.",
|
|
||||||
"Revoke invitation": "Révoquer l'invitation",
|
"Revoke invitation": "Révoquer l'invitation",
|
||||||
"Revoke": "Révoquer",
|
"Revoke": "Révoquer",
|
||||||
"Don't": "Ne pas",
|
"Don't": "Ne pas",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Toute personne ayant ce lien peut rejoindre cet espace de travail.",
|
"Anyone with this link can join this workspace.": "Toute personne ayant ce lien peut rejoindre cet espace de travail.",
|
||||||
"Invite link": "Lien d'invitation",
|
"Invite link": "Lien d'invitation",
|
||||||
"Copy": "Copier",
|
"Copy": "Copier",
|
||||||
"Copy to space": "Copier dans l'espace",
|
|
||||||
"Copied": "Copié",
|
"Copied": "Copié",
|
||||||
"Duplicate": "Dupliquer",
|
|
||||||
"Select a user": "Sélectionner un utilisateur",
|
"Select a user": "Sélectionner un utilisateur",
|
||||||
"Select a group": "Sélectionner un groupe",
|
"Select a group": "Sélectionner un groupe",
|
||||||
"Export all pages and attachments in this space.": "Exporter toutes les pages et pièces jointes dans cet espace.",
|
"Export all pages and attachments in this space.": "Exporter toutes les pages et pièces jointes dans cet espace.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Échec de l'exportation :",
|
"Export failed:": "Échec de l'exportation :",
|
||||||
"export error": "exporter l'erreur",
|
"export error": "exporter l'erreur",
|
||||||
"Export page": "Exporter la page",
|
"Export page": "Exporter la page",
|
||||||
"Export successful": "Exportation réussie",
|
|
||||||
"Export space": "Exporter l'espace",
|
"Export space": "Exporter l'espace",
|
||||||
"Export {{type}}": "Exporter {{type}}",
|
"Export {{type}}": "Exporter {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "Le fichier dépasse la limite de {{limit}} pièces jointes",
|
"File exceeds the {{limit}} attachment limit": "Le fichier dépasse la limite de {{limit}} pièces jointes",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Ajouter une ligne en dessous",
|
"Add row below": "Ajouter une ligne en dessous",
|
||||||
"Delete table": "Supprimer le tableau",
|
"Delete table": "Supprimer le tableau",
|
||||||
"Info": "Info",
|
"Info": "Info",
|
||||||
"Note": "Remarque",
|
|
||||||
"Success": "Succès",
|
"Success": "Succès",
|
||||||
"Warning": "Avertissement",
|
"Warning": "Avertissement",
|
||||||
"Danger": "Danger",
|
"Danger": "Danger",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Téléchargez n'importe quelle image depuis votre appareil.",
|
"Upload any image from your device.": "Téléchargez n'importe quelle image depuis votre appareil.",
|
||||||
"Upload any video from your device.": "Téléchargez n'importe quelle vidéo depuis votre appareil.",
|
"Upload any video from your device.": "Téléchargez n'importe quelle vidéo depuis votre appareil.",
|
||||||
"Upload any file from your device.": "Téléchargez n'importe quel fichier depuis votre appareil.",
|
"Upload any file from your device.": "Téléchargez n'importe quel fichier depuis votre appareil.",
|
||||||
"Uploading {{name}}": "Téléchargement de {{name}}",
|
|
||||||
"Uploading file": "Téléchargement du fichier",
|
|
||||||
"Table": "Tableau",
|
"Table": "Tableau",
|
||||||
"Insert a table.": "Insérez un tableau.",
|
"Insert a table.": "Insérez un tableau.",
|
||||||
"Insert collapsible block.": "Insérer un bloc repliable.",
|
"Insert collapsible block.": "Insérer un bloc repliable.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Insérer la date actuelle",
|
"Insert current date": "Insérer la date actuelle",
|
||||||
"Draw and sketch excalidraw diagrams": "Dessiner et esquisser des diagrammes Excalidraw",
|
"Draw and sketch excalidraw diagrams": "Dessiner et esquisser des diagrammes Excalidraw",
|
||||||
"Multiple": "Multiple",
|
"Multiple": "Multiple",
|
||||||
"Turn into": "Transformer en",
|
|
||||||
"Text align": "Alignement du texte",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Cette page a peut-être été supprimée, déplacée ou vous n'y avez peut-être pas accès.",
|
|
||||||
"Go to homepage": "Aller à l'accueil",
|
|
||||||
"Pages you create will show up here.": "Les pages que vous créez apparaîtront ici.",
|
|
||||||
"Heading {{level}}": "Titre {{level}}",
|
"Heading {{level}}": "Titre {{level}}",
|
||||||
"Toggle title": "Basculer le titre",
|
"Toggle title": "Basculer le titre",
|
||||||
"Write anything. Enter \"/\" for commands": "Écrivez n'importe quoi. Entrez \"/\" pour les commandes",
|
"Write anything. Enter \"/\" for commands": "Écrivez n'importe quoi. Entrez \"/\" pour les commandes",
|
||||||
"Write...": "Écrire...",
|
|
||||||
"Column count": "Nombre de colonnes",
|
|
||||||
"{{count}} Columns": "{count, plural, one {# colonne} other {# colonnes}}",
|
|
||||||
"Equal columns": "Colonnes égales",
|
|
||||||
"Left sidebar": "Barre latérale gauche",
|
|
||||||
"Right sidebar": "Barre latérale droite",
|
|
||||||
"Wide center": "Large au centre",
|
|
||||||
"Left wide": "Large à gauche",
|
|
||||||
"Right wide": "Large à droite",
|
|
||||||
"Names do not match": "Les noms ne correspondent pas",
|
"Names do not match": "Les noms ne correspondent pas",
|
||||||
"Today, {{time}}": "Aujourd'hui, {{time}}",
|
"Today, {{time}}": "Aujourd'hui, {{time}}",
|
||||||
"Yesterday, {{time}}": "Hier, {{time}}",
|
"Yesterday, {{time}}": "Hier, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Nombre de caractères : {{characterCount}}",
|
"Character count: {{characterCount}}": "Nombre de caractères : {{characterCount}}",
|
||||||
"New update": "Nouvelle mise à jour",
|
"New update": "Nouvelle mise à jour",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} est disponible",
|
"{{latestVersion}} is available": "{{latestVersion}} est disponible",
|
||||||
"Default page edit mode": "Mode d'édition de page par défaut",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Choisissez votre mode d'édition de page préféré. Évitez les modifications accidentelles.",
|
|
||||||
"Reading": "Lecture",
|
|
||||||
"Delete member": "Supprimer le membre",
|
"Delete member": "Supprimer le membre",
|
||||||
"Member deleted successfully": "Membre supprimé avec succès",
|
"Member deleted successfully": "Membre supprimé avec succès",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Êtes-vous sûr de vouloir supprimer ce membre de l'espace de travail? Cette action est irréversible.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Êtes-vous sûr de vouloir supprimer ce membre de l'espace de travail? Cette action est irréversible.",
|
||||||
"Deactivate member": "Désactiver le membre",
|
|
||||||
"Activate member": "Activer le membre",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Êtes-vous sûr de vouloir désactiver ce membre de l'espace de travail ? Cette personne ne pourra plus accéder à cet espace de travail.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Êtes-vous sûr de vouloir activer ce membre de l'espace de travail ?",
|
|
||||||
"Deactivate": "Désactiver",
|
|
||||||
"Activate": "Activer",
|
|
||||||
"Deactivated": "Désactivé",
|
|
||||||
"Move": "Déplacer",
|
"Move": "Déplacer",
|
||||||
"Move page": "Déplacer la page",
|
"Move page": "Déplacer la page",
|
||||||
"Move page to a different space.": "Déplacer la page vers un autre espace.",
|
"Move page to a different space.": "Déplacer la page vers un autre espace.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Les pages partagées publiquement des espaces dont vous êtes membre apparaîtront ici",
|
"Publicly shared pages from spaces you are a member of will appear here": "Les pages partagées publiquement des espaces dont vous êtes membre apparaîtront ici",
|
||||||
"Share deleted successfully": "Partage supprimé avec succès",
|
"Share deleted successfully": "Partage supprimé avec succès",
|
||||||
"Share not found": "Partage non trouvé",
|
"Share not found": "Partage non trouvé",
|
||||||
"Failed to share page": "Échec du partage de la page",
|
"Failed to share page": "Échec du partage de la page"
|
||||||
"Disable public sharing": "Désactiver le partage public",
|
|
||||||
"Prevent members from sharing pages publicly.": "Empêcher les membres de partager des pages publiquement.",
|
|
||||||
"Toggle public sharing": "Basculer le partage public",
|
|
||||||
"Toggle space public sharing": "Basculer le partage public de l'espace",
|
|
||||||
"Public sharing is disabled at the workspace level": "Le partage public est désactivé au niveau de l'espace de travail",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Empêcher les pages de cet espace d'être partagées publiquement.",
|
|
||||||
"Requires an enterprise license": "Nécessite une licence d'entreprise",
|
|
||||||
"Page permissions": "Autorisations de la page",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Contrôlez qui peut consulter et modifier chaque page. Disponible avec une licence Entreprise.",
|
|
||||||
"Enable public sharing": "Activer le partage public",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Êtes-vous sûr de vouloir activer le partage public ? Les membres pourront partager des pages publiquement.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Êtes-vous sûr de vouloir désactiver le partage public ? Tous les liens partagés existants dans cet espace de travail seront supprimés.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Êtes-vous sûr de vouloir activer le partage public pour cet espace ?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Êtes-vous sûr de vouloir désactiver le partage public ? Tous les liens partagés existants dans cet espace seront supprimés.",
|
|
||||||
"Public sharing is disabled": "Le partage public est désactivé",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "Le partage public a été désactivé au niveau de l'espace de travail.",
|
|
||||||
"Public sharing has been disabled for this space.": "Le partage public a été désactivé pour cet espace.",
|
|
||||||
"Copy page": "Copier la page",
|
|
||||||
"Copy page to a different space.": "Copier la page dans un autre espace.",
|
|
||||||
"Page copied successfully": "Page copiée avec succès",
|
|
||||||
"Page duplicated successfully": "Page dupliquée avec succès",
|
|
||||||
"Find": "Trouver",
|
|
||||||
"Not found": "Non trouvé",
|
|
||||||
"Previous Match (Shift+Enter)": "Correspondance précédente (Shift+Entrée)",
|
|
||||||
"Next match (Enter)": "Correspondance suivante (Entrée)",
|
|
||||||
"Match case (Alt+C)": "Respecter la casse (Alt+C)",
|
|
||||||
"Replace": "Remplacer",
|
|
||||||
"Close (Escape)": "Fermer (Échapper)",
|
|
||||||
"Replace (Enter)": "Remplacer (Entrée)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Tout remplacer (Ctrl+Alt+Entrée)",
|
|
||||||
"Replace all": "Tout remplacer",
|
|
||||||
"View all spaces": "Voir tous les espaces",
|
|
||||||
"Error": "Erreur",
|
|
||||||
"Failed to disable MFA": "Impossible de désactiver l'A2F",
|
|
||||||
"Disable two-factor authentication": "Désactiver l'authentification à deux facteurs",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "La désactivation de l'authentification à deux facteurs rendra votre compte moins sécurisé. Vous n'aurez besoin que de votre mot de passe pour vous connecter.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Veuillez entrer votre mot de passe pour désactiver l'authentification à deux facteurs :",
|
|
||||||
"Two-factor authentication has been enabled": "L'authentification à deux facteurs a été activée",
|
|
||||||
"Two-factor authentication has been disabled": "L'authentification à deux facteurs a été désactivée",
|
|
||||||
"2-step verification": "Vérification en 2 étapes",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Protégez votre compte avec une couche de vérification supplémentaire lors de la connexion.",
|
|
||||||
"Two-factor authentication is active on your account.": "L'authentification à deux facteurs est active sur votre compte.",
|
|
||||||
"Add 2FA method": "Ajouter une méthode A2F",
|
|
||||||
"Backup codes": "Codes de sauvegarde",
|
|
||||||
"Disable": "Désactiver",
|
|
||||||
"Invalid verification code": "Code de vérification invalide",
|
|
||||||
"New backup codes have been generated": "De nouveaux codes de sauvegarde ont été générés",
|
|
||||||
"Failed to regenerate backup codes": "Échec de la régénération des codes de sauvegarde",
|
|
||||||
"About backup codes": "À propos des codes de sauvegarde",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Les codes de sauvegarde peuvent être utilisés pour accéder à votre compte si vous perdez l'accès à votre application d'authentification. Chaque code ne peut être utilisé qu'une seule fois.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Vous pouvez régénérer de nouveaux codes de sauvegarde à tout moment. Cela invalidera tous les codes existants.",
|
|
||||||
"Confirm password": "Confirmer le mot de passe",
|
|
||||||
"Generate new backup codes": "Générer de nouveaux codes de sauvegarde",
|
|
||||||
"Save your new backup codes": "Enregistrez vos nouveaux codes de sauvegarde",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Assurez-vous d'enregistrer ces codes dans un endroit sécurisé. Vos anciens codes de sauvegarde ne sont plus valides.",
|
|
||||||
"Your new backup codes": "Vos nouveaux codes de sauvegarde",
|
|
||||||
"I've saved my backup codes": "J'ai enregistré mes codes de sauvegarde",
|
|
||||||
"Failed to setup MFA": "Échec de la configuration de l'A2F",
|
|
||||||
"Setup & Verify": "Configurer et vérifier",
|
|
||||||
"Add to authenticator": "Ajouter à l'authentification",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Scannez ce code QR avec votre application d'authentification",
|
|
||||||
"Can't scan the code?": "Impossible de scanner le code ?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Entrez ce code manuellement dans votre application d'authentification :",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Entrez le code à 6 chiffres de votre authentificateur",
|
|
||||||
"Verify and enable": "Vérifier et activer",
|
|
||||||
"Failed to generate QR code. Please try again.": "Échec de la génération du code QR. Veuillez réessayer.",
|
|
||||||
"Backup": "Sauvegarde",
|
|
||||||
"Save codes": "Enregistrer les codes",
|
|
||||||
"Save your backup codes": "Enregistrez vos codes de sauvegarde",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Ces codes peuvent être utilisés pour accéder à votre compte si vous perdez l'accès à votre application d'authentification. Chaque code ne peut être utilisé qu'une seule fois.",
|
|
||||||
"Print": "Imprimer",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "L'authentification à deux facteurs a été configurée. Veuillez vous reconnecter.",
|
|
||||||
"Two-Factor authentication required": "Authentification à deux facteurs requise",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Votre espace de travail nécessite l'authentification à deux facteurs pour tous les utilisateurs",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Pour continuer à accéder à votre espace de travail, vous devez configurer l'authentification à deux facteurs. Cela ajoute une couche de sécurité supplémentaire à votre compte.",
|
|
||||||
"Set up two-factor authentication": "Configurer l'authentification à deux facteurs",
|
|
||||||
"Cancel and logout": "Annuler et se déconnecter",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Votre espace de travail nécessite l'authentification à deux facteurs. Veuillez le configurer pour continuer.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Cela ajoute une couche de sécurité supplémentaire à votre compte en exigeant un code de vérification provenant de votre application d'authentification.",
|
|
||||||
"Password is required": "Mot de passe requis",
|
|
||||||
"Password must be at least 8 characters": "Le mot de passe doit comporter au moins 8 caractères",
|
|
||||||
"Please enter a 6-digit code": "Veuillez entrer un code à 6 chiffres",
|
|
||||||
"Code must be exactly 6 digits": "Le code doit être exactement de 6 chiffres",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Entrez le code à 6 chiffres trouvé dans votre application d'authentification",
|
|
||||||
"Need help authenticating?": "Besoin d'aide pour l'authentification ?",
|
|
||||||
"MFA QR Code": "Code QR de l'A2F",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Compte créé avec succès. Veuillez vous connecter pour configurer l'authentification à deux facteurs.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Réinitialisation du mot de passe réussie. Veuillez vous connecter avec votre nouveau mot de passe et compléter l'authentification à deux facteurs.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Réinitialisation du mot de passe réussie. Veuillez vous connecter avec votre nouveau mot de passe pour configurer l'authentification à deux facteurs.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "La réinitialisation du mot de passe a réussi. Veuillez vous connecter avec votre nouveau mot de passe.",
|
|
||||||
"Two-factor authentication": "Authentification à deux facteurs",
|
|
||||||
"Use authenticator app instead": "Utilisez l'application d'authentification à la place",
|
|
||||||
"Verify backup code": "Vérifier le code de sauvegarde",
|
|
||||||
"Use backup code": "Utiliser le code de sauvegarde",
|
|
||||||
"Enter one of your backup codes": "Entrez un de vos codes de sauvegarde",
|
|
||||||
"Backup code": "Code de sauvegarde",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Entrez un de vos codes de sauvegarde. Chaque code de sauvegarde ne peut être utilisé qu'une seule fois.",
|
|
||||||
"Verify": "Vérifier",
|
|
||||||
"Trash": "Corbeille",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "Les pages dans la corbeille seront définitivement supprimées après {{count}} jours.",
|
|
||||||
"Deleted": "Supprimé",
|
|
||||||
"No pages in trash": "Aucune page dans la corbeille",
|
|
||||||
"Permanently delete page?": "Supprimer définitivement la page ?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Êtes-vous sûr de vouloir supprimer définitivement « {{title}} » ? Cette action ne peut pas être annulée.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "Restaurer « {{title}} » et ses sous-pages ?",
|
|
||||||
"Move to trash": "Déplacer vers la corbeille",
|
|
||||||
"Move this page to trash?": "Déplacer cette page vers la corbeille ?",
|
|
||||||
"Restore page": "Restaurer la page",
|
|
||||||
"Page moved to trash": "Page déplacée vers la corbeille",
|
|
||||||
"Page restored successfully": "Page restaurée avec succès",
|
|
||||||
"Deleted by": "Supprimé par",
|
|
||||||
"Deleted at": "Supprimé à",
|
|
||||||
"Preview": "Aperçu",
|
|
||||||
"Subpages": "Sous-pages",
|
|
||||||
"Failed to load subpages": "Échec du chargement des sous-pages",
|
|
||||||
"No subpages": "Pas de sous-pages",
|
|
||||||
"Subpages (Child pages)": "Sous-pages (Pages enfants)",
|
|
||||||
"List all subpages of the current page": "Lister toutes les sous-pages de la page actuelle",
|
|
||||||
"Attachments": "Pièces jointes",
|
|
||||||
"All spaces": "Tous les espaces",
|
|
||||||
"Unknown": "Inconnu",
|
|
||||||
"Find a space": "Trouver un espace",
|
|
||||||
"Search in all your spaces": "Rechercher dans tous vos espaces",
|
|
||||||
"Type": "Type",
|
|
||||||
"Enterprise": "Entreprise",
|
|
||||||
"Download attachment": "Télécharger la pièce jointe",
|
|
||||||
"Allowed email domains": "Domaines de messagerie autorisés",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Seuls les utilisateurs possédant des adresses e-mail provenant de ces domaines peuvent s'inscrire via SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Entrez des noms de domaine valides séparés par une virgule ou un espace",
|
|
||||||
"Enforce two-factor authentication": "Imposer l'authentification à deux facteurs",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Une fois appliquée, tous les membres doivent activer l'authentification à deux facteurs pour accéder à l'espace de travail.",
|
|
||||||
"Toggle MFA enforcement": "Basculer l'application de l'AMF",
|
|
||||||
"Display name": "Nom d'affichage",
|
|
||||||
"Allow signup": "Autoriser l'inscription",
|
|
||||||
"Enabled": "Activé",
|
|
||||||
"Advanced Settings": "Paramètres avancés",
|
|
||||||
"Enable TLS/SSL": "Activer TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Utiliser une connexion sécurisée au serveur LDAP",
|
|
||||||
"Group sync": "Synchronisation de groupe",
|
|
||||||
"No SSO providers found.": "Aucun fournisseur SSO trouvé.",
|
|
||||||
"Delete SSO provider": "Supprimer le fournisseur SSO",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Êtes-vous sûr de vouloir supprimer ce fournisseur SSO ?",
|
|
||||||
"Action": "Action",
|
|
||||||
"{{ssoProviderType}} configuration": "Configuration {{ssoProviderType}}",
|
|
||||||
"Icon": "Icône",
|
|
||||||
"Upload image": "Téléverser une image",
|
|
||||||
"Remove image": "Supprimer l'image",
|
|
||||||
"Failed to remove image": "Échec de la suppression de l'image",
|
|
||||||
"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",
|
|
||||||
"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.",
|
|
||||||
"Toggle restrict API keys to admins": "Activer ou désactiver la restriction des clés API aux administrateurs",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "La création de clés API est restreinte aux administrateurs par l’administrateur de votre espace de travail.",
|
|
||||||
"AI settings": "Paramètres de l'IA",
|
|
||||||
"AI search": "Recherche IA",
|
|
||||||
"AI Answer": "Réponse IA",
|
|
||||||
"Ask AI": "Demander à l'IA",
|
|
||||||
"AI is thinking...": "L'IA réfléchit...",
|
|
||||||
"Ask a question...": "Posez une question...",
|
|
||||||
"AI Answers": "Réponses IA",
|
|
||||||
"AI-powered search (AI Answers)": "Recherche propulsée par IA (Réponses IA)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "La recherche IA utilise des incorporations vectorielles pour fournir des capacités de recherche sémantique à travers le contenu de votre espace de travail.",
|
|
||||||
"Toggle AI search": "Basculer la recherche IA",
|
|
||||||
"Generative AI (Ask AI)": "IA générative (Demandez à l'IA)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Activer la génération de contenu assistée par IA dans l'éditeur. Permet aux utilisateurs de générer, améliorer, traduire et transformer du texte.",
|
|
||||||
"Toggle generative AI": "Activer/désactiver l'IA générative",
|
|
||||||
"Enterprise feature": "Fonctionnalité entreprise",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "L'IA n'est disponible que dans l'édition Entreprise de Docmost. Contactez sales@docmost.com.",
|
|
||||||
"AI & MCP": "IA & MCP",
|
|
||||||
"AI": "IA",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Protocole de contexte de modèle (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Activez le serveur MCP pour permettre aux assistants et outils IA d'interagir avec le contenu de votre espace de travail.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP n'est disponible que dans l'édition Entreprise de Docmost. Contactez sales@docmost.com.",
|
|
||||||
"MCP documentation": "Documentation MCP",
|
|
||||||
"MCP Server URL": "URL du serveur MCP",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Utilisez votre clé API pour l'authentification. Vous pouvez gérer les clés API dans les paramètres de votre compte.",
|
|
||||||
"Supported tools": "Outils pris en charge",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "Votre espace de travail a MCP activé. Utilisez votre clé API pour connecter des assistants IA.",
|
|
||||||
"MCP server URL:": "URL du serveur MCP :",
|
|
||||||
"Learn more": "En savoir plus",
|
|
||||||
"View the": "Voir la",
|
|
||||||
"for usage details.": "pour les détails d'utilisation.",
|
|
||||||
"for setup instructions.": "pour les instructions de configuration.",
|
|
||||||
"API documentation": "Documentation de l'API",
|
|
||||||
"Sources": "Sources",
|
|
||||||
"AI Answers not available for attachments": "Réponses IA non disponibles pour les pièces jointes",
|
|
||||||
"No answer available": "Pas de réponse disponible",
|
|
||||||
"Background color": "Couleur de fond",
|
|
||||||
"Highlight color": "Couleur de surbrillance",
|
|
||||||
"Remove color": "Supprimer la couleur",
|
|
||||||
"Notifications": "Notifications",
|
|
||||||
"No notifications": "Aucune notification",
|
|
||||||
"No unread notifications": "Aucune notification non lue",
|
|
||||||
"All notifications": "Toutes les notifications",
|
|
||||||
"Unread only": "Non lues uniquement",
|
|
||||||
"Mark all as read": "Tout marquer comme lu",
|
|
||||||
"Mark as read": "Marquer comme lu",
|
|
||||||
"More options": "Plus d'options",
|
|
||||||
"mentioned you in a comment": "vous a mentionné dans un commentaire",
|
|
||||||
"commented on a page": "a commenté une page",
|
|
||||||
"resolved a comment": "a résolu un commentaire",
|
|
||||||
"mentioned you on a page": "vous a mentionné sur une page",
|
|
||||||
"gave you edit access to a page": "vous a donné l'accès pour modifier une page",
|
|
||||||
"gave you view access to a page": "vous a donné l'accès pour consulter une page",
|
|
||||||
"Today": "Aujourd'hui",
|
|
||||||
"Yesterday": "Hier",
|
|
||||||
"This week": "Cette semaine",
|
|
||||||
"Older": "Plus ancien",
|
|
||||||
"Restricted page": "Page restreinte",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Les pages restreintes ne peuvent pas être partagées publiquement.",
|
|
||||||
"Restricted by parent": "Restreint par la page parente",
|
|
||||||
"Restricted": "Restreint",
|
|
||||||
"Open": "Ouvert",
|
|
||||||
"Inherits restrictions from ancestor page": "Hérite des restrictions d'une page ancêtre",
|
|
||||||
"Only people listed below can access this page": "Seules les personnes listées ci-dessous peuvent accéder à cette page",
|
|
||||||
"Everyone in this space can access": "Tout le monde dans cet espace y a accès",
|
|
||||||
"No additional restrictions on this page": "Aucune restriction supplémentaire sur cette page",
|
|
||||||
"Only specific people can access": "Seules certaines personnes peuvent y accéder",
|
|
||||||
"Use only inherited restrictions": "Utiliser uniquement les restrictions héritées",
|
|
||||||
"Add restrictions on top of inherited": "Ajouter des restrictions en plus de celles héritées",
|
|
||||||
"Inherited restriction": "Restriction héritée",
|
|
||||||
"Access limited by": "Accès limité par",
|
|
||||||
"Restrict access to control who can view and edit this page": "Restreindre l'accès pour contrôler qui peut consulter et modifier cette page",
|
|
||||||
"Add additional restrictions specific to this page": "Ajouter des restrictions supplémentaires propres à cette page",
|
|
||||||
"Access": "Accès",
|
|
||||||
"People with access": "Personnes ayant accès",
|
|
||||||
"Remove all": "Tout retirer",
|
|
||||||
"Remove access": "Retirer l'accès",
|
|
||||||
"Remove all access": "Retirer tous les accès",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Êtes-vous sûr de vouloir retirer l'accès de ce membre à la page ?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Êtes-vous sûr de vouloir supprimer tous les accès spécifiques ? Cela rendra la page accessible à tous les membres de l'espace.",
|
|
||||||
"Trash retention": "Conservation de la corbeille",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Les pages dans la corbeille seront définitivement supprimées après cette période.",
|
|
||||||
"Trash retention updated": "Durée de conservation de la corbeille mise à jour",
|
|
||||||
"Failed to update trash retention": "Échec de la mise à jour de la durée de conservation de la corbeille",
|
|
||||||
"Removed page restriction": "Restriction de la page supprimée",
|
|
||||||
"Added page permission": "Autorisation de la page ajoutée",
|
|
||||||
"Removed page permission": "Autorisation de la page supprimée"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Scegli la lingua da utilizzare per l'interfaccia.",
|
"Choose your preferred interface language.": "Scegli la lingua da utilizzare per l'interfaccia.",
|
||||||
"Choose your preferred page width.": "Scegli la larghezza della pagina che preferisci.",
|
"Choose your preferred page width.": "Scegli la larghezza della pagina che preferisci.",
|
||||||
"Confirm": "Conferma",
|
"Confirm": "Conferma",
|
||||||
"Copy as Markdown": "Copia come Markdown",
|
|
||||||
"Copy link": "Copia link",
|
"Copy link": "Copia link",
|
||||||
"Create": "Crea",
|
"Create": "Crea",
|
||||||
"Create group": "Crea gruppo",
|
"Create group": "Crea gruppo",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "es. Spazio per il team di prodotto",
|
"e.g Space for product team": "es. Spazio per il team di prodotto",
|
||||||
"e.g Space for sales team to collaborate": "es. Spazio per la collaborazione del team di vendita",
|
"e.g Space for sales team to collaborate": "es. Spazio per la collaborazione del team di vendita",
|
||||||
"Edit": "Modifica",
|
"Edit": "Modifica",
|
||||||
"Read": "Leggi",
|
|
||||||
"Edit group": "Modifica gruppo",
|
"Edit group": "Modifica gruppo",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Enter a strong password": "Inserisci una password sicura",
|
"Enter a strong password": "Inserisci una password sicura",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "Nessun gruppo trovato",
|
"No group found": "Nessun gruppo trovato",
|
||||||
"No page history saved yet.": "La pagina non ha una cronologia per ora.",
|
"No page history saved yet.": "La pagina non ha una cronologia per ora.",
|
||||||
"No pages yet": "Nessuna pagina per ora",
|
"No pages yet": "Nessuna pagina per ora",
|
||||||
"No shared pages": "Nessuna pagina condivisa.",
|
|
||||||
"No results found...": "Nessun risultato trovato...",
|
"No results found...": "Nessun risultato trovato...",
|
||||||
"No user found": "Nessun utente trovato",
|
"No user found": "Nessun utente trovato",
|
||||||
"Overview": "Panoramica",
|
"Overview": "Panoramica",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "pagina",
|
"page": "pagina",
|
||||||
"Page deleted successfully": "Pagina eliminata con successo",
|
"Page deleted successfully": "Pagina eliminata con successo",
|
||||||
"Page history": "Cronologia della pagina",
|
"Page history": "Cronologia della pagina",
|
||||||
"Select version": "Seleziona versione",
|
|
||||||
"Highlight changes": "Evidenzia modifiche",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "L'importazione della pagina è in corso. Si prega di non chiudere questa scheda.",
|
"Page import is in progress. Please do not close this tab.": "L'importazione della pagina è in corso. Si prega di non chiudere questa scheda.",
|
||||||
"Pages": "Pagine",
|
"Pages": "Pagine",
|
||||||
"pages": "pagine",
|
"pages": "pagine",
|
||||||
"Password": "Password",
|
"Password": "Password",
|
||||||
"Password changed successfully": "Password cambiata con successo",
|
"Password changed successfully": "Password cambiata con successo",
|
||||||
"People": "Persone",
|
|
||||||
"Pending": "In sospeso",
|
"Pending": "In sospeso",
|
||||||
"Please confirm your action": "Si prega di confermare la propria azione",
|
"Please confirm your action": "Si prega di confermare la propria azione",
|
||||||
"Preferences": "Preferenze",
|
"Preferences": "Preferenze",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Rispondi...",
|
"Reply...": "Rispondi...",
|
||||||
"Error loading comments.": "Si è verificato un errore durante il caricamento dei commenti.",
|
"Error loading comments.": "Si è verificato un errore durante il caricamento dei commenti.",
|
||||||
"No comments yet.": "Nessun commento per ora.",
|
"No comments yet.": "Nessun commento per ora.",
|
||||||
"No open comments.": "Nessun commento aperto.",
|
|
||||||
"No resolved comments.": "Nessun commento risolto.",
|
|
||||||
"Add a comment...": "Aggiungi un commento...",
|
|
||||||
"Edit comment": "Modifica commento",
|
"Edit comment": "Modifica commento",
|
||||||
"Delete comment": "Elimina commento",
|
"Delete comment": "Elimina commento",
|
||||||
"Are you sure you want to delete this comment?": "Sei sicuro di voler eliminare questo commento?",
|
"Are you sure you want to delete this comment?": "Sei sicuro di voler eliminare questo commento?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Commento eliminato con successo",
|
"Comment deleted successfully": "Commento eliminato con successo",
|
||||||
"Failed to delete comment": "Impossibile eliminare il commento",
|
"Failed to delete comment": "Impossibile eliminare il commento",
|
||||||
"Comment resolved successfully": "Commento risolto con successo",
|
"Comment resolved successfully": "Commento risolto con successo",
|
||||||
"Comment re-opened successfully": "Commento riaperto con successo",
|
|
||||||
"Comment unresolved successfully": "Commento non risolto con successo",
|
|
||||||
"Failed to resolve comment": "Impossibile risolvere il commento",
|
"Failed to resolve comment": "Impossibile risolvere il commento",
|
||||||
"Resolve comment": "Risolvi commento",
|
|
||||||
"Unresolve comment": "Annulla risoluzione commento",
|
|
||||||
"Resolve Comment Thread": "Risolvi discussione commenti",
|
|
||||||
"Unresolve Comment Thread": "Annulla risoluzione discussione commenti",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Sei sicuro di voler risolvere questa discussione di commenti? Questo la contrassegnerà come completata.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Sei sicuro di voler annullare la risoluzione di questa discussione di commenti?",
|
|
||||||
"Resolved": "Risolto",
|
|
||||||
"No active comments.": "Nessun commento attivo.",
|
|
||||||
"Revoke invitation": "Revoca invito",
|
"Revoke invitation": "Revoca invito",
|
||||||
"Revoke": "Revoca",
|
"Revoke": "Revoca",
|
||||||
"Don't": "Non",
|
"Don't": "Non",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Chiunque con questo link può unirsi a questa area di lavoro.",
|
"Anyone with this link can join this workspace.": "Chiunque con questo link può unirsi a questa area di lavoro.",
|
||||||
"Invite link": "Link d'invito",
|
"Invite link": "Link d'invito",
|
||||||
"Copy": "Copia",
|
"Copy": "Copia",
|
||||||
"Copy to space": "Copia nello spazio",
|
|
||||||
"Copied": "Copiato",
|
"Copied": "Copiato",
|
||||||
"Duplicate": "Duplica",
|
|
||||||
"Select a user": "Seleziona un utente",
|
"Select a user": "Seleziona un utente",
|
||||||
"Select a group": "Seleziona un gruppo",
|
"Select a group": "Seleziona un gruppo",
|
||||||
"Export all pages and attachments in this space.": "Esporta tutte le pagine e gli allegati di questo spazio.",
|
"Export all pages and attachments in this space.": "Esporta tutte le pagine e gli allegati di questo spazio.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Esportazione fallita:",
|
"Export failed:": "Esportazione fallita:",
|
||||||
"export error": "errore di esportazione",
|
"export error": "errore di esportazione",
|
||||||
"Export page": "Esporta pagina",
|
"Export page": "Esporta pagina",
|
||||||
"Export successful": "Esportazione riuscita",
|
|
||||||
"Export space": "Esporta spazio",
|
"Export space": "Esporta spazio",
|
||||||
"Export {{type}}": "Esporta {{type}}",
|
"Export {{type}}": "Esporta {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "Il file supera il limite per gli allegati di {{limit}}",
|
"File exceeds the {{limit}} attachment limit": "Il file supera il limite per gli allegati di {{limit}}",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Aggiungi riga sotto",
|
"Add row below": "Aggiungi riga sotto",
|
||||||
"Delete table": "Elimina tabella",
|
"Delete table": "Elimina tabella",
|
||||||
"Info": "Informazioni",
|
"Info": "Informazioni",
|
||||||
"Note": "Nota",
|
|
||||||
"Success": "Successo",
|
"Success": "Successo",
|
||||||
"Warning": "Avviso",
|
"Warning": "Avviso",
|
||||||
"Danger": "Pericolo",
|
"Danger": "Pericolo",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Carica un'immagine dal tuo dispositivo.",
|
"Upload any image from your device.": "Carica un'immagine dal tuo dispositivo.",
|
||||||
"Upload any video from your device.": "Carica qualsiasi video dal tuo dispositivo.",
|
"Upload any video from your device.": "Carica qualsiasi video dal tuo dispositivo.",
|
||||||
"Upload any file from your device.": "Carica qualsiasi file dal tuo dispositivo.",
|
"Upload any file from your device.": "Carica qualsiasi file dal tuo dispositivo.",
|
||||||
"Uploading {{name}}": "Caricamento di {{name}}",
|
|
||||||
"Uploading file": "Caricamento file",
|
|
||||||
"Table": "Tabella",
|
"Table": "Tabella",
|
||||||
"Insert a table.": "Inserisci una tabella.",
|
"Insert a table.": "Inserisci una tabella.",
|
||||||
"Insert collapsible block.": "Inserisci blocco comprimibile.",
|
"Insert collapsible block.": "Inserisci blocco comprimibile.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Inserisci la data corrente",
|
"Insert current date": "Inserisci la data corrente",
|
||||||
"Draw and sketch excalidraw diagrams": "Disegna e schizza diagrammi excalidraw",
|
"Draw and sketch excalidraw diagrams": "Disegna e schizza diagrammi excalidraw",
|
||||||
"Multiple": "Multiplo",
|
"Multiple": "Multiplo",
|
||||||
"Turn into": "Trasforma in",
|
|
||||||
"Text align": "Allinea testo",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Questa pagina potrebbe essere stata eliminata o spostata, oppure potresti non avere accesso.",
|
|
||||||
"Go to homepage": "Vai alla pagina principale",
|
|
||||||
"Pages you create will show up here.": "Le pagine che crei appariranno qui.",
|
|
||||||
"Heading {{level}}": "Intestazione {{level}}",
|
"Heading {{level}}": "Intestazione {{level}}",
|
||||||
"Toggle title": "Attiva/disattiva titolo",
|
"Toggle title": "Attiva/disattiva titolo",
|
||||||
"Write anything. Enter \"/\" for commands": "Scrivi qualcosa. Digita \"/\" per i comandi",
|
"Write anything. Enter \"/\" for commands": "Scrivi qualcosa. Digita \"/\" per i comandi",
|
||||||
"Write...": "Scrivi...",
|
|
||||||
"Column count": "Numero di colonne",
|
|
||||||
"{{count}} Columns": "{{count}} colonne",
|
|
||||||
"Equal columns": "Colonne uguali",
|
|
||||||
"Left sidebar": "Barra laterale sinistra",
|
|
||||||
"Right sidebar": "Barra laterale destra",
|
|
||||||
"Wide center": "Centro ampio",
|
|
||||||
"Left wide": "Ampia a sinistra",
|
|
||||||
"Right wide": "Ampia a destra",
|
|
||||||
"Names do not match": "I nomi non corrispondono",
|
"Names do not match": "I nomi non corrispondono",
|
||||||
"Today, {{time}}": "Oggi, {{time}}",
|
"Today, {{time}}": "Oggi, {{time}}",
|
||||||
"Yesterday, {{time}}": "Ieri, {{time}}",
|
"Yesterday, {{time}}": "Ieri, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Conteggio caratteri: {{characterCount}}",
|
"Character count: {{characterCount}}": "Conteggio caratteri: {{characterCount}}",
|
||||||
"New update": "Nuovo aggiornamento",
|
"New update": "Nuovo aggiornamento",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} è disponibile",
|
"{{latestVersion}} is available": "{{latestVersion}} è disponibile",
|
||||||
"Default page edit mode": "Modalità di modifica pagina predefinita",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Scegli la tua modalità di modifica della pagina preferita. Evita modifiche accidentali.",
|
|
||||||
"Reading": "Lettura",
|
|
||||||
"Delete member": "Elimina membro",
|
"Delete member": "Elimina membro",
|
||||||
"Member deleted successfully": "Membro eliminato con successo",
|
"Member deleted successfully": "Membro eliminato con successo",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Sei sicuro di voler eliminare questo membro del workspace? Questa azione è irreversibile.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Sei sicuro di voler eliminare questo membro del workspace? Questa azione è irreversibile.",
|
||||||
"Deactivate member": "Disattiva membro",
|
|
||||||
"Activate member": "Attiva membro",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Sei sicuro di voler disattivare questo membro dello spazio di lavoro? Non potrà più accedere a questo spazio di lavoro.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Sei sicuro di voler attivare questo membro dello spazio di lavoro?",
|
|
||||||
"Deactivate": "Disattiva",
|
|
||||||
"Activate": "Attiva",
|
|
||||||
"Deactivated": "Disattivato",
|
|
||||||
"Move": "Sposta",
|
"Move": "Sposta",
|
||||||
"Move page": "Sposta pagina",
|
"Move page": "Sposta pagina",
|
||||||
"Move page to a different space.": "Sposta la pagina in un altro spazio.",
|
"Move page to a different space.": "Sposta la pagina in un altro spazio.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Le pagine condivise pubblicamente dagli spazi di cui sei membro appariranno qui",
|
"Publicly shared pages from spaces you are a member of will appear here": "Le pagine condivise pubblicamente dagli spazi di cui sei membro appariranno qui",
|
||||||
"Share deleted successfully": "Condivisione eliminata con successo",
|
"Share deleted successfully": "Condivisione eliminata con successo",
|
||||||
"Share not found": "Condivisione non trovata",
|
"Share not found": "Condivisione non trovata",
|
||||||
"Failed to share page": "Condivisione della pagina fallita",
|
"Failed to share page": "Condivisione della pagina fallita"
|
||||||
"Disable public sharing": "Disabilita la condivisione pubblica",
|
|
||||||
"Prevent members from sharing pages publicly.": "Impedisci ai membri di condividere pubblicamente le pagine.",
|
|
||||||
"Toggle public sharing": "Attiva/disattiva la condivisione pubblica",
|
|
||||||
"Toggle space public sharing": "Attiva/disattiva la condivisione pubblica nello spazio",
|
|
||||||
"Public sharing is disabled at the workspace level": "La condivisione pubblica è disabilitata a livello di area di lavoro",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Impedisci che le pagine in questo spazio vengano condivise pubblicamente.",
|
|
||||||
"Requires an enterprise license": "Richiede una licenza enterprise",
|
|
||||||
"Page permissions": "Autorizzazioni della pagina.",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Controlla chi può visualizzare e modificare le singole pagine. Disponibile con una licenza Enterprise.",
|
|
||||||
"Enable public sharing": "Abilita la condivisione pubblica",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Sei sicuro di voler abilitare la condivisione pubblica? I membri potranno condividere le pagine pubblicamente.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Sei sicuro di voler disabilitare la condivisione pubblica? Tutti i link condivisi esistenti in questa area di lavoro verranno eliminati.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Sei sicuro di voler abilitare la condivisione pubblica per questo spazio?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Sei sicuro di voler disabilitare la condivisione pubblica? Tutti i link condivisi esistenti in questo spazio verranno eliminati.",
|
|
||||||
"Public sharing is disabled": "La condivisione pubblica è disabilitata",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "La condivisione pubblica è stata disabilitata a livello di area di lavoro.",
|
|
||||||
"Public sharing has been disabled for this space.": "La condivisione pubblica è stata disabilitata per questo spazio.",
|
|
||||||
"Copy page": "Copia pagina",
|
|
||||||
"Copy page to a different space.": "Copia pagina in un altro spazio.",
|
|
||||||
"Page copied successfully": "Pagina copiata con successo",
|
|
||||||
"Page duplicated successfully": "Pagina duplicata con successo",
|
|
||||||
"Find": "Trova",
|
|
||||||
"Not found": "Non trovato",
|
|
||||||
"Previous Match (Shift+Enter)": "Corrispondenza precedente (Shift+Invio)",
|
|
||||||
"Next match (Enter)": "Corrispondenza successiva (Invio)",
|
|
||||||
"Match case (Alt+C)": "Maiuscole/minuscole (Alt+C)",
|
|
||||||
"Replace": "Sostituisci",
|
|
||||||
"Close (Escape)": "Chiudi (Esc)",
|
|
||||||
"Replace (Enter)": "Sostituisci (Invio)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Sostituisci tutto (Ctrl+Alt+Invio)",
|
|
||||||
"Replace all": "Sostituisci tutto",
|
|
||||||
"View all spaces": "Visualizza tutti gli spazi",
|
|
||||||
"Error": "Errore",
|
|
||||||
"Failed to disable MFA": "Disabilitazione MFA non riuscita",
|
|
||||||
"Disable two-factor authentication": "Disabilita autenticazione a due fattori",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Disabilitare l'autenticazione a due fattori renderà il tuo account meno sicuro. Avrai bisogno solo della tua password per accedere.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Inserisci la tua password per disabilitare l'autenticazione a due fattori:",
|
|
||||||
"Two-factor authentication has been enabled": "Autenticazione a due fattori abilitata",
|
|
||||||
"Two-factor authentication has been disabled": "Autenticazione a due fattori disabilitata",
|
|
||||||
"2-step verification": "Verifica in 2 passaggi",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Proteggi il tuo account con un ulteriore livello di verifica durante l'accesso.",
|
|
||||||
"Two-factor authentication is active on your account.": "L'autenticazione a due fattori è attiva sul tuo account.",
|
|
||||||
"Add 2FA method": "Aggiungi metodo 2FA",
|
|
||||||
"Backup codes": "Codici di backup",
|
|
||||||
"Disable": "Disabilita",
|
|
||||||
"Invalid verification code": "Codice di verifica non valido",
|
|
||||||
"New backup codes have been generated": "Nuovi codici di backup generati",
|
|
||||||
"Failed to regenerate backup codes": "Rigenerazione codici di backup non riuscita",
|
|
||||||
"About backup codes": "Informazioni sui codici di backup",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "I codici di backup possono essere utilizzati per accedere al tuo account se perdi l'accesso alla tua app di autenticazione. Ogni codice può essere usato solo una volta.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Puoi rigenerare nuovi codici di backup in qualsiasi momento. Questo invaliderà tutti i codici esistenti.",
|
|
||||||
"Confirm password": "Conferma password",
|
|
||||||
"Generate new backup codes": "Genera nuovi codici di backup",
|
|
||||||
"Save your new backup codes": "Salva i tuoi nuovi codici di backup",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Assicurati di salvare questi codici in un luogo sicuro. I tuoi vecchi codici di backup non sono più validi.",
|
|
||||||
"Your new backup codes": "I tuoi nuovi codici di backup",
|
|
||||||
"I've saved my backup codes": "Ho salvato i miei codici di backup",
|
|
||||||
"Failed to setup MFA": "Impostazione MFA non riuscita",
|
|
||||||
"Setup & Verify": "Imposta e Verifica",
|
|
||||||
"Add to authenticator": "Aggiungi ad authenticator",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Scansiona questo codice QR con la tua app di autenticazione",
|
|
||||||
"Can't scan the code?": "Non riesci a scansionare il codice?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Inserisci questo codice manualmente nella tua app di autenticazione:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Inserisci il codice a 6 cifre dal tuo autenticatore",
|
|
||||||
"Verify and enable": "Verifica e abilita",
|
|
||||||
"Failed to generate QR code. Please try again.": "Generazione del codice QR non riuscita. Si prega di riprovare.",
|
|
||||||
"Backup": "Backup",
|
|
||||||
"Save codes": "Salva codici",
|
|
||||||
"Save your backup codes": "Salva i tuoi codici di backup",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Questi codici possono essere utilizzati per accedere al tuo account se perdi l'accesso alla tua app di autenticazione. Ogni codice può essere usato solo una volta.",
|
|
||||||
"Print": "Stampa",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "L'autenticazione a due fattori è stata impostata. Effettua nuovamente l'accesso, per favore.",
|
|
||||||
"Two-Factor authentication required": "Autenticazione a due fattori richiesta",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Il tuo spazio di lavoro richiede l'autenticazione a due fattori per tutti gli utenti",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Per continuare ad accedere al tuo spazio di lavoro, devi impostare l'autenticazione a due fattori. Questo aggiunge un ulteriore livello di sicurezza al tuo account.",
|
|
||||||
"Set up two-factor authentication": "Imposta l'autenticazione a due fattori",
|
|
||||||
"Cancel and logout": "Annulla e disconnetti",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Il tuo spazio di lavoro richiede l'autenticazione a due fattori. Impostala per continuare.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Questo aggiunge un ulteriore livello di sicurezza al tuo account richiedendo un codice di verifica dalla tua app di autenticazione.",
|
|
||||||
"Password is required": "La password è richiesta",
|
|
||||||
"Password must be at least 8 characters": "La password deve essere di almeno 8 caratteri",
|
|
||||||
"Please enter a 6-digit code": "Inserisci un codice a 6 cifre",
|
|
||||||
"Code must be exactly 6 digits": "Il codice deve essere esattamente di 6 cifre",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Inserisci il codice a 6 cifre trovato nella tua app di autenticazione",
|
|
||||||
"Need help authenticating?": "Hai bisogno di aiuto per autenticarti?",
|
|
||||||
"MFA QR Code": "Codice QR MFA",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Account creato con successo. Effettua l'accesso per impostare l'autenticazione a due fattori.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Reimpostazione della password riuscita. Accedi con la tua nuova password e completa l'autenticazione a due fattori.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Reimpostazione della password riuscita. Accedi con la tua nuova password per impostare l'autenticazione a due fattori.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "Reimpostazione della password riuscita. Accedi con la tua nuova password.",
|
|
||||||
"Two-factor authentication": "Autenticazione a due fattori",
|
|
||||||
"Use authenticator app instead": "Usa l'app di autenticazione invece",
|
|
||||||
"Verify backup code": "Verifica codice di backup",
|
|
||||||
"Use backup code": "Usa codice di backup",
|
|
||||||
"Enter one of your backup codes": "Inserisci uno dei tuoi codici di backup",
|
|
||||||
"Backup code": "Codice di backup",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Inserisci uno dei tuoi codici di backup. Ogni codice di backup può essere utilizzato solo una volta.",
|
|
||||||
"Verify": "Verifica",
|
|
||||||
"Trash": "Cestino",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "Le pagine nel cestino verranno eliminate definitivamente dopo {{count}} giorni.",
|
|
||||||
"Deleted": "Eliminato",
|
|
||||||
"No pages in trash": "Nessuna pagina nel cestino",
|
|
||||||
"Permanently delete page?": "Eliminare definitivamente la pagina?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Sei sicuro di voler eliminare definitivamente '{{title}}'? Questa azione non può essere annullata.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "Ripristinare '{{title}}' e le sue sottopagine?",
|
|
||||||
"Move to trash": "Sposta nel cestino",
|
|
||||||
"Move this page to trash?": "Spostare questa pagina nel cestino?",
|
|
||||||
"Restore page": "Ripristina pagina",
|
|
||||||
"Page moved to trash": "Pagina spostata nel cestino",
|
|
||||||
"Page restored successfully": "Pagina ripristinata con successo",
|
|
||||||
"Deleted by": "Eliminato da",
|
|
||||||
"Deleted at": "Eliminato il",
|
|
||||||
"Preview": "Anteprima",
|
|
||||||
"Subpages": "Sottopagine",
|
|
||||||
"Failed to load subpages": "Caricamento delle sottopagine non riuscito",
|
|
||||||
"No subpages": "Nessuna sottopagina",
|
|
||||||
"Subpages (Child pages)": "Sottopagine (Pagine figlie)",
|
|
||||||
"List all subpages of the current page": "Elenca tutte le sottopagine della pagina corrente",
|
|
||||||
"Attachments": "Allegati",
|
|
||||||
"All spaces": "Tutti gli spazi",
|
|
||||||
"Unknown": "Sconosciuto",
|
|
||||||
"Find a space": "Trova uno spazio",
|
|
||||||
"Search in all your spaces": "Cerca in tutti i tuoi spazi",
|
|
||||||
"Type": "Tipo",
|
|
||||||
"Enterprise": "Impresa",
|
|
||||||
"Download attachment": "Scarica allegato",
|
|
||||||
"Allowed email domains": "Domini email consentiti",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Solo gli utenti con indirizzi email provenienti da questi domini possono registrarsi tramite SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Inserisci nomi di dominio validi separati da virgole o spazi",
|
|
||||||
"Enforce two-factor authentication": "Imponi l'autenticazione a due fattori",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Una volta impostata, tutti i membri devono abilitare l'autenticazione a due fattori per accedere all'area di lavoro.",
|
|
||||||
"Toggle MFA enforcement": "Attiva disattiva l'applicazione MFA",
|
|
||||||
"Display name": "Nome visualizzato",
|
|
||||||
"Allow signup": "Consenti iscrizione",
|
|
||||||
"Enabled": "Abilitato",
|
|
||||||
"Advanced Settings": "Impostazioni avanzate",
|
|
||||||
"Enable TLS/SSL": "Abilita TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Usa connessione sicura al server LDAP",
|
|
||||||
"Group sync": "Sincronizzazione gruppi",
|
|
||||||
"No SSO providers found.": "Nessun provider SSO trovato.",
|
|
||||||
"Delete SSO provider": "Elimina provider SSO",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Sei sicuro di voler eliminare questo provider SSO?",
|
|
||||||
"Action": "Azione",
|
|
||||||
"{{ssoProviderType}} configuration": "Configurazione {{ssoProviderType}}",
|
|
||||||
"Icon": "Icona",
|
|
||||||
"Upload image": "Carica immagine",
|
|
||||||
"Remove image": "Rimuovi immagine",
|
|
||||||
"Failed to remove image": "Rimozione immagine fallita",
|
|
||||||
"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",
|
|
||||||
"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.",
|
|
||||||
"Toggle restrict API keys to admins": "Attiva/disattiva la limitazione delle chiavi API agli amministratori",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "La creazione delle chiavi API è limitata agli amministratori dal tuo amministratore dello spazio di lavoro.",
|
|
||||||
"AI settings": "Impostazioni AI",
|
|
||||||
"AI search": "Ricerca AI",
|
|
||||||
"AI Answer": "Risposta AI",
|
|
||||||
"Ask AI": "Chiedi all'AI",
|
|
||||||
"AI is thinking...": "L'AI sta pensando...",
|
|
||||||
"Ask a question...": "Fai una domanda...",
|
|
||||||
"AI Answers": "Risposte AI",
|
|
||||||
"AI-powered search (AI Answers)": "Ricerca con AI (Risposte AI)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "La ricerca AI utilizza embeddings vettoriali per fornire capacità di ricerca semantica nel contenuto della tua area di lavoro.",
|
|
||||||
"Toggle AI search": "Attiva/disattiva ricerca AI",
|
|
||||||
"Generative AI (Ask AI)": "AI generativa (Chiedi AI)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Abilita la generazione di contenuti con AI nell'editor. Consente agli utenti di generare, migliorare, tradurre e trasformare il testo.",
|
|
||||||
"Toggle generative AI": "Attiva/Disattiva AI generativa",
|
|
||||||
"Enterprise feature": "Funzionalità Enterprise",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "L'IA è disponibile solo nell'edizione Enterprise di Docmost. Contatta sales@docmost.com.",
|
|
||||||
"AI & MCP": "IA e MCP",
|
|
||||||
"AI": "IA",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Model Context Protocol (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Abilita il server MCP per consentire ad assistenti e strumenti IA di interagire con i contenuti del tuo spazio di lavoro.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP è disponibile solo nell'edizione Enterprise di Docmost. Contatta sales@docmost.com.",
|
|
||||||
"MCP documentation": "Documentazione MCP",
|
|
||||||
"MCP Server URL": "URL del server MCP",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Usa la tua chiave API per l'autenticazione. Puoi gestire le chiavi API nelle impostazioni del tuo account.",
|
|
||||||
"Supported tools": "Strumenti supportati",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "Il tuo spazio di lavoro ha MCP abilitato. Usa la tua chiave API per collegare gli assistenti IA.",
|
|
||||||
"MCP server URL:": "URL del server MCP:",
|
|
||||||
"Learn more": "Scopri di più",
|
|
||||||
"View the": "Visualizza la",
|
|
||||||
"for usage details.": "per i dettagli sull'utilizzo.",
|
|
||||||
"for setup instructions.": "per le istruzioni di configurazione.",
|
|
||||||
"API documentation": "Documentazione API",
|
|
||||||
"Sources": "Fonti",
|
|
||||||
"AI Answers not available for attachments": "Risposte AI non disponibili per gli allegati",
|
|
||||||
"No answer available": "Nessuna risposta disponibile",
|
|
||||||
"Background color": "Colore di sfondo",
|
|
||||||
"Highlight color": "Colore evidenziato",
|
|
||||||
"Remove color": "Rimuovi colore",
|
|
||||||
"Notifications": "Notifiche",
|
|
||||||
"No notifications": "Nessuna notifica",
|
|
||||||
"No unread notifications": "Nessuna notifica non letta",
|
|
||||||
"All notifications": "Tutte le notifiche",
|
|
||||||
"Unread only": "Solo non lette",
|
|
||||||
"Mark all as read": "Segna tutto come letto",
|
|
||||||
"Mark as read": "Segna come letto",
|
|
||||||
"More options": "Altre opzioni",
|
|
||||||
"mentioned you in a comment": "ti ha menzionato in un commento",
|
|
||||||
"commented on a page": "ha commentato una pagina",
|
|
||||||
"resolved a comment": "ha risolto un commento",
|
|
||||||
"mentioned you on a page": "ti ha menzionato in una pagina",
|
|
||||||
"gave you edit access to a page": "ti ha concesso l'accesso per modificare una pagina",
|
|
||||||
"gave you view access to a page": "ti ha concesso l'accesso per visualizzare una pagina",
|
|
||||||
"Today": "Oggi",
|
|
||||||
"Yesterday": "Ieri",
|
|
||||||
"This week": "Questa settimana",
|
|
||||||
"Older": "Più vecchie",
|
|
||||||
"Restricted page": "Pagina con accesso ristretto",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Le pagine con accesso ristretto non possono essere condivise pubblicamente.",
|
|
||||||
"Restricted by parent": "Limitata dalla pagina genitore",
|
|
||||||
"Restricted": "Limitata",
|
|
||||||
"Open": "Aperta",
|
|
||||||
"Inherits restrictions from ancestor page": "Eredita le restrizioni dalla pagina genitore",
|
|
||||||
"Only people listed below can access this page": "Solo le persone elencate di seguito possono accedere a questa pagina",
|
|
||||||
"Everyone in this space can access": "Chiunque in questo spazio può accedere",
|
|
||||||
"No additional restrictions on this page": "Nessuna restrizione aggiuntiva su questa pagina",
|
|
||||||
"Only specific people can access": "Solo persone specifiche possono accedere",
|
|
||||||
"Use only inherited restrictions": "Usa solo le restrizioni ereditate",
|
|
||||||
"Add restrictions on top of inherited": "Aggiungi restrizioni oltre a quelle ereditate",
|
|
||||||
"Inherited restriction": "Restrizione ereditata",
|
|
||||||
"Access limited by": "Accesso limitato da",
|
|
||||||
"Restrict access to control who can view and edit this page": "Limita l'accesso per controllare chi può visualizzare e modificare questa pagina",
|
|
||||||
"Add additional restrictions specific to this page": "Aggiungi restrizioni aggiuntive specifiche per questa pagina",
|
|
||||||
"Access": "Accesso",
|
|
||||||
"People with access": "Persone con accesso",
|
|
||||||
"Remove all": "Rimuovi tutto",
|
|
||||||
"Remove access": "Rimuovi accesso",
|
|
||||||
"Remove all access": "Rimuovi tutti gli accessi",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Sei sicuro di voler rimuovere l'accesso di questo membro alla pagina?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Sei sicuro di voler rimuovere tutti gli accessi specifici? Questo renderà la pagina accessibile a tutti nello spazio.",
|
|
||||||
"Trash retention": "Conservazione del cestino",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Le pagine nel cestino verranno eliminate definitivamente dopo questo periodo.",
|
|
||||||
"Trash retention updated": "Conservazione del cestino aggiornata",
|
|
||||||
"Failed to update trash retention": "Impossibile aggiornare la conservazione del cestino",
|
|
||||||
"Removed page restriction": "Restrizione della pagina rimossa",
|
|
||||||
"Added page permission": "Permesso sulla pagina aggiunto",
|
|
||||||
"Removed page permission": "Permesso sulla pagina rimosso"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,23 +13,22 @@
|
|||||||
"Are you sure you want to remove this user from the group? The user will lose access to resources this group has access to.": "このユーザをグループから削除してもよろしいですか? ユーザはこのグループがアクセス権を持つリソースにアクセスできなくなります。",
|
"Are you sure you want to remove this user from the group? The user will lose access to resources this group has access to.": "このユーザをグループから削除してもよろしいですか? ユーザはこのグループがアクセス権を持つリソースにアクセスできなくなります。",
|
||||||
"Are you sure you want to remove this user from the space? The user will lose all access to this space.": "このユーザをスペースから削除してもよろしいですか? ユーザはこのスペースへのアクセス権をすべて失います。",
|
"Are you sure you want to remove this user from the space? The user will lose all access to this space.": "このユーザをスペースから削除してもよろしいですか? ユーザはこのスペースへのアクセス権をすべて失います。",
|
||||||
"Are you sure you want to restore this version? Any changes not versioned will be lost.": "このバージョンを復元してもよろしいですか? バージョン管理されていない変更は失われます。",
|
"Are you sure you want to restore this version? Any changes not versioned will be lost.": "このバージョンを復元してもよろしいですか? バージョン管理されていない変更は失われます。",
|
||||||
"Can become members of groups and spaces in workspace": "ワークスペース内のグループやスペースのメンバーになれます",
|
"Can become members of groups and spaces in workspace": "ワークスペース内のグループやスペースのメンバーになることができます",
|
||||||
"Can create and edit pages in space.": "スペース内のページを作成・編集できます",
|
"Can create and edit pages in space.": "スペース内のページを作成および編集できます。",
|
||||||
"Can edit": "編集可能",
|
"Can edit": "編集可能",
|
||||||
"Can manage workspace": "ワークスペースを管理できます",
|
"Can manage workspace": "ワークスペースを管理できます",
|
||||||
"Can manage workspace but cannot delete it": "ワークスペースを管理できますが削除はできません",
|
"Can manage workspace but cannot delete it": "ワークスペースを管理できますが、削除はできません",
|
||||||
"Can view": "閲覧可能",
|
"Can view": "閲覧可能",
|
||||||
"Can view pages in space but not edit.": "スペース内のページを閲覧できますが編集はできません",
|
"Can view pages in space but not edit.": "スペース内のページを閲覧できますが、編集はできません。",
|
||||||
"Cancel": "キャンセル",
|
"Cancel": "キャンセル",
|
||||||
"Change email": "メールアドレスの変更",
|
"Change email": "メールアドレスの変更",
|
||||||
"Change password": "パスワードの変更",
|
"Change password": "パスワードの変更",
|
||||||
"Change photo": "画像の変更",
|
"Change photo": "画像の変更",
|
||||||
"Choose a role": "ロールを選んでください",
|
"Choose a role": "ロールを選んでください",
|
||||||
"Choose your preferred color scheme.": "お好みのカラースキームを選択してください",
|
"Choose your preferred color scheme.": "お好みのカラースキームを選択してください。",
|
||||||
"Choose your preferred interface language.": "お好みの言語を選択してください",
|
"Choose your preferred interface language.": "お好みのインターフェース言語を選択してください。",
|
||||||
"Choose your preferred page width.": "お好みのページ幅を選択してください",
|
"Choose your preferred page width.": "左右の余白を縮小する場合はオンにしてください。",
|
||||||
"Confirm": "確認",
|
"Confirm": "確認",
|
||||||
"Copy as Markdown": "Markdownとしてコピー",
|
|
||||||
"Copy link": "リンクをコピー",
|
"Copy link": "リンクをコピー",
|
||||||
"Create": "新規作成",
|
"Create": "新規作成",
|
||||||
"Create group": "グループを作成",
|
"Create group": "グループを作成",
|
||||||
@@ -41,24 +40,23 @@
|
|||||||
"Date": "日付",
|
"Date": "日付",
|
||||||
"Delete": "削除",
|
"Delete": "削除",
|
||||||
"Delete group": "グループを削除",
|
"Delete group": "グループを削除",
|
||||||
"Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "このページを削除してもよろしいですか?子ページとページ履歴も削除されます。この操作は取り消せません。",
|
"Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "このページを削除してもよろしいですか?この操作により、子ページおよびページ履歴が削除されます。この操作は元に戻せません。",
|
||||||
"Description": "説明",
|
"Description": "説明",
|
||||||
"Details": "詳細",
|
"Details": "詳細",
|
||||||
"e.g ACME": "例: 山田太郎",
|
"e.g ACME": "例: 山田太郎",
|
||||||
"e.g ACME Inc": "例: 株式会社サンプル",
|
"e.g ACME Inc": "例: 株式会社サンプル",
|
||||||
"e.g Developers": "例: エンジニア",
|
"e.g Developers": "例: エンジニア",
|
||||||
"e.g Group for developers": "例: 開発チーム",
|
"e.g Group for developers": "例: エンジニアグループ",
|
||||||
"e.g product": "例: product",
|
"e.g product": "例: product",
|
||||||
"e.g Product Team": "例: プロダクトチーム",
|
"e.g Product Team": "例: 製品チーム",
|
||||||
"e.g Sales": "例: 営業部",
|
"e.g Sales": "例: 営業",
|
||||||
"e.g Space for product team": "例: プロダクトチーム用スペース",
|
"e.g Space for product team": "例: 製品チームのスペース",
|
||||||
"e.g Space for sales team to collaborate": "例: 営業チーム用スペース",
|
"e.g Space for sales team to collaborate": "例: 営業チーム連携用スペース",
|
||||||
"Edit": "編集",
|
"Edit": "編集",
|
||||||
"Read": "閲覧",
|
|
||||||
"Edit group": "グループを編集",
|
"Edit group": "グループを編集",
|
||||||
"Email": "メールアドレス",
|
"Email": "メールアドレス",
|
||||||
"Enter a strong password": "強力なパスワードを入力してください",
|
"Enter a strong password": "強力なパスワードを入力してください",
|
||||||
"Enter valid email addresses separated by comma or space max_50": "メールアドレスをカンマまたはスペース区切りで入力(最大50件)",
|
"Enter valid email addresses separated by comma or space max_50": "有効なメールアドレスをカンマまたはスペースで区切って入力してください(最大 50 個)",
|
||||||
"enter valid emails addresses": "有効なメールアドレスを入力してください",
|
"enter valid emails addresses": "有効なメールアドレスを入力してください",
|
||||||
"Enter your current password": "現在のパスワードを入力してください",
|
"Enter your current password": "現在のパスワードを入力してください",
|
||||||
"enter your full name": "氏名を入力してください",
|
"enter your full name": "氏名を入力してください",
|
||||||
@@ -82,18 +80,18 @@
|
|||||||
"Group description": "グループ説明",
|
"Group description": "グループ説明",
|
||||||
"Group name": "グループ名",
|
"Group name": "グループ名",
|
||||||
"Groups": "グループ",
|
"Groups": "グループ",
|
||||||
"Has full access to space settings and pages.": "スペース設定とページにフルアクセスできます",
|
"Has full access to space settings and pages.": "スペース設定とページにフルアクセスできます。",
|
||||||
"Home": "ホーム",
|
"Home": "ホーム",
|
||||||
"Import pages": "ページをインポート",
|
"Import pages": "ページをインポート",
|
||||||
"Import pages & space settings": "ページとスペース設定をインポート",
|
"Import pages & space settings": "ページとスペース設定をインポート",
|
||||||
"Importing pages": "ページをインポートしています",
|
"Importing pages": "ページをインポートしています",
|
||||||
"invalid invitation link": "無効な招待リンクです",
|
"invalid invitation link": "招待リンクが間違っています",
|
||||||
"Invitation signup": "招待登録",
|
"Invitation signup": "招待登録",
|
||||||
"Invite by email": "メールアドレスで招待する",
|
"Invite by email": "メールアドレスで招待する",
|
||||||
"Invite members": "メンバーを招待する",
|
"Invite members": "メンバーを招待する",
|
||||||
"Invite new members": "新しいメンバーを招待する",
|
"Invite new members": "新しいメンバーを招待する",
|
||||||
"Invited members who are yet to accept their invitation will appear here.": "招待を承諾していないメンバーがここに表示されます",
|
"Invited members who are yet to accept their invitation will appear here.": "招待をまだ承諾していないメンバーはここに表示されます。",
|
||||||
"Invited members will be granted access to spaces the groups can access": "招待されたメンバーはグループがアクセスできるスペースにアクセスできます",
|
"Invited members will be granted access to spaces the groups can access": "招待されたメンバーは、グループがアクセスできるスペースにアクセス権が付与されます",
|
||||||
"Join the workspace": "ワークスペースに参加",
|
"Join the workspace": "ワークスペースに参加",
|
||||||
"Language": "言語",
|
"Language": "言語",
|
||||||
"Light": "ライト",
|
"Light": "ライト",
|
||||||
@@ -114,24 +112,20 @@
|
|||||||
"New page": "新規ページ",
|
"New page": "新規ページ",
|
||||||
"New password": "新しいパスワード",
|
"New password": "新しいパスワード",
|
||||||
"No group found": "グループが見つかりません",
|
"No group found": "グループが見つかりません",
|
||||||
"No page history saved yet.": "ページ履歴がありません",
|
"No page history saved yet.": "まだページの履歴が保存されていません。",
|
||||||
"No pages yet": "ページがありません",
|
"No pages yet": "ページがありません",
|
||||||
"No shared pages": "共有ページはありません。",
|
"No results found...": "結果が見つかりませんでした...",
|
||||||
"No results found...": "結果が見つかりません",
|
"No user found": "ユーザがいません",
|
||||||
"No user found": "ユーザーが見つかりません",
|
|
||||||
"Overview": "概要",
|
"Overview": "概要",
|
||||||
"Owner": "所有者",
|
"Owner": "所有者",
|
||||||
"page": "ページ",
|
"page": "ページ",
|
||||||
"Page deleted successfully": "ページを削除しました",
|
"Page deleted successfully": "ページが正常に削除されました",
|
||||||
"Page history": "ページ履歴",
|
"Page history": "ページの履歴",
|
||||||
"Select version": "バージョンを選択",
|
"Page import is in progress. Please do not close this tab.": "ページのインポートが進行中です。このタブを閉じないでください。",
|
||||||
"Highlight changes": "変更を強調表示",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "ページをインポート中です。このタブを閉じないでください",
|
|
||||||
"Pages": "ページ",
|
"Pages": "ページ",
|
||||||
"pages": "ページ",
|
"pages": "ページ",
|
||||||
"Password": "パスワード",
|
"Password": "パスワード",
|
||||||
"Password changed successfully": "パスワードを変更しました",
|
"Password changed successfully": "パスワードが正常に変更されました",
|
||||||
"People": "メンバー",
|
|
||||||
"Pending": "保留中",
|
"Pending": "保留中",
|
||||||
"Please confirm your action": "アクションを確認してください",
|
"Please confirm your action": "アクションを確認してください",
|
||||||
"Preferences": "設定",
|
"Preferences": "設定",
|
||||||
@@ -148,111 +142,96 @@
|
|||||||
"Search for groups": "グループを検索",
|
"Search for groups": "グループを検索",
|
||||||
"Search for users": "ユーザーを検索",
|
"Search for users": "ユーザーを検索",
|
||||||
"Search for users and groups": "ユーザーとグループを検索",
|
"Search for users and groups": "ユーザーとグループを検索",
|
||||||
"Search...": "検索",
|
"Search...": "検索する語句を入力",
|
||||||
"Select language": "言語を選択",
|
"Select language": "言語を選択",
|
||||||
"Select role": "ロールを選択",
|
"Select role": "ロールを選択",
|
||||||
"Select role to assign to all invited members": "招待するメンバーに割り当てるロールを選択",
|
"Select role to assign to all invited members": "招待されたすべてのメンバーに割り当てるロールを選択してください",
|
||||||
"Select theme": "テーマを選択",
|
"Select theme": "テーマを選択",
|
||||||
"Send invitation": "招待を送る",
|
"Send invitation": "招待を送る",
|
||||||
"Invitation sent": "招待を送信しました",
|
"Invitation sent": "招待が送信されました",
|
||||||
"Settings": "設定",
|
"Settings": "設定",
|
||||||
"Setup workspace": "ワークスペースを設定する",
|
"Setup workspace": "ワークスペースを設定する",
|
||||||
"Sign In": "サインイン",
|
"Sign In": "サインイン",
|
||||||
"Sign Up": "新規登録",
|
"Sign Up": "アカウント登録",
|
||||||
"Slug": "スラッグ(URL識別子)",
|
"Slug": "Slug (URL用文字列)",
|
||||||
"Space": "スペース",
|
"Space": "スペース",
|
||||||
"Space description": "スペース説明",
|
"Space description": "スペース説明",
|
||||||
"Space menu": "スペースメニュー",
|
"Space menu": "スペースメニュー",
|
||||||
"Space name": "スペース名",
|
"Space name": "スペース名",
|
||||||
"Space settings": "スペース設定",
|
"Space settings": "スペース設定",
|
||||||
"Space slug": "スペースのスラッグ(URL識別子)",
|
"Space slug": "スペースのSlug (URL用文字列)",
|
||||||
"Spaces": "スペース",
|
"Spaces": "スペース",
|
||||||
"Spaces you belong to": "所属しているスペース",
|
"Spaces you belong to": "所属しているスペース",
|
||||||
"No space found": "スペースが見つかりません",
|
"No space found": "スペースが見つかりません",
|
||||||
"Search for spaces": "スペースを検索",
|
"Search for spaces": "スペースを検索",
|
||||||
"Start typing to search...": "入力して検索",
|
"Start typing to search...": "検索を開始するには入力してください...",
|
||||||
"Status": "ステータス",
|
"Status": "ステータス",
|
||||||
"Successfully imported": "インポートしました",
|
"Successfully imported": "インポートに成功しました",
|
||||||
"Successfully restored": "復元しました",
|
"Successfully restored": "正常に復元されました",
|
||||||
"System settings": "システム設定",
|
"System settings": "システム設定",
|
||||||
"Theme": "テーマ",
|
"Theme": "テーマ",
|
||||||
"To change your email, you have to enter your password and new email.": "メールアドレスを変更するには、パスワードと新しいメールアドレスを入力してください",
|
"To change your email, you have to enter your password and new email.": "メールアドレスを変更するには、パスワードと新しいメールアドレスを入力する必要があります。",
|
||||||
"Toggle full page width": "ページ幅を切り替え",
|
"Toggle full page width": "ページ幅を切り替える",
|
||||||
"Unable to import pages. Please try again.": "ページをインポートできませんでした。もう一度お試しください",
|
"Unable to import pages. Please try again.": "ページをインポートできません。もう一度お試しください。",
|
||||||
"untitled": "無題",
|
"untitled": "無題",
|
||||||
"Untitled": "無題",
|
"Untitled": "無題",
|
||||||
"Updated successfully": "更新しました",
|
"Updated successfully": "正常に更新されました",
|
||||||
"User": "ユーザー",
|
"User": "ユーザー",
|
||||||
"Workspace": "ワークスペース",
|
"Workspace": "ワークスペース",
|
||||||
"Workspace Name": "ワークスペース名",
|
"Workspace Name": "ワークスペース名",
|
||||||
"Workspace settings": "ワークスペース設定",
|
"Workspace settings": "ワークスペース設定",
|
||||||
"You can change your password here.": "パスワードを変更できます",
|
"You can change your password here.": "パスワードを変更できます。",
|
||||||
"Your Email": "メールアドレス",
|
"Your Email": "メールアドレス",
|
||||||
"Your import is complete.": "インポートが完了しました",
|
"Your import is complete.": "インポートが完了しました。",
|
||||||
"Your name": "名前",
|
"Your name": "名前",
|
||||||
"Your Name": "名前",
|
"Your Name": "名前",
|
||||||
"Your password": "パスワード",
|
"Your password": "パスワード",
|
||||||
"Your password must be a minimum of 8 characters.": "パスワードは8文字以上にしてください",
|
"Your password must be a minimum of 8 characters.": "パスワードは最低 8 文字必要です。",
|
||||||
"Sidebar toggle": "サイドバー切り替え",
|
"Sidebar toggle": "サイドバー切り替え",
|
||||||
"Comments": "コメント",
|
"Comments": "コメント",
|
||||||
"404 page not found": "404 ページが見つかりません",
|
"404 page not found": "404 ページが見つかりません",
|
||||||
"Sorry, we can't find the page you are looking for.": "お探しのページが見つかりません",
|
"Sorry, we can't find the page you are looking for.": "お探しのページが見つかりません。",
|
||||||
"Take me back to homepage": "ホームに戻る",
|
"Take me back to homepage": "ホームに戻る",
|
||||||
"Forgot password": "パスワードを忘れた",
|
"Forgot password": "パスワードを忘れた",
|
||||||
"Forgot your password?": "パスワードを忘れましたか?",
|
"Forgot your password?": "パスワードを忘れましたか?",
|
||||||
"A password reset link has been sent to your email. Please check your inbox.": "パスワードリセット用のリンクをメールに送信しました。受信トレイを確認してください",
|
"A password reset link has been sent to your email. Please check your inbox.": "パスワードリセットリンクがあなたのメールアドレスに送信されました。受信箱を確認してください。",
|
||||||
"Send reset link": "リセットリンクを送信",
|
"Send reset link": "リセットリンクを送る",
|
||||||
"Password reset": "パスワードリセット",
|
"Password reset": "パスワードリセット",
|
||||||
"Your new password": "新しいパスワード",
|
"Your new password": "新しいパスワード",
|
||||||
"Set password": "パスワードを設定",
|
"Set password": "パスワードを設定",
|
||||||
"Write a comment": "コメントを書く",
|
"Write a comment": "コメントを書く",
|
||||||
"Reply...": "返信...",
|
"Reply...": "返信...",
|
||||||
"Error loading comments.": "コメントの読み込みに失敗しました",
|
"Error loading comments.": "コメントの読み込み中にエラーが発生しました。",
|
||||||
"No comments yet.": "コメントがありません",
|
"No comments yet.": "コメントがありません。",
|
||||||
"No open comments.": "未解決のコメントはありません。",
|
|
||||||
"No resolved comments.": "解決済みのコメントはありません",
|
|
||||||
"Add a comment...": "コメントを追加...",
|
|
||||||
"Edit comment": "コメントを編集する",
|
"Edit comment": "コメントを編集する",
|
||||||
"Delete comment": "コメントを削除する",
|
"Delete comment": "コメントを削除する",
|
||||||
"Are you sure you want to delete this comment?": "このコメントを削除してもよろしいですか?",
|
"Are you sure you want to delete this comment?": "このコメントを削除してもよろしいですか?",
|
||||||
"Comment created successfully": "コメントを作成しました",
|
"Comment created successfully": "コメントが作成されました",
|
||||||
"Error creating comment": "コメントの作成に失敗しました",
|
"Error creating comment": "コメントの作成中にエラーが発生しました",
|
||||||
"Comment updated successfully": "コメントを更新しました",
|
"Comment updated successfully": "コメントが更新されました",
|
||||||
"Failed to update comment": "コメントの更新に失敗しました",
|
"Failed to update comment": "コメントの更新に失敗しました",
|
||||||
"Comment deleted successfully": "コメントを削除しました",
|
"Comment deleted successfully": "コメントが削除されました",
|
||||||
"Failed to delete comment": "コメントの削除に失敗しました",
|
"Failed to delete comment": "コメントの削除に失敗しました",
|
||||||
"Comment resolved successfully": "コメントを解決しました",
|
"Comment resolved successfully": "コメントが解決されました",
|
||||||
"Comment re-opened successfully": "コメントを再開しました",
|
|
||||||
"Comment unresolved successfully": "コメントを未解決に戻しました",
|
|
||||||
"Failed to resolve comment": "コメントの解決に失敗しました",
|
"Failed to resolve comment": "コメントの解決に失敗しました",
|
||||||
"Resolve comment": "コメントを解決",
|
|
||||||
"Unresolve comment": "コメントを未解決に戻す",
|
|
||||||
"Resolve Comment Thread": "コメントスレッドを解決",
|
|
||||||
"Unresolve Comment Thread": "コメントスレッドを未解決に戻す",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "このコメントスレッドを解決しますか?完了としてマークされます",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "このコメントスレッドを未解決に戻しますか?",
|
|
||||||
"Resolved": "解決済",
|
|
||||||
"No active comments.": "アクティブなコメントはありません",
|
|
||||||
"Revoke invitation": "招待を取り消す",
|
"Revoke invitation": "招待を取り消す",
|
||||||
"Revoke": "取り消す",
|
"Revoke": "取り消す",
|
||||||
"Don't": "取り消さない",
|
"Don't": "取り消さない",
|
||||||
"Are you sure you want to revoke this invitation? The user will not be able to join the workspace.": "この招待を取り消してもよろしいですか?ユーザーはワークスペースに参加できなくなります",
|
"Are you sure you want to revoke this invitation? The user will not be able to join the workspace.": "この招待を取り消してもよろしいですか? ユーザはワークスペースに参加できなくなります。",
|
||||||
"Resend invitation": "招待を再度送る",
|
"Resend invitation": "招待を再度送る",
|
||||||
"Anyone with this link can join this workspace.": "このリンクを知っている人は誰でもワークスペースに参加できます",
|
"Anyone with this link can join this workspace.": "このリンクを持っている人は誰でもこのワークスペースに参加できます。",
|
||||||
"Invite link": "招待リンク",
|
"Invite link": "招待リンク",
|
||||||
"Copy": "コピー",
|
"Copy": "コピー",
|
||||||
"Copy to space": "スペースにコピー",
|
|
||||||
"Copied": "コピーしました",
|
"Copied": "コピーしました",
|
||||||
"Duplicate": "複製",
|
|
||||||
"Select a user": "ユーザを選択",
|
"Select a user": "ユーザを選択",
|
||||||
"Select a group": "グループを選択",
|
"Select a group": "グループを選択",
|
||||||
"Export all pages and attachments in this space.": "このスペースのすべてのページと添付ファイルをエクスポートします",
|
"Export all pages and attachments in this space.": "このスペースのすべてのページと添付ファイルをエクスポートします。",
|
||||||
"Delete space": "スペースを削除",
|
"Delete space": "スペースを削除",
|
||||||
"Are you sure you want to delete this space?": "このスペースを削除してもよろしいですか?",
|
"Are you sure you want to delete this space?": "このスペースを削除してもよろしいですか?",
|
||||||
"Delete this space with all its pages and data.": "このスペースとすべてのページ、データを削除します",
|
"Delete this space with all its pages and data.": "このスペースおよびスペース内のすべてのページとデータを削除します。",
|
||||||
"All pages, comments, attachments and permissions in this space will be deleted irreversibly.": "スペース内のすべてのページ、コメント、添付ファイル、権限が完全に削除されます",
|
"All pages, comments, attachments and permissions in this space will be deleted irreversibly.": "このスペース内のすべてのページ、コメント、添付ファイル、および権限は完全に削除されます。",
|
||||||
"Confirm space name": "スペース名を確認する",
|
"Confirm space name": "スペース名を確認する",
|
||||||
"Type the space name <b>{{spaceName}}</b> to confirm your action.": "確認のためスペース名 <b>{{spaceName}}</b> を入力してください",
|
"Type the space name <b>{{spaceName}}</b> to confirm your action.": "アクションを確認するためにスペース名 <b>{{spaceName}}</b> を入力してください。",
|
||||||
"Format": "フォーマット",
|
"Format": "フォーマット",
|
||||||
"Include subpages": "サブページを含める",
|
"Include subpages": "サブページを含める",
|
||||||
"Include attachments": "添付ファイルを含める",
|
"Include attachments": "添付ファイルを含める",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "エクスポートに失敗しました:",
|
"Export failed:": "エクスポートに失敗しました:",
|
||||||
"export error": "エクスポートエラー",
|
"export error": "エクスポートエラー",
|
||||||
"Export page": "エクスポートページ",
|
"Export page": "エクスポートページ",
|
||||||
"Export successful": "エクスポート成功",
|
|
||||||
"Export space": "エクスポートスペース",
|
"Export space": "エクスポートスペース",
|
||||||
"Export {{type}}": "{{type}}をエクスポート",
|
"Export {{type}}": "{{type}}をエクスポート",
|
||||||
"File exceeds the {{limit}} attachment limit": "ファイルが{{limit}}の添付制限を超えています",
|
"File exceeds the {{limit}} attachment limit": "ファイルが{{limit}}の添付制限を超えています",
|
||||||
@@ -278,16 +256,15 @@
|
|||||||
"Add row below": "下に行を追加",
|
"Add row below": "下に行を追加",
|
||||||
"Delete table": "テーブルを削除",
|
"Delete table": "テーブルを削除",
|
||||||
"Info": "情報",
|
"Info": "情報",
|
||||||
"Note": "ノート",
|
|
||||||
"Success": "成功",
|
"Success": "成功",
|
||||||
"Warning": "警告",
|
"Warning": "警告",
|
||||||
"Danger": "危険",
|
"Danger": "危険",
|
||||||
"Mermaid diagram error:": "Mermaid ダイアグラムエラー:",
|
"Mermaid diagram error:": "Mermaid コードエラー",
|
||||||
"Invalid Mermaid diagram": "無効な Mermaid ダイアグラムです",
|
"Invalid Mermaid diagram": "無効な Mermaid コードです",
|
||||||
"Double-click to edit Draw.io diagram": "ダブルクリックして Draw.io 図を編集",
|
"Double-click to edit Draw.io diagram": "ダブルクリックしてDraw.ioの図を編集",
|
||||||
"Exit": "終了",
|
"Exit": "終了",
|
||||||
"Save & Exit": "保存して終了",
|
"Save & Exit": "保存して終了",
|
||||||
"Double-click to edit Excalidraw diagram": "ダブルクリックして Excalidraw 図を編集",
|
"Double-click to edit Excalidraw diagram": "ダブルクリックしてExcalidraw図を編集",
|
||||||
"Paste link": "リンクを貼り付け",
|
"Paste link": "リンクを貼り付け",
|
||||||
"Edit link": "リンクを編集",
|
"Edit link": "リンクを編集",
|
||||||
"Remove link": "リンクを削除",
|
"Remove link": "リンクを削除",
|
||||||
@@ -324,24 +301,22 @@
|
|||||||
"Bullet List": "箇条書きリスト",
|
"Bullet List": "箇条書きリスト",
|
||||||
"Numbered List": "番号付きリスト",
|
"Numbered List": "番号付きリスト",
|
||||||
"Blockquote": "引用",
|
"Blockquote": "引用",
|
||||||
"Just start typing with plain text.": "プレーンテキストを入力します",
|
"Just start typing with plain text.": "すぐに文章を書き始められます。",
|
||||||
"Track tasks with a to-do list.": "Todo リストでタスクを管理します",
|
"Track tasks with a to-do list.": "Todoリストでタスクを追跡します。",
|
||||||
"Big section heading.": "大見出し",
|
"Big section heading.": "大きいフォントのセクション見出しです。",
|
||||||
"Medium section heading.": "中見出し",
|
"Medium section heading.": "中くらいのフォントのセクション見出しです。",
|
||||||
"Small section heading.": "小見出し",
|
"Small section heading.": "小さいフォントのセクション見出しです。",
|
||||||
"Create a simple bullet list.": "箇条書きリストを作成します",
|
"Create a simple bullet list.": "シンプルな箇条書きのリストを作成します。",
|
||||||
"Create a list with numbering.": "番号付きリストを作成します",
|
"Create a list with numbering.": "番号付きのリストを作成します。",
|
||||||
"Create block quote.": "引用ブロックを作成します",
|
"Create block quote.": "引用文を作成します。",
|
||||||
"Insert code snippet.": "コードスニペットを挿入します",
|
"Insert code snippet.": "コードスニペットを入力します。",
|
||||||
"Insert horizontal rule divider": "区切り線を挿入します",
|
"Insert horizontal rule divider": "水平線を挿入します。",
|
||||||
"Upload any image from your device.": "デバイスから画像をアップロードします",
|
"Upload any image from your device.": "画像をアップロードします。",
|
||||||
"Upload any video from your device.": "デバイスから動画をアップロードします",
|
"Upload any video from your device.": "動画をアップロードします。",
|
||||||
"Upload any file from your device.": "デバイスからファイルをアップロードします",
|
"Upload any file from your device.": "ファイルをアップロードします。",
|
||||||
"Uploading {{name}}": "{{name}} をアップロード中",
|
|
||||||
"Uploading file": "ファイルをアップロード中",
|
|
||||||
"Table": "テーブル",
|
"Table": "テーブル",
|
||||||
"Insert a table.": "テーブルを挿入します",
|
"Insert a table.": "表を挿入します。",
|
||||||
"Insert collapsible block.": "折りたたみブロックを挿入します",
|
"Insert collapsible block.": "折りたたみ可能なブロックを挿入します。",
|
||||||
"Video": "動画",
|
"Video": "動画",
|
||||||
"Divider": "区切り線",
|
"Divider": "区切り線",
|
||||||
"Quote": "引用",
|
"Quote": "引用",
|
||||||
@@ -349,69 +324,45 @@
|
|||||||
"File attachment": "ファイル添付",
|
"File attachment": "ファイル添付",
|
||||||
"Toggle block": "ブロックを切り替える",
|
"Toggle block": "ブロックを切り替える",
|
||||||
"Callout": "コールアウト",
|
"Callout": "コールアウト",
|
||||||
"Insert callout notice.": "コールアウトを挿入します",
|
"Insert callout notice.": "コールアウトブロックを挿入します。",
|
||||||
"Math inline": "インライン数式",
|
"Math inline": "インライン数式",
|
||||||
"Insert inline math equation.": "インライン数式を挿入します",
|
"Insert inline math equation.": "インライン数式を挿入します。",
|
||||||
"Math block": "数式ブロック",
|
"Math block": "数式ブロック",
|
||||||
"Insert math equation": "数式を挿入します",
|
"Insert math equation": "数式を挿入します",
|
||||||
"Mermaid diagram": "Mermaid ダイアグラム",
|
"Mermaid diagram": "Mermaidコード",
|
||||||
"Insert mermaid diagram": "Mermaid ダイアグラムを挿入します",
|
"Insert mermaid diagram": "Mermaidコードを記述して図を挿入します",
|
||||||
"Insert and design Drawio diagrams": "Draw.io 図を挿入・編集します",
|
"Insert and design Drawio diagrams": "Drawioの図を挿入してデザインします",
|
||||||
"Insert current date": "現在の日付を挿入します",
|
"Insert current date": "今日の日付を挿入します",
|
||||||
"Draw and sketch excalidraw diagrams": "Excalidraw 図を挿入します",
|
"Draw and sketch excalidraw diagrams": "Excalidrawの図を埋め込みます",
|
||||||
"Multiple": "複数",
|
"Multiple": "複数",
|
||||||
"Turn into": "変換する",
|
|
||||||
"Text align": "テキストの配置",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "このページは削除されたか移動されたか、またはアクセス権がない可能性があります。},{",
|
|
||||||
"Go to homepage": "ホームページへ移動",
|
|
||||||
"Pages you create will show up here.": "ここに作成したページが表示されます。",
|
|
||||||
"Heading {{level}}": "見出し {{level}}",
|
"Heading {{level}}": "見出し {{level}}",
|
||||||
"Toggle title": "タイトルの表示/非表示を切り替える",
|
"Toggle title": "タイトルの表示/非表示を切り替える",
|
||||||
"Write anything. Enter \"/\" for commands": "文字を入力するか、「/」でコマンドを呼び出します",
|
"Write anything. Enter \"/\" for commands": "文字を入力するか、「/」でコマンドを呼び出します",
|
||||||
"Write...": "ここに入力...",
|
|
||||||
"Column count": "列数",
|
|
||||||
"{{count}} Columns": "{{count}}列",
|
|
||||||
"Equal columns": "均等な列",
|
|
||||||
"Left sidebar": "左サイドバー",
|
|
||||||
"Right sidebar": "右サイドバー",
|
|
||||||
"Wide center": "中央ワイド",
|
|
||||||
"Left wide": "左ワイド",
|
|
||||||
"Right wide": "右ワイド",
|
|
||||||
"Names do not match": "名前が一致しません",
|
"Names do not match": "名前が一致しません",
|
||||||
"Today, {{time}}": "今日、{{time}}",
|
"Today, {{time}}": "今日、{{time}}",
|
||||||
"Yesterday, {{time}}": "昨日、{{time}}",
|
"Yesterday, {{time}}": "昨日、{{time}}",
|
||||||
"Space created successfully": "スペースを作成しました",
|
"Space created successfully": "スペースを作成しました",
|
||||||
"Space updated successfully": "スペースを更新しました",
|
"Space updated successfully": "スペースを更新しました",
|
||||||
"Space deleted successfully": "スペースを削除しました",
|
"Space deleted successfully": "スペースが削除されました",
|
||||||
"Members added successfully": "メンバーを追加しました",
|
"Members added successfully": "メンバーを追加しました",
|
||||||
"Member removed successfully": "メンバーを削除しました",
|
"Member removed successfully": "メンバーが削除されました",
|
||||||
"Member role updated successfully": "メンバーのロールを更新しました",
|
"Member role updated successfully": "メンバーのロールを更新しました",
|
||||||
"Created by: <b>{{creatorName}}</b>": "作成者: <b>{{creatorName}}</b>",
|
"Created by: <b>{{creatorName}}</b>": "作成者: <b>{{creatorName}}</b>",
|
||||||
"Created at: {{time}}": "作成日: {{time}}",
|
"Created at: {{time}}": "が作成しました:{{time}}",
|
||||||
"Edited by {{name}} {{time}}": "最終編集: {{name}} {{time}}",
|
"Edited by {{name}} {{time}}": "最終編集: {{name}} {{time}}",
|
||||||
"Word count: {{wordCount}}": "単語数: {{wordCount}}",
|
"Word count: {{wordCount}}": "ワード数: {{wordCount}}",
|
||||||
"Character count: {{characterCount}}": "文字数: {{characterCount}}",
|
"Character count: {{characterCount}}": "文字数: {{characterCount}}",
|
||||||
"New update": "新規更新",
|
"New update": "新規更新",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} が利用可能です",
|
"{{latestVersion}} is available": "{{latestVersion}}は利用可能です",
|
||||||
"Default page edit mode": "デフォルトのページ編集モード",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "お好みのページ編集モードを選択してください(誤編集を防止します)",
|
|
||||||
"Reading": "読み取り",
|
|
||||||
"Delete member": "メンバーを削除する",
|
"Delete member": "メンバーを削除する",
|
||||||
"Member deleted successfully": "メンバーを削除しました",
|
"Member deleted successfully": "メンバーが削除されました",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "このメンバーを削除してもよろしいですか?この操作は取り消せません",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "ワークスペースメンバーを削除してもよろしいですか?この操作は元に戻せません。",
|
||||||
"Deactivate member": "メンバーを無効化",
|
|
||||||
"Activate member": "メンバーを有効化",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "本当にこのワークスペースのメンバーを無効化しますか?無効化すると、このワークスペースにアクセスできなくなります。",
|
|
||||||
"Are you sure you want to activate this workspace member?": "本当にこのワークスペースのメンバーを有効化しますか?",
|
|
||||||
"Deactivate": "無効化",
|
|
||||||
"Activate": "有効化",
|
|
||||||
"Deactivated": "無効化済み",
|
|
||||||
"Move": "移動",
|
"Move": "移動",
|
||||||
"Move page": "ページを移動",
|
"Move page": "ページを移動",
|
||||||
"Move page to a different space.": "ページを別のスペースに移動します",
|
"Move page to a different space.": "ページを別のスペースに移動します。",
|
||||||
"Real-time editor connection lost. Retrying...": "リアルタイム編集の接続が切断されました。再接続中...",
|
"Real-time editor connection lost. Retrying...": "リアルタイムエディターの接続が失われました。再試行しています…",
|
||||||
"Table of contents": "目次",
|
"Table of contents": "目次",
|
||||||
"Add headings (H1, H2, H3) to generate a table of contents.": "見出し(H1、H2、H3)を追加すると目次が生成されます",
|
"Add headings (H1, H2, H3) to generate a table of contents.": "見出し(H1、H2、H3)を追加して目次を生成します。",
|
||||||
"Share": "共有",
|
"Share": "共有",
|
||||||
"Public sharing": "公開共有",
|
"Public sharing": "公開共有",
|
||||||
"Shared by": "共有者",
|
"Shared by": "共有者",
|
||||||
@@ -430,268 +381,7 @@
|
|||||||
"Delete share": "共有を削除",
|
"Delete share": "共有を削除",
|
||||||
"Are you sure you want to delete this shared link?": "この共有リンクを削除してもよろしいですか?",
|
"Are you sure you want to delete this shared link?": "この共有リンクを削除してもよろしいですか?",
|
||||||
"Publicly shared pages from spaces you are a member of will appear here": "メンバーであるスペースからの公開ページがここに表示されます",
|
"Publicly shared pages from spaces you are a member of will appear here": "メンバーであるスペースからの公開ページがここに表示されます",
|
||||||
"Share deleted successfully": "共有を削除しました",
|
"Share deleted successfully": "共有が正常に削除されました",
|
||||||
"Share not found": "共有が見つかりません",
|
"Share not found": "共有が見つかりません",
|
||||||
"Failed to share page": "ページの共有に失敗しました",
|
"Failed to share page": "ページの共有に失敗しました"
|
||||||
"Disable public sharing": "公開共有を無効にする",
|
|
||||||
"Prevent members from sharing pages publicly.": "メンバーがページを公開で共有するのを防ぐ。",
|
|
||||||
"Toggle public sharing": "公開共有を切り替える",
|
|
||||||
"Toggle space public sharing": "スペースの公開共有を切り替える",
|
|
||||||
"Public sharing is disabled at the workspace level": "ワークスペースレベルで公開共有が無効になっています",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "このスペース内のページが公開で共有されるのを防ぐ。",
|
|
||||||
"Requires an enterprise license": "エンタープライズライセンスが必要です",
|
|
||||||
"Page permissions": "ページのアクセス権",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "個々のページを誰が表示・編集できるかを制御します。エンタープライズライセンスで利用可能です。",
|
|
||||||
"Enable public sharing": "公開共有を有効にする",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "本当に公開共有を有効にしますか?メンバーはページを公開で共有できるようになります。",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "本当に公開共有を無効にしますか?このワークスペース内のすべての既存の共有リンクが削除されます。",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "本当にこのスペースの公開共有を有効にしますか?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "本当に公開共有を無効にしますか?このスペースのすべての既存の共有リンクが削除されます。",
|
|
||||||
"Public sharing is disabled": "公開共有が無効になっています",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "ワークスペースレベルで公開共有が無効になりました。",
|
|
||||||
"Public sharing has been disabled for this space.": "このスペースで公開共有が無効になりました。",
|
|
||||||
"Copy page": "ページをコピー",
|
|
||||||
"Copy page to a different space.": "ページを別のスペースにコピーします",
|
|
||||||
"Page copied successfully": "ページをコピーしました",
|
|
||||||
"Page duplicated successfully": "ページを複製しました",
|
|
||||||
"Find": "検索",
|
|
||||||
"Not found": "見つかりません",
|
|
||||||
"Previous Match (Shift+Enter)": "前の一致 (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "次の一致 (Enter)",
|
|
||||||
"Match case (Alt+C)": "大文字小文字を区別 (Alt+C)",
|
|
||||||
"Replace": "置換",
|
|
||||||
"Close (Escape)": "閉じる (Escape)",
|
|
||||||
"Replace (Enter)": "置換 (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "すべて置換 (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "すべて置換",
|
|
||||||
"View all spaces": "すべてのスペースを表示",
|
|
||||||
"Error": "エラー",
|
|
||||||
"Failed to disable MFA": "MFAの無効化に失敗しました",
|
|
||||||
"Disable two-factor authentication": "二要素認証を無効化",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "二要素認証を無効にすると、アカウントのセキュリティが低下します。サインインにはパスワードのみが必要になります",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "二要素認証を無効にするにはパスワードを入力してください",
|
|
||||||
"Two-factor authentication has been enabled": "二要素認証を有効にしました",
|
|
||||||
"Two-factor authentication has been disabled": "二要素認証を無効にしました",
|
|
||||||
"2-step verification": "2段階認証",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "サインイン時に追加の認証でアカウントを保護します",
|
|
||||||
"Two-factor authentication is active on your account.": "二要素認証が有効です",
|
|
||||||
"Add 2FA method": "2FAメソッドを追加",
|
|
||||||
"Backup codes": "バックアップコード",
|
|
||||||
"Disable": "無効にする",
|
|
||||||
"Invalid verification code": "無効な認証コード",
|
|
||||||
"New backup codes have been generated": "新しいバックアップコードを生成しました",
|
|
||||||
"Failed to regenerate backup codes": "バックアップコードの再生成に失敗しました",
|
|
||||||
"About backup codes": "バックアップコードについて",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "認証アプリにアクセスできない場合、バックアップコードでアカウントにアクセスできます。各コードは1回のみ使用可能です",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "新しいバックアップコードはいつでも再生成できます。既存のコードはすべて無効になります",
|
|
||||||
"Confirm password": "パスワードを確認",
|
|
||||||
"Generate new backup codes": "新しいバックアップコードを生成",
|
|
||||||
"Save your new backup codes": "新しいバックアップコードを保存",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "これらのコードを安全な場所に保存してください。古いバックアップコードは無効になりました",
|
|
||||||
"Your new backup codes": "新しいバックアップコード",
|
|
||||||
"I've saved my backup codes": "バックアップコードを保存しました",
|
|
||||||
"Failed to setup MFA": "MFAの設定に失敗しました",
|
|
||||||
"Setup & Verify": "設定と確認",
|
|
||||||
"Add to authenticator": "認証アプリに追加",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. このQRコードを認証アプリでスキャンしてください",
|
|
||||||
"Can't scan the code?": "コードをスキャンできませんか?",
|
|
||||||
"Enter this code manually in your authenticator app:": "このコードを認証アプリに手動で入力してください:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. 認証アプリからの6桁のコードを入力してください",
|
|
||||||
"Verify and enable": "確認と有効化",
|
|
||||||
"Failed to generate QR code. Please try again.": "QRコードの生成に失敗しました。もう一度お試しください",
|
|
||||||
"Backup": "バックアップ",
|
|
||||||
"Save codes": "コードを保存",
|
|
||||||
"Save your backup codes": "バックアップコードを保存",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "認証アプリにアクセスできない場合、これらのコードでアカウントにアクセスできます。各コードは1回のみ使用可能です",
|
|
||||||
"Print": "印刷",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "二要素認証を設定しました。再度ログインしてください",
|
|
||||||
"Two-Factor authentication required": "二要素認証が必要です",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "このワークスペースではすべてのユーザーに二要素認証が必要です",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "ワークスペースにアクセスするには二要素認証を設定してください。アカウントのセキュリティが強化されます",
|
|
||||||
"Set up two-factor authentication": "二要素認証を設定",
|
|
||||||
"Cancel and logout": "キャンセルしてログアウト",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "このワークスペースでは二要素認証が必要です。続行するには設定してください",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "認証アプリからの確認コードでアカウントのセキュリティが強化されます",
|
|
||||||
"Password is required": "パスワードが必要です",
|
|
||||||
"Password must be at least 8 characters": "パスワードは8文字以上必要です",
|
|
||||||
"Please enter a 6-digit code": "6桁のコードを入力してください",
|
|
||||||
"Code must be exactly 6 digits": "コードは6桁で入力してください",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "認証アプリに表示された6桁のコードを入力してください",
|
|
||||||
"Need help authenticating?": "認証に関するヘルプが必要ですか?",
|
|
||||||
"MFA QR Code": "MFA QRコード",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "アカウントを作成しました。二要素認証を設定するためにログインしてください",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "パスワードをリセットしました。新しいパスワードでログインして二要素認証を完了してください",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "パスワードをリセットしました。新しいパスワードでログインして二要素認証を設定してください",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "パスワードをリセットしました。新しいパスワードでログインしてください",
|
|
||||||
"Two-factor authentication": "二要素認証",
|
|
||||||
"Use authenticator app instead": "代わりに認証アプリを使用",
|
|
||||||
"Verify backup code": "バックアップコードを確認",
|
|
||||||
"Use backup code": "バックアップコードを使用",
|
|
||||||
"Enter one of your backup codes": "バックアップコードのいずれかを入力してください",
|
|
||||||
"Backup code": "バックアップコード",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "バックアップコードを入力してください。各コードは1回のみ使用可能です",
|
|
||||||
"Verify": "確認",
|
|
||||||
"Trash": "ごみ箱",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "{count, plural, other {ゴミ箱内のページは#日後に完全に削除されます。}}",
|
|
||||||
"Deleted": "削除",
|
|
||||||
"No pages in trash": "ごみ箱にページがありません",
|
|
||||||
"Permanently delete page?": "ページを完全に削除しますか?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "「{{title}}」を完全に削除しますか?この操作は取り消せません",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "「{{title}}」とそのサブページを復元しますか?",
|
|
||||||
"Move to trash": "ごみ箱に移動",
|
|
||||||
"Move this page to trash?": "このページをごみ箱に移動しますか?",
|
|
||||||
"Restore page": "ページを復元",
|
|
||||||
"Page moved to trash": "ページをごみ箱に移動しました",
|
|
||||||
"Page restored successfully": "ページを復元しました",
|
|
||||||
"Deleted by": "削除者",
|
|
||||||
"Deleted at": "削除日時",
|
|
||||||
"Preview": "プレビュー",
|
|
||||||
"Subpages": "サブページ",
|
|
||||||
"Failed to load subpages": "サブページの読み込みに失敗しました",
|
|
||||||
"No subpages": "サブページがありません",
|
|
||||||
"Subpages (Child pages)": "サブページ(子ページ)",
|
|
||||||
"List all subpages of the current page": "現在のページのすべてのサブページをリスト",
|
|
||||||
"Attachments": "添付ファイル",
|
|
||||||
"All spaces": "すべてのスペース",
|
|
||||||
"Unknown": "不明",
|
|
||||||
"Find a space": "スペースを探す",
|
|
||||||
"Search in all your spaces": "あなたのすべてのスペースで検索",
|
|
||||||
"Type": "タイプ",
|
|
||||||
"Enterprise": "エンタープライズ",
|
|
||||||
"Download attachment": "添付ファイルをダウンロード",
|
|
||||||
"Allowed email domains": "許可されたメールドメイン",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "これらのドメインのメールアドレスを持つユーザーのみSSO経由で登録できます",
|
|
||||||
"Enter valid domain names separated by comma or space": "コンマまたはスペースで区切って有効なドメイン名を入力してください",
|
|
||||||
"Enforce two-factor authentication": "二要素認証を強制する",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "有効にすると、すべてのメンバーが二要素認証を設定しないとワークスペースにアクセスできなくなります",
|
|
||||||
"Toggle MFA enforcement": "MFAの強制を切り替える",
|
|
||||||
"Display name": "表示名",
|
|
||||||
"Allow signup": "登録を許可する",
|
|
||||||
"Enabled": "有効",
|
|
||||||
"Advanced Settings": "詳細設定",
|
|
||||||
"Enable TLS/SSL": "TLS/SSLを有効にする",
|
|
||||||
"Use secure connection to LDAP server": "LDAPサーバーへの安全な接続を使用する",
|
|
||||||
"Group sync": "グループ同期",
|
|
||||||
"No SSO providers found.": "SSOプロバイダーが見つかりませんでした。",
|
|
||||||
"Delete SSO provider": "SSOプロバイダーを削除する",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "このSSOプロバイダーを削除してもよろしいですか?",
|
|
||||||
"Action": "アクション",
|
|
||||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}}の構成",
|
|
||||||
"Icon": "アイコン",
|
|
||||||
"Upload image": "画像をアップロード",
|
|
||||||
"Remove image": "画像を削除",
|
|
||||||
"Failed to remove image": "画像の削除に失敗しました",
|
|
||||||
"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キーを更新",
|
|
||||||
"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キーを作成できるのは管理者とオーナーのみです。既存のメンバーキーは引き続き有効です。",
|
|
||||||
"Toggle restrict API keys to admins": "APIキーの作成制限(管理者のみ)を切り替える",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "ワークスペース管理者によってAPIキーの作成が管理者のみに制限されています。",
|
|
||||||
"AI settings": "AI設定",
|
|
||||||
"AI search": "AI検索",
|
|
||||||
"AI Answer": "AI回答",
|
|
||||||
"Ask AI": "AIに質問する",
|
|
||||||
"AI is thinking...": "AIが考え中...",
|
|
||||||
"Ask a question...": "質問を入力...",
|
|
||||||
"AI Answers": "AI回答",
|
|
||||||
"AI-powered search (AI Answers)": "AI搭載検索 (AI回答)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI検索はベクター埋め込みを使用してワークスペース全体の意味検索を実現します",
|
|
||||||
"Toggle AI search": "AI検索を切り替え",
|
|
||||||
"Generative AI (Ask AI)": "生成AI (Ask AI)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "エディターでAIを活用したコンテンツ生成を有効にします。ユーザーがテキストの生成、改善、翻訳、および変換を行うことができます。",
|
|
||||||
"Toggle generative AI": "生成AIを切り替える",
|
|
||||||
"Enterprise feature": "エンタープライズ機能",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "AI は Docmost のエンタープライズ版でのみ利用可能です。sales@docmost.com までお問い合わせください。",
|
|
||||||
"AI & MCP": "AI と MCP",
|
|
||||||
"AI": "AI",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "モデルコンテキストプロトコル(MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "MCP サーバーを有効にして、AI アシスタントやツールがワークスペースのコンテンツとやり取りできるようにします。",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP は Docmost のエンタープライズ版でのみ利用可能です。sales@docmost.com までお問い合わせください。",
|
|
||||||
"MCP documentation": "MCP ドキュメント",
|
|
||||||
"MCP Server URL": "MCP サーバーの URL",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "認証には API キーを使用してください。API キーはアカウント設定で管理できます。",
|
|
||||||
"Supported tools": "サポートされているツール",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "このワークスペースでは MCP が有効になっています。AI アシスタントを接続するには API キーを使用してください。",
|
|
||||||
"MCP server URL:": "MCP サーバーの URL:",
|
|
||||||
"Learn more": "詳細を見る",
|
|
||||||
"View the": "表示",
|
|
||||||
"for usage details.": "使用方法の詳細については。",
|
|
||||||
"for setup instructions.": "設定手順については。",
|
|
||||||
"API documentation": "API ドキュメント",
|
|
||||||
"Sources": "ソース",
|
|
||||||
"AI Answers not available for attachments": "添付ファイルにはAI回答を利用できません",
|
|
||||||
"No answer available": "回答がありません",
|
|
||||||
"Background color": "背景色",
|
|
||||||
"Highlight color": "ハイライト色",
|
|
||||||
"Remove color": "色を削除",
|
|
||||||
"Notifications": "通知",
|
|
||||||
"No notifications": "通知なし",
|
|
||||||
"No unread notifications": "未読の通知はありません",
|
|
||||||
"All notifications": "すべての通知",
|
|
||||||
"Unread only": "未読のみ",
|
|
||||||
"Mark all as read": "すべてを既読にする",
|
|
||||||
"Mark as read": "既読にする",
|
|
||||||
"More options": "その他のオプション",
|
|
||||||
"mentioned you in a comment": "コメントであなたに言及しました",
|
|
||||||
"commented on a page": "ページにコメントしました",
|
|
||||||
"resolved a comment": "コメントを解決しました",
|
|
||||||
"mentioned you on a page": "ページ上であなたに言及しました",
|
|
||||||
"gave you edit access to a page": "あなたにページの編集アクセス権を付与しました",
|
|
||||||
"gave you view access to a page": "あなたにページの閲覧アクセス権を付与しました",
|
|
||||||
"Today": "今日",
|
|
||||||
"Yesterday": "昨日",
|
|
||||||
"This week": "今週",
|
|
||||||
"Older": "以前のもの",
|
|
||||||
"Restricted page": "アクセス制限されたページ",
|
|
||||||
"Restricted pages cannot be shared publicly.": "アクセス制限されたページは公開共有できません。",
|
|
||||||
"Restricted by parent": "親ページによって制限されています",
|
|
||||||
"Restricted": "制限あり",
|
|
||||||
"Open": "制限なし",
|
|
||||||
"Inherits restrictions from ancestor page": "上位ページから制限を継承しています",
|
|
||||||
"Only people listed below can access this page": "以下に記載されている人のみがこのページにアクセスできます",
|
|
||||||
"Everyone in this space can access": "このスペース内の全員がアクセスできます",
|
|
||||||
"No additional restrictions on this page": "このページに追加の制限はありません",
|
|
||||||
"Only specific people can access": "特定の人のみがアクセスできます",
|
|
||||||
"Use only inherited restrictions": "継承された制限のみを適用する",
|
|
||||||
"Add restrictions on top of inherited": "継承された制限に追加の制限を加える",
|
|
||||||
"Inherited restriction": "継承された制限",
|
|
||||||
"Access limited by": "アクセス制限元",
|
|
||||||
"Restrict access to control who can view and edit this page": "このページを誰が表示・編集できるかを制御するためにアクセスを制限します",
|
|
||||||
"Add additional restrictions specific to this page": "このページ固有の追加制限を設定する",
|
|
||||||
"Access": "アクセス",
|
|
||||||
"People with access": "アクセスできる人",
|
|
||||||
"Remove all": "すべてを削除",
|
|
||||||
"Remove access": "アクセス権を削除",
|
|
||||||
"Remove all access": "すべてのアクセス権を削除",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "このメンバーのページへのアクセス権を削除してもよろしいですか?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "すべての特定のアクセスを削除してもよろしいですか?これによりページはスペース内の全員に公開されます。",
|
|
||||||
"Trash retention": "ゴミ箱の保持期間",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "この期間を過ぎるとゴミ箱内のページは完全に削除されます。",
|
|
||||||
"Trash retention updated": "ゴミ箱保持期間が更新されました",
|
|
||||||
"Failed to update trash retention": "ゴミ箱保持期間の更新に失敗しました",
|
|
||||||
"Removed page restriction": "ページの制限を解除しました",
|
|
||||||
"Added page permission": "ページの権限を追加しました",
|
|
||||||
"Removed page permission": "ページの権限を削除しました"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "선호하는 인터페이스 언어를 선택하세요.",
|
"Choose your preferred interface language.": "선호하는 인터페이스 언어를 선택하세요.",
|
||||||
"Choose your preferred page width.": "선호하는 페이지 너비를 선택하세요.",
|
"Choose your preferred page width.": "선호하는 페이지 너비를 선택하세요.",
|
||||||
"Confirm": "확인",
|
"Confirm": "확인",
|
||||||
"Copy as Markdown": "Markdown으로 복사",
|
|
||||||
"Copy link": "링크 복사",
|
"Copy link": "링크 복사",
|
||||||
"Create": "생성",
|
"Create": "생성",
|
||||||
"Create group": "팀 생성",
|
"Create group": "팀 생성",
|
||||||
@@ -54,13 +53,12 @@
|
|||||||
"e.g Space for product team": "예: 제품 팀을 위한 Space",
|
"e.g Space for product team": "예: 제품 팀을 위한 Space",
|
||||||
"e.g Space for sales team to collaborate": "예: 영업 팀의 Space",
|
"e.g Space for sales team to collaborate": "예: 영업 팀의 Space",
|
||||||
"Edit": "편집",
|
"Edit": "편집",
|
||||||
"Read": "읽기",
|
|
||||||
"Edit group": "팀 편집",
|
"Edit group": "팀 편집",
|
||||||
"Email": "이메일",
|
"Email": "이메일",
|
||||||
"Enter a strong password": "강력한 비밀번호를 입력하세요",
|
"Enter a strong password": "강력한 비밀번호를 입력하세요",
|
||||||
"Enter valid email addresses separated by comma or space max_50": "유효한 이메일 주소를 쉼표나 공백으로 구분하여 입력하세요 [최대: 50]",
|
"Enter valid email addresses separated by comma or space max_50": "유효한 이메일 주소를 쉼표나 공백으로 구분하여 입력하세요 [최대: 50]",
|
||||||
"enter valid emails addresses": "유효한 이메일 주소를 입력하세요",
|
"enter valid emails addresses": "유효한 이메일 주소를 입력하세요",
|
||||||
"Enter your current password": "기존 비밀번호를 입력하세요",
|
"Enter your current password": "현재 비밀번호를 입력하세요",
|
||||||
"enter your full name": "전체 이름을 입력하세요",
|
"enter your full name": "전체 이름을 입력하세요",
|
||||||
"Enter your new password": "새 비밀번호를 입력하세요",
|
"Enter your new password": "새 비밀번호를 입력하세요",
|
||||||
"Enter your new preferred email": "새로운 이메일을 입력하세요",
|
"Enter your new preferred email": "새로운 이메일을 입력하세요",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "팀을 찾을 수 없음",
|
"No group found": "팀을 찾을 수 없음",
|
||||||
"No page history saved yet.": "아직 저장된 페이지 기록이 없습니다.",
|
"No page history saved yet.": "아직 저장된 페이지 기록이 없습니다.",
|
||||||
"No pages yet": "아직 페이지가 없습니다",
|
"No pages yet": "아직 페이지가 없습니다",
|
||||||
"No shared pages": "공유된 페이지가 없습니다.",
|
|
||||||
"No results found...": "결과를 찾을 수 없습니다...",
|
"No results found...": "결과를 찾을 수 없습니다...",
|
||||||
"No user found": "사용자를 찾을 수 없음",
|
"No user found": "사용자를 찾을 수 없음",
|
||||||
"Overview": "개요",
|
"Overview": "개요",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "페이지",
|
"page": "페이지",
|
||||||
"Page deleted successfully": "페이지 삭제 완료",
|
"Page deleted successfully": "페이지 삭제 완료",
|
||||||
"Page history": "페이지 기록",
|
"Page history": "페이지 기록",
|
||||||
"Select version": "버전 선택",
|
|
||||||
"Highlight changes": "변경 사항 강조",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "페이지 가져오기가 진행 중입니다. 이 탭을 닫지 마세요.",
|
"Page import is in progress. Please do not close this tab.": "페이지 가져오기가 진행 중입니다. 이 탭을 닫지 마세요.",
|
||||||
"Pages": "페이지",
|
"Pages": "페이지",
|
||||||
"pages": "페이지",
|
"pages": "페이지",
|
||||||
"Password": "비밀번호",
|
"Password": "비밀번호",
|
||||||
"Password changed successfully": "비밀번호 변경 완료",
|
"Password changed successfully": "비밀번호 변경 완료",
|
||||||
"People": "사용자",
|
|
||||||
"Pending": "대기 중",
|
"Pending": "대기 중",
|
||||||
"Please confirm your action": "작업을 확인해 주세요",
|
"Please confirm your action": "작업을 확인해 주세요",
|
||||||
"Preferences": "설정",
|
"Preferences": "설정",
|
||||||
@@ -176,7 +170,7 @@
|
|||||||
"Successfully restored": "복원 완료",
|
"Successfully restored": "복원 완료",
|
||||||
"System settings": "시스템 설정",
|
"System settings": "시스템 설정",
|
||||||
"Theme": "배경",
|
"Theme": "배경",
|
||||||
"To change your email, you have to enter your password and new email.": "이메일을 변경하려면 기존 비밀번호와 새 이메일을 입력해야 합니다.",
|
"To change your email, you have to enter your password and new email.": "이메일을 변경하려면 현재 비밀번호와 새 이메일을 입력해야 합니다.",
|
||||||
"Toggle full page width": "전체 페이지 너비 전환",
|
"Toggle full page width": "전체 페이지 너비 전환",
|
||||||
"Unable to import pages. Please try again.": "페이지를 가져올 수 없습니다. 다시 시도해주세요.",
|
"Unable to import pages. Please try again.": "페이지를 가져올 수 없습니다. 다시 시도해주세요.",
|
||||||
"untitled": "제목 없음",
|
"untitled": "제목 없음",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "답글...",
|
"Reply...": "답글...",
|
||||||
"Error loading comments.": "댓글 불러오기 오류.",
|
"Error loading comments.": "댓글 불러오기 오류.",
|
||||||
"No comments yet.": "아직 댓글이 없습니다.",
|
"No comments yet.": "아직 댓글이 없습니다.",
|
||||||
"No open comments.": "열린 댓글이 없습니다.",
|
|
||||||
"No resolved comments.": "해결된 댓글이 없습니다.",
|
|
||||||
"Add a comment...": "댓글 추가...",
|
|
||||||
"Edit comment": "댓글 수정",
|
"Edit comment": "댓글 수정",
|
||||||
"Delete comment": "댓글 삭제",
|
"Delete comment": "댓글 삭제",
|
||||||
"Are you sure you want to delete this comment?": "이 댓글을 삭제하시겠습니까?",
|
"Are you sure you want to delete this comment?": "이 댓글을 삭제하시겠습니까?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "댓글 삭제 완료",
|
"Comment deleted successfully": "댓글 삭제 완료",
|
||||||
"Failed to delete comment": "댓글 삭제 실패",
|
"Failed to delete comment": "댓글 삭제 실패",
|
||||||
"Comment resolved successfully": "댓글 처리 완료",
|
"Comment resolved successfully": "댓글 처리 완료",
|
||||||
"Comment re-opened successfully": "댓글이 성공적으로 다시 열렸습니다",
|
|
||||||
"Comment unresolved successfully": "댓글 미해결로 변경 완료",
|
|
||||||
"Failed to resolve comment": "댓글 처리 실패",
|
"Failed to resolve comment": "댓글 처리 실패",
|
||||||
"Resolve comment": "댓글 해결하기",
|
|
||||||
"Unresolve comment": "댓글 미해결로 변경하기",
|
|
||||||
"Resolve Comment Thread": "댓글 스레드 해결하기",
|
|
||||||
"Unresolve Comment Thread": "댓글 스레드 미해결로 변경하기",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "이 댓글 스레드를 해결하시겠습니까? 완료로 표시됩니다.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "이 댓글 스레드를 미해결로 변경하시겠습니까?",
|
|
||||||
"Resolved": "해결됨",
|
|
||||||
"No active comments.": "활성 댓글이 없습니다.",
|
|
||||||
"Revoke invitation": "초대 취소",
|
"Revoke invitation": "초대 취소",
|
||||||
"Revoke": "취소",
|
"Revoke": "취소",
|
||||||
"Don't": "하지 않음",
|
"Don't": "하지 않음",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "이 링크를 가진 모든 사용자가 이 Workspace에 참여할 수 있습니다.",
|
"Anyone with this link can join this workspace.": "이 링크를 가진 모든 사용자가 이 Workspace에 참여할 수 있습니다.",
|
||||||
"Invite link": "초대 링크",
|
"Invite link": "초대 링크",
|
||||||
"Copy": "복사",
|
"Copy": "복사",
|
||||||
"Copy to space": "공간에 복사하기",
|
|
||||||
"Copied": "복사됨",
|
"Copied": "복사됨",
|
||||||
"Duplicate": "중복",
|
|
||||||
"Select a user": "사용자 선택",
|
"Select a user": "사용자 선택",
|
||||||
"Select a group": "팀 선택",
|
"Select a group": "팀 선택",
|
||||||
"Export all pages and attachments in this space.": "이 Space의 모든 페이지와 첨부파일을 내보냅니다.",
|
"Export all pages and attachments in this space.": "이 Space의 모든 페이지와 첨부파일을 내보냅니다.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "내보내기 실패:",
|
"Export failed:": "내보내기 실패:",
|
||||||
"export error": "내보내기 오류",
|
"export error": "내보내기 오류",
|
||||||
"Export page": "페이지 내보내기",
|
"Export page": "페이지 내보내기",
|
||||||
"Export successful": "내보내기 성공",
|
|
||||||
"Export space": "Space 내보내기",
|
"Export space": "Space 내보내기",
|
||||||
"Export {{type}}": "{{type}} 내보내기",
|
"Export {{type}}": "{{type}} 내보내기",
|
||||||
"File exceeds the {{limit}} attachment limit": "첨부 파일 크기 제한 {{limit}}을 초과했습니다",
|
"File exceeds the {{limit}} attachment limit": "첨부 파일 크기 제한 {{limit}}을 초과했습니다",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "아래에 행 추가",
|
"Add row below": "아래에 행 추가",
|
||||||
"Delete table": "테이블 삭제",
|
"Delete table": "테이블 삭제",
|
||||||
"Info": "정보",
|
"Info": "정보",
|
||||||
"Note": "참고",
|
|
||||||
"Success": "완료",
|
"Success": "완료",
|
||||||
"Warning": "주의",
|
"Warning": "주의",
|
||||||
"Danger": "위험",
|
"Danger": "위험",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "기기에서 이미지를 업로드하세요.",
|
"Upload any image from your device.": "기기에서 이미지를 업로드하세요.",
|
||||||
"Upload any video from your device.": "기기에서 비디오를 업로드하세요.",
|
"Upload any video from your device.": "기기에서 비디오를 업로드하세요.",
|
||||||
"Upload any file from your device.": "기기에서 파일을 업로드하세요.",
|
"Upload any file from your device.": "기기에서 파일을 업로드하세요.",
|
||||||
"Uploading {{name}}": "{{name}} 업로드 중",
|
|
||||||
"Uploading file": "파일 업로드 중",
|
|
||||||
"Table": "테이블",
|
"Table": "테이블",
|
||||||
"Insert a table.": "테이블 삽입.",
|
"Insert a table.": "테이블 삽입.",
|
||||||
"Insert collapsible block.": "접을 수 있는 블록 삽입.",
|
"Insert collapsible block.": "접을 수 있는 블록 삽입.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "현재 날짜 삽입",
|
"Insert current date": "현재 날짜 삽입",
|
||||||
"Draw and sketch excalidraw diagrams": "Excalidraw diagram 그리기 및 스케치",
|
"Draw and sketch excalidraw diagrams": "Excalidraw diagram 그리기 및 스케치",
|
||||||
"Multiple": "복제",
|
"Multiple": "복제",
|
||||||
"Turn into": "변경하기",
|
|
||||||
"Text align": "텍스트 정렬",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "이 페이지는 삭제되었거나 이동되었거나 접근 권한이 없을 수 있습니다.",
|
|
||||||
"Go to homepage": "홈으로 이동",
|
|
||||||
"Pages you create will show up here.": "여기에 생성한 페이지가 표시됩니다.",
|
|
||||||
"Heading {{level}}": "제목 {{level}}",
|
"Heading {{level}}": "제목 {{level}}",
|
||||||
"Toggle title": "제목 토글",
|
"Toggle title": "제목 토글",
|
||||||
"Write anything. Enter \"/\" for commands": "아무거나 입력하세요. 명령어를 사용하려면 \"/\"를 입력하세요",
|
"Write anything. Enter \"/\" for commands": "아무거나 입력하세요. 명령어를 사용하려면 \"/\"를 입력하세요",
|
||||||
"Write...": "작성...",
|
|
||||||
"Column count": "열 개수",
|
|
||||||
"{{count}} Columns": "{{count}}열",
|
|
||||||
"Equal columns": "열 너비 균등",
|
|
||||||
"Left sidebar": "왼쪽 사이드바",
|
|
||||||
"Right sidebar": "오른쪽 사이드바",
|
|
||||||
"Wide center": "가운데 넓게",
|
|
||||||
"Left wide": "왼쪽 넓게",
|
|
||||||
"Right wide": "오른쪽 넓게",
|
|
||||||
"Names do not match": "이름이 일치하지 않습니다",
|
"Names do not match": "이름이 일치하지 않습니다",
|
||||||
"Today, {{time}}": "오늘, {{time}}",
|
"Today, {{time}}": "오늘, {{time}}",
|
||||||
"Yesterday, {{time}}": "어제, {{time}}",
|
"Yesterday, {{time}}": "어제, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "문자 수: {{characterCount}}",
|
"Character count: {{characterCount}}": "문자 수: {{characterCount}}",
|
||||||
"New update": "새로운 업데이트",
|
"New update": "새로운 업데이트",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}}이 사용 가능합니다",
|
"{{latestVersion}} is available": "{{latestVersion}}이 사용 가능합니다",
|
||||||
"Default page edit mode": "기본 페이지 편집 모드",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "선호하는 페이지 편집 모드를 선택하세요. 실수로 인한 편집을 방지하세요.",
|
|
||||||
"Reading": "읽기",
|
|
||||||
"Delete member": "회원 삭제",
|
"Delete member": "회원 삭제",
|
||||||
"Member deleted successfully": "멤버가 성공적으로 제거되었습니다",
|
"Member deleted successfully": "멤버가 성공적으로 제거되었습니다",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "이 워크스페이스 멤버를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "이 워크스페이스 멤버를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
||||||
"Deactivate member": "멤버 비활성화",
|
|
||||||
"Activate member": "멤버 활성화",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "이 워크스페이스 멤버를 비활성화하시겠습니까? 해당 사용자는 더 이상 이 워크스페이스에 접근할 수 없습니다.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "이 워크스페이스 멤버를 활성화하시겠습니까?",
|
|
||||||
"Deactivate": "비활성화",
|
|
||||||
"Activate": "활성화",
|
|
||||||
"Deactivated": "비활성화됨",
|
|
||||||
"Move": "이동",
|
"Move": "이동",
|
||||||
"Move page": "페이지 이동",
|
"Move page": "페이지 이동",
|
||||||
"Move page to a different space.": "페이지를 다른 공간으로 이동합니다.",
|
"Move page to a different space.": "페이지를 다른 공간으로 이동합니다.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "회원인 공간의 공개 공유된 페이지가 여기에 표시됩니다",
|
"Publicly shared pages from spaces you are a member of will appear here": "회원인 공간의 공개 공유된 페이지가 여기에 표시됩니다",
|
||||||
"Share deleted successfully": "공유가 성공적으로 삭제되었습니다",
|
"Share deleted successfully": "공유가 성공적으로 삭제되었습니다",
|
||||||
"Share not found": "공유를 찾을 수 없습니다",
|
"Share not found": "공유를 찾을 수 없습니다",
|
||||||
"Failed to share page": "페이지 공유에 실패했습니다",
|
"Failed to share page": "페이지 공유에 실패했습니다"
|
||||||
"Disable public sharing": "공유 비활성화",
|
|
||||||
"Prevent members from sharing pages publicly.": "멤버들이 페이지를 공개적으로 공유하지 못하도록 방지하십시오.",
|
|
||||||
"Toggle public sharing": "공유 전환",
|
|
||||||
"Toggle space public sharing": "공간 공유 전환",
|
|
||||||
"Public sharing is disabled at the workspace level": "워크스페이스 수준에서 공유가 비활성화되었습니다.",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "이 공간의 페이지가 공개적으로 공유되지 않도록 방지하십시오.",
|
|
||||||
"Requires an enterprise license": "기업 라이센스가 필요합니다.",
|
|
||||||
"Page permissions": "페이지 권한},{",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "개별 페이지의 조회 및 편집 권한을 제어합니다. 엔터프라이즈 라이선스에서 이용 가능합니다.",
|
|
||||||
"Enable public sharing": "공유 활성화",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "공유를 활성화하시겠습니까? 멤버들이 페이지를 공개적으로 공유할 수 있게 됩니다.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "정말로 공유를 비활성화하시겠습니까? 이 워크스페이스의 모든 기존 공유 링크가 삭제됩니다.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "이 공간의 공유를 활성화하시겠습니까?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "정말로 공유를 비활성화하시겠습니까? 이 공간의 모든 기존 공유 링크가 삭제됩니다.",
|
|
||||||
"Public sharing is disabled": "공유가 비활성화되었습니다.",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "워크스페이스 수준에서 공유가 비활성화되었습니다.",
|
|
||||||
"Public sharing has been disabled for this space.": "이 공간의 공유가 비활성화되었습니다.",
|
|
||||||
"Copy page": "페이지 복사하기",
|
|
||||||
"Copy page to a different space.": "다른 공간으로 페이지 복사하기.",
|
|
||||||
"Page copied successfully": "페이지가 성공적으로 복사되었습니다",
|
|
||||||
"Page duplicated successfully": "페이지가 성공적으로 복제되었습니다",
|
|
||||||
"Find": "찾기",
|
|
||||||
"Not found": "찾을 수 없음",
|
|
||||||
"Previous Match (Shift+Enter)": "이전 일치 항목 (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "다음 일치 항목 (Enter)",
|
|
||||||
"Match case (Alt+C)": "대소문자 구분 (Alt+C)",
|
|
||||||
"Replace": "교체",
|
|
||||||
"Close (Escape)": "닫기 (Escape)",
|
|
||||||
"Replace (Enter)": "교체 (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "모두 교체하기 (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "모두 교체하기",
|
|
||||||
"View all spaces": "모든 공간 보기",
|
|
||||||
"Error": "오류",
|
|
||||||
"Failed to disable MFA": "MFA 비활성화 실패",
|
|
||||||
"Disable two-factor authentication": "이중 인증 비활성화",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "이중 인증을 비활성화하면 계정의 보안이 낮아집니다. 로그인 시 비밀번호만 필요하게 됩니다.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "이중 인증 비활성화를 위해 비밀번호를 입력하세요:",
|
|
||||||
"Two-factor authentication has been enabled": "이중 인증이 활성화되었습니다",
|
|
||||||
"Two-factor authentication has been disabled": "이중 인증이 비활성화되었습니다",
|
|
||||||
"2-step verification": "2단계 인증",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "로그인 시 추가 인증 단계를 통해 계정을 보호하세요.",
|
|
||||||
"Two-factor authentication is active on your account.": "이중 인증이 계정에 활성화되어 있습니다.",
|
|
||||||
"Add 2FA method": "2FA 방법 추가",
|
|
||||||
"Backup codes": "백업 코드",
|
|
||||||
"Disable": "비활성화",
|
|
||||||
"Invalid verification code": "유효하지 않은 인증 코드",
|
|
||||||
"New backup codes have been generated": "새 백업 코드가 생성되었습니다",
|
|
||||||
"Failed to regenerate backup codes": "백업 코드 재생성 실패",
|
|
||||||
"About backup codes": "백업 코드에 대하여",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "인증 앱에 접근할 수 없게 된 경우, 백업 코드를 사용하여 계정에 접근할 수 있습니다. 각 코드는 한 번만 사용할 수 있습니다.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "언제든지 새 백업 코드를 재생성할 수 있습니다. 이 작업은 기존 모든 코드를 무효화합니다.",
|
|
||||||
"Confirm password": "비밀번호 확인",
|
|
||||||
"Generate new backup codes": "새 백업 코드 생성하기",
|
|
||||||
"Save your new backup codes": "새 백업 코드 저장하기",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "이 코드를 안전한 장소에 저장하세요. 이전 백업 코드는 더 이상 유효하지 않습니다.",
|
|
||||||
"Your new backup codes": "새 백업 코드",
|
|
||||||
"I've saved my backup codes": "백업 코드를 저장했습니다",
|
|
||||||
"Failed to setup MFA": "MFA 설정 실패",
|
|
||||||
"Setup & Verify": "설정 및 확인",
|
|
||||||
"Add to authenticator": "인증앱에 추가",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. 인증앱으로 이 QR 코드를 스캔하십시오.",
|
|
||||||
"Can't scan the code?": "코드를 스캔할 수 없습니까?",
|
|
||||||
"Enter this code manually in your authenticator app:": "이 코드를 인증앱에 수동으로 입력해 주세요:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. 인증앱에서 6자리 코드를 입력하십시오",
|
|
||||||
"Verify and enable": "확인 및 활성화",
|
|
||||||
"Failed to generate QR code. Please try again.": "QR 코드 생성 실패. 다시 시도해 주세요.",
|
|
||||||
"Backup": "백업",
|
|
||||||
"Save codes": "코드 저장",
|
|
||||||
"Save your backup codes": "백업 코드 저장하기",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "인증 앱에 대한 접근 권한을 잃은 경우, 이 코드를 사용하여 귀하의 계정에 접근할 수 있습니다. 각 코드는 한 번만 사용할 수 있습니다.",
|
|
||||||
"Print": "인쇄",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "이중 인증이 설정되었습니다. 다시 로그인해 주세요.",
|
|
||||||
"Two-Factor authentication required": "이중 인증 필요",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "워크스페이스에서는 모든 사용자에게 이중 인증이 필요합니다.",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "워크스페이스 접근을 계속하려면 이중 인증을 설정해야 합니다. 이는 계정에 추가 보안 계층을 추가합니다.",
|
|
||||||
"Set up two-factor authentication": "이중 인증 설정하기",
|
|
||||||
"Cancel and logout": "취소 및 로그아웃",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "워크스페이스에서는 이중 인증이 필요합니다. 계속하려면 설정해 주세요.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "인증앱에서 얻은 인증 코드를 요구하여 계정의 보안에 추가적인 계층을 추가합니다.",
|
|
||||||
"Password is required": "비밀번호가 필요합니다",
|
|
||||||
"Password must be at least 8 characters": "비밀번호는 최소 8자 이상이어야 합니다",
|
|
||||||
"Please enter a 6-digit code": "6자리 코드를 입력해 주세요",
|
|
||||||
"Code must be exactly 6 digits": "코드는 정확히 6자리여야 합니다",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "인증앱에서 찾은 6자리 코드를 입력하십시오",
|
|
||||||
"Need help authenticating?": "인증에 도움이 필요하십니까?",
|
|
||||||
"MFA QR Code": "MFA QR 코드",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "계정이 성공적으로 생성되었습니다. 이중 인증을 설정하려면 로그인해 주세요.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "비밀번호 재설정 성공. 새 비밀번호로 로그인하여 이중 인증을 완료하세요.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "비밀번호 재설정 성공. 새 비밀번호로 로그인하여 이중 인증을 설정하세요.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "비밀번호 재설정이 성공적으로 완료되었습니다. 새 비밀번호로 로그인하세요.",
|
|
||||||
"Two-factor authentication": "이중 인증",
|
|
||||||
"Use authenticator app instead": "대신 인증 앱 사용",
|
|
||||||
"Verify backup code": "백업 코드 확인",
|
|
||||||
"Use backup code": "백업 코드 사용",
|
|
||||||
"Enter one of your backup codes": "백업 코드 중 하나를 입력하세요",
|
|
||||||
"Backup code": "백업 코드",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "백업 코드 중 하나를 입력하세요. 각 백업 코드는 한 번만 사용할 수 있습니다.",
|
|
||||||
"Verify": "확인",
|
|
||||||
"Trash": "휴지통",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "휴지통의 페이지는 {{count}}일 후 영구적으로 삭제됩니다.",
|
|
||||||
"Deleted": "삭제됨",
|
|
||||||
"No pages in trash": "휴지통에 페이지가 없습니다",
|
|
||||||
"Permanently delete page?": "페이지를 영구적으로 삭제하시겠습니까?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "'{{title}}'을(를) 영구적으로 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "'{{title}}' 및 하위 페이지를 복구하시겠습니까?",
|
|
||||||
"Move to trash": "휴지통으로 이동",
|
|
||||||
"Move this page to trash?": "이 페이지를 휴지통으로 이동하시겠습니까?",
|
|
||||||
"Restore page": "페이지 복구",
|
|
||||||
"Page moved to trash": "페이지가 휴지통으로 이동되었습니다",
|
|
||||||
"Page restored successfully": "페이지가 성공적으로 복구되었습니다",
|
|
||||||
"Deleted by": "삭제자",
|
|
||||||
"Deleted at": "삭제 시간",
|
|
||||||
"Preview": "미리보기",
|
|
||||||
"Subpages": "하위 페이지",
|
|
||||||
"Failed to load subpages": "하위 페이지 로드 실패",
|
|
||||||
"No subpages": "하위 페이지 없음",
|
|
||||||
"Subpages (Child pages)": "하위 페이지 (자식 페이지)",
|
|
||||||
"List all subpages of the current page": "현재 페이지의 모든 하위 페이지 목록",
|
|
||||||
"Attachments": "첨부 파일",
|
|
||||||
"All spaces": "전체 공간",
|
|
||||||
"Unknown": "알 수 없음",
|
|
||||||
"Find a space": "공간 찾기",
|
|
||||||
"Search in all your spaces": "모든 공간에서 검색",
|
|
||||||
"Type": "유형",
|
|
||||||
"Enterprise": "기업",
|
|
||||||
"Download attachment": "첨부 파일 다운로드",
|
|
||||||
"Allowed email domains": "허용된 이메일 도메인",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "이 도메인의 이메일 주소를 가진 사용자만 SSO를 통해 가입할 수 있습니다.",
|
|
||||||
"Enter valid domain names separated by comma or space": "콤마 또는 공백으로 구분하여 유효한 도메인 이름 입력",
|
|
||||||
"Enforce two-factor authentication": "이중 인증 시행",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "시행되면 모든 멤버가 작업 공간에 액세스하기 위해 이중 인증을 활성화해야 합니다.",
|
|
||||||
"Toggle MFA enforcement": "MFA 시행 전환",
|
|
||||||
"Display name": "표시 이름",
|
|
||||||
"Allow signup": "가입 허용",
|
|
||||||
"Enabled": "활성화됨",
|
|
||||||
"Advanced Settings": "고급 설정",
|
|
||||||
"Enable TLS/SSL": "TLS\\/SSL 활성화",
|
|
||||||
"Use secure connection to LDAP server": "LDAP 서버에 안전한 연결 사용",
|
|
||||||
"Group sync": "그룹 동기화",
|
|
||||||
"No SSO providers found.": "SSO 제공자를 찾을 수 없습니다.",
|
|
||||||
"Delete SSO provider": "SSO 제공자 삭제",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "이 SSO 제공자를 삭제하시겠습니까?",
|
|
||||||
"Action": "작업",
|
|
||||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} 구성",
|
|
||||||
"Icon": "아이콘",
|
|
||||||
"Upload image": "이미지 업로드",
|
|
||||||
"Remove image": "이미지 제거",
|
|
||||||
"Failed to remove image": "이미지 제거 실패",
|
|
||||||
"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 키 갱신",
|
|
||||||
"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 키는 관리자와 소유자만 생성할 수 있습니다. 기존 멤버 키는 계속 사용할 수 있습니다.",
|
|
||||||
"Toggle restrict API keys to admins": "API 키 생성 제한(관리자 전용) 설정 전환",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "API 키 생성이 워크스페이스 관리자로 인해 관리자에게만 제한되었습니다.",
|
|
||||||
"AI settings": "AI 설정",
|
|
||||||
"AI search": "AI 검색",
|
|
||||||
"AI Answer": "AI 답변",
|
|
||||||
"Ask AI": "AI에게 묻기",
|
|
||||||
"AI is thinking...": "AI가 생각 중입니다...",
|
|
||||||
"Ask a question...": "질문하세요...",
|
|
||||||
"AI Answers": "AI 답변",
|
|
||||||
"AI-powered search (AI Answers)": "AI 구동 검색 (AI 답변)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI 검색은 벡터 임베딩을 사용하여 작업공간 콘텐츠에 대한 의미 검색 기능을 제공합니다.",
|
|
||||||
"Toggle AI search": "AI 검색 전환",
|
|
||||||
"Generative AI (Ask AI)": "생성 AI (Ask AI)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "편집기에서 AI 구동 콘텐츠 생성을 활성화합니다. 사용자가 텍스트를 생성, 개선, 번역 및 변환할 수 있습니다.",
|
|
||||||
"Toggle generative AI": "생성 AI 토글",
|
|
||||||
"Enterprise feature": "엔터프라이즈 기능",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "AI는 Docmost 엔터프라이즈 에디션에서만 제공됩니다. sales@docmost.com으로 문의하세요.",
|
|
||||||
"AI & MCP": "AI 및 MCP",
|
|
||||||
"AI": "AI",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "모델 컨텍스트 프로토콜(MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "AI 어시스턴트와 도구가 워크스페이스 콘텐츠와 상호작용할 수 있도록 MCP 서버를 활성화하세요.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP는 Docmost 엔터프라이즈 에디션에서만 제공됩니다. sales@docmost.com으로 문의하세요.",
|
|
||||||
"MCP documentation": "MCP 문서",
|
|
||||||
"MCP Server URL": "MCP 서버 URL",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "인증을 위해 API 키를 사용하세요. API 키는 계정 설정에서 관리할 수 있습니다.",
|
|
||||||
"Supported tools": "지원되는 도구",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "워크스페이스에 MCP가 활성화되어 있습니다. AI 어시스턴트를 연결하려면 API 키를 사용하세요.",
|
|
||||||
"MCP server URL:": "MCP 서버 URL:",
|
|
||||||
"Learn more": "자세히 알아보기",
|
|
||||||
"View the": "다음을",
|
|
||||||
"for usage details.": "에서 사용 방법을 확인하세요.",
|
|
||||||
"for setup instructions.": "에서 설정 지침을 확인하세요.",
|
|
||||||
"API documentation": "API 문서",
|
|
||||||
"Sources": "출처",
|
|
||||||
"AI Answers not available for attachments": "첨부 파일에 대해 AI 답변을 사용할 수 없습니다",
|
|
||||||
"No answer available": "답변을 제공할 수 없습니다",
|
|
||||||
"Background color": "배경 색",
|
|
||||||
"Highlight color": "강조 색",
|
|
||||||
"Remove color": "색 제거",
|
|
||||||
"Notifications": "알림",
|
|
||||||
"No notifications": "알림 없음",
|
|
||||||
"No unread notifications": "읽지 않은 알림 없음",
|
|
||||||
"All notifications": "모든 알림",
|
|
||||||
"Unread only": "읽지 않음만",
|
|
||||||
"Mark all as read": "모두 읽음으로 표시",
|
|
||||||
"Mark as read": "읽음으로 표시",
|
|
||||||
"More options": "추가 옵션",
|
|
||||||
"mentioned you in a comment": "댓글에서 당신을 언급했습니다",
|
|
||||||
"commented on a page": "페이지에 댓글을 달았습니다",
|
|
||||||
"resolved a comment": "댓글을 해결했습니다",
|
|
||||||
"mentioned you on a page": "페이지에서 당신을 언급했습니다",
|
|
||||||
"gave you edit access to a page": "페이지 편집 권한을 부여했습니다",
|
|
||||||
"gave you view access to a page": "페이지 보기 권한을 부여했습니다",
|
|
||||||
"Today": "오늘",
|
|
||||||
"Yesterday": "어제",
|
|
||||||
"This week": "이번 주",
|
|
||||||
"Older": "이전",
|
|
||||||
"Restricted page": "제한된 페이지",
|
|
||||||
"Restricted pages cannot be shared publicly.": "제한된 페이지는 공개적으로 공유할 수 없습니다.",
|
|
||||||
"Restricted by parent": "상위 페이지에 의해 제한됨",
|
|
||||||
"Restricted": "제한됨",
|
|
||||||
"Open": "공개",
|
|
||||||
"Inherits restrictions from ancestor page": "상위 페이지로부터 제한을 상속함",
|
|
||||||
"Only people listed below can access this page": "아래에 나열된 사용자만 이 페이지에 접근할 수 있습니다.",
|
|
||||||
"Everyone in this space can access": "이 공간의 모든 사용자가 접근할 수 있습니다.",
|
|
||||||
"No additional restrictions on this page": "이 페이지에는 추가 제한이 없습니다.",
|
|
||||||
"Only specific people can access": "특정 사용자만 접근할 수 있습니다.",
|
|
||||||
"Use only inherited restrictions": "상속된 제한만 사용",
|
|
||||||
"Add restrictions on top of inherited": "상속된 제한 위에 추가 제한 적용",
|
|
||||||
"Inherited restriction": "상속된 제한",
|
|
||||||
"Access limited by": "접근 제한:",
|
|
||||||
"Restrict access to control who can view and edit this page": "이 페이지를 누가 조회하고 편집할 수 있는지 제어하려면 접근을 제한하세요.",
|
|
||||||
"Add additional restrictions specific to this page": "이 페이지에 대한 추가 제한을 적용하세요.",
|
|
||||||
"Access": "접근",
|
|
||||||
"People with access": "접근 권한이 있는 사용자",
|
|
||||||
"Remove all": "모두 제거",
|
|
||||||
"Remove access": "접근 권한 제거",
|
|
||||||
"Remove all access": "모든 접근 권한 제거",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "이 멤버의 페이지 접근 권한을 제거하시겠습니까?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "모든 특정 접근 권한을 제거하시겠습니까? 이렇게 하면 페이지가 공간의 모든 사용자에게 공개됩니다.",
|
|
||||||
"Trash retention": "휴지통 보관 기간",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "이 기간이 지나면 휴지통의 페이지는 영구적으로 삭제됩니다.",
|
|
||||||
"Trash retention updated": "휴지통 보관 기간이 업데이트되었습니다.",
|
|
||||||
"Failed to update trash retention": "휴지통 보관 기간 업데이트에 실패했습니다.",
|
|
||||||
"Removed page restriction": "페이지 제한이 제거됨",
|
|
||||||
"Added page permission": "페이지 권한이 추가됨",
|
|
||||||
"Removed page permission": "페이지 권한이 제거됨"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,13 +29,12 @@
|
|||||||
"Choose your preferred interface language.": "Kies uw gewenste interfacetaal.",
|
"Choose your preferred interface language.": "Kies uw gewenste interfacetaal.",
|
||||||
"Choose your preferred page width.": "Kies uw gewenste paginabreedte.",
|
"Choose your preferred page width.": "Kies uw gewenste paginabreedte.",
|
||||||
"Confirm": "Bevestig",
|
"Confirm": "Bevestig",
|
||||||
"Copy as Markdown": "Kopiëren als Markdown",
|
|
||||||
"Copy link": "Link kopiëren",
|
"Copy link": "Link kopiëren",
|
||||||
"Create": "Aanmaken",
|
"Create": "Aanmaken",
|
||||||
"Create group": "Groep aanmaken",
|
"Create group": "Groep aanmaken",
|
||||||
"Create page": "Pagina aanmaken",
|
"Create page": "Pagina aanmaken",
|
||||||
"Create space": "Ruimte aanmaken",
|
"Create space": "Ruimte aanmaken",
|
||||||
"Create workspace": "Werkruimte aanmaken",
|
"Create workspace": "Wwerkruimte aanmaken",
|
||||||
"Current password": "Huidig wachtwoord",
|
"Current password": "Huidig wachtwoord",
|
||||||
"Dark": "Donker",
|
"Dark": "Donker",
|
||||||
"Date": "Datum",
|
"Date": "Datum",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "bijv. Ruimte voor productteam",
|
"e.g Space for product team": "bijv. Ruimte voor productteam",
|
||||||
"e.g Space for sales team to collaborate": "bijv. Ruimte voor verkoopteam om samen te werken",
|
"e.g Space for sales team to collaborate": "bijv. Ruimte voor verkoopteam om samen te werken",
|
||||||
"Edit": "Bewerken",
|
"Edit": "Bewerken",
|
||||||
"Read": "Lezen",
|
|
||||||
"Edit group": "Groep bewerken",
|
"Edit group": "Groep bewerken",
|
||||||
"Email": "E-mailadres",
|
"Email": "E-mailadres",
|
||||||
"Enter a strong password": "Voer een sterk wachtwoord in",
|
"Enter a strong password": "Voer een sterk wachtwoord in",
|
||||||
@@ -92,7 +90,7 @@
|
|||||||
"Invite by email": "Uitnodigen via e-mail",
|
"Invite by email": "Uitnodigen via e-mail",
|
||||||
"Invite members": "Leden uitnodigen",
|
"Invite members": "Leden uitnodigen",
|
||||||
"Invite new members": "Nieuwe leden uitnodigen",
|
"Invite new members": "Nieuwe leden uitnodigen",
|
||||||
"Invited members who are yet to accept their invitation will appear here.": "Uitgenodigde leden die hun uitnodiging nog moeten accepteren zullen hier worden getoond.",
|
"Invited members who are yet to accept their invitation will appear here.": "Uigenodigde leden die hun uitnodiging nog moeten accepteren zullen hier worden getoond.",
|
||||||
"Invited members will be granted access to spaces the groups can access": "Uitgenodigde leden wordt toegang gegeven tot ruimtes de groepen toegang toe heeft",
|
"Invited members will be granted access to spaces the groups can access": "Uitgenodigde leden wordt toegang gegeven tot ruimtes de groepen toegang toe heeft",
|
||||||
"Join the workspace": "Word lid van de werkruimte",
|
"Join the workspace": "Word lid van de werkruimte",
|
||||||
"Language": "Taal",
|
"Language": "Taal",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "Geen groep gevonden",
|
"No group found": "Geen groep gevonden",
|
||||||
"No page history saved yet.": "Er is nog geen pagina geschiedenis opgeslagen.",
|
"No page history saved yet.": "Er is nog geen pagina geschiedenis opgeslagen.",
|
||||||
"No pages yet": "Nog geen pagina's",
|
"No pages yet": "Nog geen pagina's",
|
||||||
"No shared pages": "Geen gedeelde pagina's",
|
|
||||||
"No results found...": "Geen resultaten gevonden...",
|
"No results found...": "Geen resultaten gevonden...",
|
||||||
"No user found": "Geen gebruiker gevonden",
|
"No user found": "Geen gebruiker gevonden",
|
||||||
"Overview": "Overzicht",
|
"Overview": "Overzicht",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "pagina",
|
"page": "pagina",
|
||||||
"Page deleted successfully": "Pagina succesvol verwijderd",
|
"Page deleted successfully": "Pagina succesvol verwijderd",
|
||||||
"Page history": "Pagina geschiedenis",
|
"Page history": "Pagina geschiedenis",
|
||||||
"Select version": "Selecteer versie",
|
|
||||||
"Highlight changes": "Wijzigingen markeren",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "Importeren van pagina's is bezig. Sluit dit tabblad niet.",
|
"Page import is in progress. Please do not close this tab.": "Importeren van pagina's is bezig. Sluit dit tabblad niet.",
|
||||||
"Pages": "Pagina's",
|
"Pages": "Pagina's",
|
||||||
"pages": "pagina's",
|
"pages": "pagina's",
|
||||||
"Password": "Wachtwoord",
|
"Password": "Wachtwoord",
|
||||||
"Password changed successfully": "Wachtwoord met succes gewijzigd",
|
"Password changed successfully": "Wachtwoord met succes gewijzigd",
|
||||||
"People": "Personen",
|
|
||||||
"Pending": "Wachtende",
|
"Pending": "Wachtende",
|
||||||
"Please confirm your action": "Bevestig alstublieft uw actie",
|
"Please confirm your action": "Bevestig alstublieft uw actie",
|
||||||
"Preferences": "Voorkeuren",
|
"Preferences": "Voorkeuren",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Antwoord...",
|
"Reply...": "Antwoord...",
|
||||||
"Error loading comments.": "Fout bij het laden van reacties.",
|
"Error loading comments.": "Fout bij het laden van reacties.",
|
||||||
"No comments yet.": "Nog geen reacties.",
|
"No comments yet.": "Nog geen reacties.",
|
||||||
"No open comments.": "Geen openstaande opmerkingen.",
|
|
||||||
"No resolved comments.": "Geen opgeloste reacties.",
|
|
||||||
"Add a comment...": "Voeg een opmerking toe...",
|
|
||||||
"Edit comment": "Bewerk reactie",
|
"Edit comment": "Bewerk reactie",
|
||||||
"Delete comment": "Verwijder reactie",
|
"Delete comment": "Verwijder reactie",
|
||||||
"Are you sure you want to delete this comment?": "Weet je zeker dat je deze reactie wilt verwijderen?",
|
"Are you sure you want to delete this comment?": "Weet je zeker dat je deze reactie wilt verwijderen?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Reactie met succes verwijderd",
|
"Comment deleted successfully": "Reactie met succes verwijderd",
|
||||||
"Failed to delete comment": "Verwijderen van reactie mislukt",
|
"Failed to delete comment": "Verwijderen van reactie mislukt",
|
||||||
"Comment resolved successfully": "Reactie succesvol opgelost",
|
"Comment resolved successfully": "Reactie succesvol opgelost",
|
||||||
"Comment re-opened successfully": "Reactie succesvol heropend",
|
|
||||||
"Comment unresolved successfully": "Reactie succesvol niet-opgelost gemaakt",
|
|
||||||
"Failed to resolve comment": "Reactie oplossen mislukt",
|
"Failed to resolve comment": "Reactie oplossen mislukt",
|
||||||
"Resolve comment": "Reactie oplossen",
|
|
||||||
"Unresolve comment": "Reactie niet oplossen",
|
|
||||||
"Resolve Comment Thread": "Reactiedraad oplossen",
|
|
||||||
"Unresolve Comment Thread": "Reactiedraad niet oplossen",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Weet u zeker dat u deze reactiedraad wilt oplossen? Dit zal het als voltooid markeren.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Weet u zeker dat u deze reactiedraad niet wilt oplossen?",
|
|
||||||
"Resolved": "Opgelost",
|
|
||||||
"No active comments.": "Geen actieve reacties.",
|
|
||||||
"Revoke invitation": "Uitnodiging intrekken",
|
"Revoke invitation": "Uitnodiging intrekken",
|
||||||
"Revoke": "Intrekken",
|
"Revoke": "Intrekken",
|
||||||
"Don't": "Niet doen",
|
"Don't": "Niet doen",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Iedereen met deze link kan zich aansluiten bij deze werkruimte.",
|
"Anyone with this link can join this workspace.": "Iedereen met deze link kan zich aansluiten bij deze werkruimte.",
|
||||||
"Invite link": "Uitnodigingslink",
|
"Invite link": "Uitnodigingslink",
|
||||||
"Copy": "Kopieer",
|
"Copy": "Kopieer",
|
||||||
"Copy to space": "Kopiëren naar ruimte",
|
|
||||||
"Copied": "Gekopieerd",
|
"Copied": "Gekopieerd",
|
||||||
"Duplicate": "Dupliceren",
|
|
||||||
"Select a user": "Selecteer een gebruiker",
|
"Select a user": "Selecteer een gebruiker",
|
||||||
"Select a group": "Selecteer een groep",
|
"Select a group": "Selecteer een groep",
|
||||||
"Export all pages and attachments in this space.": "Exporteer alle pagina's en bijlagen in deze ruimte.",
|
"Export all pages and attachments in this space.": "Exporteer alle pagina's en bijlagen in deze ruimte.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Exporteren mislukt:",
|
"Export failed:": "Exporteren mislukt:",
|
||||||
"export error": "Exporteer fout",
|
"export error": "Exporteer fout",
|
||||||
"Export page": "Exporteer pagina",
|
"Export page": "Exporteer pagina",
|
||||||
"Export successful": "Export succesvol",
|
|
||||||
"Export space": "Exporteer ruimte",
|
"Export space": "Exporteer ruimte",
|
||||||
"Export {{type}}": "Exporteer {{type}}",
|
"Export {{type}}": "Exporteer {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "Bestand overschrijdt de bijlagelimiet van {{limit}}",
|
"File exceeds the {{limit}} attachment limit": "Bestand overschrijdt de bijlagelimiet van {{limit}}",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Rij hieronder toevoegen",
|
"Add row below": "Rij hieronder toevoegen",
|
||||||
"Delete table": "Verwijder tabel",
|
"Delete table": "Verwijder tabel",
|
||||||
"Info": "Info",
|
"Info": "Info",
|
||||||
"Note": "Opmerking",
|
|
||||||
"Success": "Geslaagd",
|
"Success": "Geslaagd",
|
||||||
"Warning": "Waarschuwing",
|
"Warning": "Waarschuwing",
|
||||||
"Danger": "Gevaar",
|
"Danger": "Gevaar",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Upload een afbeelding vanaf uw apparaat.",
|
"Upload any image from your device.": "Upload een afbeelding vanaf uw apparaat.",
|
||||||
"Upload any video from your device.": "Upload een video vanaf uw apparaat.",
|
"Upload any video from your device.": "Upload een video vanaf uw apparaat.",
|
||||||
"Upload any file from your device.": "Upload een bestand vanaf uw apparaat.",
|
"Upload any file from your device.": "Upload een bestand vanaf uw apparaat.",
|
||||||
"Uploading {{name}}": "Uploaden {{name}}",
|
|
||||||
"Uploading file": "Bestand uploaden",
|
|
||||||
"Table": "Tabel",
|
"Table": "Tabel",
|
||||||
"Insert a table.": "Voeg een tabel in.",
|
"Insert a table.": "Voeg een tabel in.",
|
||||||
"Insert collapsible block.": "Inklapbaar blok invoegen.",
|
"Insert collapsible block.": "Inklapbaar blok invoegen.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Huidige datum invoeren",
|
"Insert current date": "Huidige datum invoeren",
|
||||||
"Draw and sketch excalidraw diagrams": "Teken en schets excalidraw diagrammen",
|
"Draw and sketch excalidraw diagrams": "Teken en schets excalidraw diagrammen",
|
||||||
"Multiple": "Meerdere",
|
"Multiple": "Meerdere",
|
||||||
"Turn into": "Omzetten naar",
|
|
||||||
"Text align": "Tekstuitlijning",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Deze pagina is mogelijk verwijderd of verplaatst, of u heeft er geen toegang toe.",
|
|
||||||
"Go to homepage": "Ga naar de startpagina",
|
|
||||||
"Pages you create will show up here.": "Pagina's die u aanmaakt, verschijnen hier.",
|
|
||||||
"Heading {{level}}": "Kop {{level}}",
|
"Heading {{level}}": "Kop {{level}}",
|
||||||
"Toggle title": "Schakel titel in/uit",
|
"Toggle title": "Schakel titel in/uit",
|
||||||
"Write anything. Enter \"/\" for commands": "Schrijf iets. Voer \"/\" in voor commando's",
|
"Write anything. Enter \"/\" for commands": "Schrijf iets. Voer \"/\" in voor commando's",
|
||||||
"Write...": "Typ...",
|
|
||||||
"Column count": "Aantal kolommen",
|
|
||||||
"{{count}} Columns": "{{count}} kolommen",
|
|
||||||
"Equal columns": "Gelijke kolommen",
|
|
||||||
"Left sidebar": "Linker zijbalk",
|
|
||||||
"Right sidebar": "Rechter zijbalk",
|
|
||||||
"Wide center": "Brede middenkolom",
|
|
||||||
"Left wide": "Brede linkerkolom",
|
|
||||||
"Right wide": "Brede rechterkolom",
|
|
||||||
"Names do not match": "Namen komen niet overeen",
|
"Names do not match": "Namen komen niet overeen",
|
||||||
"Today, {{time}}": "Vandaag, {{time}}",
|
"Today, {{time}}": "Vandaag, {{time}}",
|
||||||
"Yesterday, {{time}}": "Gisteren, {{time}}",
|
"Yesterday, {{time}}": "Gisteren, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Aantal tekens: {{characterCount}}",
|
"Character count: {{characterCount}}": "Aantal tekens: {{characterCount}}",
|
||||||
"New update": "Nieuwe update",
|
"New update": "Nieuwe update",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} is beschikbaar",
|
"{{latestVersion}} is available": "{{latestVersion}} is beschikbaar",
|
||||||
"Default page edit mode": "Standaard pagina bewerkmodus",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Kies uw voorkeurs bewerkmodus voor pagina's. Vermijd per ongeluk bewerken.",
|
|
||||||
"Reading": "Lezen",
|
|
||||||
"Delete member": "Verwijder lid",
|
"Delete member": "Verwijder lid",
|
||||||
"Member deleted successfully": "Lid succesvol verwijderd",
|
"Member deleted successfully": "Lid succesvol verwijderd",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Weet u zeker dat u dit lid van de werkruimte wilt verwijderen? Deze actie kan niet ongedaan gemaakt worden.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Weet u zeker dat u dit lid van de werkruimte wilt verwijderen? Deze actie kan niet ongedaan gemaakt worden.",
|
||||||
"Deactivate member": "Lid deactiveren",
|
|
||||||
"Activate member": "Lid activeren",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Weet u zeker dat u dit lid van de werkruimte wilt deactiveren? Deze persoon heeft daarna geen toegang meer tot deze werkruimte.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Weet u zeker dat u dit lid van de werkruimte wilt activeren?",
|
|
||||||
"Deactivate": "Deactiveren",
|
|
||||||
"Activate": "Activeren",
|
|
||||||
"Deactivated": "Gedeactiveerd",
|
|
||||||
"Move": "Verplaatsen",
|
"Move": "Verplaatsen",
|
||||||
"Move page": "Pagina verplaatsen",
|
"Move page": "Pagina verplaatsen",
|
||||||
"Move page to a different space.": "Verplaats pagina naar een andere ruimte.",
|
"Move page to a different space.": "Verplaats pagina naar een andere ruimte.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Openbaar gedeelde pagina's van ruimtes waarvan u lid bent, verschijnen hier",
|
"Publicly shared pages from spaces you are a member of will appear here": "Openbaar gedeelde pagina's van ruimtes waarvan u lid bent, verschijnen hier",
|
||||||
"Share deleted successfully": "Delen succesvol verwijderd",
|
"Share deleted successfully": "Delen succesvol verwijderd",
|
||||||
"Share not found": "Delen niet gevonden",
|
"Share not found": "Delen niet gevonden",
|
||||||
"Failed to share page": "Pagina delen mislukt",
|
"Failed to share page": "Pagina delen mislukt"
|
||||||
"Disable public sharing": "Openbaar delen uitschakelen",
|
|
||||||
"Prevent members from sharing pages publicly.": "Voorkom dat leden pagina's openbaar delen.",
|
|
||||||
"Toggle public sharing": "Wissel openbaar delen",
|
|
||||||
"Toggle space public sharing": "Wissel openbaar delen van ruimte",
|
|
||||||
"Public sharing is disabled at the workspace level": "Openbaar delen is uitgeschakeld op werkruimteniveau",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Voorkom dat pagina's in deze ruimte openbaar worden gedeeld.",
|
|
||||||
"Requires an enterprise license": "Vereist een bedrijfslicentie",
|
|
||||||
"Page permissions": "Pagina rechten",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Beheer wie individuele pagina's kan bekijken en bewerken. Beschikbaar met een Enterprise-licentie.",
|
|
||||||
"Enable public sharing": "Openbaar delen inschakelen",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Weet je zeker dat je openbaar delen wilt inschakelen? Leden kunnen pagina's openbaar delen.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Weet je zeker dat je openbaar delen wilt uitschakelen? Alle bestaande gedeelde links in deze werkruimte zullen worden verwijderd.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Weet je zeker dat je openbaar delen voor deze ruimte wilt inschakelen?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Weet je zeker dat je openbaar delen wilt uitschakelen? Alle bestaande gedeelde links in deze ruimte zullen worden verwijderd.",
|
|
||||||
"Public sharing is disabled": "Openbaar delen is uitgeschakeld",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "Openbaar delen is uitgeschakeld op werkruimteniveau.",
|
|
||||||
"Public sharing has been disabled for this space.": "Openbaar delen is uitgeschakeld voor deze ruimte.",
|
|
||||||
"Copy page": "Pagina kopiëren",
|
|
||||||
"Copy page to a different space.": "Kopieer pagina naar een andere ruimte.",
|
|
||||||
"Page copied successfully": "Pagina succesvol gekopieerd",
|
|
||||||
"Page duplicated successfully": "Pagina succesvol gedupliceerd",
|
|
||||||
"Find": "Zoeken",
|
|
||||||
"Not found": "Niet gevonden",
|
|
||||||
"Previous Match (Shift+Enter)": "Vorige overeenkomst (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Volgende overeenkomst (Enter)",
|
|
||||||
"Match case (Alt+C)": "Hoofdlettergevoeligheid (Alt+C)",
|
|
||||||
"Replace": "Vervangen",
|
|
||||||
"Close (Escape)": "Sluiten (Escape)",
|
|
||||||
"Replace (Enter)": "Vervangen (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Alles vervangen (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Alles vervangen",
|
|
||||||
"View all spaces": "Bekijk alle ruimtes",
|
|
||||||
"Error": "Fout",
|
|
||||||
"Failed to disable MFA": "MFA uitschakelen mislukt",
|
|
||||||
"Disable two-factor authentication": "Twee-factor authenticatie uitschakelen",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Indien u twee-factor authenticatie uitschakelt, zal uw account minder veilig zijn. U heeft alleen uw wachtwoord nodig om in te loggen.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Voer uw wachtwoord in om twee-factor authenticatie uit te schakelen:",
|
|
||||||
"Two-factor authentication has been enabled": "Twee-factor authenticatie is ingeschakeld",
|
|
||||||
"Two-factor authentication has been disabled": "Twee-factor authenticatie is uitgeschakeld",
|
|
||||||
"2-step verification": "2-staps verificatie",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Bescherm uw account met een extra verificatielaag tijdens het inloggen.",
|
|
||||||
"Two-factor authentication is active on your account.": "Twee-factor authenticatie is actief op uw account.",
|
|
||||||
"Add 2FA method": "2FA-methode toevoegen",
|
|
||||||
"Backup codes": "Back-up codes",
|
|
||||||
"Disable": "Uitschakelen",
|
|
||||||
"Invalid verification code": "Ongeldige verificatiecode",
|
|
||||||
"New backup codes have been generated": "Nieuwe back-up codes zijn gegenereerd",
|
|
||||||
"Failed to regenerate backup codes": "Back-up codes opnieuw genereren mislukt",
|
|
||||||
"About backup codes": "Over back-up codes",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Back-up codes kunnen worden gebruikt om uw account te bereiken als u toegang tot uw authenticator-app verliest. Elke code kan slechts één keer worden gebruikt.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "U kunt te allen tijde nieuwe back-up codes genereren. Dit zal alle bestaande codes ongeldig maken.",
|
|
||||||
"Confirm password": "Bevestig wachtwoord",
|
|
||||||
"Generate new backup codes": "Genereer nieuwe back-up codes",
|
|
||||||
"Save your new backup codes": "Sla uw nieuwe back-up codes op",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Zorg ervoor dat u deze codes op een veilige plek opslaat. Uw oude back-up codes zijn niet langer geldig.",
|
|
||||||
"Your new backup codes": "Uw nieuwe back-up codes",
|
|
||||||
"I've saved my backup codes": "Ik heb mijn back-up codes opgeslagen",
|
|
||||||
"Failed to setup MFA": "MFA instellen mislukt",
|
|
||||||
"Setup & Verify": "Instellen & Verifiëren",
|
|
||||||
"Add to authenticator": "Toevoegen aan de authenticator",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Scan deze QR-code met uw authenticator-app",
|
|
||||||
"Can't scan the code?": "Kan de code niet scannen?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Voer deze code handmatig in uw authenticator-app in:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Voer de 6-cijferige code van uw authenticator in",
|
|
||||||
"Verify and enable": "Verifiëren en inschakelen",
|
|
||||||
"Failed to generate QR code. Please try again.": "Het genereren van de QR-code is mislukt. Probeer het opnieuw.",
|
|
||||||
"Backup": "Back-up",
|
|
||||||
"Save codes": "Codes opslaan",
|
|
||||||
"Save your backup codes": "Sla uw back-up codes op",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Deze codes kunnen worden gebruikt om toegang te krijgen tot uw account als u de toegang tot uw authenticator-app verliest. Elke code kan slechts één keer worden gebruikt.",
|
|
||||||
"Print": "Afdrukken",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "Twee-factor authenticatie is ingesteld. Log alstublieft opnieuw in.",
|
|
||||||
"Two-Factor authentication required": "Twee-factor authenticatie vereist",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Uw werkruimte vereist twee-factor authenticatie voor alle gebruikers",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Om toegang te blijven krijgen tot uw werkruimte, moet u twee-factor authenticatie instellen. Dit voegt een extra beveiligingslaag toe aan uw account.",
|
|
||||||
"Set up two-factor authentication": "Stel twee-factor authenticatie in",
|
|
||||||
"Cancel and logout": "Annuleren en uitloggen",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Uw werkruimte vereist twee-factor authenticatie. Stel het in om door te gaan.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Dit voegt een extra beveiligingslaag toe aan uw account door een verificatiecode van uw authenticator-app te vereisen.",
|
|
||||||
"Password is required": "Wachtwoord is vereist",
|
|
||||||
"Password must be at least 8 characters": "Wachtwoord moet minimaal 8 tekens zijn",
|
|
||||||
"Please enter a 6-digit code": "Voer alstublieft een 6-cijferige code in",
|
|
||||||
"Code must be exactly 6 digits": "Code moet exact 6 cijfers zijn",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Voer de 6-cijferige code in die in uw authenticator-app staat",
|
|
||||||
"Need help authenticating?": "Hulp nodig bij het authenticeren?",
|
|
||||||
"MFA QR Code": "MFA QR-code",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Account succesvol aangemaakt. Log alstublieft in om twee-factor authenticatie in te stellen.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Wachtwoord reset succesvol. Log in met uw nieuwe wachtwoord en voltooi twee-factor authenticatie.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Wachtwoord reset succesvol. Log in met uw nieuwe wachtwoord om twee-factor authenticatie in te stellen.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "De wachtwoord reset was succesvol. Log in met uw nieuwe wachtwoord.",
|
|
||||||
"Two-factor authentication": "Twee-factor authenticatie",
|
|
||||||
"Use authenticator app instead": "Gebruik in plaats daarvan de authenticator-app",
|
|
||||||
"Verify backup code": "Back-up code verifiëren",
|
|
||||||
"Use backup code": "Gebruik back-up code",
|
|
||||||
"Enter one of your backup codes": "Voer een van uw back-up codes in",
|
|
||||||
"Backup code": "Back-up code",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Voer een van uw back-up codes in. Elke back-up code kan slechts één keer worden gebruikt.",
|
|
||||||
"Verify": "Verifiëren",
|
|
||||||
"Trash": "Prullenbak",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "Pagina's in de prullenbak worden na {{count}} dagen permanent verwijderd.",
|
|
||||||
"Deleted": "Verwijderd",
|
|
||||||
"No pages in trash": "Geen pagina's in de prullenbak",
|
|
||||||
"Permanently delete page?": "Pagina permanent verwijderen?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Weet u zeker dat u '{{title}}' permanent wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "'{{title}}' en zijn subpagina's herstellen?",
|
|
||||||
"Move to trash": "Naar de prullenbak verplaatsen",
|
|
||||||
"Move this page to trash?": "Deze pagina naar de prullenbak verplaatsen?",
|
|
||||||
"Restore page": "Pagina herstellen",
|
|
||||||
"Page moved to trash": "Pagina verplaatst naar de prullenbak",
|
|
||||||
"Page restored successfully": "Pagina succesvol hersteld",
|
|
||||||
"Deleted by": "Verwijderd door",
|
|
||||||
"Deleted at": "Verwijderd op",
|
|
||||||
"Preview": "Voorbeeld",
|
|
||||||
"Subpages": "Subpagina's",
|
|
||||||
"Failed to load subpages": "Laden van subpagina's mislukt",
|
|
||||||
"No subpages": "Geen subpagina's",
|
|
||||||
"Subpages (Child pages)": "Subpagina's (Kindpagina's)",
|
|
||||||
"List all subpages of the current page": "Lijst van alle subpagina's van de huidige pagina",
|
|
||||||
"Attachments": "Bijlagen",
|
|
||||||
"All spaces": "Alle ruimtes",
|
|
||||||
"Unknown": "Onbekend",
|
|
||||||
"Find a space": "Vind een ruimte",
|
|
||||||
"Search in all your spaces": "Zoek in al je ruimtes",
|
|
||||||
"Type": "Type",
|
|
||||||
"Enterprise": "Onderneming",
|
|
||||||
"Download attachment": "Bijlage downloaden",
|
|
||||||
"Allowed email domains": "Toegestane e-maildomeinen",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Alleen gebruikers met e-mailadressen van deze domeinen kunnen zich aanmelden via SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Voer geldige domeinnamen in, gescheiden door komma of spatie",
|
|
||||||
"Enforce two-factor authentication": "Handhaaf tweefactorauthenticatie",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Na handhaving moeten alle leden tweefactorauthenticatie inschakelen om toegang te krijgen tot de werkomgeving.",
|
|
||||||
"Toggle MFA enforcement": "Schakel MFA-handhaving in of uit",
|
|
||||||
"Display name": "Weergavenaam",
|
|
||||||
"Allow signup": "Aanmelden toestaan",
|
|
||||||
"Enabled": "Ingeschakeld",
|
|
||||||
"Advanced Settings": "Geavanceerde instellingen",
|
|
||||||
"Enable TLS/SSL": "TLS/SSL inschakelen",
|
|
||||||
"Use secure connection to LDAP server": "Gebruik een beveiligde verbinding met de LDAP-server",
|
|
||||||
"Group sync": "Groepssynchronisatie",
|
|
||||||
"No SSO providers found.": "Geen SSO-providers gevonden.",
|
|
||||||
"Delete SSO provider": "Verwijder SSO-provider",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Weet u zeker dat u deze SSO-provider wilt verwijderen?",
|
|
||||||
"Action": "Actie",
|
|
||||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} configuratie",
|
|
||||||
"Icon": "Icoon",
|
|
||||||
"Upload image": "Afbeelding uploaden",
|
|
||||||
"Remove image": "Afbeelding verwijderen",
|
|
||||||
"Failed to remove image": "Afbeelding verwijderen mislukt",
|
|
||||||
"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",
|
|
||||||
"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.",
|
|
||||||
"Toggle restrict API keys to admins": "Schakel het beperken van API-sleutels tot beheerders in/uit",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "Het aanmaken van API-sleutels is door je werkruimtebeheerder beperkt tot beheerders.",
|
|
||||||
"AI settings": "AI-instellingen",
|
|
||||||
"AI search": "AI-zoekopdracht",
|
|
||||||
"AI Answer": "AI Antwoord",
|
|
||||||
"Ask AI": "Vraag AI",
|
|
||||||
"AI is thinking...": "AI is aan het nadenken...",
|
|
||||||
"Ask a question...": "Stel een vraag...",
|
|
||||||
"AI Answers": "AI Antwoorden",
|
|
||||||
"AI-powered search (AI Answers)": "AI-gestuurde zoekopdracht (AI Antwoorden)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI-zoekopdracht maakt gebruik van vectorembeddings om semantische zoekmogelijkheden te bieden in uw werkruimte-inhoud.",
|
|
||||||
"Toggle AI search": "Schakel AI-zoekopdracht in/uit",
|
|
||||||
"Generative AI (Ask AI)": "Generatieve AI (Vraag het AI)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Schakel AI-gestuurde inhoudsgeneratie in de editor in. Hiermee kunnen gebruikers tekst genereren, verbeteren, vertalen en transformeren.",
|
|
||||||
"Toggle generative AI": "Generatieve AI schakelen",
|
|
||||||
"Enterprise feature": "Enterprise-functie",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "AI is alleen beschikbaar in de Docmost Enterprise-editie. Neem contact op met sales@docmost.com.",
|
|
||||||
"AI & MCP": "AI & MCP",
|
|
||||||
"AI": "AI",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Model Context Protocol (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Schakel de MCP-server in zodat AI-assistenten en tools kunnen interageren met de inhoud van uw werkruimte.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP is alleen beschikbaar in de Docmost Enterprise-editie. Neem contact op met sales@docmost.com.",
|
|
||||||
"MCP documentation": "MCP-documentatie",
|
|
||||||
"MCP Server URL": "MCP-server-URL",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Gebruik uw API-sleutel voor authenticatie. U kunt API-sleutels beheren in uw accountinstellingen.",
|
|
||||||
"Supported tools": "Ondersteunde tools",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "In uw werkruimte is MCP ingeschakeld. Gebruik uw API-sleutel om AI-assistenten te koppelen.",
|
|
||||||
"MCP server URL:": "MCP-server-URL:",
|
|
||||||
"Learn more": "Meer informatie",
|
|
||||||
"View the": "Bekijk de",
|
|
||||||
"for usage details.": "voor details over het gebruik.",
|
|
||||||
"for setup instructions.": "voor installatie-instructies.",
|
|
||||||
"API documentation": "API-documentatie",
|
|
||||||
"Sources": "Bronnen",
|
|
||||||
"AI Answers not available for attachments": "AI Antwoorden niet beschikbaar voor bijlagen",
|
|
||||||
"No answer available": "Geen antwoord beschikbaar",
|
|
||||||
"Background color": "Achtergrondkleur",
|
|
||||||
"Highlight color": "Markeerkleur",
|
|
||||||
"Remove color": "Kleur verwijderen",
|
|
||||||
"Notifications": "Meldingen",
|
|
||||||
"No notifications": "Geen meldingen",
|
|
||||||
"No unread notifications": "Geen ongelezen meldingen",
|
|
||||||
"All notifications": "Alle meldingen",
|
|
||||||
"Unread only": "Alleen ongelezen",
|
|
||||||
"Mark all as read": "Markeer alles als gelezen",
|
|
||||||
"Mark as read": "Markeer als gelezen",
|
|
||||||
"More options": "Meer opties",
|
|
||||||
"mentioned you in a comment": "noemde je in een reactie",
|
|
||||||
"commented on a page": "reageerde op een pagina",
|
|
||||||
"resolved a comment": "heeft een opmerking opgelost",
|
|
||||||
"mentioned you on a page": "noemde je op een pagina",
|
|
||||||
"gave you edit access to a page": "heeft je toegang gegeven om een pagina te bewerken",
|
|
||||||
"gave you view access to a page": "heeft je toegang gegeven om een pagina te bekijken",
|
|
||||||
"Today": "Vandaag",
|
|
||||||
"Yesterday": "Gisteren",
|
|
||||||
"This week": "Deze week",
|
|
||||||
"Older": "Ouder",
|
|
||||||
"Restricted page": "Beperkte pagina",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Beperkte pagina's kunnen niet openbaar worden gedeeld.",
|
|
||||||
"Restricted by parent": "Beperkt door bovenliggende",
|
|
||||||
"Restricted": "Beperkt",
|
|
||||||
"Open": "Open",
|
|
||||||
"Inherits restrictions from ancestor page": "Erft restricties van de bovenliggende pagina",
|
|
||||||
"Only people listed below can access this page": "Alleen onderstaande personen hebben toegang tot deze pagina",
|
|
||||||
"Everyone in this space can access": "Iedereen in deze ruimte heeft toegang",
|
|
||||||
"No additional restrictions on this page": "Geen aanvullende restricties op deze pagina",
|
|
||||||
"Only specific people can access": "Alleen specifieke personen hebben toegang",
|
|
||||||
"Use only inherited restrictions": "Gebruik alleen overgenomen restricties",
|
|
||||||
"Add restrictions on top of inherited": "Restricties toevoegen bovenop geërfd",
|
|
||||||
"Inherited restriction": "Overgenomen restrictie",
|
|
||||||
"Access limited by": "Toegang beperkt door",
|
|
||||||
"Restrict access to control who can view and edit this page": "Beperk de toegang om te bepalen wie deze pagina kan bekijken en bewerken",
|
|
||||||
"Add additional restrictions specific to this page": "Voeg extra beperkingen toe voor deze pagina",
|
|
||||||
"Access": "Toegang",
|
|
||||||
"People with access": "Personen die toegang",
|
|
||||||
"Remove all": "Alles verwijderen",
|
|
||||||
"Remove access": "Toegang verwijderen",
|
|
||||||
"Remove all access": "Alle toegang verwijderen",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Weet u zeker dat u de toegang van dit lid tot de pagina wilt intrekken?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Weet u zeker dat u alle specifieke toegang wilt verwijderen? Hiermee wordt de pagina voor iedereen in de ruimte beschikbaar.",
|
|
||||||
"Trash retention": "Bewaartermijn prullenbak",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Pagina's in de prullenbak worden na deze periode permanent verwijderd.",
|
|
||||||
"Trash retention updated": "Bewaartermijn prullenbak bijgewerkt",
|
|
||||||
"Failed to update trash retention": "Bijwerken van de bewaartermijn voor de prullenbak is mislukt.",
|
|
||||||
"Removed page restriction": "Pagina-restrictie verwijderd",
|
|
||||||
"Added page permission": "Paginatoestemming toegevoegd",
|
|
||||||
"Removed page permission": "Paginatoestemming verwijderd"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Escolha o idioma da interface.",
|
"Choose your preferred interface language.": "Escolha o idioma da interface.",
|
||||||
"Choose your preferred page width.": "Escolha a largura preferida da página.",
|
"Choose your preferred page width.": "Escolha a largura preferida da página.",
|
||||||
"Confirm": "Confirmar",
|
"Confirm": "Confirmar",
|
||||||
"Copy as Markdown": "Copiar como Markdown",
|
|
||||||
"Copy link": "Copiar link",
|
"Copy link": "Copiar link",
|
||||||
"Create": "Criar",
|
"Create": "Criar",
|
||||||
"Create group": "Criar grupo",
|
"Create group": "Criar grupo",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "ex.: Espaço para a equipe de produto",
|
"e.g Space for product team": "ex.: Espaço para a equipe de produto",
|
||||||
"e.g Space for sales team to collaborate": "ex.: Espaço para a equipe de vendas colaborar",
|
"e.g Space for sales team to collaborate": "ex.: Espaço para a equipe de vendas colaborar",
|
||||||
"Edit": "Editar",
|
"Edit": "Editar",
|
||||||
"Read": "Ler",
|
|
||||||
"Edit group": "Editar grupo",
|
"Edit group": "Editar grupo",
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Enter a strong password": "Insira uma senha forte",
|
"Enter a strong password": "Insira uma senha forte",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "Nenhum grupo encontrado",
|
"No group found": "Nenhum grupo encontrado",
|
||||||
"No page history saved yet.": "Nenhum histórico de página salvo ainda.",
|
"No page history saved yet.": "Nenhum histórico de página salvo ainda.",
|
||||||
"No pages yet": "Nenhuma página ainda",
|
"No pages yet": "Nenhuma página ainda",
|
||||||
"No shared pages": "Sem páginas compartilhadas",
|
|
||||||
"No results found...": "Nenhum resultado encontrado...",
|
"No results found...": "Nenhum resultado encontrado...",
|
||||||
"No user found": "Nenhum usuário encontrado",
|
"No user found": "Nenhum usuário encontrado",
|
||||||
"Overview": "Visão geral",
|
"Overview": "Visão geral",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "página",
|
"page": "página",
|
||||||
"Page deleted successfully": "Página excluída com sucesso",
|
"Page deleted successfully": "Página excluída com sucesso",
|
||||||
"Page history": "Histórico da página",
|
"Page history": "Histórico da página",
|
||||||
"Select version": "Selecionar versão",
|
|
||||||
"Highlight changes": "Destacar alterações",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "A importação da página está em andamento. Por favor, não feche esta aba.",
|
"Page import is in progress. Please do not close this tab.": "A importação da página está em andamento. Por favor, não feche esta aba.",
|
||||||
"Pages": "Páginas",
|
"Pages": "Páginas",
|
||||||
"pages": "páginas",
|
"pages": "páginas",
|
||||||
"Password": "Senha",
|
"Password": "Senha",
|
||||||
"Password changed successfully": "Senha alterada com sucesso",
|
"Password changed successfully": "Senha alterada com sucesso",
|
||||||
"People": "Pessoas",
|
|
||||||
"Pending": "Pendente",
|
"Pending": "Pendente",
|
||||||
"Please confirm your action": "Por favor, confirme sua ação",
|
"Please confirm your action": "Por favor, confirme sua ação",
|
||||||
"Preferences": "Preferências",
|
"Preferences": "Preferências",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Responder...",
|
"Reply...": "Responder...",
|
||||||
"Error loading comments.": "Erro ao carregar comentários.",
|
"Error loading comments.": "Erro ao carregar comentários.",
|
||||||
"No comments yet.": "Ainda sem comentários.",
|
"No comments yet.": "Ainda sem comentários.",
|
||||||
"No open comments.": "Sem comentários em aberto.",
|
|
||||||
"No resolved comments.": "Sem comentários resolvidos.",
|
|
||||||
"Add a comment...": "Adicione um comentário...",
|
|
||||||
"Edit comment": "Editar comentário",
|
"Edit comment": "Editar comentário",
|
||||||
"Delete comment": "Excluir comentário",
|
"Delete comment": "Excluir comentário",
|
||||||
"Are you sure you want to delete this comment?": "Você tem certeza de que deseja excluir este comentário?",
|
"Are you sure you want to delete this comment?": "Você tem certeza de que deseja excluir este comentário?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Comentário excluído com sucesso",
|
"Comment deleted successfully": "Comentário excluído com sucesso",
|
||||||
"Failed to delete comment": "Falha ao excluir comentário",
|
"Failed to delete comment": "Falha ao excluir comentário",
|
||||||
"Comment resolved successfully": "Comentário resolvido com sucesso",
|
"Comment resolved successfully": "Comentário resolvido com sucesso",
|
||||||
"Comment re-opened successfully": "Comentário reaberto com sucesso",
|
|
||||||
"Comment unresolved successfully": "Comentário não resolvido com sucesso",
|
|
||||||
"Failed to resolve comment": "Falha ao resolver comentário",
|
"Failed to resolve comment": "Falha ao resolver comentário",
|
||||||
"Resolve comment": "Resolver comentário",
|
|
||||||
"Unresolve comment": "Não resolver comentário",
|
|
||||||
"Resolve Comment Thread": "Resolver Fio de Comentários",
|
|
||||||
"Unresolve Comment Thread": "Não resolver Fio de Comentários",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Tem certeza de que deseja resolver este fio de comentários? Isso o marcará como concluído.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Tem certeza de que deseja não resolver este fio de comentários?",
|
|
||||||
"Resolved": "Resolvido",
|
|
||||||
"No active comments.": "Sem comentários ativos.",
|
|
||||||
"Revoke invitation": "Cancelar o convite",
|
"Revoke invitation": "Cancelar o convite",
|
||||||
"Revoke": "Anular",
|
"Revoke": "Anular",
|
||||||
"Don't": "Não",
|
"Don't": "Não",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Qualquer um com este link pode participar deste espaço de trabalho.",
|
"Anyone with this link can join this workspace.": "Qualquer um com este link pode participar deste espaço de trabalho.",
|
||||||
"Invite link": "Link do convite",
|
"Invite link": "Link do convite",
|
||||||
"Copy": "Copiar",
|
"Copy": "Copiar",
|
||||||
"Copy to space": "Copiar para o espaço",
|
|
||||||
"Copied": "Copiado",
|
"Copied": "Copiado",
|
||||||
"Duplicate": "Duplicar",
|
|
||||||
"Select a user": "Selecione um usuário",
|
"Select a user": "Selecione um usuário",
|
||||||
"Select a group": "Selecione um grupo",
|
"Select a group": "Selecione um grupo",
|
||||||
"Export all pages and attachments in this space.": "Exportar todas as páginas e anexos deste espaço.",
|
"Export all pages and attachments in this space.": "Exportar todas as páginas e anexos deste espaço.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Falha ao exportar:",
|
"Export failed:": "Falha ao exportar:",
|
||||||
"export error": "erro de exportação",
|
"export error": "erro de exportação",
|
||||||
"Export page": "Exportar página",
|
"Export page": "Exportar página",
|
||||||
"Export successful": "Exportação bem-sucedida",
|
|
||||||
"Export space": "Exportar espaço",
|
"Export space": "Exportar espaço",
|
||||||
"Export {{type}}": "Exportar para {{type}}",
|
"Export {{type}}": "Exportar para {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "O arquivo excede o limite de anexos {{limit}}",
|
"File exceeds the {{limit}} attachment limit": "O arquivo excede o limite de anexos {{limit}}",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Adicionar linha abaixo",
|
"Add row below": "Adicionar linha abaixo",
|
||||||
"Delete table": "Excluir tabela",
|
"Delete table": "Excluir tabela",
|
||||||
"Info": "Informação",
|
"Info": "Informação",
|
||||||
"Note": "Observação",
|
|
||||||
"Success": "Sucesso",
|
"Success": "Sucesso",
|
||||||
"Warning": "Aviso",
|
"Warning": "Aviso",
|
||||||
"Danger": "Perigo",
|
"Danger": "Perigo",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Envie qualquer imagem do seu dispositivo.",
|
"Upload any image from your device.": "Envie qualquer imagem do seu dispositivo.",
|
||||||
"Upload any video from your device.": "Envie qualquer vídeo do seu dispositivo.",
|
"Upload any video from your device.": "Envie qualquer vídeo do seu dispositivo.",
|
||||||
"Upload any file from your device.": "Envie qualquer arquivo do seu dispositivo.",
|
"Upload any file from your device.": "Envie qualquer arquivo do seu dispositivo.",
|
||||||
"Uploading {{name}}": "Enviando {{name}}",
|
|
||||||
"Uploading file": "Enviando arquivo",
|
|
||||||
"Table": "Tabela",
|
"Table": "Tabela",
|
||||||
"Insert a table.": "Insira uma tabela.",
|
"Insert a table.": "Insira uma tabela.",
|
||||||
"Insert collapsible block.": "Insira um bloco colapsável.",
|
"Insert collapsible block.": "Insira um bloco colapsável.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Insira a data atual",
|
"Insert current date": "Insira a data atual",
|
||||||
"Draw and sketch excalidraw diagrams": "Desenhe e esboce diagramas Excalidraw",
|
"Draw and sketch excalidraw diagrams": "Desenhe e esboce diagramas Excalidraw",
|
||||||
"Multiple": "Múltiplo",
|
"Multiple": "Múltiplo",
|
||||||
"Turn into": "Transformar em",
|
|
||||||
"Text align": "Alinhar texto",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Esta página pode ter sido excluída, movida ou você pode não ter acesso a ela.",
|
|
||||||
"Go to homepage": "Ir para a página inicial",
|
|
||||||
"Pages you create will show up here.": "As páginas que você criar aparecerão aqui.",
|
|
||||||
"Heading {{level}}": "Título {{level}}",
|
"Heading {{level}}": "Título {{level}}",
|
||||||
"Toggle title": "Alternar título",
|
"Toggle title": "Alternar título",
|
||||||
"Write anything. Enter \"/\" for commands": "Escreva qualquer coisa. Digite \"/\" para comandos",
|
"Write anything. Enter \"/\" for commands": "Escreva qualquer coisa. Digite \"/\" para comandos",
|
||||||
"Write...": "Escreva...",
|
|
||||||
"Column count": "Número de colunas",
|
|
||||||
"{{count}} Columns": "{{count}} colunas",
|
|
||||||
"Equal columns": "Colunas iguais",
|
|
||||||
"Left sidebar": "Barra lateral esquerda",
|
|
||||||
"Right sidebar": "Barra lateral direita",
|
|
||||||
"Wide center": "Centro largo",
|
|
||||||
"Left wide": "Largo à esquerda",
|
|
||||||
"Right wide": "Largo à direita",
|
|
||||||
"Names do not match": "Os nomes não coincidem",
|
"Names do not match": "Os nomes não coincidem",
|
||||||
"Today, {{time}}": "Hoje, {{time}}",
|
"Today, {{time}}": "Hoje, {{time}}",
|
||||||
"Yesterday, {{time}}": "Ontem, {{time}}",
|
"Yesterday, {{time}}": "Ontem, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Contagem de caracteres: {{characterCount}}",
|
"Character count: {{characterCount}}": "Contagem de caracteres: {{characterCount}}",
|
||||||
"New update": "Nova atualização",
|
"New update": "Nova atualização",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} está disponível",
|
"{{latestVersion}} is available": "{{latestVersion}} está disponível",
|
||||||
"Default page edit mode": "Modo de edição de página padrão",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Escolha o modo de edição de página preferido. Evite edições acidentais.",
|
|
||||||
"Reading": "Leitura",
|
|
||||||
"Delete member": "Excluir membro",
|
"Delete member": "Excluir membro",
|
||||||
"Member deleted successfully": "Membro removido com sucesso",
|
"Member deleted successfully": "Membro removido com sucesso",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Você tem certeza que deseja deletar este membro do workspace? Esta ação é irreversível.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Você tem certeza que deseja deletar este membro do workspace? Esta ação é irreversível.",
|
||||||
"Deactivate member": "Desativar membro",
|
|
||||||
"Activate member": "Ativar membro",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Tem certeza de que deseja desativar este membro do espaço de trabalho? Ele não poderá mais acessar este espaço de trabalho.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Tem certeza de que deseja ativar este membro do espaço de trabalho?",
|
|
||||||
"Deactivate": "Desativar",
|
|
||||||
"Activate": "Ativar",
|
|
||||||
"Deactivated": "Desativado",
|
|
||||||
"Move": "Mover",
|
"Move": "Mover",
|
||||||
"Move page": "Mover página",
|
"Move page": "Mover página",
|
||||||
"Move page to a different space.": "Mover página para um espaço diferente.",
|
"Move page to a different space.": "Mover página para um espaço diferente.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Páginas compartilhadas publicamente de espaços que você é membro aparecerão aqui",
|
"Publicly shared pages from spaces you are a member of will appear here": "Páginas compartilhadas publicamente de espaços que você é membro aparecerão aqui",
|
||||||
"Share deleted successfully": "Compartilhamento excluído com sucesso",
|
"Share deleted successfully": "Compartilhamento excluído com sucesso",
|
||||||
"Share not found": "Compartilhamento não encontrado",
|
"Share not found": "Compartilhamento não encontrado",
|
||||||
"Failed to share page": "Falha ao compartilhar página",
|
"Failed to share page": "Falha ao compartilhar página"
|
||||||
"Disable public sharing": "Desativar compartilhamento público",
|
|
||||||
"Prevent members from sharing pages publicly.": "Impedir que os membros compartilhem páginas publicamente.",
|
|
||||||
"Toggle public sharing": "Alternar compartilhamento público",
|
|
||||||
"Toggle space public sharing": "Alternar compartilhamento público do espaço",
|
|
||||||
"Public sharing is disabled at the workspace level": "O compartilhamento público está desativado no nível do espaço de trabalho",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Impedir que as páginas neste espaço sejam compartilhadas publicamente.",
|
|
||||||
"Requires an enterprise license": "Requer uma licença empresarial",
|
|
||||||
"Page permissions": "Permissões da página},{",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Controle quem pode visualizar e editar páginas individuais. Disponível com licença empresarial.",
|
|
||||||
"Enable public sharing": "Ativar compartilhamento público",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Tem certeza de que deseja ativar o compartilhamento público? Os membros poderão compartilhar páginas publicamente.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Tem certeza de que deseja desativar o compartilhamento público? Todos os links compartilhados existentes neste espaço de trabalho serão excluídos.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Tem certeza de que deseja ativar o compartilhamento público para este espaço?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Tem certeza de que deseja desativar o compartilhamento público? Todos os links compartilhados existentes neste espaço serão excluídos.",
|
|
||||||
"Public sharing is disabled": "Compartilhamento público está desativado",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "O compartilhamento público foi desativado no nível do espaço de trabalho.",
|
|
||||||
"Public sharing has been disabled for this space.": "O compartilhamento público foi desativado para este espaço.",
|
|
||||||
"Copy page": "Copiar página",
|
|
||||||
"Copy page to a different space.": "Copiar página para um espaço diferente.",
|
|
||||||
"Page copied successfully": "Página copiada com sucesso",
|
|
||||||
"Page duplicated successfully": "Página duplicada com sucesso",
|
|
||||||
"Find": "Encontrar",
|
|
||||||
"Not found": "Não encontrado",
|
|
||||||
"Previous Match (Shift+Enter)": "Correspondência anterior (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Próxima correspondência (Enter)",
|
|
||||||
"Match case (Alt+C)": "Diferenciar maiúsculas de minúsculas (Alt+C)",
|
|
||||||
"Replace": "Substituir",
|
|
||||||
"Close (Escape)": "Fechar (Escape)",
|
|
||||||
"Replace (Enter)": "Substituir (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Substituir tudo (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Substituir tudo",
|
|
||||||
"View all spaces": "Ver todos os espaços",
|
|
||||||
"Error": "Erro",
|
|
||||||
"Failed to disable MFA": "Falha ao desativar a MFA",
|
|
||||||
"Disable two-factor authentication": "Desativar autenticação de dois fatores",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Desativar a autenticação de dois fatores tornará sua conta menos segura. Você só precisará de sua senha para entrar.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Por favor, insira sua senha para desativar a autenticação de dois fatores:",
|
|
||||||
"Two-factor authentication has been enabled": "Autenticação de dois fatores foi ativada",
|
|
||||||
"Two-factor authentication has been disabled": "Autenticação de dois fatores foi desativada",
|
|
||||||
"2-step verification": "Verificação em duas etapas",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Proteja sua conta com uma camada adicional de verificação ao entrar.",
|
|
||||||
"Two-factor authentication is active on your account.": "Autenticação de dois fatores está ativa na sua conta.",
|
|
||||||
"Add 2FA method": "Adicionar método de 2FA",
|
|
||||||
"Backup codes": "Códigos de backup",
|
|
||||||
"Disable": "Desativar",
|
|
||||||
"Invalid verification code": "Código de verificação inválido",
|
|
||||||
"New backup codes have been generated": "Novos códigos de backup foram gerados",
|
|
||||||
"Failed to regenerate backup codes": "Falha ao regenerar códigos de backup",
|
|
||||||
"About backup codes": "Sobre códigos de backup",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Códigos de backup podem ser usados para acessar sua conta se perder acesso ao aplicativo autenticador. Cada código só pode ser usado uma vez.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Você pode regenerar novos códigos de backup a qualquer momento. Isso invalidará todos os códigos existentes.",
|
|
||||||
"Confirm password": "Confirmar senha",
|
|
||||||
"Generate new backup codes": "Gerar novos códigos de backup",
|
|
||||||
"Save your new backup codes": "Salvar seus novos códigos de backup",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Certifique-se de salvar esses códigos em um local seguro. Seus códigos de backup antigos não são mais válidos.",
|
|
||||||
"Your new backup codes": "Seus novos códigos de backup",
|
|
||||||
"I've saved my backup codes": "Eu salvei meus códigos de backup",
|
|
||||||
"Failed to setup MFA": "Falha ao configurar a MFA",
|
|
||||||
"Setup & Verify": "Configurar & Verificar",
|
|
||||||
"Add to authenticator": "Adicionar ao autenticador",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Escaneie este código QR com seu aplicativo autenticador",
|
|
||||||
"Can't scan the code?": "Não consegue escanear o código?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Digite este código manualmente em seu aplicativo autenticador:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Digite o código de 6 dígitos do seu autenticador",
|
|
||||||
"Verify and enable": "Verificar e ativar",
|
|
||||||
"Failed to generate QR code. Please try again.": "Falha ao gerar código QR. Por favor, tente novamente.",
|
|
||||||
"Backup": "Backup",
|
|
||||||
"Save codes": "Salvar códigos",
|
|
||||||
"Save your backup codes": "Salvar seus códigos de backup",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Esses códigos podem ser usados para acessar sua conta se você perder o acesso ao aplicativo autenticador. Cada código só pode ser usado uma vez.",
|
|
||||||
"Print": "Imprimir",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "A autenticação de dois fatores foi configurada. Por favor, faça login novamente.",
|
|
||||||
"Two-Factor authentication required": "Autenticação de dois fatores necessária",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Seu espaço de trabalho requer autenticação de dois fatores para todos os usuários",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Para continuar acessando seu espaço de trabalho, você deve configurar a autenticação de dois fatores. Isso adiciona uma camada extra de segurança à sua conta.",
|
|
||||||
"Set up two-factor authentication": "Configurar autenticação de dois fatores",
|
|
||||||
"Cancel and logout": "Cancelar e sair",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Seu espaço de trabalho requer autenticação de dois fatores. Por favor, configure para continuar.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Isso adiciona uma camada extra de segurança à sua conta, exigindo um código de verificação de seu aplicativo autenticador.",
|
|
||||||
"Password is required": "Senha é necessária",
|
|
||||||
"Password must be at least 8 characters": "A senha deve ter pelo menos 8 caracteres",
|
|
||||||
"Please enter a 6-digit code": "Por favor, insira um código de 6 dígitos",
|
|
||||||
"Code must be exactly 6 digits": "O código deve ter exatamente 6 dígitos",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Insira o código de 6 dígitos encontrado em seu aplicativo autenticador",
|
|
||||||
"Need help authenticating?": "Precisa de ajuda para autenticar?",
|
|
||||||
"MFA QR Code": "Código QR de MFA",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Conta criada com sucesso. Por favor, faça login para configurar a autenticação de dois fatores.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Redefinição de senha bem-sucedida. Por favor, faça login com sua nova senha e complete a autenticação de dois fatores.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Redefinição de senha bem-sucedida. Por favor, faça login com sua nova senha para configurar a autenticação de dois fatores.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "Redefinição de senha foi bem-sucedida. Por favor, faça login com sua nova senha.",
|
|
||||||
"Two-factor authentication": "Autenticação de dois fatores",
|
|
||||||
"Use authenticator app instead": "Use o aplicativo autenticador em vez disso",
|
|
||||||
"Verify backup code": "Verificar código de backup",
|
|
||||||
"Use backup code": "Usar código de backup",
|
|
||||||
"Enter one of your backup codes": "Digite um de seus códigos de backup",
|
|
||||||
"Backup code": "Código de backup",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Digite um de seus códigos de backup. Cada código de backup só pode ser usado uma vez.",
|
|
||||||
"Verify": "Verificar",
|
|
||||||
"Trash": "Lixeira",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "{count, plural, one {A página na lixeira será excluída permanentemente após # dia.} other {As páginas na lixeira serão excluídas permanentemente após # dias.}}",
|
|
||||||
"Deleted": "Excluído",
|
|
||||||
"No pages in trash": "Sem páginas na lixeira",
|
|
||||||
"Permanently delete page?": "Excluir página permanentemente?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Tem certeza de que deseja excluir permanentemente '{{title}}'? Esta ação não pode ser desfeita.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "Restaurar '{{title}}' e suas subpáginas?",
|
|
||||||
"Move to trash": "Mover para a lixeira",
|
|
||||||
"Move this page to trash?": "Mover esta página para a lixeira?",
|
|
||||||
"Restore page": "Restaurar página",
|
|
||||||
"Page moved to trash": "Página movida para a lixeira",
|
|
||||||
"Page restored successfully": "Página restaurada com sucesso",
|
|
||||||
"Deleted by": "Excluído por",
|
|
||||||
"Deleted at": "Excluído em",
|
|
||||||
"Preview": "Visualização",
|
|
||||||
"Subpages": "Subpáginas",
|
|
||||||
"Failed to load subpages": "Falha ao carregar subpáginas",
|
|
||||||
"No subpages": "Sem subpáginas",
|
|
||||||
"Subpages (Child pages)": "Subpáginas (Páginas filhas)",
|
|
||||||
"List all subpages of the current page": "Listar todas as subpáginas da página atual",
|
|
||||||
"Attachments": "Anexos",
|
|
||||||
"All spaces": "Todos os espaços",
|
|
||||||
"Unknown": "Desconhecido",
|
|
||||||
"Find a space": "Encontrar um espaço",
|
|
||||||
"Search in all your spaces": "Pesquisar em todos os seus espaços",
|
|
||||||
"Type": "Tipo",
|
|
||||||
"Enterprise": "Empresa",
|
|
||||||
"Download attachment": "Baixar anexo",
|
|
||||||
"Allowed email domains": "Domínios de email permitidos",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Apenas usuários com endereços de email desses domínios podem se inscrever via SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Insira nomes de domínio válidos separados por vírgula ou espaço",
|
|
||||||
"Enforce two-factor authentication": "Impor autenticação de dois fatores",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Uma vez imposto, todos os membros devem habilitar a autenticação de dois fatores para acessar o espaço de trabalho.",
|
|
||||||
"Toggle MFA enforcement": "Alternar imposição de MFA",
|
|
||||||
"Display name": "Nome de exibição",
|
|
||||||
"Allow signup": "Permitir inscrição",
|
|
||||||
"Enabled": "Habilitado",
|
|
||||||
"Advanced Settings": "Configurações Avançadas",
|
|
||||||
"Enable TLS/SSL": "Habilitar TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Usar conexão segura com o servidor LDAP",
|
|
||||||
"Group sync": "Sincronização de grupo",
|
|
||||||
"No SSO providers found.": "Nenhum provedor de SSO encontrado.",
|
|
||||||
"Delete SSO provider": "Excluir provedor de SSO",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Tem certeza de que deseja excluir este provedor de SSO?",
|
|
||||||
"Action": "Ação",
|
|
||||||
"{{ssoProviderType}} configuration": "Configuração de {{ssoProviderType}}",
|
|
||||||
"Icon": "Ícone",
|
|
||||||
"Upload image": "Fazer upload da imagem",
|
|
||||||
"Remove image": "Remover imagem",
|
|
||||||
"Failed to remove image": "Falha ao remover imagem",
|
|
||||||
"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",
|
|
||||||
"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.",
|
|
||||||
"Toggle restrict API keys to admins": "Alternar restrição de chaves de API para administradores",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "A criação de chaves de API foi restringida aos administradores pelo administrador do seu workspace.",
|
|
||||||
"AI settings": "Configurações de IA",
|
|
||||||
"AI search": "Pesquisa IA",
|
|
||||||
"AI Answer": "Resposta de IA",
|
|
||||||
"Ask AI": "Pergunte à IA",
|
|
||||||
"AI is thinking...": "IA está pensando...",
|
|
||||||
"Ask a question...": "Faça uma pergunta...",
|
|
||||||
"AI Answers": "Respostas de IA",
|
|
||||||
"AI-powered search (AI Answers)": "Pesquisa com IA (Respostas de IA)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "A pesquisa IA usa vetores de incorporação para fornecer capacidades de pesquisa semântica em todo o conteúdo do seu espaço de trabalho.",
|
|
||||||
"Toggle AI search": "Alternar pesquisa de IA",
|
|
||||||
"Generative AI (Ask AI)": "IA generativa (Perguntar à IA)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Habilitar geração de conteúdo com IA no editor. Permite aos usuários gerar, melhorar, traduzir e transformar texto.",
|
|
||||||
"Toggle generative AI": "Alternar IA generativa",
|
|
||||||
"Enterprise feature": "Recurso empresarial",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "A IA está disponível apenas na edição empresarial do Docmost. Contate sales@docmost.com.",
|
|
||||||
"AI & MCP": "IA e MCP",
|
|
||||||
"AI": "IA",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Protocolo de Contexto de Modelo (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Ative o servidor MCP para permitir que assistentes de IA e ferramentas interajam com o conteúdo do seu espaço de trabalho.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "O MCP está disponível apenas na edição empresarial do Docmost. Contate sales@docmost.com.",
|
|
||||||
"MCP documentation": "Documentação do MCP",
|
|
||||||
"MCP Server URL": "URL do servidor MCP",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Use sua chave de API para autenticação. Você pode gerenciar chaves de API nas configurações da sua conta.",
|
|
||||||
"Supported tools": "Ferramentas compatíveis",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "Seu espaço de trabalho tem MCP habilitado. Use sua chave de API para conectar assistentes de IA.",
|
|
||||||
"MCP server URL:": "URL do servidor MCP:",
|
|
||||||
"Learn more": "Saiba mais",
|
|
||||||
"View the": "Veja o",
|
|
||||||
"for usage details.": "para detalhes de uso.",
|
|
||||||
"for setup instructions.": "para instruções de configuração.",
|
|
||||||
"API documentation": "Documentação da API",
|
|
||||||
"Sources": "Fontes",
|
|
||||||
"AI Answers not available for attachments": "Respostas de IA não disponíveis para anexos",
|
|
||||||
"No answer available": "Nenhuma resposta disponível",
|
|
||||||
"Background color": "Cor de fundo",
|
|
||||||
"Highlight color": "Cor de destaque",
|
|
||||||
"Remove color": "Remover cor",
|
|
||||||
"Notifications": "Notificações",
|
|
||||||
"No notifications": "Sem notificações",
|
|
||||||
"No unread notifications": "Sem notificações não lidas",
|
|
||||||
"All notifications": "Todas as notificações",
|
|
||||||
"Unread only": "Somente não lidas",
|
|
||||||
"Mark all as read": "Marcar todas como lidas",
|
|
||||||
"Mark as read": "Marcar como lida",
|
|
||||||
"More options": "Mais opções",
|
|
||||||
"mentioned you in a comment": "mencionou você em um comentário",
|
|
||||||
"commented on a page": "comentou em uma página",
|
|
||||||
"resolved a comment": "resolveu um comentário",
|
|
||||||
"mentioned you on a page": "mencionou você em uma página",
|
|
||||||
"gave you edit access to a page": "concedeu a você acesso para editar a página",
|
|
||||||
"gave you view access to a page": "concedeu a você acesso para visualizar a página",
|
|
||||||
"Today": "Hoje",
|
|
||||||
"Yesterday": "Ontem",
|
|
||||||
"This week": "Esta semana",
|
|
||||||
"Older": "Mais antigo",
|
|
||||||
"Restricted page": "Página restrita",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Páginas restritas não podem ser compartilhadas publicamente.",
|
|
||||||
"Restricted by parent": "Restrita pela página pai",
|
|
||||||
"Restricted": "Restrito",
|
|
||||||
"Open": "Aberto",
|
|
||||||
"Inherits restrictions from ancestor page": "Herda restrições da página ancestral",
|
|
||||||
"Only people listed below can access this page": "Apenas as pessoas listadas abaixo podem acessar esta página",
|
|
||||||
"Everyone in this space can access": "Todos neste espaço podem acessar",
|
|
||||||
"No additional restrictions on this page": "Sem restrições adicionais nesta página",
|
|
||||||
"Only specific people can access": "Apenas pessoas específicas podem acessar",
|
|
||||||
"Use only inherited restrictions": "Usar apenas restrições herdadas",
|
|
||||||
"Add restrictions on top of inherited": "Adicionar restrições além das herdadas",
|
|
||||||
"Inherited restriction": "Restrição herdada",
|
|
||||||
"Access limited by": "Acesso limitado por",
|
|
||||||
"Restrict access to control who can view and edit this page": "Restringir o acesso para controlar quem pode visualizar e editar esta página",
|
|
||||||
"Add additional restrictions specific to this page": "Adicionar restrições adicionais específicas para esta página",
|
|
||||||
"Access": "Acesso",
|
|
||||||
"People with access": "Pessoas com acesso",
|
|
||||||
"Remove all": "Remover tudo",
|
|
||||||
"Remove access": "Remover acesso",
|
|
||||||
"Remove all access": "Remover todo o acesso",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Tem certeza de que deseja remover o acesso deste membro à página?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Tem certeza de que deseja remover todo o acesso específico? Isso fará com que a página fique aberta para todos no espaço.",
|
|
||||||
"Trash retention": "Retenção da lixeira",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "As páginas na lixeira serão excluídas permanentemente após este período.",
|
|
||||||
"Trash retention updated": "Retenção da lixeira atualizada",
|
|
||||||
"Failed to update trash retention": "Falha ao atualizar a retenção da lixeira",
|
|
||||||
"Removed page restriction": "Restrição de página removida",
|
|
||||||
"Added page permission": "Permissão de página adicionada",
|
|
||||||
"Removed page permission": "Permissão de página removida"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"Admin": "Администратор",
|
"Admin": "Администратор",
|
||||||
"Are you sure you want to delete this group? Members will lose access to resources this group has access to.": "Вы уверены, что хотите удалить эту группу? Участники потеряют доступ к материалам, к которым у этой группы есть доступ.",
|
"Are you sure you want to delete this group? Members will lose access to resources this group has access to.": "Вы уверены, что хотите удалить эту группу? Участники потеряют доступ к материалам, к которым у этой группы есть доступ.",
|
||||||
"Are you sure you want to delete this page?": "Вы уверены, что хотите удалить эту страницу?",
|
"Are you sure you want to delete this page?": "Вы уверены, что хотите удалить эту страницу?",
|
||||||
"Are you sure you want to remove this user from the group? The user will lose access to resources this group has access to.": "Вы уверены, что хотите удалить этого пользователя из группы? Пользователь потеряет доступ к материалам, к которым есть доступ у этой группы.",
|
"Are you sure you want to remove this user from the group? The user will lose access to resources this group has access to.": "Вы уверены, что хотите удалить этого пользователя из группы? Пользователь потеряет доступ к материалам, к которым у этой группы есть доступ.",
|
||||||
"Are you sure you want to remove this user from the space? The user will lose all access to this space.": "Вы уверены, что хотите удалить этого пользователя из пространства? Пользователь потеряет весь доступ к этому пространству.",
|
"Are you sure you want to remove this user from the space? The user will lose all access to this space.": "Вы уверены, что хотите удалить этого пользователя из пространства? Пользователь потеряет весь доступ к этому пространству.",
|
||||||
"Are you sure you want to restore this version? Any changes not versioned will be lost.": "Вы уверены, что хотите восстановить эту версию? Все не зафиксированные изменения будут потеряны.",
|
"Are you sure you want to restore this version? Any changes not versioned will be lost.": "Вы уверены, что хотите восстановить эту версию? Все не зафиксированные изменения будут потеряны.",
|
||||||
"Can become members of groups and spaces in workspace": "Могут становиться участниками групп и пространств в рабочей области",
|
"Can become members of groups and spaces in workspace": "Могут становиться участниками групп и пространств в рабочей области",
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "Выберите предпочитаемый язык интерфейса.",
|
"Choose your preferred interface language.": "Выберите предпочитаемый язык интерфейса.",
|
||||||
"Choose your preferred page width.": "Выберите предпочитаемую ширину страницы.",
|
"Choose your preferred page width.": "Выберите предпочитаемую ширину страницы.",
|
||||||
"Confirm": "Подтвердить",
|
"Confirm": "Подтвердить",
|
||||||
"Copy as Markdown": "Копировать как Markdown",
|
|
||||||
"Copy link": "Копировать ссылку",
|
"Copy link": "Копировать ссылку",
|
||||||
"Create": "Создать",
|
"Create": "Создать",
|
||||||
"Create group": "Создать группу",
|
"Create group": "Создать группу",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "например, Пространство для продуктовой команды",
|
"e.g Space for product team": "например, Пространство для продуктовой команды",
|
||||||
"e.g Space for sales team to collaborate": "например, Пространство для совместной работы команды продаж",
|
"e.g Space for sales team to collaborate": "например, Пространство для совместной работы команды продаж",
|
||||||
"Edit": "Редактировать",
|
"Edit": "Редактировать",
|
||||||
"Read": "Читать",
|
|
||||||
"Edit group": "Редактировать группу",
|
"Edit group": "Редактировать группу",
|
||||||
"Email": "Электронная почта",
|
"Email": "Электронная почта",
|
||||||
"Enter a strong password": "Введите надёжный пароль",
|
"Enter a strong password": "Введите надёжный пароль",
|
||||||
@@ -63,7 +61,7 @@
|
|||||||
"Enter your current password": "Введите ваш текущий пароль",
|
"Enter your current password": "Введите ваш текущий пароль",
|
||||||
"enter your full name": "введите ваше полное имя",
|
"enter your full name": "введите ваше полное имя",
|
||||||
"Enter your new password": "Введите ваш новый пароль",
|
"Enter your new password": "Введите ваш новый пароль",
|
||||||
"Enter your new preferred email": "Введите ваш новый предпочтительный адрес электронной почты",
|
"Enter your new preferred email": "Введите ваш новый предпочитаемый адрес электронной почты",
|
||||||
"Enter your password": "Введите ваш пароль",
|
"Enter your password": "Введите ваш пароль",
|
||||||
"Error fetching page data.": "Ошибка при загрузке данных страницы.",
|
"Error fetching page data.": "Ошибка при загрузке данных страницы.",
|
||||||
"Error loading page history.": "Ошибка при загрузке истории страницы.",
|
"Error loading page history.": "Ошибка при загрузке истории страницы.",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "Группа не найдена",
|
"No group found": "Группа не найдена",
|
||||||
"No page history saved yet.": "История страниц ещё не сохранена.",
|
"No page history saved yet.": "История страниц ещё не сохранена.",
|
||||||
"No pages yet": "Страниц пока нет",
|
"No pages yet": "Страниц пока нет",
|
||||||
"No shared pages": "Нет общих страниц",
|
|
||||||
"No results found...": "Результаты не найдены...",
|
"No results found...": "Результаты не найдены...",
|
||||||
"No user found": "Пользователь не найден",
|
"No user found": "Пользователь не найден",
|
||||||
"Overview": "Обзор",
|
"Overview": "Обзор",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "страница",
|
"page": "страница",
|
||||||
"Page deleted successfully": "Страница успешно удалена",
|
"Page deleted successfully": "Страница успешно удалена",
|
||||||
"Page history": "История страницы",
|
"Page history": "История страницы",
|
||||||
"Select version": "Выбрать версию",
|
|
||||||
"Highlight changes": "Выделить изменения",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "Импорт страницы в процессе. Пожалуйста, не закрывайте эту вкладку.",
|
"Page import is in progress. Please do not close this tab.": "Импорт страницы в процессе. Пожалуйста, не закрывайте эту вкладку.",
|
||||||
"Pages": "Страницы",
|
"Pages": "Страницы",
|
||||||
"pages": "страницы",
|
"pages": "страницы",
|
||||||
"Password": "Пароль",
|
"Password": "Пароль",
|
||||||
"Password changed successfully": "Пароль успешно изменён",
|
"Password changed successfully": "Пароль успешно изменён",
|
||||||
"People": "Люди",
|
|
||||||
"Pending": "В ожидании",
|
"Pending": "В ожидании",
|
||||||
"Please confirm your action": "Пожалуйста, подтвердите ваше действие",
|
"Please confirm your action": "Пожалуйста, подтвердите ваше действие",
|
||||||
"Preferences": "Настройки",
|
"Preferences": "Настройки",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "Ответить...",
|
"Reply...": "Ответить...",
|
||||||
"Error loading comments.": "Ошибка при загрузке комментариев.",
|
"Error loading comments.": "Ошибка при загрузке комментариев.",
|
||||||
"No comments yet.": "Комментариев пока нет.",
|
"No comments yet.": "Комментариев пока нет.",
|
||||||
"No open comments.": "Нет открытых комментариев.",
|
|
||||||
"No resolved comments.": "Нет решённых комментариев.",
|
|
||||||
"Add a comment...": "Добавить комментарий...",
|
|
||||||
"Edit comment": "Редактировать комментарий",
|
"Edit comment": "Редактировать комментарий",
|
||||||
"Delete comment": "Удалить комментарий",
|
"Delete comment": "Удалить комментарий",
|
||||||
"Are you sure you want to delete this comment?": "Вы уверены, что хотите удалить этот комментарий?",
|
"Are you sure you want to delete this comment?": "Вы уверены, что хотите удалить этот комментарий?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "Комментарий успешно удалён",
|
"Comment deleted successfully": "Комментарий успешно удалён",
|
||||||
"Failed to delete comment": "Не удалось удалить комментарий",
|
"Failed to delete comment": "Не удалось удалить комментарий",
|
||||||
"Comment resolved successfully": "Комментарий успешно разрешён",
|
"Comment resolved successfully": "Комментарий успешно разрешён",
|
||||||
"Comment re-opened successfully": "Комментарий успешно открыт заново",
|
|
||||||
"Comment unresolved successfully": "Комментарий успешно размечен как нерешённый",
|
|
||||||
"Failed to resolve comment": "Не удалось разрешить комментарий",
|
"Failed to resolve comment": "Не удалось разрешить комментарий",
|
||||||
"Resolve comment": "Разрешить комментарий",
|
|
||||||
"Unresolve comment": "Отметить комментарий как нерешённый",
|
|
||||||
"Resolve Comment Thread": "Закрыть цепочку комментариев",
|
|
||||||
"Unresolve Comment Thread": "Отметить цепочку комментариев как нерешённую",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Вы уверены, что хотите закрыть эту цепочку комментариев? Это пометит её как завершённую.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Вы уверены, что хотите отметить эту цепочку комментариев как нерешённую?",
|
|
||||||
"Resolved": "Решено",
|
|
||||||
"No active comments.": "Нет активных комментариев.",
|
|
||||||
"Revoke invitation": "Отозвать приглашение",
|
"Revoke invitation": "Отозвать приглашение",
|
||||||
"Revoke": "Отозвать",
|
"Revoke": "Отозвать",
|
||||||
"Don't": "Нет",
|
"Don't": "Нет",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "Любой, у кого есть данная ссылка, может присоединиться к этой рабочей области.",
|
"Anyone with this link can join this workspace.": "Любой, у кого есть данная ссылка, может присоединиться к этой рабочей области.",
|
||||||
"Invite link": "Ссылка для приглашения",
|
"Invite link": "Ссылка для приглашения",
|
||||||
"Copy": "Копировать",
|
"Copy": "Копировать",
|
||||||
"Copy to space": "Копировать в пространство",
|
|
||||||
"Copied": "Скопировано",
|
"Copied": "Скопировано",
|
||||||
"Duplicate": "Дублировать",
|
|
||||||
"Select a user": "Выберите пользователя",
|
"Select a user": "Выберите пользователя",
|
||||||
"Select a group": "Выберите группу",
|
"Select a group": "Выберите группу",
|
||||||
"Export all pages and attachments in this space.": "Экспортировать все страницы и вложения в этом пространстве.",
|
"Export all pages and attachments in this space.": "Экспортировать все страницы и вложения в этом пространстве.",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "Экспортирование не удалось:",
|
"Export failed:": "Экспортирование не удалось:",
|
||||||
"export error": "ошибка экспорта",
|
"export error": "ошибка экспорта",
|
||||||
"Export page": "Экспорт страницы",
|
"Export page": "Экспорт страницы",
|
||||||
"Export successful": "Экспорт выполнен успешно",
|
|
||||||
"Export space": "Экспорт пространства",
|
"Export space": "Экспорт пространства",
|
||||||
"Export {{type}}": "Экспорт {{type}}",
|
"Export {{type}}": "Экспорт {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "Файл превышает лимит вложений {{limit}}",
|
"File exceeds the {{limit}} attachment limit": "Файл превышает лимит вложений {{limit}}",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "Добавить строку ниже",
|
"Add row below": "Добавить строку ниже",
|
||||||
"Delete table": "Удалить таблицу",
|
"Delete table": "Удалить таблицу",
|
||||||
"Info": "Информация",
|
"Info": "Информация",
|
||||||
"Note": "Примечание",
|
|
||||||
"Success": "Успешно",
|
"Success": "Успешно",
|
||||||
"Warning": "Предупреждение",
|
"Warning": "Предупреждение",
|
||||||
"Danger": "Важно",
|
"Danger": "Важно",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "Загрузить любое изображение с вашего устройства.",
|
"Upload any image from your device.": "Загрузить любое изображение с вашего устройства.",
|
||||||
"Upload any video from your device.": "Загрузить любое видео с вашего устройства.",
|
"Upload any video from your device.": "Загрузить любое видео с вашего устройства.",
|
||||||
"Upload any file from your device.": "Загрузить любой файл с вашего устройства.",
|
"Upload any file from your device.": "Загрузить любой файл с вашего устройства.",
|
||||||
"Uploading {{name}}": "Загрузка {{name}}",
|
|
||||||
"Uploading file": "Загрузка файла",
|
|
||||||
"Table": "Таблица",
|
"Table": "Таблица",
|
||||||
"Insert a table.": "Вставить таблицу.",
|
"Insert a table.": "Вставить таблицу.",
|
||||||
"Insert collapsible block.": "Вставить сворачиваемый блок.",
|
"Insert collapsible block.": "Вставить сворачиваемый блок.",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "Вставить текущую дату",
|
"Insert current date": "Вставить текущую дату",
|
||||||
"Draw and sketch excalidraw diagrams": "Вставить и рисовать диаграммы Excalidraw",
|
"Draw and sketch excalidraw diagrams": "Вставить и рисовать диаграммы Excalidraw",
|
||||||
"Multiple": "Несколько",
|
"Multiple": "Несколько",
|
||||||
"Turn into": "Преобразовать в",
|
|
||||||
"Text align": "Выравнивание текста",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Эта страница могла быть удалена, перемещена, или у вас может отсутствовать доступ к ней.",
|
|
||||||
"Go to homepage": "Вернуться на главную",
|
|
||||||
"Pages you create will show up here.": "Созданные вами страницы появятся здесь.",
|
|
||||||
"Heading {{level}}": "Заголовок {{level}}",
|
"Heading {{level}}": "Заголовок {{level}}",
|
||||||
"Toggle title": "Переключить заголовок",
|
"Toggle title": "Переключить заголовок",
|
||||||
"Write anything. Enter \"/\" for commands": "Начните писать. Введите \"/\" для списка команд",
|
"Write anything. Enter \"/\" for commands": "Начните писать. Введите \"/\" для списка команд",
|
||||||
"Write...": "Напишите...",
|
|
||||||
"Column count": "Количество столбцов",
|
|
||||||
"{{count}} Columns": "{count, plural, one{# столбец} few{# столбца} many{# столбцов} other{# столбца}}",
|
|
||||||
"Equal columns": "Равные столбцы",
|
|
||||||
"Left sidebar": "Левая боковая панель",
|
|
||||||
"Right sidebar": "Правая боковая панель",
|
|
||||||
"Wide center": "Широкий по центру",
|
|
||||||
"Left wide": "Широкий слева",
|
|
||||||
"Right wide": "Широкий справа",
|
|
||||||
"Names do not match": "Названия не совпадают",
|
"Names do not match": "Названия не совпадают",
|
||||||
"Today, {{time}}": "Сегодня, {{time}}",
|
"Today, {{time}}": "Сегодня, {{time}}",
|
||||||
"Yesterday, {{time}}": "Вчера, {{time}}",
|
"Yesterday, {{time}}": "Вчера, {{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "Количество символов: {{characterCount}}",
|
"Character count: {{characterCount}}": "Количество символов: {{characterCount}}",
|
||||||
"New update": "Новое обновление",
|
"New update": "Новое обновление",
|
||||||
"{{latestVersion}} is available": "Доступна новая версия {{latestVersion}}",
|
"{{latestVersion}} is available": "Доступна новая версия {{latestVersion}}",
|
||||||
"Default page edit mode": "Режим редактирования страницы по умолчанию",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Выберите предпочитаемый режим редактирования страницы. Избегайте случайных изменений.",
|
|
||||||
"Reading": "Чтение",
|
|
||||||
"Delete member": "Удалить участника",
|
"Delete member": "Удалить участника",
|
||||||
"Member deleted successfully": "Участник успешно удален",
|
"Member deleted successfully": "Участник успешно удален",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Вы уверены, что хотите удалить этого участника рабочей области? Это действие необратимо.",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "Вы уверены, что хотите удалить этого участника рабочей области? Это действие необратимо.",
|
||||||
"Deactivate member": "Деактивировать участника",
|
|
||||||
"Activate member": "Активировать участника",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Вы уверены, что хотите деактивировать этого участника рабочего пространства? Они больше не смогут получить доступ к этому рабочему пространству.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Вы уверены, что хотите активировать этого участника рабочего пространства?",
|
|
||||||
"Deactivate": "Деактивировать",
|
|
||||||
"Activate": "Активировать",
|
|
||||||
"Deactivated": "Деактивирован",
|
|
||||||
"Move": "Переместить",
|
"Move": "Переместить",
|
||||||
"Move page": "Переместить страницу",
|
"Move page": "Переместить страницу",
|
||||||
"Move page to a different space.": "Переместите страницу в другое пространство.",
|
"Move page to a different space.": "Переместите страницу в другое пространство.",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "Общие страницы из пространств, участником которых вы являетесь, появятся здесь",
|
"Publicly shared pages from spaces you are a member of will appear here": "Общие страницы из пространств, участником которых вы являетесь, появятся здесь",
|
||||||
"Share deleted successfully": "Общий доступ успешно удален",
|
"Share deleted successfully": "Общий доступ успешно удален",
|
||||||
"Share not found": "Общий доступ не найден",
|
"Share not found": "Общий доступ не найден",
|
||||||
"Failed to share page": "Не удалось поделиться страницей",
|
"Failed to share page": "Не удалось поделиться страницей"
|
||||||
"Disable public sharing": "Отключить общий доступ",
|
|
||||||
"Prevent members from sharing pages publicly.": "Запретить участникам делиться страницами публично.",
|
|
||||||
"Toggle public sharing": "Переключить общий доступ",
|
|
||||||
"Toggle space public sharing": "Переключить общий доступ для пространства",
|
|
||||||
"Public sharing is disabled at the workspace level": "Общий доступ отключен на уровне рабочего пространства",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Запретить делиться страницами в этом пространстве публично.",
|
|
||||||
"Requires an enterprise license": "Требуется корпоративная лицензия",
|
|
||||||
"Page permissions": "Права доступа к странице},{",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Контролируйте, кто может просматривать и редактировать отдельные страницы. Доступно при наличии лицензии Enterprise.",
|
|
||||||
"Enable public sharing": "Включить общий доступ",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Вы уверены, что хотите включить общий доступ? Участники смогут делиться страницами публично.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Вы уверены, что хотите отключить общий доступ? Все существующие ссылки в этом рабочем пространстве будут удалены.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Вы уверены, что хотите включить общий доступ для этого пространства?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Вы уверены, что хотите отключить общий доступ? Все существующие ссылки в этом пространстве будут удалены.",
|
|
||||||
"Public sharing is disabled": "Общий доступ отключен",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "Общий доступ был отключен на уровне рабочего пространства.",
|
|
||||||
"Public sharing has been disabled for this space.": "Общий доступ был отключен для этого пространства.",
|
|
||||||
"Copy page": "Копировать страницу",
|
|
||||||
"Copy page to a different space.": "Копировать страницу в другое пространство.",
|
|
||||||
"Page copied successfully": "Страница успешно скопирована",
|
|
||||||
"Page duplicated successfully": "Страница успешно дублирована",
|
|
||||||
"Find": "Найти",
|
|
||||||
"Not found": "Не найдено",
|
|
||||||
"Previous Match (Shift+Enter)": "Предыдущее совпадение (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Следующее совпадение (Enter)",
|
|
||||||
"Match case (Alt+C)": "Учитывать регистр (Alt+C)",
|
|
||||||
"Replace": "Заменить",
|
|
||||||
"Close (Escape)": "Закрыть (Escape)",
|
|
||||||
"Replace (Enter)": "Заменить (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Заменить все (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Заменить все",
|
|
||||||
"View all spaces": "Просмотреть все пространства",
|
|
||||||
"Error": "Ошибка",
|
|
||||||
"Failed to disable MFA": "Не удалось отключить двухфакторную аутентификацию",
|
|
||||||
"Disable two-factor authentication": "Отключить двухфакторную аутентификацию",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Отключение двухфакторной аутентификации сделает вашу учетную запись менее безопасной. Для входа потребуется только пароль.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Пожалуйста, введите ваш пароль, чтобы отключить двухфакторную аутентификацию:",
|
|
||||||
"Two-factor authentication has been enabled": "Двухфакторная аутентификация включена",
|
|
||||||
"Two-factor authentication has been disabled": "Двухфакторная аутентификация отключена",
|
|
||||||
"2-step verification": "Двухэтапная проверка",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Защитите свою учетную запись дополнительным уровнем проверки при входе.",
|
|
||||||
"Two-factor authentication is active on your account.": "Двухфакторная аутентификация активна на вашей учетной записи.",
|
|
||||||
"Add 2FA method": "Добавить метод 2FA",
|
|
||||||
"Backup codes": "Резервные коды",
|
|
||||||
"Disable": "Отключить",
|
|
||||||
"Invalid verification code": "Неверный код проверки",
|
|
||||||
"New backup codes have been generated": "Созданы новые резервные коды",
|
|
||||||
"Failed to regenerate backup codes": "Не удалось создать новые резервные коды",
|
|
||||||
"About backup codes": "О резервных кодах",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Резервные коды можно использовать для доступа к вашей учетной записи, если вы потеряли доступ к приложению-аутентификатору. Каждый код можно использовать только один раз.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Вы можете создать новые резервные коды в любое время. Это аннулирует все существующие коды.",
|
|
||||||
"Confirm password": "Подтвердите пароль",
|
|
||||||
"Generate new backup codes": "Создать новые резервные коды",
|
|
||||||
"Save your new backup codes": "Сохраните ваши новые резервные коды",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Убедитесь, что сохранили эти коды в безопасном месте. Ваши старые резервные коды больше недействительны.",
|
|
||||||
"Your new backup codes": "Ваши новые резервные коды",
|
|
||||||
"I've saved my backup codes": "Я сохранил(а) свои резервные коды",
|
|
||||||
"Failed to setup MFA": "Не удалось настроить многофакторную аутентификацию",
|
|
||||||
"Setup & Verify": "Настроить и проверить",
|
|
||||||
"Add to authenticator": "Добавить в аутентификатор",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Отсканируйте этот QR-код с помощью вашего приложения-аутентификатора",
|
|
||||||
"Can't scan the code?": "Не удается сканировать код?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Введите этот код вручную в приложении-аутентификаторе:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Введите 6-значный код из вашего аутентификатора",
|
|
||||||
"Verify and enable": "Проверить и включить",
|
|
||||||
"Failed to generate QR code. Please try again.": "Не удалось создать QR-код. Пожалуйста, попробуйте снова.",
|
|
||||||
"Backup": "Резервное копирование",
|
|
||||||
"Save codes": "Сохранить коды",
|
|
||||||
"Save your backup codes": "Сохраните ваши резервные коды",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Эти коды можно использовать для доступа к вашей учетной записи, если вы потеряли доступ к приложению-аутентификатору. Каждый код можно использовать только один раз.",
|
|
||||||
"Print": "Печать",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "Двухфакторная аутентификация настроена. Пожалуйста, войдите снова.",
|
|
||||||
"Two-Factor authentication required": "Требуется двухфакторная аутентификация",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Ваше рабочее пространство требует двухфакторной аутентификации для всех пользователей",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Чтобы продолжать доступ к вашему рабочему пространству, вы должны настроить двухфакторную аутентификацию. Это добавляет дополнительный уровень безопасности к вашей учетной записи.",
|
|
||||||
"Set up two-factor authentication": "Настройте двухфакторную аутентификацию",
|
|
||||||
"Cancel and logout": "Отменить и выйти",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Ваше рабочее пространство требует двухфакторной аутентификации. Пожалуйста, настройте её, чтобы продолжить.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Это добавляет дополнительный уровень безопасности к вашей учетной записи, требуя код проверки из вашего приложения-аутентификатора.",
|
|
||||||
"Password is required": "Требуется пароль",
|
|
||||||
"Password must be at least 8 characters": "Пароль должен содержать как минимум 8 символов",
|
|
||||||
"Please enter a 6-digit code": "Пожалуйста, введите 6-значный код",
|
|
||||||
"Code must be exactly 6 digits": "Код должен содержать ровно 6 цифр",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Введите 6-значный код из вашего приложения-аутентификатора",
|
|
||||||
"Need help authenticating?": "Нужна помощь с аутентификацией?",
|
|
||||||
"MFA QR Code": "QR-код двухфакторной аутентификации",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Учетная запись успешно создана. Пожалуйста, войдите, чтобы настроить двухфакторную аутентификацию.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Сброс пароля выполнен успешно. Пожалуйста, войдите с вашим новым паролем и завершите настройку двухфакторной аутентификации.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Сброс пароля выполнен успешно. Пожалуйста, войдите с вашим новым паролем, чтобы настроить двухфакторную аутентификацию.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "Сброс пароля выполнен успешно. Пожалуйста, войдите с вашим новым паролем.",
|
|
||||||
"Two-factor authentication": "Двухфакторная аутентификация",
|
|
||||||
"Use authenticator app instead": "Используйте приложение-аутентификатор вместо этого",
|
|
||||||
"Verify backup code": "Проверка резервного кода",
|
|
||||||
"Use backup code": "Использовать резервный код",
|
|
||||||
"Enter one of your backup codes": "Введите один из ваших резервных кодов",
|
|
||||||
"Backup code": "Резервный код",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Введите один из ваших резервных кодов. Каждый резервный код можно использовать только один раз.",
|
|
||||||
"Verify": "Проверить",
|
|
||||||
"Trash": "Корзина",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "{count, plural, one {Страница в корзине будет окончательно удалена через # день.} few {Страницы в корзине будут окончательно удалены через # дня.} many {Страницы в корзине будут окончательно удалены через # дней.} other {Страницы в корзине будут окончательно удалены через # дней.}}",
|
|
||||||
"Deleted": "Удалено",
|
|
||||||
"No pages in trash": "В корзине нет страниц",
|
|
||||||
"Permanently delete page?": "Удалить страницу окончательно?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Вы уверены, что хотите окончательно удалить '{{title}}'? Это действие невозможно отменить.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "Восстановить '{{title}}' и её подстраницы?",
|
|
||||||
"Move to trash": "Переместить в корзину",
|
|
||||||
"Move this page to trash?": "Переместить эту страницу в корзину?",
|
|
||||||
"Restore page": "Восстановить страницу",
|
|
||||||
"Page moved to trash": "Страница перемещена в корзину",
|
|
||||||
"Page restored successfully": "Страница успешно восстановлена",
|
|
||||||
"Deleted by": "Удалено пользователем",
|
|
||||||
"Deleted at": "Удалено в",
|
|
||||||
"Preview": "Предпросмотр",
|
|
||||||
"Subpages": "Подстраницы",
|
|
||||||
"Failed to load subpages": "Не удалось загрузить под страницы",
|
|
||||||
"No subpages": "Нет подстраниц",
|
|
||||||
"Subpages (Child pages)": "Подстраницы (вложенные страницы)",
|
|
||||||
"List all subpages of the current page": "Показать все под страницы",
|
|
||||||
"Attachments": "Вложения",
|
|
||||||
"All spaces": "Все пространства",
|
|
||||||
"Unknown": "Неизвестно",
|
|
||||||
"Find a space": "Найти пространство",
|
|
||||||
"Search in all your spaces": "Поиск во всех ваших пространствах",
|
|
||||||
"Type": "Тип",
|
|
||||||
"Enterprise": "Предприятие",
|
|
||||||
"Download attachment": "Скачать вложение",
|
|
||||||
"Allowed email domains": "Разрешенные домены электронной почты",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Только пользователи с электронными адресами из этих доменов могут зарегистрироваться через SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Введите допустимые доменные имена, разделённые запятыми или пробелами",
|
|
||||||
"Enforce two-factor authentication": "Обязательная двухфакторная аутентификация",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "После введения обязательности все участники должны будут включить двухфакторную аутентификацию для доступа к рабочему пространству.",
|
|
||||||
"Toggle MFA enforcement": "Переключить обязательность MFA",
|
|
||||||
"Display name": "Отображаемое имя",
|
|
||||||
"Allow signup": "Разрешить регистрацию",
|
|
||||||
"Enabled": "Включено",
|
|
||||||
"Advanced Settings": "Расширенные настройки",
|
|
||||||
"Enable TLS/SSL": "Включить TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Использовать защищённое соединение с сервером LDAP",
|
|
||||||
"Group sync": "Синхронизация группы",
|
|
||||||
"No SSO providers found.": "Поставщики SSO не найдены.",
|
|
||||||
"Delete SSO provider": "Удалить поставщика SSO",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Вы уверены, что хотите удалить этого поставщика SSO?",
|
|
||||||
"Action": "Действие",
|
|
||||||
"{{ssoProviderType}} configuration": "Настройка {{ssoProviderType}}",
|
|
||||||
"Icon": "Иконка",
|
|
||||||
"Upload image": "Загрузить изображение",
|
|
||||||
"Remove image": "Удалить изображение",
|
|
||||||
"Failed to remove image": "Не удалось удалить изображение",
|
|
||||||
"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 ключ",
|
|
||||||
"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-ключи. Существующие ключи участников продолжат работать.",
|
|
||||||
"Toggle restrict API keys to admins": "Переключить ограничение создания API-ключей только для администраторов",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "Создание API-ключей ограничено администраторами вашего рабочего пространства.",
|
|
||||||
"AI settings": "Настройки ИИ",
|
|
||||||
"AI search": "Поиск ИИ",
|
|
||||||
"AI Answer": "Ответ ИИ",
|
|
||||||
"Ask AI": "Спросить ИИ",
|
|
||||||
"AI is thinking...": "ИИ обрабатывает запрос...",
|
|
||||||
"Ask a question...": "Задайте вопрос...",
|
|
||||||
"AI Answers": "Ответы ИИ",
|
|
||||||
"AI-powered search (AI Answers)": "Поиск на базе ИИ (Ответы ИИ)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "Поиск ИИ использует векторные встраивания для обеспечения семантического поиска по содержимому вашего рабочего пространства.",
|
|
||||||
"Toggle AI search": "Переключить поиск ИИ",
|
|
||||||
"Generative AI (Ask AI)": "Генеративный ИИ (Спросить ИИ)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Включите создание контента на базе ИИ в редакторе. Позволяет пользователям генерировать, улучшать, переводить и преобразовывать текст.",
|
|
||||||
"Toggle generative AI": "Переключить генеративный ИИ",
|
|
||||||
"Enterprise feature": "Корпоративная функция",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "ИИ доступен только в корпоративной версии Docmost. Свяжитесь по адресу sales@docmost.com.",
|
|
||||||
"AI & MCP": "ИИ и MCP",
|
|
||||||
"AI": "ИИ",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Протокол контекста модели (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Включите сервер MCP, чтобы ИИ-ассистенты и инструменты могли взаимодействовать с содержимым вашего рабочего пространства.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP доступен только в корпоративной версии Docmost. Свяжитесь по адресу sales@docmost.com.",
|
|
||||||
"MCP documentation": "Документация MCP",
|
|
||||||
"MCP Server URL": "URL сервера MCP",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Используйте ваш API-ключ для аутентификации. Управлять API-ключами можно в настройках аккаунта.",
|
|
||||||
"Supported tools": "Поддерживаемые инструменты",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "В вашем рабочем пространстве включён MCP. Используйте свой API-ключ для подключения ИИ-ассистентов.",
|
|
||||||
"MCP server URL:": "URL сервера MCP:",
|
|
||||||
"Learn more": "Подробнее",
|
|
||||||
"View the": "Просмотреть",
|
|
||||||
"for usage details.": "для подробностей использования.",
|
|
||||||
"for setup instructions.": "для инструкций по настройке.",
|
|
||||||
"API documentation": "Документация API",
|
|
||||||
"Sources": "Источники",
|
|
||||||
"AI Answers not available for attachments": "Ответы ИИ недоступны для вложений",
|
|
||||||
"No answer available": "Ответ недоступен",
|
|
||||||
"Background color": "Цвет фона",
|
|
||||||
"Highlight color": "Цвет выделения",
|
|
||||||
"Remove color": "Удалить цвет",
|
|
||||||
"Notifications": "Уведомления",
|
|
||||||
"No notifications": "Нет уведомлений",
|
|
||||||
"No unread notifications": "Нет непрочитанных уведомлений",
|
|
||||||
"All notifications": "Все уведомления",
|
|
||||||
"Unread only": "Только непрочитанные",
|
|
||||||
"Mark all as read": "Отметить все как прочитанные",
|
|
||||||
"Mark as read": "Отметить как прочитанное",
|
|
||||||
"More options": "Больше возможностей",
|
|
||||||
"mentioned you in a comment": "упомянул вас в комментарии",
|
|
||||||
"commented on a page": "прокомментировал на странице",
|
|
||||||
"resolved a comment": "разрешил комментарий",
|
|
||||||
"mentioned you on a page": "упомянул вас на странице",
|
|
||||||
"gave you edit access to a page": "предоставил вам доступ на редактирование страницы",
|
|
||||||
"gave you view access to a page": "предоставил вам доступ для просмотра страницы",
|
|
||||||
"Today": "Сегодня",
|
|
||||||
"Yesterday": "Вчера",
|
|
||||||
"This week": "На этой неделе",
|
|
||||||
"Older": "Старше",
|
|
||||||
"Restricted page": "Страница с ограниченным доступом",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Страницы с ограниченным доступом нельзя сделать общедоступными.",
|
|
||||||
"Restricted by parent": "Ограничено родительской страницей",
|
|
||||||
"Restricted": "Ограничено",
|
|
||||||
"Open": "Открыто",
|
|
||||||
"Inherits restrictions from ancestor page": "Наследует ограничения от родительской страницы",
|
|
||||||
"Only people listed below can access this page": "Доступ к этой странице имеют только перечисленные ниже пользователи",
|
|
||||||
"Everyone in this space can access": "Доступ имеют все участники этого пространства",
|
|
||||||
"No additional restrictions on this page": "На этой странице нет дополнительных ограничений",
|
|
||||||
"Only specific people can access": "Доступ имеют только определённые пользователи",
|
|
||||||
"Use only inherited restrictions": "Использовать только унаследованные ограничения",
|
|
||||||
"Add restrictions on top of inherited": "Добавить ограничения поверх унаследованных",
|
|
||||||
"Inherited restriction": "Унаследованное ограничение",
|
|
||||||
"Access limited by": "Доступ ограничен",
|
|
||||||
"Restrict access to control who can view and edit this page": "Ограничьте доступ, чтобы контролировать, кто может просматривать и редактировать эту страницу",
|
|
||||||
"Add additional restrictions specific to this page": "Добавить дополнительные ограничения, применимые только к этой странице",
|
|
||||||
"Access": "Доступ",
|
|
||||||
"People with access": "Пользователи с доступом",
|
|
||||||
"Remove all": "Удалить всё",
|
|
||||||
"Remove access": "Удалить доступ",
|
|
||||||
"Remove all access": "Удалить весь доступ",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Вы уверены, что хотите удалить доступ этого участника к странице?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Вы уверены, что хотите удалить все специальные права доступа? Это сделает страницу доступной всем участникам пространства.",
|
|
||||||
"Trash retention": "Срок хранения корзины",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Страницы в корзине будут окончательно удалены по истечении этого срока.",
|
|
||||||
"Trash retention updated": "Срок хранения корзины обновлён",
|
|
||||||
"Failed to update trash retention": "Не удалось обновить срок хранения корзины",
|
|
||||||
"Removed page restriction": "Ограничение доступа к странице удалено",
|
|
||||||
"Added page permission": "Добавлено разрешение доступа к странице",
|
|
||||||
"Removed page permission": "Удалено разрешение доступа к странице"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,697 +0,0 @@
|
|||||||
{
|
|
||||||
"Account": "Обліковий запис",
|
|
||||||
"Active": "Активний",
|
|
||||||
"Add": "Додати",
|
|
||||||
"Add group members": "Додати учасників групи",
|
|
||||||
"Add groups": "Додати групи",
|
|
||||||
"Add members": "Додати учасників",
|
|
||||||
"Add to groups": "Додати до груп",
|
|
||||||
"Add space members": "Додати учасників простору",
|
|
||||||
"Admin": "Адміністратор",
|
|
||||||
"Are you sure you want to delete this group? Members will lose access to resources this group has access to.": "Ви впевнені, що хочете видалити цю групу? Учасники втратять доступ до матеріалів, до яких ця група має доступ.",
|
|
||||||
"Are you sure you want to delete this page?": "Ви впевнені, що хочете видалити цю сторінку?",
|
|
||||||
"Are you sure you want to remove this user from the group? The user will lose access to resources this group has access to.": "Ви впевнені, що хочете видалити цього користувача з групи? Користувач втратить доступ до матеріалів, до яких ця група має доступ.",
|
|
||||||
"Are you sure you want to remove this user from the space? The user will lose all access to this space.": "Ви впевнені, що хочете видалити цього користувача з простору? Користувач втратить весь доступ до цього простору.",
|
|
||||||
"Are you sure you want to restore this version? Any changes not versioned will be lost.": "Ви впевнені, що хочете відновити цю версію? Усі не збережені зміни будуть втрачені.",
|
|
||||||
"Can become members of groups and spaces in workspace": "Можуть ставати учасниками груп та просторів у робочій області",
|
|
||||||
"Can create and edit pages in space.": "Може створювати та редагувати сторінки в просторі.",
|
|
||||||
"Can edit": "Може редагувати",
|
|
||||||
"Can manage workspace": "Може керувати робочою областю",
|
|
||||||
"Can manage workspace but cannot delete it": "Може керувати робочою областю, але не може її видалити",
|
|
||||||
"Can view": "Може переглядати",
|
|
||||||
"Can view pages in space but not edit.": "Може переглядати сторінки в просторі, але не може їх редагувати.",
|
|
||||||
"Cancel": "Скасувати",
|
|
||||||
"Change email": "Змінити електронну пошту",
|
|
||||||
"Change password": "Змінити пароль",
|
|
||||||
"Change photo": "Змінити фото",
|
|
||||||
"Choose a role": "Оберіть роль",
|
|
||||||
"Choose your preferred color scheme.": "Оберіть бажану кольорову схему.",
|
|
||||||
"Choose your preferred interface language.": "Оберіть бажану мову інтерфейсу.",
|
|
||||||
"Choose your preferred page width.": "Оберіть бажану ширину сторінки.",
|
|
||||||
"Confirm": "Підтвердити",
|
|
||||||
"Copy as Markdown": "Скопіювати як Markdown",
|
|
||||||
"Copy link": "Копіювати посилання",
|
|
||||||
"Create": "Створити",
|
|
||||||
"Create group": "Створити групу",
|
|
||||||
"Create page": "Створити сторінку",
|
|
||||||
"Create space": "Створити простір",
|
|
||||||
"Create workspace": "Створити робочу область",
|
|
||||||
"Current password": "Поточний пароль",
|
|
||||||
"Dark": "Темна",
|
|
||||||
"Date": "Дата",
|
|
||||||
"Delete": "Видалити",
|
|
||||||
"Delete group": "Видалити групу",
|
|
||||||
"Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Ви впевнені, що хочете видалити цю сторінку? Це видалить її дочірні сторінки, а також історію сторінки. Ця дія необоротна.",
|
|
||||||
"Description": "Опис",
|
|
||||||
"Details": "Деталі",
|
|
||||||
"e.g ACME": "наприклад, ACME",
|
|
||||||
"e.g ACME Inc": "наприклад, ACME Inc",
|
|
||||||
"e.g Developers": "наприклад, Розробники",
|
|
||||||
"e.g Group for developers": "наприклад, Група для розробників",
|
|
||||||
"e.g product": "наприклад, продукт",
|
|
||||||
"e.g Product Team": "наприклад, Продуктова команда",
|
|
||||||
"e.g Sales": "наприклад, Продажі",
|
|
||||||
"e.g Space for product team": "наприклад, Простір для продуктової команди",
|
|
||||||
"e.g Space for sales team to collaborate": "наприклад, Простір для спільної роботи команди продажів",
|
|
||||||
"Edit": "Редагувати",
|
|
||||||
"Read": "Читати",
|
|
||||||
"Edit group": "Редагувати групу",
|
|
||||||
"Email": "Електронна пошта",
|
|
||||||
"Enter a strong password": "Введіть надійний пароль",
|
|
||||||
"Enter valid email addresses separated by comma or space max_50": "Введіть дійсні адреси електронної пошти, розділені комою або пробілом [макс: 50]",
|
|
||||||
"enter valid emails addresses": "введіть дійсні адреси електронної пошти",
|
|
||||||
"Enter your current password": "Введіть ваш поточний пароль",
|
|
||||||
"enter your full name": "введіть ваше повне ім'я",
|
|
||||||
"Enter your new password": "Введіть ваш новий пароль",
|
|
||||||
"Enter your new preferred email": "Введіть вашу нову бажану електронну пошту",
|
|
||||||
"Enter your password": "Введіть ваш пароль",
|
|
||||||
"Error fetching page data.": "Помилка при завантаженні даних сторінки.",
|
|
||||||
"Error loading page history.": "Помилка при завантаженні історії сторінки.",
|
|
||||||
"Export": "Експорт",
|
|
||||||
"Failed to create page": "Не вдалося створити сторінку",
|
|
||||||
"Failed to delete page": "Не вдалося видалити сторінку",
|
|
||||||
"Failed to fetch recent pages": "Не вдалося отримати нещодавні сторінки",
|
|
||||||
"Failed to import pages": "Не вдалося імпортувати сторінки",
|
|
||||||
"Failed to load page. An error occurred.": "Не вдалося завантажити сторінку. Сталася помилка.",
|
|
||||||
"Failed to update data": "Не вдалося оновити дані",
|
|
||||||
"Full access": "Повний доступ",
|
|
||||||
"Full page width": "Ширина на всю сторінку",
|
|
||||||
"Full width": "На всю ширину",
|
|
||||||
"General": "Загальні",
|
|
||||||
"Group": "Група",
|
|
||||||
"Group description": "Опис групи",
|
|
||||||
"Group name": "Назва групи",
|
|
||||||
"Groups": "Групи",
|
|
||||||
"Has full access to space settings and pages.": "Має повний доступ до налаштувань простору та сторінок.",
|
|
||||||
"Home": "Головна",
|
|
||||||
"Import pages": "Імпорт сторінок",
|
|
||||||
"Import pages & space settings": "Імпорт сторінок і налаштування простору",
|
|
||||||
"Importing pages": "Імпортування сторінок",
|
|
||||||
"invalid invitation link": "посилання на запрошення недійсне",
|
|
||||||
"Invitation signup": "Реєстрація за запрошенням",
|
|
||||||
"Invite by email": "Запросити електронною поштою",
|
|
||||||
"Invite members": "Запросити учасників",
|
|
||||||
"Invite new members": "Запросити нових учасників",
|
|
||||||
"Invited members who are yet to accept their invitation will appear here.": "Запрошені учасники, які ще не прийняли запрошення, з'являться тут.",
|
|
||||||
"Invited members will be granted access to spaces the groups can access": "Запрошені учасники отримають доступ до просторів, доступ до яких має група",
|
|
||||||
"Join the workspace": "Приєднатися до робочої області",
|
|
||||||
"Language": "Мова",
|
|
||||||
"Light": "Світла",
|
|
||||||
"Link copied": "Посилання скопійовано",
|
|
||||||
"Login": "Увійти",
|
|
||||||
"Logout": "Вийти",
|
|
||||||
"Manage Group": "Керування групою",
|
|
||||||
"Manage members": "Керування учасниками",
|
|
||||||
"member": "учасник",
|
|
||||||
"Member": "Учасник",
|
|
||||||
"members": "учасники",
|
|
||||||
"Members": "Учасники",
|
|
||||||
"My preferences": "Мої налаштування",
|
|
||||||
"My Profile": "Мій профіль",
|
|
||||||
"My profile": "Мій профіль",
|
|
||||||
"Name": "Ім'я",
|
|
||||||
"New email": "Нова електронна адреса",
|
|
||||||
"New page": "Нова сторінка",
|
|
||||||
"New password": "Новий пароль",
|
|
||||||
"No group found": "Групу не знайдено",
|
|
||||||
"No page history saved yet.": "Історія сторінок ще не збережена.",
|
|
||||||
"No pages yet": "Сторінок поки немає",
|
|
||||||
"No shared pages": "Немає спільних сторінок",
|
|
||||||
"No results found...": "Результати не знайдено...",
|
|
||||||
"No user found": "Користувача не знайдено",
|
|
||||||
"Overview": "Огляд",
|
|
||||||
"Owner": "Власник",
|
|
||||||
"page": "сторінка",
|
|
||||||
"Page deleted successfully": "Сторінку успішно видалено",
|
|
||||||
"Page history": "Історія сторінки",
|
|
||||||
"Select version": "Вибрати версію",
|
|
||||||
"Highlight changes": "Підсвітити зміни",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "Імпорт сторінки в процесі. Будь ласка, не закривайте цю вкладку.",
|
|
||||||
"Pages": "Сторінки",
|
|
||||||
"pages": "сторінки",
|
|
||||||
"Password": "Пароль",
|
|
||||||
"Password changed successfully": "Пароль успішно змінено",
|
|
||||||
"People": "Користувачі",
|
|
||||||
"Pending": "В очікуванні",
|
|
||||||
"Please confirm your action": "Будь ласка, підтвердіть вашу дію",
|
|
||||||
"Preferences": "Налаштування",
|
|
||||||
"Print PDF": "Друк PDF",
|
|
||||||
"Profile": "Профіль",
|
|
||||||
"Recently updated": "Нещодавно оновлено",
|
|
||||||
"Remove": "Видалити",
|
|
||||||
"Remove group member": "Видалити учасника групи",
|
|
||||||
"Remove space member": "Видалити учасника простору",
|
|
||||||
"Restore": "Відновити",
|
|
||||||
"Role": "Роль",
|
|
||||||
"Save": "Зберегти",
|
|
||||||
"Search": "Пошук",
|
|
||||||
"Search for groups": "Пошук груп",
|
|
||||||
"Search for users": "Пошук користувачів",
|
|
||||||
"Search for users and groups": "Пошук користувачів та груп",
|
|
||||||
"Search...": "Пошук...",
|
|
||||||
"Select language": "Оберіть мову",
|
|
||||||
"Select role": "Оберіть роль",
|
|
||||||
"Select role to assign to all invited members": "Оберіть роль для всіх запрошених учасників",
|
|
||||||
"Select theme": "Оберіть тему",
|
|
||||||
"Send invitation": "Надіслати запрошення",
|
|
||||||
"Invitation sent": "Запрошення надіслано",
|
|
||||||
"Settings": "Налаштування",
|
|
||||||
"Setup workspace": "Налаштувати робочу область",
|
|
||||||
"Sign In": "Вхід",
|
|
||||||
"Sign Up": "Реєстрація",
|
|
||||||
"Slug": "Slug",
|
|
||||||
"Space": "Простір",
|
|
||||||
"Space description": "Опис простору",
|
|
||||||
"Space menu": "Меню простору",
|
|
||||||
"Space name": "Назва простору",
|
|
||||||
"Space settings": "Налаштування простору",
|
|
||||||
"Space slug": "Slug простору",
|
|
||||||
"Spaces": "Простори",
|
|
||||||
"Spaces you belong to": "Простори, до яких ви належите",
|
|
||||||
"No space found": "Простори не знайдено",
|
|
||||||
"Search for spaces": "Пошук просторів",
|
|
||||||
"Start typing to search...": "Почніть вводити для пошуку...",
|
|
||||||
"Status": "Статус",
|
|
||||||
"Successfully imported": "Успішно імпортовано",
|
|
||||||
"Successfully restored": "Успішно відновлено",
|
|
||||||
"System settings": "Системні налаштування",
|
|
||||||
"Theme": "Тема",
|
|
||||||
"To change your email, you have to enter your password and new email.": "Щоб змінити електронну пошту, вам потрібно ввести пароль і нову адресу.",
|
|
||||||
"Toggle full page width": "Перемкнути ширину на всю сторінку",
|
|
||||||
"Unable to import pages. Please try again.": "Не вдалося імпортувати сторінки. Будь ласка, спробуйте ще раз.",
|
|
||||||
"untitled": "без назви",
|
|
||||||
"Untitled": "Без назви",
|
|
||||||
"Updated successfully": "Оновлено успішно",
|
|
||||||
"User": "Користувач",
|
|
||||||
"Workspace": "Робоча область",
|
|
||||||
"Workspace Name": "Ім'я робочої області",
|
|
||||||
"Workspace settings": "Налаштування робочої області",
|
|
||||||
"You can change your password here.": "Ви можете змінити свій пароль тут.",
|
|
||||||
"Your Email": "Ваша електронна пошта",
|
|
||||||
"Your import is complete.": "Ваш імпорт завершено.",
|
|
||||||
"Your name": "Ваше ім'я",
|
|
||||||
"Your Name": "Ваше ім'я",
|
|
||||||
"Your password": "Ваш пароль",
|
|
||||||
"Your password must be a minimum of 8 characters.": "Ваш пароль повинен містити мінімум 8 символів.",
|
|
||||||
"Sidebar toggle": "Перемкнути бічну панель",
|
|
||||||
"Comments": "Коментарі",
|
|
||||||
"404 page not found": "404 сторінку не знайдено",
|
|
||||||
"Sorry, we can't find the page you are looking for.": "На жаль, ми не можемо знайти сторінку, яку ви шукаєте.",
|
|
||||||
"Take me back to homepage": "Повернутися на головну сторінку",
|
|
||||||
"Forgot password": "Забули пароль",
|
|
||||||
"Forgot your password?": "Забули пароль?",
|
|
||||||
"A password reset link has been sent to your email. Please check your inbox.": "Посилання для скидання пароля було надіслано на вашу електронну адресу. Будь ласка, перевірте вхідні повідомлення.",
|
|
||||||
"Send reset link": "Надіслати посилання для скидання",
|
|
||||||
"Password reset": "Скидання пароля",
|
|
||||||
"Your new password": "Ваш новий пароль",
|
|
||||||
"Set password": "Встановити пароль",
|
|
||||||
"Write a comment": "Написати коментар",
|
|
||||||
"Reply...": "Відповісти...",
|
|
||||||
"Error loading comments.": "Помилка при завантаженні коментарів.",
|
|
||||||
"No comments yet.": "Коментарів поки немає.",
|
|
||||||
"No open comments.": "Немає відкритих коментарів.",
|
|
||||||
"No resolved comments.": "Немає вирішених коментарів.",
|
|
||||||
"Add a comment...": "Додати коментар...",
|
|
||||||
"Edit comment": "Редагувати коментар",
|
|
||||||
"Delete comment": "Видалити коментар",
|
|
||||||
"Are you sure you want to delete this comment?": "Ви впевнені, що хочете видалити цей коментар?",
|
|
||||||
"Comment created successfully": "Коментар успішно створено",
|
|
||||||
"Error creating comment": "Помилка при створенні коментаря",
|
|
||||||
"Comment updated successfully": "Коментар успішно оновлено",
|
|
||||||
"Failed to update comment": "Не вдалося оновити коментар",
|
|
||||||
"Comment deleted successfully": "Коментар успішно видалено",
|
|
||||||
"Failed to delete comment": "Не вдалося видалити коментар",
|
|
||||||
"Comment resolved successfully": "Коментар успішно вирішено",
|
|
||||||
"Comment re-opened successfully": "Коментар успішно відкрито повторно",
|
|
||||||
"Comment unresolved successfully": "Коментар успішно розв'язано",
|
|
||||||
"Failed to resolve comment": "Не вдалося вирішити коментар",
|
|
||||||
"Resolve comment": "Вирішити коментар",
|
|
||||||
"Unresolve comment": "Розв'язати коментар",
|
|
||||||
"Resolve Comment Thread": "Вирішити ланцюжок коментарів",
|
|
||||||
"Unresolve Comment Thread": "Розв'язати ланцюжок коментарів",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "Ви впевнені, що хочете вирішити цей ланцюжок коментарів? Це позначить його як завершений.",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "Ви впевнені, що хочете розв'язати цей ланцюжок коментарів?",
|
|
||||||
"Resolved": "Вирішено",
|
|
||||||
"No active comments.": "Немає активних коментарів.",
|
|
||||||
"Revoke invitation": "Відкликати запрошення",
|
|
||||||
"Revoke": "Відкликати",
|
|
||||||
"Don't": "Ні",
|
|
||||||
"Are you sure you want to revoke this invitation? The user will not be able to join the workspace.": "Ви впевнені, що хочете відкликати це запрошення? Користувач не зможе приєднатися до робочої області.",
|
|
||||||
"Resend invitation": "Надіслати запрошення повторно",
|
|
||||||
"Anyone with this link can join this workspace.": "Будь-хто, хто має це посилання, може приєднатися до цієї робочої області.",
|
|
||||||
"Invite link": "Посилання для запрошення",
|
|
||||||
"Copy": "Копіювати",
|
|
||||||
"Copy to space": "Скопіювати в простір",
|
|
||||||
"Copied": "Скопійовано",
|
|
||||||
"Duplicate": "Дублювати",
|
|
||||||
"Select a user": "Оберіть користувача",
|
|
||||||
"Select a group": "Оберіть групу",
|
|
||||||
"Export all pages and attachments in this space.": "Експортувати всі сторінки та вкладення в цьому просторі.",
|
|
||||||
"Delete space": "Видалити простір",
|
|
||||||
"Are you sure you want to delete this space?": "Ви впевнені, що хочете видалити цей простір?",
|
|
||||||
"Delete this space with all its pages and data.": "Видалити цей простір з усіма його сторінками та даними.",
|
|
||||||
"All pages, comments, attachments and permissions in this space will be deleted irreversibly.": "Усі сторінки, коментарі, вкладення та дозволи в цьому просторі будуть видалені безповоротно.",
|
|
||||||
"Confirm space name": "Підтвердіть назву простору",
|
|
||||||
"Type the space name <b>{{spaceName}}</b> to confirm your action.": "Введіть назву простору <b>{{spaceName}}</b>, щоб підтвердити вашу дію.",
|
|
||||||
"Format": "Формат",
|
|
||||||
"Include subpages": "Включити вкладені сторінки",
|
|
||||||
"Include attachments": "Включити вкладення",
|
|
||||||
"Select export format": "Виберіть формат експорту",
|
|
||||||
"Export failed:": "Експортування не вдалося:",
|
|
||||||
"export error": "помилка експорту",
|
|
||||||
"Export page": "Експорт сторінки",
|
|
||||||
"Export successful": "Експорт виконано успішно",
|
|
||||||
"Export space": "Експорт простору",
|
|
||||||
"Export {{type}}": "Експорт {{type}}",
|
|
||||||
"File exceeds the {{limit}} attachment limit": "Файл перевищує ліміт вкладень {{limit}}",
|
|
||||||
"Align left": "По лівому краю",
|
|
||||||
"Align right": "По правому краю",
|
|
||||||
"Align center": "По центру",
|
|
||||||
"Justify": "По ширині",
|
|
||||||
"Merge cells": "Об'єднати комірки",
|
|
||||||
"Split cell": "Розділити комірку",
|
|
||||||
"Delete column": "Видалити стовпець",
|
|
||||||
"Delete row": "Видалити рядок",
|
|
||||||
"Add left column": "Додати стовпець ліворуч",
|
|
||||||
"Add right column": "Додати стовпець праворуч",
|
|
||||||
"Add row above": "Додати рядок вище",
|
|
||||||
"Add row below": "Додати рядок нижче",
|
|
||||||
"Delete table": "Видалити таблицю",
|
|
||||||
"Info": "Інформація",
|
|
||||||
"Note": "Примітка",
|
|
||||||
"Success": "Успішно",
|
|
||||||
"Warning": "Попередження",
|
|
||||||
"Danger": "Важливо",
|
|
||||||
"Mermaid diagram error:": "Помилка діаграми Mermaid:",
|
|
||||||
"Invalid Mermaid diagram": "Неприпустима діаграма Mermaid",
|
|
||||||
"Double-click to edit Draw.io diagram": "Клацніть двічі для редагування діаграми Draw.io",
|
|
||||||
"Exit": "Вийти",
|
|
||||||
"Save & Exit": "Зберегти та вийти",
|
|
||||||
"Double-click to edit Excalidraw diagram": "Клацніть двічі для редагування діаграми Excalidraw",
|
|
||||||
"Paste link": "Вставити посилання",
|
|
||||||
"Edit link": "Редагувати посилання",
|
|
||||||
"Remove link": "Видалити посилання",
|
|
||||||
"Add link": "Додати посилання",
|
|
||||||
"Please enter a valid url": "Будь ласка, введіть коректний url",
|
|
||||||
"Empty equation": "Порожнє рівняння",
|
|
||||||
"Invalid equation": "Неприпустиме рівняння",
|
|
||||||
"Color": "Колір",
|
|
||||||
"Text color": "Колір тексту",
|
|
||||||
"Default": "За замовчуванням",
|
|
||||||
"Blue": "Синій",
|
|
||||||
"Green": "Зелений",
|
|
||||||
"Purple": "Фіолетовий",
|
|
||||||
"Red": "Червоний",
|
|
||||||
"Yellow": "Жовтий",
|
|
||||||
"Orange": "Помаранчевий",
|
|
||||||
"Pink": "Рожевий",
|
|
||||||
"Gray": "Сірий",
|
|
||||||
"Embed link": "Вбудоване посилання",
|
|
||||||
"Invalid {{provider}} embed link": "Невірне посилання для вбудовування {{provider}}",
|
|
||||||
"Embed {{provider}}": "Вбудувати {{provider}}",
|
|
||||||
"Enter {{provider}} link to embed": "Введіть посилання для вбудовування {{provider}}",
|
|
||||||
"Bold": "Жирний",
|
|
||||||
"Italic": "Курсив",
|
|
||||||
"Underline": "Підкреслений",
|
|
||||||
"Strike": "Закреслений",
|
|
||||||
"Code": "Код",
|
|
||||||
"Comment": "Коментар",
|
|
||||||
"Text": "Текст",
|
|
||||||
"Heading 1": "Заголовок 1",
|
|
||||||
"Heading 2": "Заголовок 2",
|
|
||||||
"Heading 3": "Заголовок 3",
|
|
||||||
"To-do List": "Список справ",
|
|
||||||
"Bullet List": "Маркований список",
|
|
||||||
"Numbered List": "Нумерований список",
|
|
||||||
"Blockquote": "Блок цитування",
|
|
||||||
"Just start typing with plain text.": "Просто почніть друкувати звичайний текст.",
|
|
||||||
"Track tasks with a to-do list.": "Відстежуйте завдання за допомогою списку справ.",
|
|
||||||
"Big section heading.": "Великий заголовок розділу.",
|
|
||||||
"Medium section heading.": "Середній заголовок розділу.",
|
|
||||||
"Small section heading.": "Малий заголовок розділу.",
|
|
||||||
"Create a simple bullet list.": "Створити простий маркований список.",
|
|
||||||
"Create a list with numbering.": "Створити нумерований список.",
|
|
||||||
"Create block quote.": "Створити блок цитування.",
|
|
||||||
"Insert code snippet.": "Вставити фрагмент коду.",
|
|
||||||
"Insert horizontal rule divider": "Вставити горизонтальний роздільник",
|
|
||||||
"Upload any image from your device.": "Завантажити будь-яке зображення з вашого пристрою.",
|
|
||||||
"Upload any video from your device.": "Завантажити будь-яке відео з вашого пристрою.",
|
|
||||||
"Upload any file from your device.": "Завантажити будь-який файл з вашого пристрою.",
|
|
||||||
"Uploading {{name}}": "Завантаження {{name}}",
|
|
||||||
"Uploading file": "Завантаження файлу",
|
|
||||||
"Table": "Таблиця",
|
|
||||||
"Insert a table.": "Вставити таблицю.",
|
|
||||||
"Insert collapsible block.": "Вставити блок, що згортається.",
|
|
||||||
"Video": "Відео",
|
|
||||||
"Divider": "Роздільник",
|
|
||||||
"Quote": "Цитата",
|
|
||||||
"Image": "Зображення",
|
|
||||||
"File attachment": "Прикріплений файл",
|
|
||||||
"Toggle block": "Блок, що згортається",
|
|
||||||
"Callout": "Виноска",
|
|
||||||
"Insert callout notice.": "Вставити виноску з повідомленням.",
|
|
||||||
"Math inline": "Формула",
|
|
||||||
"Insert inline math equation.": "Вставити математичне рівняння в рядок.",
|
|
||||||
"Math block": "Блок формул",
|
|
||||||
"Insert math equation": "Вставити математичне рівняння",
|
|
||||||
"Mermaid diagram": "Діаграма Mermaid",
|
|
||||||
"Insert mermaid diagram": "Вставити діаграму Mermaid",
|
|
||||||
"Insert and design Drawio diagrams": "Вставити та розробити діаграми Draw.io",
|
|
||||||
"Insert current date": "Вставити поточну дату",
|
|
||||||
"Draw and sketch excalidraw diagrams": "Вставити та малювати діаграми Excalidraw",
|
|
||||||
"Multiple": "Декілька",
|
|
||||||
"Turn into": "Перетворити",
|
|
||||||
"Text align": "Вирівнювання тексту",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "Цю сторінку могли видалити, перемістити або у вас може не бути до неї доступу.",
|
|
||||||
"Go to homepage": "Перейти на головну",
|
|
||||||
"Pages you create will show up here.": "Сторінки, які ви створите, з'являться тут.",
|
|
||||||
"Heading {{level}}": "Заголовок {{level}}",
|
|
||||||
"Toggle title": "Перемкнути заголовок",
|
|
||||||
"Write anything. Enter \"/\" for commands": "Почніть писати. Введіть \"/\" для списку команд",
|
|
||||||
"Write...": "Напишіть...",
|
|
||||||
"Column count": "Кількість колонок",
|
|
||||||
"{{count}} Columns": "{count, plural, one{# колонка} few{# колонки} many{# колонок} other{# колонки}}",
|
|
||||||
"Equal columns": "Рівні колонки",
|
|
||||||
"Left sidebar": "Ліва бічна панель",
|
|
||||||
"Right sidebar": "Права бічна панель",
|
|
||||||
"Wide center": "Широка центральна колонка",
|
|
||||||
"Left wide": "Широка ліва колонка",
|
|
||||||
"Right wide": "Широка права колонка",
|
|
||||||
"Names do not match": "Назви не співпадають",
|
|
||||||
"Today, {{time}}": "Сьогодні, {{time}}",
|
|
||||||
"Yesterday, {{time}}": "Вчора, {{time}}",
|
|
||||||
"Space created successfully": "Простір успішно створено",
|
|
||||||
"Space updated successfully": "Простір успішно оновлено",
|
|
||||||
"Space deleted successfully": "Простір успішно видалено",
|
|
||||||
"Members added successfully": "Учасників успішно додано",
|
|
||||||
"Member removed successfully": "Учасника успішно видалено",
|
|
||||||
"Member role updated successfully": "Роль учасника успішно оновлено",
|
|
||||||
"Created by: <b>{{creatorName}}</b>": "Автор: <b>{{creatorName}}</b>",
|
|
||||||
"Created at: {{time}}": "Дата створення: {{time}}",
|
|
||||||
"Edited by {{name}} {{time}}": "Змінено {{name}} {{time}}",
|
|
||||||
"Word count: {{wordCount}}": "Кількість слів: {{wordCount}}",
|
|
||||||
"Character count: {{characterCount}}": "Кількість символів: {{characterCount}}",
|
|
||||||
"New update": "Нове оновлення",
|
|
||||||
"{{latestVersion}} is available": "Доступна нова версія {{latestVersion}}",
|
|
||||||
"Default page edit mode": "Режим редагування сторінки за замовчуванням",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "Виберіть бажаний режим редагування сторінки. Уникайте випадкових редагувань.",
|
|
||||||
"Reading": "Читання",
|
|
||||||
"Delete member": "Видалити учасника",
|
|
||||||
"Member deleted successfully": "Учасника успішно видалено",
|
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "Ви впевнені, що хочете видалити цього учасника робочої області? Ця дія незворотна.",
|
|
||||||
"Deactivate member": "Деактивувати учасника",
|
|
||||||
"Activate member": "Активувати учасника",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "Ви впевнені, що хочете деактивувати цього учасника робочого простору? Вони більше не зможуть отримати доступ до цього робочого простору.",
|
|
||||||
"Are you sure you want to activate this workspace member?": "Ви впевнені, що хочете активувати цього учасника робочого простору?",
|
|
||||||
"Deactivate": "Деактивувати",
|
|
||||||
"Activate": "Активувати",
|
|
||||||
"Deactivated": "Деактивовано",
|
|
||||||
"Move": "Перемістити",
|
|
||||||
"Move page": "Перемістити сторінку",
|
|
||||||
"Move page to a different space.": "Перемістити сторінку в інший простір.",
|
|
||||||
"Real-time editor connection lost. Retrying...": "З'єднання з редактором у реальному часі втрачено. Повторна спроба...",
|
|
||||||
"Table of contents": "Зміст",
|
|
||||||
"Add headings (H1, H2, H3) to generate a table of contents.": "Додайте заголовки (H1, H2, H3), щоб створити зміст.",
|
|
||||||
"Share": "Поділитися",
|
|
||||||
"Public sharing": "Публічний доступ",
|
|
||||||
"Shared by": "Поділився",
|
|
||||||
"Shared at": "Поділився в",
|
|
||||||
"Inherits public sharing from": "Успадковує публічний доступ від",
|
|
||||||
"Share to web": "Поділитися в інтернеті",
|
|
||||||
"Shared to web": "Розміщено в інтернеті",
|
|
||||||
"Anyone with the link can view this page": "Будь-хто, хто має посилання, може переглянути цю сторінку",
|
|
||||||
"Make this page publicly accessible": "Зробити цю сторінку загальнодоступною",
|
|
||||||
"Include sub-pages": "Включити підсторінки",
|
|
||||||
"Make sub-pages public too": "Зробити підсторінки також загальнодоступними",
|
|
||||||
"Allow search engines to index page": "Дозволити пошуковим системам індексувати сторінку",
|
|
||||||
"Open page": "Відкрити сторінку",
|
|
||||||
"Page": "Сторінка",
|
|
||||||
"Delete public share link": "Видалити посилання на публічний доступ",
|
|
||||||
"Delete share": "Видалити спільний доступ",
|
|
||||||
"Are you sure you want to delete this shared link?": "Ви впевнені, що хочете видалити це посилання спільного доступу?",
|
|
||||||
"Publicly shared pages from spaces you are a member of will appear here": "Публічні сторінки з просторів, учасником яких ви є, з'являться тут",
|
|
||||||
"Share deleted successfully": "Спільний доступ успішно видалено",
|
|
||||||
"Share not found": "Спільний доступ не знайдено",
|
|
||||||
"Failed to share page": "Не вдалося поділитися сторінкою",
|
|
||||||
"Disable public sharing": "Вимкнути публічний доступ",
|
|
||||||
"Prevent members from sharing pages publicly.": "Перешкодити учасникам публічно ділитися сторінками.",
|
|
||||||
"Toggle public sharing": "Перемикання публічного доступу",
|
|
||||||
"Toggle space public sharing": "Перемикання публічного доступу до просторів",
|
|
||||||
"Public sharing is disabled at the workspace level": "Публічний доступ вимкнуто на рівні робочого простору",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "Перешкодити публічному поширенню сторінок у цьому просторі.",
|
|
||||||
"Requires an enterprise license": "Потребує корпоративної ліцензії",
|
|
||||||
"Page permissions": "Права доступу до сторінки.",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "Керуйте тим, хто може переглядати та редагувати окремі сторінки. Доступно з корпоративною ліцензією.",
|
|
||||||
"Enable public sharing": "Увімкнути публічний доступ",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "Ви впевнені, що хочете увімкнути публічний доступ? Учасники зможуть публічно ділитися сторінками.",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "Ви впевнені, що хочете вимкнути публічний доступ? Усі існуючі посилання для спільного доступу в цьому робочому просторі будуть видалені.",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "Ви впевнені, що хочете увімкнути публічний доступ для цього простору?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "Ви впевнені, що хочете вимкнути публічний доступ? Усі існуючі посилання для спільного доступу в цьому просторі будуть видалені.",
|
|
||||||
"Public sharing is disabled": "Публічний доступ вимкнуто",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "Публічний доступ було вимкнено на рівні робочого простору.",
|
|
||||||
"Public sharing has been disabled for this space.": "Публічний доступ було вимкнено для цього простору.",
|
|
||||||
"Copy page": "Копіювати сторінки",
|
|
||||||
"Copy page to a different space.": "Скопіювати сторінку в інший простір.",
|
|
||||||
"Page copied successfully": "Сторінку успішно скопійовано",
|
|
||||||
"Page duplicated successfully": "Сторінку успішно дубльовано",
|
|
||||||
"Find": "Знайти",
|
|
||||||
"Not found": "Не знайдено",
|
|
||||||
"Previous Match (Shift+Enter)": "Попередній збіг (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "Наступний збіг (Enter)",
|
|
||||||
"Match case (Alt+C)": "Враховувати регістр (Alt+C)",
|
|
||||||
"Replace": "Замінити",
|
|
||||||
"Close (Escape)": "Закрити (Escape)",
|
|
||||||
"Replace (Enter)": "Замінити (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "Замінити все (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "Замінити все",
|
|
||||||
"View all spaces": "Переглянути всі простори",
|
|
||||||
"Error": "Помилка",
|
|
||||||
"Failed to disable MFA": "Не вдалося вимкнути MFA",
|
|
||||||
"Disable two-factor authentication": "Вимкнути двоетапну аутентифікацію",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "Вимкнення двоетапної аутентифікації зробить ваш обліковий запис менш захищеним. Для входу потрібен лише пароль.",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "Будь ласка, введіть свій пароль, щоб вимкнути двоетапну аутентифікацію:",
|
|
||||||
"Two-factor authentication has been enabled": "Двоетапну аутентифікацію включено",
|
|
||||||
"Two-factor authentication has been disabled": "Двоетапну аутентифікацію вимкнено",
|
|
||||||
"2-step verification": "Двоетапна перевірка",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "Захистіть свій обліковий запис за допомогою додаткового шару перевірки при вході.",
|
|
||||||
"Two-factor authentication is active on your account.": "Двоетапну аутентифікацію активовано у вашому обліковому записі.",
|
|
||||||
"Add 2FA method": "Додати метод 2FA",
|
|
||||||
"Backup codes": "Резервні коди",
|
|
||||||
"Disable": "Вимкнути",
|
|
||||||
"Invalid verification code": "Невірний код перевірки",
|
|
||||||
"New backup codes have been generated": "Нові резервні коди створено",
|
|
||||||
"Failed to regenerate backup codes": "Не вдалося повторно створити резервні коди",
|
|
||||||
"About backup codes": "Про резервні коди",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Резервні коди можуть бути використані для доступу до вашого облікового запису, якщо ви втратите доступ до додатку аутентифікатора. Кожен код можна використовувати лише один раз.",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "Ви можете повторно створити нові резервні коди в будь-який час. Це зробить усі існуючі коди недійсними.",
|
|
||||||
"Confirm password": "Підтвердити пароль",
|
|
||||||
"Generate new backup codes": "Створити нові резервні коди",
|
|
||||||
"Save your new backup codes": "Збережіть нові резервні коди",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "Обов'язково збережіть ці коди у безпечному місці. Ваші старі резервні коди більше не дійсні.",
|
|
||||||
"Your new backup codes": "Ваші нові резервні коди",
|
|
||||||
"I've saved my backup codes": "Я зберіг резервні коди",
|
|
||||||
"Failed to setup MFA": "Не вдалося налаштувати MFA",
|
|
||||||
"Setup & Verify": "Налаштувати та перевірити",
|
|
||||||
"Add to authenticator": "Додати до аутентифікатора",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. Скануйте цей QR-код за допомогою додатку аутентифікатора",
|
|
||||||
"Can't scan the code?": "Не можете відсканувати код?",
|
|
||||||
"Enter this code manually in your authenticator app:": "Введіть цей код вручну у додатку аутентифікатора:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. Введіть 6-значний код із аутентифікатора",
|
|
||||||
"Verify and enable": "Перевірити та увімкнути",
|
|
||||||
"Failed to generate QR code. Please try again.": "Не вдалося створити QR-код. Будь ласка, спробуйте ще раз.",
|
|
||||||
"Backup": "Резервне копіювання",
|
|
||||||
"Save codes": "Зберегти коди",
|
|
||||||
"Save your backup codes": "Зберегти резервні коди",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "Ці коди можуть бути використані для доступу до вашого облікового запису, якщо ви втратите доступ до додатку аутентифікатора. Кожен код можна використовувати лише один раз.",
|
|
||||||
"Print": "Друкувати",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "Двоетапну аутентифікацію налаштовано. Будь ласка, увійдіть знову.",
|
|
||||||
"Two-Factor authentication required": "Потрібна двоетапна аутентифікація",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "Ваш робочий простір вимагає двоетапної аутентифікації для всіх користувачів",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "Щоб продовжити доступ до робочого простору, вам потрібно налаштувати двоетапну аутентифікацію. Це додає додатковий шар захисту до вашого облікового запису.",
|
|
||||||
"Set up two-factor authentication": "Налаштувати двоетапну аутентифікацію",
|
|
||||||
"Cancel and logout": "Скасувати та вийти",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "Ваш робочий простір вимагає двоетапної аутентифікації. Будь ласка, налаштуйте це щоб продовжити.",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "Це додає додатковий шар захисту до вашого облікового запису, вимагаючи код підтвердження з вашого додатку аутентифікатора.",
|
|
||||||
"Password is required": "Вимагається пароль",
|
|
||||||
"Password must be at least 8 characters": "Пароль повинен містити щонайменше 8 символів",
|
|
||||||
"Please enter a 6-digit code": "Будь ласка, введіть 6-значний код",
|
|
||||||
"Code must be exactly 6 digits": "Код повинен мати точно 6 цифр",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "Введіть 6-значний код з вашого додатку аутентифікатора",
|
|
||||||
"Need help authenticating?": "Потрібна допомога з аутентифікацією?",
|
|
||||||
"MFA QR Code": "MFA QR-код",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "Обліковий запис успішно створено. Будь ласка, увійдіть, щоб налаштувати двоетапну аутентифікацію.",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "Скидання паролю успішне. Будь ласка, увійдіть за допомогою нового паролю та завершіть двоетапну аутентифікацію.",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "Скидання паролю успішне. Будь ласка, увійдіть за допомогою нового паролю, щоб налаштувати двоетапну аутентифікацію.",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "Скидання паролю успішне. Будь ласка, увійдіть за допомогою нового паролю.",
|
|
||||||
"Two-factor authentication": "Двоетапна аутентифікація",
|
|
||||||
"Use authenticator app instead": "Використовуйте додаток аутентифікатора замість цього",
|
|
||||||
"Verify backup code": "Перевірити резервний код",
|
|
||||||
"Use backup code": "Використовуйте резервний код",
|
|
||||||
"Enter one of your backup codes": "Введіть один з ваших резервних кодів",
|
|
||||||
"Backup code": "Резервний код",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "Введіть один з ваших резервних кодів. Кожен резервний код можна використовувати лише один раз.",
|
|
||||||
"Verify": "Перевірити",
|
|
||||||
"Trash": "Кошик",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "Сторінки в кошику будуть остаточно видалені через {count, plural, one{# день} few{# дні} many{# днів} other{# дня}}.",
|
|
||||||
"Deleted": "Видалено",
|
|
||||||
"No pages in trash": "Немає сторінок у кошику",
|
|
||||||
"Permanently delete page?": "Остаточно видалити сторінку?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "Ви впевнені, що хочете остаточно видалити '{{title}}'? Цю дію не можна скасувати.",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "Відновити '{{title}}' та її підсторінки?",
|
|
||||||
"Move to trash": "Перемістити до кошика",
|
|
||||||
"Move this page to trash?": "Перемістити цю сторінку до кошика?",
|
|
||||||
"Restore page": "Відновити сторінку",
|
|
||||||
"Page moved to trash": "Сторінка переміщена до кошика",
|
|
||||||
"Page restored successfully": "Сторінку успішно відновлено",
|
|
||||||
"Deleted by": "Видалено",
|
|
||||||
"Deleted at": "Видалено о",
|
|
||||||
"Preview": "Попередній перегляд",
|
|
||||||
"Subpages": "Підсторінки",
|
|
||||||
"Failed to load subpages": "Не вдалося завантажити підсторінки",
|
|
||||||
"No subpages": "Немає підсторінок",
|
|
||||||
"Subpages (Child pages)": "Підсторінки (дочірні сторінки)",
|
|
||||||
"List all subpages of the current page": "Перелік всіх підсторінок поточної сторінки",
|
|
||||||
"Attachments": "Вкладення",
|
|
||||||
"All spaces": "Усі простори",
|
|
||||||
"Unknown": "Невідомо",
|
|
||||||
"Find a space": "Знайти простір",
|
|
||||||
"Search in all your spaces": "Шукати у всіх ваших просторах",
|
|
||||||
"Type": "Тип",
|
|
||||||
"Enterprise": "Підприємство",
|
|
||||||
"Download attachment": "Завантажити вкладення",
|
|
||||||
"Allowed email domains": "Дозволені домени електронної пошти",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "Лише користувачі з адресами електронної пошти з цих доменів можуть реєструватися через SSO.",
|
|
||||||
"Enter valid domain names separated by comma or space": "Введіть дійсні доменні імена, розділені комою або пробілом",
|
|
||||||
"Enforce two-factor authentication": "Вимагати двофакторну автентифікацію",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "Після увімкнення всі учасники повинні ввімкнути двофакторну автентифікацію для доступу до робочого простору.",
|
|
||||||
"Toggle MFA enforcement": "Перемикання вимоги MFA",
|
|
||||||
"Display name": "Відображуване ім'я",
|
|
||||||
"Allow signup": "Дозволити реєстрацію",
|
|
||||||
"Enabled": "Увімкнено",
|
|
||||||
"Advanced Settings": "Розширені налаштування",
|
|
||||||
"Enable TLS/SSL": "Увімкнути TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "Використовувати захищене з'єднання з сервером LDAP",
|
|
||||||
"Group sync": "Синхронізація групи",
|
|
||||||
"No SSO providers found.": "Постачальників SSO не знайдено.",
|
|
||||||
"Delete SSO provider": "Видалити постачальника SSO",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "Ви впевнені, що хочете видалити цього постачальника SSO?",
|
|
||||||
"Action": "Дія",
|
|
||||||
"{{ssoProviderType}} configuration": "Конфігурація {{ssoProviderType}}",
|
|
||||||
"Icon": "Іконка",
|
|
||||||
"Upload image": "Завантажити зображення",
|
|
||||||
"Remove image": "Видалити зображення",
|
|
||||||
"Failed to remove image": "Не вдалося видалити зображення",
|
|
||||||
"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",
|
|
||||||
"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-ключі. Існуючі ключі учасників і надалі працюватимуть.",
|
|
||||||
"Toggle restrict API keys to admins": "Увімкнути або вимкнути обмеження створення API-ключів лише для адміністраторів",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "Створення API-ключів дозволено лише адміністраторам за налаштуванням адміністратора робочого простору.",
|
|
||||||
"AI settings": "Налаштування ШІ",
|
|
||||||
"AI search": "Пошук з ШІ",
|
|
||||||
"AI Answer": "Відповідь ШІ",
|
|
||||||
"Ask AI": "Запитати ШІ",
|
|
||||||
"AI is thinking...": "ШІ думає...",
|
|
||||||
"Ask a question...": "Задайте питання...",
|
|
||||||
"AI Answers": "Відповіді ШІ",
|
|
||||||
"AI-powered search (AI Answers)": "Пошук на базі ШІ (Відповіді ШІ)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "Пошук з ШІ використовує векторні вбудовування для надання можливостей семантичного пошуку у вашому робочому вмісті.",
|
|
||||||
"Toggle AI search": "Переключити пошук з ШІ",
|
|
||||||
"Generative AI (Ask AI)": "Генеративний ШІ (Запитати ШІ)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "Увімкнути генерацію контенту за допомогою ШІ в редакторі. Дозволяє користувачам генерувати, покращувати, перекладати та трансформувати текст.",
|
|
||||||
"Toggle generative AI": "Переключити генеративний ШІ",
|
|
||||||
"Enterprise feature": "Функція корпоративної версії",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "ШІ доступний лише в корпоративній редакції Docmost. Зверніться до sales@docmost.com.",
|
|
||||||
"AI & MCP": "ШІ та MCP",
|
|
||||||
"AI": "ШІ",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "Протокол контексту моделі (MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "Увімкніть MCP‑сервер, щоб дозволити ШІ‑помічникам та інструментам взаємодіяти з вмістом вашого робочого простору.",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP доступний лише в корпоративній редакції Docmost. Зверніться до sales@docmost.com.",
|
|
||||||
"MCP documentation": "Документація MCP",
|
|
||||||
"MCP Server URL": "URL сервера MCP",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "Використовуйте свій API‑ключ для аутентифікації. Ви можете керувати API‑ключами в налаштуваннях облікового запису.",
|
|
||||||
"Supported tools": "Підтримувані інструменти",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "У вашому робочому просторі MCP увімкнено. Використайте свій API‑ключ, щоб підключити ШІ‑помічників.",
|
|
||||||
"MCP server URL:": "URL сервера MCP:",
|
|
||||||
"Learn more": "Дізнатися більше",
|
|
||||||
"View the": "Переглянути",
|
|
||||||
"for usage details.": "для відомостей про використання.",
|
|
||||||
"for setup instructions.": "для інструкцій з налаштування.",
|
|
||||||
"API documentation": "Документація API",
|
|
||||||
"Sources": "Джерела",
|
|
||||||
"AI Answers not available for attachments": "Відповіді ШІ недоступні для вкладень",
|
|
||||||
"No answer available": "Відповідь недоступна",
|
|
||||||
"Background color": "Колір фону",
|
|
||||||
"Highlight color": "Колір підсвічування",
|
|
||||||
"Remove color": "Видалити колір",
|
|
||||||
"Notifications": "Сповіщення",
|
|
||||||
"No notifications": "Немає сповіщень",
|
|
||||||
"No unread notifications": "Немає непрочитаних сповіщень",
|
|
||||||
"All notifications": "Усі сповіщення",
|
|
||||||
"Unread only": "Тільки непрочитані",
|
|
||||||
"Mark all as read": "Позначити все як прочитане",
|
|
||||||
"Mark as read": "Позначити як прочитане",
|
|
||||||
"More options": "Більше опцій",
|
|
||||||
"mentioned you in a comment": "згадали вас у коментарі",
|
|
||||||
"commented on a page": "прокоментували на сторінці",
|
|
||||||
"resolved a comment": "вирішили коментар",
|
|
||||||
"mentioned you on a page": "згадали вас на сторінці",
|
|
||||||
"gave you edit access to a page": "надав вам доступ для редагування сторінки",
|
|
||||||
"gave you view access to a page": "надав вам доступ для перегляду сторінки",
|
|
||||||
"Today": "Сьогодні",
|
|
||||||
"Yesterday": "Вчора",
|
|
||||||
"This week": "Цього тижня",
|
|
||||||
"Older": "Старіші",
|
|
||||||
"Restricted page": "Сторінка з обмеженим доступом",
|
|
||||||
"Restricted pages cannot be shared publicly.": "Сторінки з обмеженим доступом не можна робити загальнодоступними.",
|
|
||||||
"Restricted by parent": "Обмежено батьківською сторінкою",
|
|
||||||
"Restricted": "Обмежено",
|
|
||||||
"Open": "Відкрита",
|
|
||||||
"Inherits restrictions from ancestor page": "Наслідує обмеження від батьківської сторінки",
|
|
||||||
"Only people listed below can access this page": "Доступ до цієї сторінки мають лише люди, вказані нижче.",
|
|
||||||
"Everyone in this space can access": "Усі в цьому просторі мають доступ",
|
|
||||||
"No additional restrictions on this page": "Додаткових обмежень на цій сторінці немає.",
|
|
||||||
"Only specific people can access": "Доступ мають лише конкретні особи.",
|
|
||||||
"Use only inherited restrictions": "Використовувати лише успадковані обмеження",
|
|
||||||
"Add restrictions on top of inherited": "Додати обмеження поверх успадкованих",
|
|
||||||
"Inherited restriction": "Успадковане обмеження",
|
|
||||||
"Access limited by": "Доступ обмежено через",
|
|
||||||
"Restrict access to control who can view and edit this page": "Обмежте доступ, щоб контролювати, хто може переглядати та редагувати цю сторінку.",
|
|
||||||
"Add additional restrictions specific to this page": "Додати додаткові обмеження для цієї сторінки.",
|
|
||||||
"Access": "Доступ",
|
|
||||||
"People with access": "Особи з доступом",
|
|
||||||
"Remove all": "Видалити все",
|
|
||||||
"Remove access": "Видалити доступ",
|
|
||||||
"Remove all access": "Видалити весь доступ",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "Ви впевнені, що хочете видалити доступ цього учасника до сторінки?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "Ви впевнені, що хочете видалити всі індивідуальні дозволи доступу? Це зробить сторінку доступною для всіх у просторі.",
|
|
||||||
"Trash retention": "Термін зберігання у кошику",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "Сторінки в кошику будуть остаточно видалені після цього періоду.",
|
|
||||||
"Trash retention updated": "Термін зберігання у кошику оновлено",
|
|
||||||
"Failed to update trash retention": "Не вдалося оновити термін зберігання у кошику",
|
|
||||||
"Removed page restriction": "Обмеження сторінки видалено",
|
|
||||||
"Added page permission": "Додано дозвіл на сторінку",
|
|
||||||
"Removed page permission": "Дозвіл на сторінку видалено"
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
"Choose your preferred interface language.": "选择您喜欢的界面语言。",
|
"Choose your preferred interface language.": "选择您喜欢的界面语言。",
|
||||||
"Choose your preferred page width.": "选择您喜欢的页面宽度。",
|
"Choose your preferred page width.": "选择您喜欢的页面宽度。",
|
||||||
"Confirm": "确认",
|
"Confirm": "确认",
|
||||||
"Copy as Markdown": "复制为Markdown",
|
|
||||||
"Copy link": "复制链接",
|
"Copy link": "复制链接",
|
||||||
"Create": "创建",
|
"Create": "创建",
|
||||||
"Create group": "创建群组",
|
"Create group": "创建群组",
|
||||||
@@ -54,7 +53,6 @@
|
|||||||
"e.g Space for product team": "例如:产品团队的空间",
|
"e.g Space for product team": "例如:产品团队的空间",
|
||||||
"e.g Space for sales team to collaborate": "例如:销售团队协作的空间",
|
"e.g Space for sales team to collaborate": "例如:销售团队协作的空间",
|
||||||
"Edit": "编辑",
|
"Edit": "编辑",
|
||||||
"Read": "阅读",
|
|
||||||
"Edit group": "编辑群组",
|
"Edit group": "编辑群组",
|
||||||
"Email": "电子邮箱",
|
"Email": "电子邮箱",
|
||||||
"Enter a strong password": "输入一个强密码",
|
"Enter a strong password": "输入一个强密码",
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
"No group found": "未找到群组",
|
"No group found": "未找到群组",
|
||||||
"No page history saved yet.": "尚未保存页面历史。",
|
"No page history saved yet.": "尚未保存页面历史。",
|
||||||
"No pages yet": "暂无页面",
|
"No pages yet": "暂无页面",
|
||||||
"No shared pages": "没有共享页面",
|
|
||||||
"No results found...": "未找到结果...",
|
"No results found...": "未找到结果...",
|
||||||
"No user found": "未找到用户",
|
"No user found": "未找到用户",
|
||||||
"Overview": "概览",
|
"Overview": "概览",
|
||||||
@@ -124,14 +121,11 @@
|
|||||||
"page": "个页面",
|
"page": "个页面",
|
||||||
"Page deleted successfully": "页面已成功删除",
|
"Page deleted successfully": "页面已成功删除",
|
||||||
"Page history": "页面历史",
|
"Page history": "页面历史",
|
||||||
"Select version": "选择版本",
|
|
||||||
"Highlight changes": "突出显示更改",
|
|
||||||
"Page import is in progress. Please do not close this tab.": "页面导入正在进行中。请不要关闭此标签页。",
|
"Page import is in progress. Please do not close this tab.": "页面导入正在进行中。请不要关闭此标签页。",
|
||||||
"Pages": "页面",
|
"Pages": "页面",
|
||||||
"pages": "个页面",
|
"pages": "个页面",
|
||||||
"Password": "密码",
|
"Password": "密码",
|
||||||
"Password changed successfully": "密码更改成功",
|
"Password changed successfully": "密码更改成功",
|
||||||
"People": "人员",
|
|
||||||
"Pending": "待定",
|
"Pending": "待定",
|
||||||
"Please confirm your action": "请确认您的操作",
|
"Please confirm your action": "请确认您的操作",
|
||||||
"Preferences": "偏好设置",
|
"Preferences": "偏好设置",
|
||||||
@@ -209,9 +203,6 @@
|
|||||||
"Reply...": "回复...",
|
"Reply...": "回复...",
|
||||||
"Error loading comments.": "加载评论时出错",
|
"Error loading comments.": "加载评论时出错",
|
||||||
"No comments yet.": "目前还没有评论",
|
"No comments yet.": "目前还没有评论",
|
||||||
"No open comments.": "没有未解决的评论。",
|
|
||||||
"No resolved comments.": "没有已解决的评论。",
|
|
||||||
"Add a comment...": "添加评论...",
|
|
||||||
"Edit comment": "编辑评论",
|
"Edit comment": "编辑评论",
|
||||||
"Delete comment": "删除评论",
|
"Delete comment": "删除评论",
|
||||||
"Are you sure you want to delete this comment?": "你确定要删除这条评论吗?",
|
"Are you sure you want to delete this comment?": "你确定要删除这条评论吗?",
|
||||||
@@ -222,17 +213,7 @@
|
|||||||
"Comment deleted successfully": "成功删除评论",
|
"Comment deleted successfully": "成功删除评论",
|
||||||
"Failed to delete comment": "删除评论失败",
|
"Failed to delete comment": "删除评论失败",
|
||||||
"Comment resolved successfully": "成功标记评论为解决",
|
"Comment resolved successfully": "成功标记评论为解决",
|
||||||
"Comment re-opened successfully": "成功重新打开评论",
|
|
||||||
"Comment unresolved successfully": "成功标记评论为未解决",
|
|
||||||
"Failed to resolve comment": "标记评论为解决失败",
|
"Failed to resolve comment": "标记评论为解决失败",
|
||||||
"Resolve comment": "解决评论",
|
|
||||||
"Unresolve comment": "取消解决评论",
|
|
||||||
"Resolve Comment Thread": "解决评论线程",
|
|
||||||
"Unresolve Comment Thread": "取消解决评论线程",
|
|
||||||
"Are you sure you want to resolve this comment thread? This will mark it as completed.": "确定要解决此评论线程吗?这将标记为已完成。",
|
|
||||||
"Are you sure you want to unresolve this comment thread?": "确定要取消解决此评论线程吗?",
|
|
||||||
"Resolved": "已解决",
|
|
||||||
"No active comments.": "没有活跃的评论。",
|
|
||||||
"Revoke invitation": "撤回邀请",
|
"Revoke invitation": "撤回邀请",
|
||||||
"Revoke": "撤销",
|
"Revoke": "撤销",
|
||||||
"Don't": "不要",
|
"Don't": "不要",
|
||||||
@@ -241,9 +222,7 @@
|
|||||||
"Anyone with this link can join this workspace.": "任何拥有此连接的人都可以加入此工作区",
|
"Anyone with this link can join this workspace.": "任何拥有此连接的人都可以加入此工作区",
|
||||||
"Invite link": "邀请链接",
|
"Invite link": "邀请链接",
|
||||||
"Copy": "复制",
|
"Copy": "复制",
|
||||||
"Copy to space": "复制到空间",
|
|
||||||
"Copied": "已复制",
|
"Copied": "已复制",
|
||||||
"Duplicate": "重复",
|
|
||||||
"Select a user": "选择一个用户",
|
"Select a user": "选择一个用户",
|
||||||
"Select a group": "选择一个组",
|
"Select a group": "选择一个组",
|
||||||
"Export all pages and attachments in this space.": "导出当前空间的所有页面和附件",
|
"Export all pages and attachments in this space.": "导出当前空间的所有页面和附件",
|
||||||
@@ -260,7 +239,6 @@
|
|||||||
"Export failed:": "导出失败:",
|
"Export failed:": "导出失败:",
|
||||||
"export error": "导出出错",
|
"export error": "导出出错",
|
||||||
"Export page": "导出页面",
|
"Export page": "导出页面",
|
||||||
"Export successful": "导出成功",
|
|
||||||
"Export space": "导出空间",
|
"Export space": "导出空间",
|
||||||
"Export {{type}}": "导出为 {{type}}",
|
"Export {{type}}": "导出为 {{type}}",
|
||||||
"File exceeds the {{limit}} attachment limit": "文件超出了 {{limit}} 类型附件限制",
|
"File exceeds the {{limit}} attachment limit": "文件超出了 {{limit}} 类型附件限制",
|
||||||
@@ -278,7 +256,6 @@
|
|||||||
"Add row below": "在下方插入行",
|
"Add row below": "在下方插入行",
|
||||||
"Delete table": "删除表格",
|
"Delete table": "删除表格",
|
||||||
"Info": "信息",
|
"Info": "信息",
|
||||||
"Note": "注意",
|
|
||||||
"Success": "成功",
|
"Success": "成功",
|
||||||
"Warning": "警告",
|
"Warning": "警告",
|
||||||
"Danger": "危险",
|
"Danger": "危险",
|
||||||
@@ -337,8 +314,6 @@
|
|||||||
"Upload any image from your device.": "从设备上传任何图像",
|
"Upload any image from your device.": "从设备上传任何图像",
|
||||||
"Upload any video from your device.": "从设备上传任何视频",
|
"Upload any video from your device.": "从设备上传任何视频",
|
||||||
"Upload any file from your device.": "从设备上传任何文件",
|
"Upload any file from your device.": "从设备上传任何文件",
|
||||||
"Uploading {{name}}": "正在上传{{name}}",
|
|
||||||
"Uploading file": "正在上传文件",
|
|
||||||
"Table": "表格",
|
"Table": "表格",
|
||||||
"Insert a table.": "插入一个表格",
|
"Insert a table.": "插入一个表格",
|
||||||
"Insert collapsible block.": "插入一个折叠块",
|
"Insert collapsible block.": "插入一个折叠块",
|
||||||
@@ -360,23 +335,9 @@
|
|||||||
"Insert current date": "插入当前日期",
|
"Insert current date": "插入当前日期",
|
||||||
"Draw and sketch excalidraw diagrams": "绘制 Excalidraw 图表",
|
"Draw and sketch excalidraw diagrams": "绘制 Excalidraw 图表",
|
||||||
"Multiple": "多个",
|
"Multiple": "多个",
|
||||||
"Turn into": "变成",
|
|
||||||
"Text align": "文本对齐",
|
|
||||||
"This page may have been deleted, moved, or you may not have access.": "此页面可能已被删除、移动,或者您可能无权访问。{",
|
|
||||||
"Go to homepage": "前往首页",
|
|
||||||
"Pages you create will show up here.": "您创建的页面将显示在此处。",
|
|
||||||
"Heading {{level}}": "{{level}} 级标题",
|
"Heading {{level}}": "{{level}} 级标题",
|
||||||
"Toggle title": "切换标题",
|
"Toggle title": "切换标题",
|
||||||
"Write anything. Enter \"/\" for commands": "开始编写内容,输入 \"/\" 以使用指令",
|
"Write anything. Enter \"/\" for commands": "开始编写内容,输入 \"/\" 以使用指令",
|
||||||
"Write...": "写点内容...",
|
|
||||||
"Column count": "列数",
|
|
||||||
"{{count}} Columns": "{{count}} 列",
|
|
||||||
"Equal columns": "等宽列",
|
|
||||||
"Left sidebar": "左侧边栏",
|
|
||||||
"Right sidebar": "右侧边栏",
|
|
||||||
"Wide center": "中间加宽",
|
|
||||||
"Left wide": "左侧加宽",
|
|
||||||
"Right wide": "右侧加宽",
|
|
||||||
"Names do not match": "名称不匹配",
|
"Names do not match": "名称不匹配",
|
||||||
"Today, {{time}}": "今天,{{time}}",
|
"Today, {{time}}": "今天,{{time}}",
|
||||||
"Yesterday, {{time}}": "昨天,{{time}}",
|
"Yesterday, {{time}}": "昨天,{{time}}",
|
||||||
@@ -393,19 +354,9 @@
|
|||||||
"Character count: {{characterCount}}": "字符数:{{characterCount}}",
|
"Character count: {{characterCount}}": "字符数:{{characterCount}}",
|
||||||
"New update": "新更新",
|
"New update": "新更新",
|
||||||
"{{latestVersion}} is available": "{{latestVersion}} 已经可以使用",
|
"{{latestVersion}} is available": "{{latestVersion}} 已经可以使用",
|
||||||
"Default page edit mode": "默认页面编辑模式",
|
|
||||||
"Choose your preferred page edit mode. Avoid accidental edits.": "选择您偏好的页面编辑模式。避免意外编辑。",
|
|
||||||
"Reading": "阅读",
|
|
||||||
"Delete member": "删除成员",
|
"Delete member": "删除成员",
|
||||||
"Member deleted successfully": "成员删除成功",
|
"Member deleted successfully": "成员删除成功",
|
||||||
"Are you sure you want to delete this workspace member? This action is irreversible.": "您确定要删除此工作区成员吗?此操作不可逆。",
|
"Are you sure you want to delete this workspace member? This action is irreversible.": "您确定要删除此工作区成员吗?此操作不可逆。",
|
||||||
"Deactivate member": "停用成员",
|
|
||||||
"Activate member": "激活成员",
|
|
||||||
"Are you sure you want to deactivate this workspace member? They will no longer be able to access this workspace.": "您确定要停用此工作区成员吗?该成员将无法再访问此工作区。",
|
|
||||||
"Are you sure you want to activate this workspace member?": "您确定要激活此工作区成员吗?",
|
|
||||||
"Deactivate": "停用",
|
|
||||||
"Activate": "激活",
|
|
||||||
"Deactivated": "已停用",
|
|
||||||
"Move": "移动",
|
"Move": "移动",
|
||||||
"Move page": "移动页面",
|
"Move page": "移动页面",
|
||||||
"Move page to a different space.": "将页面移动到不同的空间。",
|
"Move page to a different space.": "将页面移动到不同的空间。",
|
||||||
@@ -432,266 +383,5 @@
|
|||||||
"Publicly shared pages from spaces you are a member of will appear here": "您所在空间的公开共享页面会显示在此处",
|
"Publicly shared pages from spaces you are a member of will appear here": "您所在空间的公开共享页面会显示在此处",
|
||||||
"Share deleted successfully": "分享已成功删除",
|
"Share deleted successfully": "分享已成功删除",
|
||||||
"Share not found": "未找到分享",
|
"Share not found": "未找到分享",
|
||||||
"Failed to share page": "页面分享失败",
|
"Failed to share page": "页面分享失败"
|
||||||
"Disable public sharing": "禁用公开分享",
|
|
||||||
"Prevent members from sharing pages publicly.": "阻止成员公开分享页面。",
|
|
||||||
"Toggle public sharing": "切换公开分享",
|
|
||||||
"Toggle space public sharing": "切换空间公开分享",
|
|
||||||
"Public sharing is disabled at the workspace level": "公开分享在工作区级别被禁用",
|
|
||||||
"Prevent pages in this space from being shared publicly.": "阻止此空间中的页面被公开分享。",
|
|
||||||
"Requires an enterprise license": "需要企业许可证",
|
|
||||||
"Page permissions": "页面权限},{",
|
|
||||||
"Control who can view and edit individual pages. Available with an enterprise license.": "控制谁可以查看和编辑单个页面。此功能在企业版许可下可用。",
|
|
||||||
"Enable public sharing": "启用公开分享",
|
|
||||||
"Are you sure you want to enable public sharing? Members will be able to share pages publicly.": "您确定要启用公开分享吗?成员将能够公开分享页面。",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this workspace will be deleted.": "您确定要禁用公开分享吗?此工作区中的所有现有共享链接都将被删除。",
|
|
||||||
"Are you sure you want to enable public sharing for this space?": "您确定要为此空间启用公开分享吗?",
|
|
||||||
"Are you sure you want to disable public sharing? All existing shared links in this space will be deleted.": "您确定要禁用公开分享吗?此空间中的所有现有共享链接都将被删除。",
|
|
||||||
"Public sharing is disabled": "公开分享已被禁用",
|
|
||||||
"Public sharing has been disabled at the workspace level.": "公开分享已在工作区级别被禁用。",
|
|
||||||
"Public sharing has been disabled for this space.": "此空间的公开分享已被禁用。",
|
|
||||||
"Copy page": "复制页面",
|
|
||||||
"Copy page to a different space.": "将页面复制到不同的空间。",
|
|
||||||
"Page copied successfully": "页面复制成功",
|
|
||||||
"Page duplicated successfully": "页面复制成功",
|
|
||||||
"Find": "查找",
|
|
||||||
"Not found": "未找到",
|
|
||||||
"Previous Match (Shift+Enter)": "上一个匹配 (Shift+Enter)",
|
|
||||||
"Next match (Enter)": "下一个匹配 (Enter)",
|
|
||||||
"Match case (Alt+C)": "区分大小写 (Alt+C)",
|
|
||||||
"Replace": "替换",
|
|
||||||
"Close (Escape)": "关闭 (Escape)",
|
|
||||||
"Replace (Enter)": "替换 (Enter)",
|
|
||||||
"Replace all (Ctrl+Alt+Enter)": "全部替换 (Ctrl+Alt+Enter)",
|
|
||||||
"Replace all": "全部替换",
|
|
||||||
"View all spaces": "查看所有空间",
|
|
||||||
"Error": "错误",
|
|
||||||
"Failed to disable MFA": "停用 MFA 失败",
|
|
||||||
"Disable two-factor authentication": "停用双因素认证",
|
|
||||||
"Disabling two-factor authentication will make your account less secure. You'll only need your password to sign in.": "停用双因素认证会降低账户安全性。您只需密码即可登录。",
|
|
||||||
"Please enter your password to disable two-factor authentication:": "请输入您的密码以停用双因素认证:",
|
|
||||||
"Two-factor authentication has been enabled": "双因素认证已启用",
|
|
||||||
"Two-factor authentication has been disabled": "双因素认证已停用",
|
|
||||||
"2-step verification": "两步验证",
|
|
||||||
"Protect your account with an additional verification layer when signing in.": "通过额外的验证层保护您的账户安全。",
|
|
||||||
"Two-factor authentication is active on your account.": "您的账户已激活双因素认证。",
|
|
||||||
"Add 2FA method": "添加 2FA 方法",
|
|
||||||
"Backup codes": "备份代码",
|
|
||||||
"Disable": "停用",
|
|
||||||
"Invalid verification code": "无效的验证码",
|
|
||||||
"New backup codes have been generated": "已生成新的备份代码",
|
|
||||||
"Failed to regenerate backup codes": "重新生成备份代码失败",
|
|
||||||
"About backup codes": "关于备份代码",
|
|
||||||
"Backup codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "如果您无法访问身份验证器应用,可使用备份代码访问账户。每个代码仅可使用一次。",
|
|
||||||
"You can regenerate new backup codes at any time. This will invalidate all existing codes.": "您可以随时重新生成新的备份代码。这将使所有现有代码失效。",
|
|
||||||
"Confirm password": "确认密码",
|
|
||||||
"Generate new backup codes": "生成新的备份代码",
|
|
||||||
"Save your new backup codes": "保存您的新备份代码",
|
|
||||||
"Make sure to save these codes in a secure place. Your old backup codes are no longer valid.": "请确保将这些代码保存在安全的地方。您的旧备份代码不再有效。",
|
|
||||||
"Your new backup codes": "您的新备份代码",
|
|
||||||
"I've saved my backup codes": "我已经保存了我的备份代码",
|
|
||||||
"Failed to setup MFA": "设置 MFA 失败",
|
|
||||||
"Setup & Verify": "设置并验证",
|
|
||||||
"Add to authenticator": "添加到身份验证器",
|
|
||||||
"1. Scan this QR code with your authenticator app": "1. 用身份验证器应用扫描此二维码",
|
|
||||||
"Can't scan the code?": "无法扫描代码?",
|
|
||||||
"Enter this code manually in your authenticator app:": "在您的身份验证器应用中手动输入此代码:",
|
|
||||||
"2. Enter the 6-digit code from your authenticator": "2. 输入来自身份验证器的6位代码",
|
|
||||||
"Verify and enable": "验证并启用",
|
|
||||||
"Failed to generate QR code. Please try again.": "生成二维码失败。请重试。",
|
|
||||||
"Backup": "备份",
|
|
||||||
"Save codes": "保存代码",
|
|
||||||
"Save your backup codes": "保存您的备份代码",
|
|
||||||
"These codes can be used to access your account if you lose access to your authenticator app. Each code can only be used once.": "如果无法访问身份验证器应用,可以使用这些代码访问账户。每个代码仅可使用一次。",
|
|
||||||
"Print": "打印",
|
|
||||||
"Two-factor authentication has been set up. Please log in again.": "双因素认证已设置。请重新登录。",
|
|
||||||
"Two-Factor authentication required": "需要双因素认证",
|
|
||||||
"Your workspace requires two-factor authentication for all users": "您的工作区要求所有用户启用双因素认证",
|
|
||||||
"To continue accessing your workspace, you must set up two-factor authentication. This adds an extra layer of security to your account.": "要继续访问工作区,必须设置双因素认证。此操作为您的账户添加一层额外的安全保障。",
|
|
||||||
"Set up two-factor authentication": "设置双因素认证",
|
|
||||||
"Cancel and logout": "取消并退出登录",
|
|
||||||
"Your workspace requires two-factor authentication. Please set it up to continue.": "您的工作区需要双因素认证。请设置以继续。",
|
|
||||||
"This adds an extra layer of security to your account by requiring a verification code from your authenticator app.": "通过要求您的身份验证器应用提供验证码,此操作为您的账户增加了一层额外的安全保障。",
|
|
||||||
"Password is required": "需要密码",
|
|
||||||
"Password must be at least 8 characters": "密码必须至少包含8个字符",
|
|
||||||
"Please enter a 6-digit code": "请输入6位代码",
|
|
||||||
"Code must be exactly 6 digits": "代码必须正好是6位",
|
|
||||||
"Enter the 6-digit code found in your authenticator app": "输入在您的身份验证器应用中找到的6位代码",
|
|
||||||
"Need help authenticating?": "需要帮助进行身份验证吗?",
|
|
||||||
"MFA QR Code": "MFA二维码",
|
|
||||||
"Account created successfully. Please log in to set up two-factor authentication.": "账户创建成功。请登录以设置双因素认证。",
|
|
||||||
"Password reset successful. Please log in with your new password and complete two-factor authentication.": "密码重置成功。请使用新密码登录并完成双因素认证。",
|
|
||||||
"Password reset successful. Please log in with your new password to set up two-factor authentication.": "密码重置成功。请使用新密码登录以设置双因素认证。",
|
|
||||||
"Password reset was successful. Please log in with your new password.": "密码重置成功。请使用新密码登录。",
|
|
||||||
"Two-factor authentication": "双因素认证",
|
|
||||||
"Use authenticator app instead": "改用身份验证器应用",
|
|
||||||
"Verify backup code": "验证备份代码",
|
|
||||||
"Use backup code": "使用备份代码",
|
|
||||||
"Enter one of your backup codes": "输入您的一个备份代码",
|
|
||||||
"Backup code": "备份代码",
|
|
||||||
"Enter one of your backup codes. Each backup code can only be used once.": "输入您的一个备份代码。每个备份代码只能使用一次。",
|
|
||||||
"Verify": "验证",
|
|
||||||
"Trash": "垃圾箱",
|
|
||||||
"Pages in trash will be permanently deleted after {{count}} days.": "垃圾箱中的页面将在{{count}}天后被永久删除。",
|
|
||||||
"Deleted": "已删除",
|
|
||||||
"No pages in trash": "垃圾箱中没有页面",
|
|
||||||
"Permanently delete page?": "永久删除页面?",
|
|
||||||
"Are you sure you want to permanently delete '{{title}}'? This action cannot be undone.": "确定要永久删除“{{title}}”吗?此操作无法撤销。",
|
|
||||||
"Restore '{{title}}' and its sub-pages?": "恢复“{{title}}”及其子页面?",
|
|
||||||
"Move to trash": "移至垃圾箱",
|
|
||||||
"Move this page to trash?": "将此页面移至垃圾箱?",
|
|
||||||
"Restore page": "恢复页面",
|
|
||||||
"Page moved to trash": "页面已移至垃圾箱",
|
|
||||||
"Page restored successfully": "页面恢复成功",
|
|
||||||
"Deleted by": "删除人",
|
|
||||||
"Deleted at": "删除时间",
|
|
||||||
"Preview": "预览",
|
|
||||||
"Subpages": "子页面",
|
|
||||||
"Failed to load subpages": "加载子页面失败",
|
|
||||||
"No subpages": "没有子页面",
|
|
||||||
"Subpages (Child pages)": "子页面(子页面)",
|
|
||||||
"List all subpages of the current page": "列出当前页面的所有子页面",
|
|
||||||
"Attachments": "附件",
|
|
||||||
"All spaces": "所有空间",
|
|
||||||
"Unknown": "未知",
|
|
||||||
"Find a space": "查找空间",
|
|
||||||
"Search in all your spaces": "在您的所有空间中搜索",
|
|
||||||
"Type": "类型",
|
|
||||||
"Enterprise": "企业",
|
|
||||||
"Download attachment": "下载附件",
|
|
||||||
"Allowed email domains": "允许的电子邮件域",
|
|
||||||
"Only users with email addresses from these domains can signup via SSO.": "只有来自这些域的电子邮件地址的用户才能通过SSO注册。",
|
|
||||||
"Enter valid domain names separated by comma or space": "输入用逗号或空格分隔的有效域名",
|
|
||||||
"Enforce two-factor authentication": "强制实施双因素认证",
|
|
||||||
"Once enforced, all members must enable two-factor authentication to access the workspace.": "一旦实施,所有成员必须启用双因素认证才能访问工作区。",
|
|
||||||
"Toggle MFA enforcement": "切换多因素认证实施",
|
|
||||||
"Display name": "显示名称",
|
|
||||||
"Allow signup": "允许注册",
|
|
||||||
"Enabled": "已启用",
|
|
||||||
"Advanced Settings": "高级设置",
|
|
||||||
"Enable TLS/SSL": "启用TLS/SSL",
|
|
||||||
"Use secure connection to LDAP server": "使用安全连接到LDAP服务器",
|
|
||||||
"Group sync": "组同步",
|
|
||||||
"No SSO providers found.": "未找到SSO提供商。",
|
|
||||||
"Delete SSO provider": "删除SSO提供商",
|
|
||||||
"Are you sure you want to delete this SSO provider?": "您确定要删除此SSO提供商吗?",
|
|
||||||
"Action": "操作",
|
|
||||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} 配置",
|
|
||||||
"Icon": "图标",
|
|
||||||
"Upload image": "上传图片",
|
|
||||||
"Remove image": "删除图片",
|
|
||||||
"Failed to remove image": "无法删除图片",
|
|
||||||
"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密钥",
|
|
||||||
"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 密钥。现有成员密钥将继续有效。",
|
|
||||||
"Toggle restrict API keys to admins": "切换仅限管理员创建 API 密钥",
|
|
||||||
"API key creation is restricted to admins by your workspace administrator.": "API 密钥的创建已被您的工作区管理员限制为仅管理员可用。",
|
|
||||||
"AI settings": "AI设置",
|
|
||||||
"AI search": "AI搜索",
|
|
||||||
"AI Answer": "AI回答",
|
|
||||||
"Ask AI": "询问AI",
|
|
||||||
"AI is thinking...": "AI正在思考...",
|
|
||||||
"Ask a question...": "提问...",
|
|
||||||
"AI Answers": "AI答案",
|
|
||||||
"AI-powered search (AI Answers)": "AI驱动的搜索 (AI答案)",
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI搜索使用向量嵌入提供跨工作空间内容的语义搜索功能。",
|
|
||||||
"Toggle AI search": "切换AI搜索",
|
|
||||||
"Generative AI (Ask AI)": "生成型AI (询问AI)",
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.": "在编辑器中启用AI驱动的内容生成。允许用户生成、改进、翻译和转换文本。",
|
|
||||||
"Toggle generative AI": "切换生成型AI",
|
|
||||||
"Enterprise feature": "企业版功能",
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "AI 仅在 Docmost 企业版中提供。请联系 sales@docmost.com。",
|
|
||||||
"AI & MCP": "AI 与 MCP",
|
|
||||||
"AI": "AI",
|
|
||||||
"MCP": "MCP",
|
|
||||||
"Model Context Protocol (MCP)": "模型上下文协议(MCP)",
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.": "启用 MCP 服务器以允许 AI 助手和工具与您的工作区内容交互。",
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "MCP 仅在 Docmost 企业版中提供。请联系 sales@docmost.com。",
|
|
||||||
"MCP documentation": "MCP 文档",
|
|
||||||
"MCP Server URL": "MCP 服务器 URL",
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.": "使用您的 API 密钥进行身份验证。您可以在账户设置中管理 API 密钥。",
|
|
||||||
"Supported tools": "支持的工具",
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.": "您的工作区已启用 MCP。使用您的 API 密钥连接 AI 助手。",
|
|
||||||
"MCP server URL:": "MCP 服务器 URL:",
|
|
||||||
"Learn more": "了解更多",
|
|
||||||
"View the": "查看",
|
|
||||||
"for usage details.": "以获取使用详情。",
|
|
||||||
"for setup instructions.": "以获取设置说明。",
|
|
||||||
"API documentation": "API 文档",
|
|
||||||
"Sources": "来源",
|
|
||||||
"AI Answers not available for attachments": "AI答案不适用于附件",
|
|
||||||
"No answer available": "无可用答案",
|
|
||||||
"Background color": "背景颜色",
|
|
||||||
"Highlight color": "突出显示颜色",
|
|
||||||
"Remove color": "移除颜色",
|
|
||||||
"Notifications": "通知",
|
|
||||||
"No notifications": "没有通知",
|
|
||||||
"No unread notifications": "没有未读通知",
|
|
||||||
"All notifications": "所有通知",
|
|
||||||
"Unread only": "仅未读",
|
|
||||||
"Mark all as read": "标记所有为已读",
|
|
||||||
"Mark as read": "标记为已读",
|
|
||||||
"More options": "更多选项",
|
|
||||||
"mentioned you in a comment": "在评论中提到你",
|
|
||||||
"commented on a page": "在页面上评论",
|
|
||||||
"resolved a comment": "解决了一个评论",
|
|
||||||
"mentioned you on a page": "在页面上提到你",
|
|
||||||
"gave you edit access to a page": "已授予你编辑该页面的权限",
|
|
||||||
"gave you view access to a page": "已授予你查看该页面的权限",
|
|
||||||
"Today": "今天",
|
|
||||||
"Yesterday": "昨天",
|
|
||||||
"This week": "本周",
|
|
||||||
"Older": "较早",
|
|
||||||
"Restricted page": "受限页面",
|
|
||||||
"Restricted pages cannot be shared publicly.": "受限页面不能公开共享。",
|
|
||||||
"Restricted by parent": "受父页面限制",
|
|
||||||
"Restricted": "受限",
|
|
||||||
"Open": "公开",
|
|
||||||
"Inherits restrictions from ancestor page": "继承自上级页面的限制",
|
|
||||||
"Only people listed below can access this page": "只有下面列出的人可以访问此页面",
|
|
||||||
"Everyone in this space can access": "此空间中的所有人均可访问",
|
|
||||||
"No additional restrictions on this page": "此页面无额外限制",
|
|
||||||
"Only specific people can access": "仅特定人员可访问",
|
|
||||||
"Use only inherited restrictions": "仅使用继承的限制",
|
|
||||||
"Add restrictions on top of inherited": "在继承的限制之上添加限制",
|
|
||||||
"Inherited restriction": "继承的限制",
|
|
||||||
"Access limited by": "访问受限于",
|
|
||||||
"Restrict access to control who can view and edit this page": "限制访问以控制谁可以查看和编辑此页面",
|
|
||||||
"Add additional restrictions specific to this page": "为此页面添加额外的特定限制",
|
|
||||||
"Access": "访问",
|
|
||||||
"People with access": "有访问权限的人员",
|
|
||||||
"Remove all": "全部移除",
|
|
||||||
"Remove access": "移除访问权限",
|
|
||||||
"Remove all access": "移除所有访问权限",
|
|
||||||
"Are you sure you want to remove this member's access to the page?": "您确定要移除此成员对该页面的访问权限吗?",
|
|
||||||
"Are you sure you want to remove all specific access? This will make the page open to everyone in the space.": "您确定要删除所有特定访问权限吗?这将使该页面对该空间中的所有人开放。",
|
|
||||||
"Trash retention": "垃圾箱保留期",
|
|
||||||
"Pages in trash will be permanently deleted after this period.": "该期限结束后,垃圾箱中的页面将被永久删除。",
|
|
||||||
"Trash retention updated": "垃圾箱保留期已更新",
|
|
||||||
"Failed to update trash retention": "更新垃圾箱保留期失败",
|
|
||||||
"Removed page restriction": "已移除页面限制",
|
|
||||||
"Added page permission": "已添加页面权限",
|
|
||||||
"Removed page permission": "已移除页面权限"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Docmost",
|
|
||||||
"short_name": "Docmost",
|
|
||||||
"start_url": "/",
|
|
||||||
"display": "standalone",
|
|
||||||
"background_color": "#222",
|
|
||||||
"theme_color": "#222",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "icons/favicon-16x16.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "16x16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "icons/favicon-32x32.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "32x32"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "icons/app-icon-192x192.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "180x180 192x192"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "icons/app-icon-512x512.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
+10
-23
@@ -14,6 +14,7 @@ import AccountPreferences from "@/pages/settings/account/account-preferences.tsx
|
|||||||
import SpaceHome from "@/pages/space/space-home.tsx";
|
import SpaceHome from "@/pages/space/space-home.tsx";
|
||||||
import PageRedirect from "@/pages/page/page-redirect.tsx";
|
import PageRedirect from "@/pages/page/page-redirect.tsx";
|
||||||
import Layout from "@/components/layouts/global/layout.tsx";
|
import Layout from "@/components/layouts/global/layout.tsx";
|
||||||
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
import InviteSignup from "@/pages/auth/invite-signup.tsx";
|
import InviteSignup from "@/pages/auth/invite-signup.tsx";
|
||||||
import ForgotPassword from "@/pages/auth/forgot-password.tsx";
|
import ForgotPassword from "@/pages/auth/forgot-password.tsx";
|
||||||
import PasswordReset from "./pages/auth/password-reset";
|
import PasswordReset from "./pages/auth/password-reset";
|
||||||
@@ -28,16 +29,8 @@ import { useRedirectToCloudSelect } from "@/ee/hooks/use-redirect-to-cloud-selec
|
|||||||
import SharedPage from "@/pages/share/shared-page.tsx";
|
import SharedPage from "@/pages/share/shared-page.tsx";
|
||||||
import Shares from "@/pages/settings/shares/shares.tsx";
|
import Shares from "@/pages/settings/shares/shares.tsx";
|
||||||
import ShareLayout from "@/features/share/components/share-layout.tsx";
|
import ShareLayout from "@/features/share/components/share-layout.tsx";
|
||||||
import ShareRedirect from "@/pages/share/share-redirect.tsx";
|
import ShareRedirect from '@/pages/share/share-redirect.tsx';
|
||||||
import { useTrackOrigin } from "@/hooks/use-track-origin";
|
import { useTrackOrigin } from "@/hooks/use-track-origin";
|
||||||
import SpacesPage from "@/pages/spaces/spaces.tsx";
|
|
||||||
import { MfaChallengePage } from "@/ee/mfa/pages/mfa-challenge-page";
|
|
||||||
import { MfaSetupRequiredPage } from "@/ee/mfa/pages/mfa-setup-required-page";
|
|
||||||
import SpaceTrash from "@/pages/space/space-trash.tsx";
|
|
||||||
import UserApiKeys from "@/ee/api-key/pages/user-api-keys";
|
|
||||||
import WorkspaceApiKeys from "@/ee/api-key/pages/workspace-api-keys";
|
|
||||||
import AiSettings from "@/ee/ai/pages/ai-settings.tsx";
|
|
||||||
import AuditLogs from "@/ee/audit/pages/audit-logs.tsx";
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -52,8 +45,6 @@ export default function App() {
|
|||||||
<Route path={"/invites/:invitationId"} element={<InviteSignup />} />
|
<Route path={"/invites/:invitationId"} element={<InviteSignup />} />
|
||||||
<Route path={"/forgot-password"} element={<ForgotPassword />} />
|
<Route path={"/forgot-password"} element={<ForgotPassword />} />
|
||||||
<Route path={"/password-reset"} element={<PasswordReset />} />
|
<Route path={"/password-reset"} element={<PasswordReset />} />
|
||||||
<Route path={"/login/mfa"} element={<MfaChallengePage />} />
|
|
||||||
<Route path={"/login/mfa/setup"} element={<MfaSetupRequiredPage />} />
|
|
||||||
|
|
||||||
{!isCloud() && (
|
{!isCloud() && (
|
||||||
<Route path={"/setup/register"} element={<SetupWorkspace />} />
|
<Route path={"/setup/register"} element={<SetupWorkspace />} />
|
||||||
@@ -67,10 +58,7 @@ export default function App() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Route element={<ShareLayout />}>
|
<Route element={<ShareLayout />}>
|
||||||
<Route
|
<Route path={"/share/:shareId/p/:pageSlug"} element={<SharedPage />} />
|
||||||
path={"/share/:shareId/p/:pageSlug"}
|
|
||||||
element={<SharedPage />}
|
|
||||||
/>
|
|
||||||
<Route path={"/share/p/:pageSlug"} element={<SharedPage />} />
|
<Route path={"/share/p/:pageSlug"} element={<SharedPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
@@ -79,12 +67,16 @@ export default function App() {
|
|||||||
|
|
||||||
<Route element={<Layout />}>
|
<Route element={<Layout />}>
|
||||||
<Route path={"/home"} element={<Home />} />
|
<Route path={"/home"} element={<Home />} />
|
||||||
<Route path={"/spaces"} element={<SpacesPage />} />
|
|
||||||
<Route path={"/s/:spaceSlug"} element={<SpaceHome />} />
|
<Route path={"/s/:spaceSlug"} element={<SpaceHome />} />
|
||||||
<Route path={"/s/:spaceSlug/trash"} element={<SpaceTrash />} />
|
|
||||||
<Route
|
<Route
|
||||||
path={"/s/:spaceSlug/p/:pageSlug"}
|
path={"/s/:spaceSlug/p/:pageSlug"}
|
||||||
element={<Page />}
|
element={
|
||||||
|
<ErrorBoundary
|
||||||
|
fallback={<>{t("Failed to load page. An error occurred.")}</>}
|
||||||
|
>
|
||||||
|
<Page />
|
||||||
|
</ErrorBoundary>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route path={"/settings"}>
|
<Route path={"/settings"}>
|
||||||
@@ -93,18 +85,13 @@ export default function App() {
|
|||||||
path={"account/preferences"}
|
path={"account/preferences"}
|
||||||
element={<AccountPreferences />}
|
element={<AccountPreferences />}
|
||||||
/>
|
/>
|
||||||
<Route path={"account/api-keys"} element={<UserApiKeys />} />
|
|
||||||
<Route path={"workspace"} element={<WorkspaceSettings />} />
|
<Route path={"workspace"} element={<WorkspaceSettings />} />
|
||||||
<Route path={"members"} element={<WorkspaceMembers />} />
|
<Route path={"members"} element={<WorkspaceMembers />} />
|
||||||
<Route path={"api-keys"} element={<WorkspaceApiKeys />} />
|
|
||||||
<Route path={"groups"} element={<Groups />} />
|
<Route path={"groups"} element={<Groups />} />
|
||||||
<Route path={"groups/:groupId"} element={<GroupInfo />} />
|
<Route path={"groups/:groupId"} element={<GroupInfo />} />
|
||||||
<Route path={"spaces"} element={<Spaces />} />
|
<Route path={"spaces"} element={<Spaces />} />
|
||||||
<Route path={"sharing"} element={<Shares />} />
|
<Route path={"sharing"} element={<Shares />} />
|
||||||
<Route path={"security"} element={<Security />} />
|
<Route path={"security"} element={<Security />} />
|
||||||
<Route path={"ai"} element={<AiSettings />} />
|
|
||||||
<Route path={"ai/mcp"} element={<AiSettings />} />
|
|
||||||
<Route path={"audit"} element={<AuditLogs />} />
|
|
||||||
{!isCloud() && <Route path={"license"} element={<License />} />}
|
{!isCloud() && <Route path={"license"} element={<License />} />}
|
||||||
{isCloud() && <Route path={"billing"} element={<Billing />} />}
|
{isCloud() && <Route path={"billing"} element={<Billing />} />}
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
import React, { useRef } from "react";
|
|
||||||
import { Menu, Box, Loader } from "@mantine/core";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { IconTrash, IconUpload } from "@tabler/icons-react";
|
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
|
||||||
import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
|
|
||||||
interface AvatarUploaderProps {
|
|
||||||
currentImageUrl?: string | null;
|
|
||||||
fallbackName?: string;
|
|
||||||
radius?: string | number;
|
|
||||||
size?: string | number;
|
|
||||||
variant?: string;
|
|
||||||
type: AvatarIconType;
|
|
||||||
onUpload: (file: File) => Promise<void>;
|
|
||||||
onRemove: () => Promise<void>;
|
|
||||||
isLoading?: boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AvatarUploader({
|
|
||||||
currentImageUrl,
|
|
||||||
fallbackName,
|
|
||||||
radius,
|
|
||||||
variant,
|
|
||||||
size,
|
|
||||||
type,
|
|
||||||
onUpload,
|
|
||||||
onRemove,
|
|
||||||
isLoading = false,
|
|
||||||
disabled = false,
|
|
||||||
}: AvatarUploaderProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
const handleFileInputChange = async (
|
|
||||||
event: React.ChangeEvent<HTMLInputElement>,
|
|
||||||
) => {
|
|
||||||
const file = event.target.files?.[0];
|
|
||||||
if (!file || disabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate file size (max 10MB)
|
|
||||||
const maxSizeInBytes = 10 * 1024 * 1024;
|
|
||||||
if (file.size > maxSizeInBytes) {
|
|
||||||
notifications.show({
|
|
||||||
message: t("Image exceeds 10MB limit."),
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
// Reset the input
|
|
||||||
if (fileInputRef.current) {
|
|
||||||
fileInputRef.current.value = "";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await onUpload(file);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
notifications.show({
|
|
||||||
message: t("Failed to upload image"),
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the input so the same file can be selected again
|
|
||||||
if (fileInputRef.current) {
|
|
||||||
fileInputRef.current.value = "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUploadClick = () => {
|
|
||||||
if (fileInputRef.current) {
|
|
||||||
fileInputRef.current.click();
|
|
||||||
} else {
|
|
||||||
console.error("File input ref is null!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRemove = async () => {
|
|
||||||
if (disabled) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await onRemove();
|
|
||||||
notifications.show({
|
|
||||||
message: t("Image removed successfully"),
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
notifications.show({
|
|
||||||
message: t("Failed to remove image"),
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
ref={fileInputRef}
|
|
||||||
onChange={handleFileInputChange}
|
|
||||||
accept="image/png,image/jpeg,image/jpg"
|
|
||||||
style={{ display: "none" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Menu shadow="md" width={200} withArrow disabled={disabled || isLoading}>
|
|
||||||
<Menu.Target>
|
|
||||||
<Box style={{ position: "relative", display: "inline-block" }}>
|
|
||||||
<CustomAvatar
|
|
||||||
component="button"
|
|
||||||
size={size}
|
|
||||||
avatarUrl={currentImageUrl}
|
|
||||||
name={fallbackName}
|
|
||||||
style={{
|
|
||||||
cursor: disabled || isLoading ? "default" : "pointer",
|
|
||||||
opacity: isLoading ? 0.6 : 1,
|
|
||||||
}}
|
|
||||||
radius={radius}
|
|
||||||
variant={variant}
|
|
||||||
type={type}
|
|
||||||
/>
|
|
||||||
{isLoading && (
|
|
||||||
<Box
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
transform: "translate(-50%, -50%)",
|
|
||||||
zIndex: 200,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Loader size="sm" />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Menu.Target>
|
|
||||||
|
|
||||||
<Menu.Dropdown>
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconUpload size={16} />}
|
|
||||||
disabled={isLoading || disabled}
|
|
||||||
onClick={handleUploadClick}
|
|
||||||
>
|
|
||||||
{t("Upload image")}
|
|
||||||
</Menu.Item>
|
|
||||||
|
|
||||||
{currentImageUrl && (
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconTrash size={16} />}
|
|
||||||
color="red"
|
|
||||||
onClick={handleRemove}
|
|
||||||
disabled={isLoading || disabled}
|
|
||||||
>
|
|
||||||
{t("Remove image")}
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// Source: https://github.com/mantinedev/mantine/blob/master/packages/@mantine/core/src/components/CopyButton/CopyButton.tsx - MIT
|
|
||||||
// modified to use the polyfilled clipboard api
|
|
||||||
import React from "react";
|
|
||||||
import { useClipboard } from "@/hooks/use-clipboard";
|
|
||||||
import { useProps } from "@mantine/core";
|
|
||||||
|
|
||||||
interface CopyButtonProps {
|
|
||||||
/** Children callback, provides current status and copy function as an argument */
|
|
||||||
children: (payload: { copied: boolean; copy: () => void }) => React.ReactNode;
|
|
||||||
|
|
||||||
/** Value that is copied to the clipboard when the button is clicked */
|
|
||||||
value: string;
|
|
||||||
|
|
||||||
/** Copied status timeout in ms @default `1000` */
|
|
||||||
timeout?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultProps = {
|
|
||||||
timeout: 1000,
|
|
||||||
} satisfies Partial<CopyButtonProps>;
|
|
||||||
|
|
||||||
export function CopyButton(props: CopyButtonProps) {
|
|
||||||
const { children, timeout, value, ...others } = useProps(
|
|
||||||
"CopyButton",
|
|
||||||
defaultProps,
|
|
||||||
props,
|
|
||||||
);
|
|
||||||
const clipboard = useClipboard({ timeout });
|
|
||||||
const copy = () => clipboard.copy(value);
|
|
||||||
return <>{children({ copy, copied: clipboard.copied, ...others })}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyButton.displayName = "@mantine/core/CopyButton";
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ActionIcon, Tooltip } from "@mantine/core";
|
import { ActionIcon, CopyButton, Tooltip } from "@mantine/core";
|
||||||
import { CopyButton } from "@/components/common/copy-button";
|
|
||||||
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|||||||
@@ -29,27 +29,19 @@ export default function ExportModal({
|
|||||||
}: ExportModalProps) {
|
}: ExportModalProps) {
|
||||||
const [format, setFormat] = useState<ExportFormat>(ExportFormat.Markdown);
|
const [format, setFormat] = useState<ExportFormat>(ExportFormat.Markdown);
|
||||||
const [includeChildren, setIncludeChildren] = useState<boolean>(false);
|
const [includeChildren, setIncludeChildren] = useState<boolean>(false);
|
||||||
const [includeAttachments, setIncludeAttachments] = useState<boolean>(false);
|
const [includeAttachments, setIncludeAttachments] = useState<boolean>(true);
|
||||||
const [isExporting, setIsExporting] = useState<boolean>(false);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
setIsExporting(true);
|
|
||||||
try {
|
try {
|
||||||
if (type === "page") {
|
if (type === "page") {
|
||||||
await exportPage({
|
await exportPage({ pageId: id, format, includeChildren });
|
||||||
pageId: id,
|
|
||||||
format,
|
|
||||||
includeChildren,
|
|
||||||
includeAttachments,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (type === "space") {
|
if (type === "space") {
|
||||||
await exportSpace({ spaceId: id, format, includeAttachments });
|
await exportSpace({ spaceId: id, format, includeAttachments });
|
||||||
}
|
}
|
||||||
notifications.show({
|
setIncludeChildren(false);
|
||||||
message: t("Export successful"),
|
setIncludeAttachments(true);
|
||||||
});
|
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
@@ -57,8 +49,6 @@ export default function ExportModal({
|
|||||||
color: "red",
|
color: "red",
|
||||||
});
|
});
|
||||||
console.error("export error", err);
|
console.error("export error", err);
|
||||||
} finally {
|
|
||||||
setIsExporting(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,18 +96,6 @@ export default function ExportModal({
|
|||||||
checked={includeChildren}
|
checked={includeChildren}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group justify="space-between" wrap="nowrap" mt="md">
|
|
||||||
<div>
|
|
||||||
<Text size="md">{t("Include attachments")}</Text>
|
|
||||||
</div>
|
|
||||||
<Switch
|
|
||||||
onChange={(event) =>
|
|
||||||
setIncludeAttachments(event.currentTarget.checked)
|
|
||||||
}
|
|
||||||
checked={includeAttachments}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -143,7 +121,7 @@ export default function ExportModal({
|
|||||||
<Button onClick={onClose} variant="default">
|
<Button onClick={onClose} variant="default">
|
||||||
{t("Cancel")}
|
{t("Cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleExport} loading={isExporting}>{t("Export")}</Button>
|
<Button onClick={handleExport}>{t("Export")}</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal.Content>
|
</Modal.Content>
|
||||||
|
|||||||
@@ -4,15 +4,14 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
interface NoTableResultsProps {
|
interface NoTableResultsProps {
|
||||||
colSpan: number;
|
colSpan: number;
|
||||||
text?: string;
|
|
||||||
}
|
}
|
||||||
export default function NoTableResults({ colSpan, text }: NoTableResultsProps) {
|
export default function NoTableResults({ colSpan }: NoTableResultsProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Td colSpan={colSpan}>
|
<Table.Td colSpan={colSpan}>
|
||||||
<Text fw={500} c="dimmed" ta="center">
|
<Text fw={500} c="dimmed" ta="center">
|
||||||
{text || t("No results found...")}
|
{t("No results found...")}
|
||||||
</Text>
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ import { Button, Group } from "@mantine/core";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export interface PagePaginationProps {
|
export interface PagePaginationProps {
|
||||||
|
currentPage: number;
|
||||||
hasPrevPage: boolean;
|
hasPrevPage: boolean;
|
||||||
hasNextPage: boolean;
|
hasNextPage: boolean;
|
||||||
onPrev: () => void;
|
onPageChange: (newPage: number) => void;
|
||||||
onNext: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Paginate({
|
export default function Paginate({
|
||||||
|
currentPage,
|
||||||
hasPrevPage,
|
hasPrevPage,
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
onPrev,
|
onPageChange,
|
||||||
onNext,
|
|
||||||
}: PagePaginationProps) {
|
}: PagePaginationProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export default function Paginate({
|
|||||||
<Button
|
<Button
|
||||||
variant="default"
|
variant="default"
|
||||||
size="compact-sm"
|
size="compact-sm"
|
||||||
onClick={onPrev}
|
onClick={() => onPageChange(currentPage - 1)}
|
||||||
disabled={!hasPrevPage}
|
disabled={!hasPrevPage}
|
||||||
>
|
>
|
||||||
{t("Prev")}
|
{t("Prev")}
|
||||||
@@ -34,7 +34,7 @@ export default function Paginate({
|
|||||||
<Button
|
<Button
|
||||||
variant="default"
|
variant="default"
|
||||||
size="compact-sm"
|
size="compact-sm"
|
||||||
onClick={onNext}
|
onClick={() => onPageChange(currentPage + 1)}
|
||||||
disabled={!hasNextPage}
|
disabled={!hasNextPage}
|
||||||
>
|
>
|
||||||
{t("Next")}
|
{t("Next")}
|
||||||
|
|||||||
@@ -5,28 +5,26 @@ import {
|
|||||||
Badge,
|
Badge,
|
||||||
Table,
|
Table,
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
} from "@mantine/core";
|
} from '@mantine/core';
|
||||||
import { Link } from "react-router-dom";
|
import {Link} from 'react-router-dom';
|
||||||
import PageListSkeleton from "@/components/ui/page-list-skeleton.tsx";
|
import PageListSkeleton from '@/components/ui/page-list-skeleton.tsx';
|
||||||
import { buildPageUrl } from "@/features/page/page.utils.ts";
|
import { buildPageUrl } from '@/features/page/page.utils.ts';
|
||||||
import { formattedDate } from "@/lib/time.ts";
|
import { formattedDate } from '@/lib/time.ts';
|
||||||
import { useRecentChangesQuery } from "@/features/page/queries/page-query.ts";
|
import { useRecentChangesQuery } from '@/features/page/queries/page-query.ts';
|
||||||
import { IconFileDescription, IconFiles } from "@tabler/icons-react";
|
import { IconFileDescription } from '@tabler/icons-react';
|
||||||
import { EmptyState } from "@/components/ui/empty-state.tsx";
|
import { getSpaceUrl } from '@/lib/config.ts';
|
||||||
import { getSpaceUrl } from "@/lib/config.ts";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getInitialsColor } from "@/lib/get-initials-color.ts";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
spaceId?: string;
|
spaceId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RecentChanges({ spaceId }: Props) {
|
export default function RecentChanges({spaceId}: Props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data: pages, isLoading, isError } = useRecentChangesQuery(spaceId);
|
const {data: pages, isLoading, isError} = useRecentChangesQuery(spaceId);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <PageListSkeleton />;
|
return <PageListSkeleton/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
@@ -46,8 +44,8 @@ export default function RecentChanges({ spaceId }: Props) {
|
|||||||
>
|
>
|
||||||
<Group wrap="nowrap">
|
<Group wrap="nowrap">
|
||||||
{page.icon || (
|
{page.icon || (
|
||||||
<ActionIcon variant="transparent" color="gray" size={18}>
|
<ActionIcon variant='transparent' color='gray' size={18}>
|
||||||
<IconFileDescription size={18} />
|
<IconFileDescription size={18}/>
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -60,23 +58,18 @@ export default function RecentChanges({ spaceId }: Props) {
|
|||||||
{!spaceId && (
|
{!spaceId && (
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Badge
|
<Badge
|
||||||
color={getInitialsColor(page?.space.name)}
|
color="blue"
|
||||||
variant="light"
|
variant="light"
|
||||||
component={Link}
|
component={Link}
|
||||||
to={getSpaceUrl(page?.space.slug)}
|
to={getSpaceUrl(page?.space.slug)}
|
||||||
style={{ cursor: "pointer" }}
|
style={{cursor: 'pointer'}}
|
||||||
>
|
>
|
||||||
{page?.space.name}
|
{page?.space.name}
|
||||||
</Badge>
|
</Badge>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
)}
|
)}
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Text
|
<Text c="dimmed" style={{whiteSpace: 'nowrap'}} size="xs" fw={500}>
|
||||||
c="dimmed"
|
|
||||||
style={{ whiteSpace: "nowrap" }}
|
|
||||||
size="xs"
|
|
||||||
fw={500}
|
|
||||||
>
|
|
||||||
{formattedDate(page.updatedAt)}
|
{formattedDate(page.updatedAt)}
|
||||||
</Text>
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
@@ -86,10 +79,8 @@ export default function RecentChanges({ spaceId }: Props) {
|
|||||||
</Table>
|
</Table>
|
||||||
</Table.ScrollContainer>
|
</Table.ScrollContainer>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState
|
<Text size="md" ta="center">
|
||||||
icon={IconFiles}
|
{t("No pages yet")}
|
||||||
title={t("No pages yet")}
|
</Text>
|
||||||
description={t("Pages you create will show up here.")}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { Group, Text } from "@mantine/core";
|
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
|
||||||
import React from "react";
|
|
||||||
import { IUser } from '@/features/user/types/user.types.ts';
|
|
||||||
|
|
||||||
interface UserInfoProps {
|
|
||||||
user: Partial<IUser>;
|
|
||||||
size?: string;
|
|
||||||
}
|
|
||||||
export function UserInfo({ user, size }: UserInfoProps) {
|
|
||||||
return (
|
|
||||||
<Group gap="sm" wrap="nowrap">
|
|
||||||
<CustomAvatar avatarUrl={user?.avatarUrl} name={user?.name} size={size} />
|
|
||||||
<div>
|
|
||||||
<Text fz="sm" fw={500} lineClamp={1}>
|
|
||||||
{user?.name}
|
|
||||||
</Text>
|
|
||||||
<Text fz="xs" c="dimmed">
|
|
||||||
{user?.email}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</Group>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { rem } from "@mantine/core";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
size?: number | string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ConfluenceIcon({ size }: Props) {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
style={{ width: rem(size), height: rem(size) }}
|
|
||||||
>
|
|
||||||
<path d="M.87 18.257c-.248.382-.53.875-.763 1.245a.764.764 0 0 0 .255 1.04l4.965 3.054a.764.764 0 0 0 1.058-.26c.199-.332.454-.763.733-1.221 1.967-3.247 3.945-2.853 7.508-1.146l4.957 2.337a.764.764 0 0 0 1.028-.382l2.364-5.346a.764.764 0 0 0-.382-1 599.851 599.851 0 0 1-4.965-2.361C10.911 10.97 5.224 11.185.87 18.257zM23.131 5.743c.249-.405.531-.875.764-1.25a.764.764 0 0 0-.256-1.034L18.675.404a.764.764 0 0 0-1.058.26c-.195.335-.451.763-.734 1.225-1.966 3.246-3.945 2.85-7.508 1.146L4.437.694a.764.764 0 0 0-1.027.382L1.046 6.422a.764.764 0 0 0 .382 1c1.039.49 3.105 1.467 4.965 2.361 6.698 3.246 12.392 3.029 16.738-4.04z" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { rem } from "@mantine/core";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
size?: number | string;
|
|
||||||
stroke?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function IconColumns4({ size = 24, stroke = 2 }: Props) {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width={rem(size)}
|
|
||||||
height={rem(size)}
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth={stroke}
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M3 4a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v16a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-16" />
|
|
||||||
<path d="M7.5 3v18" />
|
|
||||||
<path d="M12 3v18" />
|
|
||||||
<path d="M16.5 3v18" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import { rem } from "@mantine/core";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
size?: number | string;
|
|
||||||
stroke?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function IconColumns5({ size = 24, stroke = 2 }: Props) {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width={rem(size)}
|
|
||||||
height={rem(size)}
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth={stroke}
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M3 4a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v16a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1v-16" />
|
|
||||||
<path d="M6.6 3v18" />
|
|
||||||
<path d="M10.2 3v18" />
|
|
||||||
<path d="M13.8 3v18" />
|
|
||||||
<path d="M17.4 3v18" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -14,15 +14,6 @@ import SidebarToggle from "@/components/ui/sidebar-toggle-button.tsx";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import useTrial from "@/ee/hooks/use-trial.tsx";
|
import useTrial from "@/ee/hooks/use-trial.tsx";
|
||||||
import { isCloud } from "@/lib/config.ts";
|
import { isCloud } from "@/lib/config.ts";
|
||||||
import {
|
|
||||||
SearchControl,
|
|
||||||
SearchMobileControl,
|
|
||||||
} from "@/features/search/components/search-control.tsx";
|
|
||||||
import {
|
|
||||||
searchSpotlight,
|
|
||||||
shareSearchSpotlight,
|
|
||||||
} from "@/features/search/constants.ts";
|
|
||||||
import { NotificationPopover } from "@/features/notification/components/notification-popover.tsx";
|
|
||||||
|
|
||||||
const links = [{ link: APP_ROUTE.HOME, label: "Home" }];
|
const links = [{ link: APP_ROUTE.HOME, label: "Home" }];
|
||||||
|
|
||||||
@@ -36,8 +27,6 @@ export function AppHeader() {
|
|||||||
const { isTrial, trialDaysLeft } = useTrial();
|
const { isTrial, trialDaysLeft } = useTrial();
|
||||||
|
|
||||||
const isHomeRoute = location.pathname.startsWith("/home");
|
const isHomeRoute = location.pathname.startsWith("/home");
|
||||||
const isSpacesRoute = location.pathname === "/spaces";
|
|
||||||
const hideSidebar = isHomeRoute || isSpacesRoute;
|
|
||||||
|
|
||||||
const items = links.map((link) => (
|
const items = links.map((link) => (
|
||||||
<Link key={link.label} to={link.link} className={classes.link}>
|
<Link key={link.label} to={link.link} className={classes.link}>
|
||||||
@@ -49,7 +38,7 @@ export function AppHeader() {
|
|||||||
<>
|
<>
|
||||||
<Group h="100%" px="md" justify="space-between" wrap={"nowrap"}>
|
<Group h="100%" px="md" justify="space-between" wrap={"nowrap"}>
|
||||||
<Group wrap="nowrap">
|
<Group wrap="nowrap">
|
||||||
{!hideSidebar && (
|
{!isHomeRoute && (
|
||||||
<>
|
<>
|
||||||
<Tooltip label={t("Sidebar toggle")}>
|
<Tooltip label={t("Sidebar toggle")}>
|
||||||
<SidebarToggle
|
<SidebarToggle
|
||||||
@@ -88,17 +77,7 @@ export function AppHeader() {
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<div>
|
|
||||||
<Group visibleFrom="sm">
|
|
||||||
<SearchControl onClick={searchSpotlight.open} />
|
|
||||||
</Group>
|
|
||||||
<Group hiddenFrom="sm">
|
|
||||||
<SearchMobileControl onSearch={searchSpotlight.open} />
|
|
||||||
</Group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Group px={"xl"} wrap="nowrap">
|
<Group px={"xl"} wrap="nowrap">
|
||||||
<NotificationPopover />
|
|
||||||
{isCloud() && isTrial && trialDaysLeft !== 0 && (
|
{isCloud() && isTrial && trialDaysLeft !== 0 && (
|
||||||
<Badge
|
<Badge
|
||||||
variant="light"
|
variant="light"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Box, ScrollArea, Text } from "@mantine/core";
|
import { Box, ScrollArea, Text } from "@mantine/core";
|
||||||
import CommentListWithTabs from "@/features/comment/components/comment-list-with-tabs.tsx";
|
import CommentList from "@/features/comment/components/comment-list.tsx";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
@@ -18,7 +18,7 @@ export default function Aside() {
|
|||||||
|
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case "comments":
|
case "comments":
|
||||||
component = <CommentListWithTabs />;
|
component = <CommentList />;
|
||||||
title = "Comments";
|
title = "Comments";
|
||||||
break;
|
break;
|
||||||
case "toc":
|
case "toc":
|
||||||
@@ -31,24 +31,20 @@ export default function Aside() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box p="md" style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
<Box p="md">
|
||||||
{component && (
|
{component && (
|
||||||
<>
|
<>
|
||||||
<Text mb="md" fw={500}>
|
<Text mb="md" fw={500}>
|
||||||
{t(title)}
|
{t(title)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{tab === "comments" ? (
|
<ScrollArea
|
||||||
<CommentListWithTabs />
|
style={{ height: "85vh" }}
|
||||||
) : (
|
scrollbarSize={5}
|
||||||
<ScrollArea
|
type="scroll"
|
||||||
style={{ height: "85vh" }}
|
>
|
||||||
scrollbarSize={5}
|
<div style={{ paddingBottom: "200px" }}>{component}</div>
|
||||||
type="scroll"
|
</ScrollArea>
|
||||||
>
|
|
||||||
<div style={{ paddingBottom: "200px" }}>{component}</div>
|
|
||||||
</ScrollArea>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -73,15 +73,13 @@ export default function GlobalAppShell({
|
|||||||
const isSettingsRoute = location.pathname.startsWith("/settings");
|
const isSettingsRoute = location.pathname.startsWith("/settings");
|
||||||
const isSpaceRoute = location.pathname.startsWith("/s/");
|
const isSpaceRoute = location.pathname.startsWith("/s/");
|
||||||
const isHomeRoute = location.pathname.startsWith("/home");
|
const isHomeRoute = location.pathname.startsWith("/home");
|
||||||
const isSpacesRoute = location.pathname === "/spaces";
|
|
||||||
const isPageRoute = location.pathname.includes("/p/");
|
const isPageRoute = location.pathname.includes("/p/");
|
||||||
const hideSidebar = isHomeRoute || isSpacesRoute;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppShell
|
<AppShell
|
||||||
header={{ height: 45 }}
|
header={{ height: 45 }}
|
||||||
navbar={
|
navbar={
|
||||||
!hideSidebar && {
|
!isHomeRoute && {
|
||||||
width: isSpaceRoute ? sidebarWidth : 300,
|
width: isSpaceRoute ? sidebarWidth : 300,
|
||||||
breakpoint: "sm",
|
breakpoint: "sm",
|
||||||
collapsed: {
|
collapsed: {
|
||||||
@@ -102,7 +100,7 @@ export default function GlobalAppShell({
|
|||||||
<AppShell.Header px="md" className={classes.header}>
|
<AppShell.Header px="md" className={classes.header}>
|
||||||
<AppHeader />
|
<AppHeader />
|
||||||
</AppShell.Header>
|
</AppShell.Header>
|
||||||
{!hideSidebar && (
|
{!isHomeRoute && (
|
||||||
<AppShell.Navbar
|
<AppShell.Navbar
|
||||||
className={classes.navbar}
|
className={classes.navbar}
|
||||||
withBorder={false}
|
withBorder={false}
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
import { UserProvider } from "@/features/user/user-provider.tsx";
|
import { UserProvider } from "@/features/user/user-provider.tsx";
|
||||||
import { Outlet, useParams } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
import GlobalAppShell from "@/components/layouts/global/global-app-shell.tsx";
|
import GlobalAppShell from "@/components/layouts/global/global-app-shell.tsx";
|
||||||
import { PosthogUser } from "@/ee/components/posthog-user.tsx";
|
|
||||||
import { isCloud } from "@/lib/config.ts";
|
|
||||||
import { SearchSpotlight } from "@/features/search/components/search-spotlight.tsx";
|
|
||||||
import React from "react";
|
|
||||||
import { useGetSpaceBySlugQuery } from "@/features/space/queries/space-query.ts";
|
|
||||||
|
|
||||||
export default function Layout() {
|
export default function Layout() {
|
||||||
const { spaceSlug } = useParams();
|
|
||||||
const { data: space } = useGetSpaceBySlugQuery(spaceSlug);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserProvider>
|
<UserProvider>
|
||||||
<GlobalAppShell>
|
<GlobalAppShell>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</GlobalAppShell>
|
</GlobalAppShell>
|
||||||
{isCloud() && <PosthogUser />}
|
|
||||||
<SearchSpotlight spaceId={space?.id} />
|
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,9 @@
|
|||||||
|
import { Group, Menu, UnstyledButton, Text } from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
Group,
|
|
||||||
Menu,
|
|
||||||
Text,
|
|
||||||
UnstyledButton,
|
|
||||||
useMantineColorScheme,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import {
|
|
||||||
IconBrightnessFilled,
|
|
||||||
IconBrush,
|
IconBrush,
|
||||||
IconCheck,
|
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
IconDeviceDesktop,
|
|
||||||
IconLogout,
|
IconLogout,
|
||||||
IconMoon,
|
|
||||||
IconSettings,
|
IconSettings,
|
||||||
IconSun,
|
|
||||||
IconUserCircle,
|
IconUserCircle,
|
||||||
IconUsers,
|
IconUsers,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
@@ -25,13 +14,11 @@ import APP_ROUTE from "@/lib/app-route.ts";
|
|||||||
import useAuth from "@/features/auth/hooks/use-auth.ts";
|
import useAuth from "@/features/auth/hooks/use-auth.ts";
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts";
|
|
||||||
|
|
||||||
export default function TopMenu() {
|
export default function TopMenu() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [currentUser] = useAtom(currentUserAtom);
|
const [currentUser] = useAtom(currentUserAtom);
|
||||||
const { logout } = useAuth();
|
const { logout } = useAuth();
|
||||||
const { colorScheme, setColorScheme } = useMantineColorScheme();
|
|
||||||
|
|
||||||
const user = currentUser?.user;
|
const user = currentUser?.user;
|
||||||
const workspace = currentUser?.workspace;
|
const workspace = currentUser?.workspace;
|
||||||
@@ -50,7 +37,6 @@ export default function TopMenu() {
|
|||||||
name={workspace?.name}
|
name={workspace?.name}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
size="sm"
|
size="sm"
|
||||||
type={AvatarIconType.WORKSPACE_ICON}
|
|
||||||
/>
|
/>
|
||||||
<Text fw={500} size="sm" lh={1} mr={3} lineClamp={1}>
|
<Text fw={500} size="sm" lh={1} mr={3} lineClamp={1}>
|
||||||
{workspace?.name}
|
{workspace?.name}
|
||||||
@@ -89,7 +75,7 @@ export default function TopMenu() {
|
|||||||
name={user.name}
|
name={user.name}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div style={{ width: 190 }}>
|
<div style={{width: 190}}>
|
||||||
<Text size="sm" fw={500} lineClamp={1}>
|
<Text size="sm" fw={500} lineClamp={1}>
|
||||||
{user.name}
|
{user.name}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -115,44 +101,6 @@ export default function TopMenu() {
|
|||||||
{t("My preferences")}
|
{t("My preferences")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
||||||
<Menu.Sub>
|
|
||||||
<Menu.Sub.Target>
|
|
||||||
<Menu.Sub.Item leftSection={<IconBrightnessFilled size={16} />}>
|
|
||||||
{t("Theme")}
|
|
||||||
</Menu.Sub.Item>
|
|
||||||
</Menu.Sub.Target>
|
|
||||||
|
|
||||||
<Menu.Sub.Dropdown>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => setColorScheme("light")}
|
|
||||||
leftSection={<IconSun size={16} />}
|
|
||||||
rightSection={
|
|
||||||
colorScheme === "light" ? <IconCheck size={16} /> : null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("Light")}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => setColorScheme("dark")}
|
|
||||||
leftSection={<IconMoon size={16} />}
|
|
||||||
rightSection={
|
|
||||||
colorScheme === "dark" ? <IconCheck size={16} /> : null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("Dark")}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => setColorScheme("auto")}
|
|
||||||
leftSection={<IconDeviceDesktop size={16} />}
|
|
||||||
rightSection={
|
|
||||||
colorScheme === "auto" ? <IconCheck size={16} /> : null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("System settings")}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu.Sub.Dropdown>
|
|
||||||
</Menu.Sub>
|
|
||||||
|
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
|
|
||||||
<Menu.Item onClick={logout} leftSection={<IconLogout size={16} />}>
|
<Menu.Item onClick={logout} leftSection={<IconLogout size={16} />}>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function AppVersion() {
|
|||||||
href="https://github.com/docmost/docmost/releases"
|
href="https://github.com/docmost/docmost/releases"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{appVersion?.currentVersion && <>v{appVersion?.currentVersion}</>}
|
v{APP_VERSION}
|
||||||
</Text>
|
</Text>
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -10,11 +10,9 @@ import { getWorkspaceMembers } from "@/features/workspace/services/workspace-ser
|
|||||||
import { getLicenseInfo } from "@/ee/licence/services/license-service.ts";
|
import { getLicenseInfo } from "@/ee/licence/services/license-service.ts";
|
||||||
import { getSsoProviders } from "@/ee/security/services/security-service.ts";
|
import { getSsoProviders } from "@/ee/security/services/security-service.ts";
|
||||||
import { getShares } from "@/features/share/services/share-service.ts";
|
import { getShares } from "@/features/share/services/share-service.ts";
|
||||||
import { getApiKeys } from "@/ee/api-key";
|
|
||||||
import { getAuditLogs } from "@/ee/audit/services/audit-service";
|
|
||||||
|
|
||||||
export const prefetchWorkspaceMembers = () => {
|
export const prefetchWorkspaceMembers = () => {
|
||||||
const params: QueryParams = { limit: 100, query: "" };
|
const params = { limit: 100, page: 1, query: "" } as QueryParams;
|
||||||
queryClient.prefetchQuery({
|
queryClient.prefetchQuery({
|
||||||
queryKey: ["workspaceMembers", params],
|
queryKey: ["workspaceMembers", params],
|
||||||
queryFn: () => getWorkspaceMembers(params),
|
queryFn: () => getWorkspaceMembers(params),
|
||||||
@@ -23,15 +21,15 @@ export const prefetchWorkspaceMembers = () => {
|
|||||||
|
|
||||||
export const prefetchSpaces = () => {
|
export const prefetchSpaces = () => {
|
||||||
queryClient.prefetchQuery({
|
queryClient.prefetchQuery({
|
||||||
queryKey: ["spaces", {}],
|
queryKey: ["spaces", { page: 1 }],
|
||||||
queryFn: () => getSpaces({}),
|
queryFn: () => getSpaces({ page: 1 }),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const prefetchGroups = () => {
|
export const prefetchGroups = () => {
|
||||||
queryClient.prefetchQuery({
|
queryClient.prefetchQuery({
|
||||||
queryKey: ["groups", {}],
|
queryKey: ["groups", { page: 1 }],
|
||||||
queryFn: () => getGroups({}),
|
queryFn: () => getGroups({ page: 1 }),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,29 +61,7 @@ export const prefetchSsoProviders = () => {
|
|||||||
|
|
||||||
export const prefetchShares = () => {
|
export const prefetchShares = () => {
|
||||||
queryClient.prefetchQuery({
|
queryClient.prefetchQuery({
|
||||||
queryKey: ["share-list", {}],
|
queryKey: ["share-list", { page: 1 }],
|
||||||
queryFn: () => getShares({}),
|
queryFn: () => getShares({ page: 1, limit: 100 }),
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const prefetchApiKeys = () => {
|
|
||||||
queryClient.prefetchQuery({
|
|
||||||
queryKey: ["api-key-list", {}],
|
|
||||||
queryFn: () => getApiKeys({}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const prefetchApiKeyManagement = () => {
|
|
||||||
queryClient.prefetchQuery({
|
|
||||||
queryKey: ["api-key-list", { adminView: true }],
|
|
||||||
queryFn: () => getApiKeys({ adminView: true }),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const prefetchAuditLogs = () => {
|
|
||||||
const params = { limit: 50 };
|
|
||||||
queryClient.prefetchQuery({
|
|
||||||
queryKey: ["audit-logs", params],
|
|
||||||
queryFn: () => getAuditLogs(params),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Group, Text, ScrollArea, ActionIcon, Tooltip } from "@mantine/core";
|
import { Group, Text, ScrollArea, ActionIcon } from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
IconUser,
|
IconUser,
|
||||||
IconSettings,
|
IconSettings,
|
||||||
@@ -12,19 +12,15 @@ import {
|
|||||||
IconLock,
|
IconLock,
|
||||||
IconKey,
|
IconKey,
|
||||||
IconWorld,
|
IconWorld,
|
||||||
IconSparkles,
|
|
||||||
IconHistory,
|
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import { Link, useLocation } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import classes from "./settings.module.css";
|
import classes from "./settings.module.css";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { isCloud } from "@/lib/config.ts";
|
import { isCloud } from "@/lib/config.ts";
|
||||||
import useUserRole from "@/hooks/use-user-role.tsx";
|
import useUserRole from "@/hooks/use-user-role.tsx";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai/index";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||||
import {
|
import {
|
||||||
prefetchApiKeyManagement,
|
|
||||||
prefetchApiKeys,
|
|
||||||
prefetchBilling,
|
prefetchBilling,
|
||||||
prefetchGroups,
|
prefetchGroups,
|
||||||
prefetchLicense,
|
prefetchLicense,
|
||||||
@@ -32,7 +28,6 @@ import {
|
|||||||
prefetchSpaces,
|
prefetchSpaces,
|
||||||
prefetchSsoProviders,
|
prefetchSsoProviders,
|
||||||
prefetchWorkspaceMembers,
|
prefetchWorkspaceMembers,
|
||||||
prefetchAuditLogs,
|
|
||||||
} from "@/components/settings/settings-queries.tsx";
|
} from "@/components/settings/settings-queries.tsx";
|
||||||
import AppVersion from "@/components/settings/app-version.tsx";
|
import AppVersion from "@/components/settings/app-version.tsx";
|
||||||
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
||||||
@@ -46,9 +41,7 @@ interface DataItem {
|
|||||||
isCloud?: boolean;
|
isCloud?: boolean;
|
||||||
isEnterprise?: boolean;
|
isEnterprise?: boolean;
|
||||||
isAdmin?: boolean;
|
isAdmin?: boolean;
|
||||||
isOwner?: boolean;
|
|
||||||
isSelfhosted?: boolean;
|
isSelfhosted?: boolean;
|
||||||
showDisabledInNonEE?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DataGroup {
|
interface DataGroup {
|
||||||
@@ -66,14 +59,6 @@ const groupedData: DataGroup[] = [
|
|||||||
icon: IconBrush,
|
icon: IconBrush,
|
||||||
path: "/settings/account/preferences",
|
path: "/settings/account/preferences",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: "API keys",
|
|
||||||
icon: IconKey,
|
|
||||||
path: "/settings/account/api-keys",
|
|
||||||
isCloud: true,
|
|
||||||
isEnterprise: true,
|
|
||||||
showDisabledInNonEE: true,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -99,35 +84,10 @@ const groupedData: DataGroup[] = [
|
|||||||
isCloud: true,
|
isCloud: true,
|
||||||
isEnterprise: true,
|
isEnterprise: true,
|
||||||
isAdmin: true,
|
isAdmin: true,
|
||||||
showDisabledInNonEE: true,
|
|
||||||
},
|
},
|
||||||
{ label: "Groups", icon: IconUsersGroup, path: "/settings/groups" },
|
{ label: "Groups", icon: IconUsersGroup, path: "/settings/groups" },
|
||||||
{ label: "Spaces", icon: IconSpaces, path: "/settings/spaces" },
|
{ label: "Spaces", icon: IconSpaces, path: "/settings/spaces" },
|
||||||
{ label: "Public sharing", icon: IconWorld, path: "/settings/sharing" },
|
{ label: "Public sharing", icon: IconWorld, path: "/settings/sharing" },
|
||||||
{
|
|
||||||
label: "API management",
|
|
||||||
icon: IconKey,
|
|
||||||
path: "/settings/api-keys",
|
|
||||||
isCloud: true,
|
|
||||||
isEnterprise: true,
|
|
||||||
isAdmin: true,
|
|
||||||
showDisabledInNonEE: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "AI settings",
|
|
||||||
icon: IconSparkles,
|
|
||||||
path: "/settings/ai",
|
|
||||||
isAdmin: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Audit log",
|
|
||||||
icon: IconHistory,
|
|
||||||
path: "/settings/audit",
|
|
||||||
isEnterprise: true,
|
|
||||||
isOwner: true,
|
|
||||||
isSelfhosted: true,
|
|
||||||
showDisabledInNonEE: true,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -147,7 +107,7 @@ export default function SettingsSidebar() {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [active, setActive] = useState(location.pathname);
|
const [active, setActive] = useState(location.pathname);
|
||||||
const { goBack } = useSettingsNavigation();
|
const { goBack } = useSettingsNavigation();
|
||||||
const { isAdmin, isOwner } = useUserRole();
|
const { isAdmin } = useUserRole();
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [workspace] = useAtom(workspaceAtom);
|
||||||
const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
|
const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
|
||||||
const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
|
const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
|
||||||
@@ -156,43 +116,29 @@ export default function SettingsSidebar() {
|
|||||||
setActive(location.pathname);
|
setActive(location.pathname);
|
||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
const hasRoleAccess = (item: DataItem) => {
|
|
||||||
if (item.isOwner) return isOwner;
|
|
||||||
if (item.isAdmin) return isAdmin;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const canShowItem = (item: DataItem) => {
|
const canShowItem = (item: DataItem) => {
|
||||||
if (item.showDisabledInNonEE && item.isEnterprise) {
|
|
||||||
if (item.isSelfhosted && isCloud()) return false;
|
|
||||||
return hasRoleAccess(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isCloud && item.isEnterprise) {
|
if (item.isCloud && item.isEnterprise) {
|
||||||
if (!(isCloud() || workspace?.hasLicenseKey)) return false;
|
if (!(isCloud() || workspace?.hasLicenseKey)) return false;
|
||||||
return hasRoleAccess(item);
|
return item.isAdmin ? isAdmin : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isCloud) {
|
if (item.isCloud) {
|
||||||
return isCloud() ? hasRoleAccess(item) : false;
|
return isCloud() ? (item.isAdmin ? isAdmin : true) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isSelfhosted) {
|
if (item.isSelfhosted) {
|
||||||
return !isCloud() ? hasRoleAccess(item) : false;
|
return !isCloud() ? (item.isAdmin ? isAdmin : true) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isEnterprise) {
|
if (item.isEnterprise) {
|
||||||
return workspace?.hasLicenseKey ? hasRoleAccess(item) : false;
|
return workspace?.hasLicenseKey ? (item.isAdmin ? isAdmin : true) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasRoleAccess(item);
|
if (item.isAdmin) {
|
||||||
};
|
return isAdmin;
|
||||||
|
|
||||||
const isItemDisabled = (item: DataItem) => {
|
|
||||||
if (item.showDisabledInNonEE && item.isEnterprise) {
|
|
||||||
return !(isCloud() || workspace?.hasLicenseKey);
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const menuItems = groupedData.map((group) => {
|
const menuItems = groupedData.map((group) => {
|
||||||
@@ -235,61 +181,27 @@ export default function SettingsSidebar() {
|
|||||||
case "Public sharing":
|
case "Public sharing":
|
||||||
prefetchHandler = prefetchShares;
|
prefetchHandler = prefetchShares;
|
||||||
break;
|
break;
|
||||||
case "API keys":
|
|
||||||
prefetchHandler = prefetchApiKeys;
|
|
||||||
break;
|
|
||||||
case "API management":
|
|
||||||
prefetchHandler = prefetchApiKeyManagement;
|
|
||||||
break;
|
|
||||||
case "Audit log":
|
|
||||||
prefetchHandler = prefetchAuditLogs;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDisabled = isItemDisabled(item);
|
return (
|
||||||
const linkElement = (
|
|
||||||
<Link
|
<Link
|
||||||
onMouseEnter={!isDisabled ? prefetchHandler : undefined}
|
onMouseEnter={prefetchHandler}
|
||||||
className={classes.link}
|
className={classes.link}
|
||||||
data-active={active.startsWith(item.path) || undefined}
|
data-active={active.startsWith(item.path) || undefined}
|
||||||
data-disabled={isDisabled || undefined}
|
|
||||||
key={item.label}
|
key={item.label}
|
||||||
to={isDisabled ? "#" : item.path}
|
to={item.path}
|
||||||
onClick={(e) => {
|
onClick={() => {
|
||||||
if (isDisabled) {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mobileSidebarOpened) {
|
if (mobileSidebarOpened) {
|
||||||
toggleMobileSidebar();
|
toggleMobileSidebar();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
|
||||||
opacity: isDisabled ? 0.5 : 1,
|
|
||||||
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<item.icon className={classes.linkIcon} stroke={2} />
|
<item.icon className={classes.linkIcon} stroke={2} />
|
||||||
<span>{t(item.label)}</span>
|
<span>{t(item.label)}</span>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isDisabled) {
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
key={item.label}
|
|
||||||
label={t("Available in enterprise edition")}
|
|
||||||
position="right"
|
|
||||||
withArrow
|
|
||||||
>
|
|
||||||
{linkElement}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return linkElement;
|
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import { useRef, useState, ReactNode } from "react";
|
|
||||||
import { Text, TextProps, Tooltip } from "@mantine/core";
|
|
||||||
|
|
||||||
type AutoTooltipTextProps = TextProps & {
|
|
||||||
children: ReactNode;
|
|
||||||
tooltipLabel?: string;
|
|
||||||
tooltipProps?: Omit<
|
|
||||||
React.ComponentProps<typeof Tooltip>,
|
|
||||||
"children" | "label"
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function AutoTooltipText({
|
|
||||||
children,
|
|
||||||
tooltipLabel,
|
|
||||||
tooltipProps,
|
|
||||||
...textProps
|
|
||||||
}: AutoTooltipTextProps) {
|
|
||||||
const textRef = useRef<HTMLParagraphElement>(null);
|
|
||||||
const [isTruncated, setIsTruncated] = useState(false);
|
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
|
||||||
const element = textRef.current;
|
|
||||||
if (element) {
|
|
||||||
setIsTruncated(element.scrollWidth > element.clientWidth);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const label = tooltipLabel ?? (typeof children === "string" ? children : "");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
label={label}
|
|
||||||
disabled={!isTruncated || !label}
|
|
||||||
multiline
|
|
||||||
withArrow
|
|
||||||
{...tooltipProps}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
ref={textRef}
|
|
||||||
truncate
|
|
||||||
onMouseEnter={handleMouseEnter}
|
|
||||||
{...textProps}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Avatar } from "@mantine/core";
|
import { Avatar } from "@mantine/core";
|
||||||
import { getAvatarUrl } from "@/lib/config.ts";
|
import { getAvatarUrl } from "@/lib/config.ts";
|
||||||
import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts";
|
|
||||||
|
|
||||||
interface CustomAvatarProps {
|
interface CustomAvatarProps {
|
||||||
avatarUrl?: string;
|
avatarUrl: string;
|
||||||
name: string;
|
name: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
size?: string | number;
|
size?: string | number;
|
||||||
@@ -12,15 +11,13 @@ interface CustomAvatarProps {
|
|||||||
variant?: string;
|
variant?: string;
|
||||||
style?: any;
|
style?: any;
|
||||||
component?: any;
|
component?: any;
|
||||||
type?: AvatarIconType;
|
|
||||||
mt?: string | number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CustomAvatar = React.forwardRef<
|
export const CustomAvatar = React.forwardRef<
|
||||||
HTMLInputElement,
|
HTMLInputElement,
|
||||||
CustomAvatarProps
|
CustomAvatarProps
|
||||||
>(({ avatarUrl, name, type, ...props }: CustomAvatarProps, ref) => {
|
>(({ avatarUrl, name, ...props }: CustomAvatarProps, ref) => {
|
||||||
const avatarLink = getAvatarUrl(avatarUrl, type);
|
const avatarLink = getAvatarUrl(avatarUrl);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@@ -15,11 +15,6 @@ export interface EmojiPickerInterface {
|
|||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
removeEmojiAction: () => void;
|
removeEmojiAction: () => void;
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
actionIconProps?: {
|
|
||||||
size?: string;
|
|
||||||
variant?: string;
|
|
||||||
c?: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function EmojiPicker({
|
function EmojiPicker({
|
||||||
@@ -27,7 +22,6 @@ function EmojiPicker({
|
|||||||
icon,
|
icon,
|
||||||
removeEmojiAction,
|
removeEmojiAction,
|
||||||
readOnly,
|
readOnly,
|
||||||
actionIconProps,
|
|
||||||
}: EmojiPickerInterface) {
|
}: EmojiPickerInterface) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [opened, handlers] = useDisclosure(false);
|
const [opened, handlers] = useDisclosure(false);
|
||||||
@@ -70,12 +64,7 @@ function EmojiPicker({
|
|||||||
closeOnEscape={true}
|
closeOnEscape={true}
|
||||||
>
|
>
|
||||||
<Popover.Target ref={setTarget}>
|
<Popover.Target ref={setTarget}>
|
||||||
<ActionIcon
|
<ActionIcon c="gray" variant="transparent" onClick={handlers.toggle}>
|
||||||
c={actionIconProps?.c || "gray"}
|
|
||||||
variant={actionIconProps?.variant || "transparent"}
|
|
||||||
size={actionIconProps?.size}
|
|
||||||
onClick={handlers.toggle}
|
|
||||||
>
|
|
||||||
{icon}
|
{icon}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
.root {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 60px 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import { Stack, Text } from "@mantine/core";
|
|
||||||
import { type TablerIcon } from "@tabler/icons-react";
|
|
||||||
import { ReactNode } from "react";
|
|
||||||
import classes from "./empty-state.module.css";
|
|
||||||
|
|
||||||
type EmptyStateProps = {
|
|
||||||
icon: TablerIcon;
|
|
||||||
title: string;
|
|
||||||
description?: string;
|
|
||||||
action?: ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function EmptyState({ icon: Icon, title, description, action }: EmptyStateProps) {
|
|
||||||
return (
|
|
||||||
<div className={classes.root}>
|
|
||||||
<Stack align="center" gap="xs">
|
|
||||||
<Icon size={40} stroke={1.5} color="var(--mantine-color-dimmed)" />
|
|
||||||
<Text size="lg" fw={500}>
|
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
{description && (
|
|
||||||
<Text size="sm" c="dimmed" maw={350}>
|
|
||||||
{description}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{action}
|
|
||||||
</Stack>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { Box } from "@mantine/core";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface ResponsiveSettingsRowProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ResponsiveSettingsRow({ children }: ResponsiveSettingsRowProps) {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "1rem",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResponsiveSettingsContentProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ResponsiveSettingsContent({ children }: ResponsiveSettingsContentProps) {
|
|
||||||
return (
|
|
||||||
<Box style={{ flex: "1 1 300px", minWidth: 0 }}>
|
|
||||||
{children}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResponsiveSettingsControlProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ResponsiveSettingsControl({ children }: ResponsiveSettingsControlProps) {
|
|
||||||
return (
|
|
||||||
<Box style={{ flex: "0 0 auto" }}>
|
|
||||||
{children}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import React, { useMemo } from "react";
|
|
||||||
import { Paper, Text, Group, Stack, Loader, Box } from "@mantine/core";
|
|
||||||
import { IconSparkles, IconFileText } from "@tabler/icons-react";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import { IAiSearchResponse } from "../services/ai-search-service.ts";
|
|
||||||
import { buildPageUrl } from "@/features/page/page.utils.ts";
|
|
||||||
import { markdownToHtml } from "@docmost/editor-ext";
|
|
||||||
import DOMPurify from "dompurify";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
interface AiSearchResultProps {
|
|
||||||
result?: IAiSearchResponse;
|
|
||||||
isLoading?: boolean;
|
|
||||||
streamingAnswer?: string;
|
|
||||||
streamingSources?: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AiSearchResult({
|
|
||||||
result,
|
|
||||||
isLoading,
|
|
||||||
streamingAnswer = "",
|
|
||||||
streamingSources = [],
|
|
||||||
}: AiSearchResultProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
// Use streaming data if available, otherwise fall back to result
|
|
||||||
const answer = streamingAnswer || result?.answer || "";
|
|
||||||
const sources =
|
|
||||||
streamingSources.length > 0 ? streamingSources : result?.sources || [];
|
|
||||||
|
|
||||||
// Deduplicate sources by pageId, keeping the one with highest similarity
|
|
||||||
const deduplicatedSources = useMemo(() => {
|
|
||||||
if (!sources || sources.length === 0) return [];
|
|
||||||
|
|
||||||
const pageMap = new Map();
|
|
||||||
sources.forEach((source) => {
|
|
||||||
const existing = pageMap.get(source.pageId);
|
|
||||||
if (!existing || source.similarity > existing.similarity) {
|
|
||||||
pageMap.set(source.pageId, source);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Array.from(pageMap.values());
|
|
||||||
}, [sources]);
|
|
||||||
|
|
||||||
if (isLoading && !answer) {
|
|
||||||
return (
|
|
||||||
<Paper p="md" radius="md" withBorder>
|
|
||||||
<Group>
|
|
||||||
<Loader size="sm" />
|
|
||||||
<Text size="sm">{t("AI is thinking...")}</Text>
|
|
||||||
</Group>
|
|
||||||
</Paper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!answer && !isLoading) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack gap="md" p="md">
|
|
||||||
<Paper p="md" radius="md" withBorder>
|
|
||||||
<Group gap="xs" mb="sm">
|
|
||||||
<IconSparkles size={20} color="var(--mantine-color-blue-6)" />
|
|
||||||
<Text fw={600} size="sm">
|
|
||||||
{t("AI Answer")}
|
|
||||||
</Text>
|
|
||||||
{isLoading && <Loader size="xs" />}
|
|
||||||
</Group>
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: DOMPurify.sanitize(markdownToHtml(answer) as string),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
|
|
||||||
{deduplicatedSources.length > 0 && (
|
|
||||||
<Stack gap="xs">
|
|
||||||
<Text size="xs" fw={600} c="dimmed">
|
|
||||||
{t("Sources")}
|
|
||||||
</Text>
|
|
||||||
{deduplicatedSources.map((source) => (
|
|
||||||
<Box
|
|
||||||
key={source.pageId}
|
|
||||||
component={Link}
|
|
||||||
to={buildPageUrl(source.spaceSlug, source.slugId, source.title)}
|
|
||||||
style={{
|
|
||||||
textDecoration: "none",
|
|
||||||
color: "inherit",
|
|
||||||
display: "block",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper
|
|
||||||
p="xs"
|
|
||||||
radius="sm"
|
|
||||||
withBorder
|
|
||||||
style={{ cursor: "pointer" }}
|
|
||||||
>
|
|
||||||
<Group gap="xs">
|
|
||||||
<IconFileText size={16} />
|
|
||||||
<Text size="sm" truncate>
|
|
||||||
{source.title}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
.aiMenu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 600px;
|
|
||||||
min-height: 2.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aiInput {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& input {
|
|
||||||
height: 44px;
|
|
||||||
border-radius: 22px;
|
|
||||||
padding-left: 20px;
|
|
||||||
padding-right: 40px;
|
|
||||||
border: 1px solid
|
|
||||||
light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
||||||
font-size: var(--mantine-font-size-sm);
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: light-dark(
|
|
||||||
var(--mantine-color-gray-4),
|
|
||||||
var(--mantine-color-dark-3)
|
|
||||||
);
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.menuItemSelected {
|
|
||||||
background-color: var(--mantine-color-gray-1);
|
|
||||||
|
|
||||||
@mixin dark {
|
|
||||||
background-color: var(--mantine-color-dark-5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.resultPreview {
|
|
||||||
background-color: light-dark(
|
|
||||||
var(--mantine-color-white),
|
|
||||||
var(--mantine-color-dark-6)
|
|
||||||
);
|
|
||||||
border: 1px solid
|
|
||||||
light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resultPreviewWrapper {
|
|
||||||
font-size: var(--mantine-font-size-md);
|
|
||||||
line-height: 1.6;
|
|
||||||
padding: var(--mantine-spacing-md);
|
|
||||||
|
|
||||||
*:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
*:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,349 +0,0 @@
|
|||||||
import { Editor } from "@tiptap/react";
|
|
||||||
import { ActionIcon, TextInput } from "@mantine/core";
|
|
||||||
import { useDebouncedCallback, useMediaQuery } from "@mantine/hooks";
|
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
||||||
import { createPortal } from "react-dom";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { IconArrowUp } from "@tabler/icons-react";
|
|
||||||
import { showAiMenuAtom } from "@/features/editor/atoms/editor-atoms.ts";
|
|
||||||
import { useAiGenerateStreamMutation } from "@/ee/ai/queries/ai-query.ts";
|
|
||||||
import { AiAction } from "@/ee/ai/types/ai.types.ts";
|
|
||||||
import { CommandItem, commandItems, CommandSet } from "./command-items.ts";
|
|
||||||
import { CommandSelector } from "./command-selector.tsx";
|
|
||||||
import { ResultPreview } from "./result-preview.tsx";
|
|
||||||
import classes from "./ai-menu.module.css";
|
|
||||||
import { marked } from "marked";
|
|
||||||
import { DOMSerializer } from "@tiptap/pm/model";
|
|
||||||
import { copyToClipboard, htmlToMarkdown } from "@docmost/editor-ext";
|
|
||||||
import { useLocation } from "react-router-dom";
|
|
||||||
|
|
||||||
interface EditorAiMenuProps {
|
|
||||||
editor: Editor | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EditorAiMenu = ({ editor }: EditorAiMenuProps): JSX.Element | null => {
|
|
||||||
const aiGenerateStreamMutation = useAiGenerateStreamMutation();
|
|
||||||
const location = useLocation();
|
|
||||||
const isSmBreakpoint = useMediaQuery("(max-width: 48em)");
|
|
||||||
const [showAiMenu, setShowAiMenu] = useAtom(showAiMenuAtom);
|
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
||||||
const [prompt, setPrompt] = useState("");
|
|
||||||
const [output, setOutput] = useState("");
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [selectedIndex, setSelectedIndex] = useState(-1);
|
|
||||||
const [activeCommandSet, setActiveCommandSet] = useState<CommandSet>("main");
|
|
||||||
const [lastAction, setLastAction] = useState<CommandItem | null>(null);
|
|
||||||
const [menuPlacement, setMenuPlacement] = useState<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
width: number;
|
|
||||||
}>({
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
width: 0,
|
|
||||||
});
|
|
||||||
const currentItems = useMemo(() => {
|
|
||||||
return commandItems[activeCommandSet].filter((item) => {
|
|
||||||
return item.name.toLowerCase().includes(prompt.toLowerCase());
|
|
||||||
});
|
|
||||||
}, [prompt, output, activeCommandSet]);
|
|
||||||
const updateMenuPlacement = useCallback(() => {
|
|
||||||
if (!editor || !showAiMenu) return;
|
|
||||||
|
|
||||||
const { view } = editor;
|
|
||||||
const { from, to } = editor.state.selection;
|
|
||||||
const editorRect = view.dom.getBoundingClientRect();
|
|
||||||
const fromCoords = view.coordsAtPos(from);
|
|
||||||
const toCoords = view.coordsAtPos(to);
|
|
||||||
const topOffset = 8;
|
|
||||||
const editorPadding = isSmBreakpoint ? 16 : 48;
|
|
||||||
|
|
||||||
const anchorBottom =
|
|
||||||
toCoords.bottom > 0 && toCoords.bottom < window.innerHeight
|
|
||||||
? toCoords.bottom
|
|
||||||
: fromCoords.bottom;
|
|
||||||
|
|
||||||
const menuMaxWidth = 600;
|
|
||||||
const editorLeft = editorRect.left + editorPadding;
|
|
||||||
const editorRight = editorRect.right - editorPadding;
|
|
||||||
const availableWidth = editorRight - editorLeft;
|
|
||||||
const menuWidth = Math.min(menuMaxWidth, availableWidth);
|
|
||||||
|
|
||||||
let menuLeft = Math.max(editorLeft, fromCoords.left);
|
|
||||||
if (menuLeft + menuWidth > editorRight) {
|
|
||||||
menuLeft = editorRight - menuWidth;
|
|
||||||
}
|
|
||||||
menuLeft = Math.max(editorLeft, menuLeft);
|
|
||||||
|
|
||||||
setMenuPlacement({
|
|
||||||
top: anchorBottom + topOffset + window.scrollY,
|
|
||||||
left: menuLeft + window.scrollX,
|
|
||||||
width: menuWidth,
|
|
||||||
});
|
|
||||||
}, [editor, showAiMenu, isSmBreakpoint]);
|
|
||||||
const resetMenu = useCallback(() => {
|
|
||||||
setPrompt("");
|
|
||||||
setOutput("");
|
|
||||||
setActiveCommandSet("main");
|
|
||||||
setLastAction(null);
|
|
||||||
aiGenerateStreamMutation.reset();
|
|
||||||
}, [aiGenerateStreamMutation.reset]);
|
|
||||||
const debouncedUpdateMenuPlacement = useDebouncedCallback(
|
|
||||||
updateMenuPlacement,
|
|
||||||
60,
|
|
||||||
);
|
|
||||||
const handleGenerate = useCallback(
|
|
||||||
(item?: CommandItem) => {
|
|
||||||
if (!editor || isLoading) return;
|
|
||||||
|
|
||||||
let command: CommandItem | null = item || null;
|
|
||||||
|
|
||||||
if (!command) {
|
|
||||||
if (!prompt) return;
|
|
||||||
|
|
||||||
command = {
|
|
||||||
id: "custom",
|
|
||||||
name: "Custom",
|
|
||||||
action: AiAction.CUSTOM,
|
|
||||||
prompt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { from, to } = editor.state.selection;
|
|
||||||
const slice = editor.state.doc.slice(from, to);
|
|
||||||
const serializer = DOMSerializer.fromSchema(editor.schema);
|
|
||||||
const fragment = serializer.serializeFragment(slice.content);
|
|
||||||
const wrapper = document.createElement("div");
|
|
||||||
wrapper.appendChild(fragment);
|
|
||||||
const content = htmlToMarkdown(wrapper.innerHTML);
|
|
||||||
|
|
||||||
setOutput("");
|
|
||||||
setIsLoading(true);
|
|
||||||
aiGenerateStreamMutation.mutate({
|
|
||||||
action: command.action,
|
|
||||||
prompt: command.prompt,
|
|
||||||
content,
|
|
||||||
onChunk: (chunk) => {
|
|
||||||
setOutput((output) => output + chunk.content);
|
|
||||||
},
|
|
||||||
onComplete: () => {
|
|
||||||
setPrompt("");
|
|
||||||
setIsLoading(false);
|
|
||||||
setActiveCommandSet("result");
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
setIsLoading(false);
|
|
||||||
resetMenu();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
setLastAction(command);
|
|
||||||
},
|
|
||||||
[
|
|
||||||
editor,
|
|
||||||
prompt,
|
|
||||||
isLoading,
|
|
||||||
aiGenerateStreamMutation.mutateAsync,
|
|
||||||
resetMenu,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
const handleCommand = useCallback(
|
|
||||||
(item?: CommandItem) => {
|
|
||||||
setPrompt("");
|
|
||||||
|
|
||||||
if (!item) {
|
|
||||||
return handleGenerate();
|
|
||||||
}
|
|
||||||
if (item.id === "back") {
|
|
||||||
return setActiveCommandSet("main");
|
|
||||||
}
|
|
||||||
if (item.id === "result-replace") {
|
|
||||||
const chain = editor.chain().focus();
|
|
||||||
|
|
||||||
if (lastAction.action === AiAction.CONTINUE_WRITING) {
|
|
||||||
chain.setTextSelection(editor.state.selection.to);
|
|
||||||
}
|
|
||||||
|
|
||||||
const html = (marked.parse(output) as string).trim();
|
|
||||||
const isSingleParagraph =
|
|
||||||
html.startsWith("<p>") &&
|
|
||||||
html.endsWith("</p>") &&
|
|
||||||
html.lastIndexOf("<p>") === 0;
|
|
||||||
|
|
||||||
// Strip <p> wrapper for single-paragraph output to preserve inline context,
|
|
||||||
// then decode HTML entities via DOMParser since TipTap would otherwise
|
|
||||||
// treat the tagless string as plain text and insert entities literally.
|
|
||||||
const content = isSingleParagraph
|
|
||||||
? new DOMParser().parseFromString(html.slice(3, -4), "text/html")
|
|
||||||
.body.innerHTML
|
|
||||||
: html;
|
|
||||||
|
|
||||||
chain.insertContent(content).run();
|
|
||||||
|
|
||||||
return setShowAiMenu(false);
|
|
||||||
}
|
|
||||||
if (item.id === "result-insert-below") {
|
|
||||||
editor
|
|
||||||
.chain()
|
|
||||||
.focus()
|
|
||||||
.setTextSelection(editor.state.selection.to)
|
|
||||||
.insertContent(marked.parse(output))
|
|
||||||
.run();
|
|
||||||
|
|
||||||
return setShowAiMenu(false);
|
|
||||||
}
|
|
||||||
if (item.id === "result-copy") {
|
|
||||||
copyToClipboard(output);
|
|
||||||
|
|
||||||
return setShowAiMenu(false);
|
|
||||||
}
|
|
||||||
if (item.id === "result-discard") {
|
|
||||||
setOutput("");
|
|
||||||
|
|
||||||
return resetMenu();
|
|
||||||
}
|
|
||||||
if (item.id === "result-try-again" && lastAction) {
|
|
||||||
return handleGenerate(lastAction);
|
|
||||||
}
|
|
||||||
if (item.subCommandSet) {
|
|
||||||
return setActiveCommandSet(item.subCommandSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
return handleGenerate(item);
|
|
||||||
},
|
|
||||||
[editor, output, lastAction, handleGenerate, resetMenu],
|
|
||||||
);
|
|
||||||
const handleKeyDown = useCallback(
|
|
||||||
(event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
||||||
const totalItems = currentItems.length;
|
|
||||||
const cycleSize = totalItems + 1;
|
|
||||||
|
|
||||||
if (event.key === "Escape") {
|
|
||||||
return setShowAiMenu(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
return setSelectedIndex((selectedIndex) => {
|
|
||||||
const direction = event.key === "ArrowDown" ? 1 : -1;
|
|
||||||
const newIndex = selectedIndex + direction;
|
|
||||||
|
|
||||||
if (newIndex < -1) return cycleSize - 1;
|
|
||||||
if (newIndex >= cycleSize) return 0;
|
|
||||||
|
|
||||||
return newIndex;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === "Enter") {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
return handleCommand(currentItems[selectedIndex]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[currentItems, selectedIndex],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!editor) return;
|
|
||||||
|
|
||||||
const handleClose = () => setShowAiMenu(false);
|
|
||||||
const observer = new ResizeObserver(() => {
|
|
||||||
debouncedUpdateMenuPlacement();
|
|
||||||
});
|
|
||||||
|
|
||||||
updateMenuPlacement();
|
|
||||||
editor.on("focus", handleClose);
|
|
||||||
editor.on("blur", handleClose);
|
|
||||||
window.addEventListener("resize", debouncedUpdateMenuPlacement);
|
|
||||||
window.addEventListener("scroll", debouncedUpdateMenuPlacement, true);
|
|
||||||
observer.observe(editor.view.dom);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
editor.off("focus", handleClose);
|
|
||||||
editor.off("blur", handleClose);
|
|
||||||
window.removeEventListener("resize", debouncedUpdateMenuPlacement);
|
|
||||||
window.removeEventListener("scroll", debouncedUpdateMenuPlacement, true);
|
|
||||||
observer.disconnect();
|
|
||||||
};
|
|
||||||
}, [editor, updateMenuPlacement, debouncedUpdateMenuPlacement]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setShowAiMenu(false);
|
|
||||||
}, [location]);
|
|
||||||
useEffect(() => {
|
|
||||||
if (showAiMenu) {
|
|
||||||
resetMenu();
|
|
||||||
}
|
|
||||||
}, [showAiMenu, resetMenu]);
|
|
||||||
useEffect(() => {
|
|
||||||
// Focus input when menu opens or command set changes
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
inputRef.current?.focus({ preventScroll: true });
|
|
||||||
});
|
|
||||||
}, [showAiMenu, isLoading, currentItems]);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!currentItems.length) {
|
|
||||||
setSelectedIndex(-1);
|
|
||||||
}
|
|
||||||
setSelectedIndex(prompt || activeCommandSet !== "main" ? 0 : -1);
|
|
||||||
}, [prompt, activeCommandSet, currentItems]);
|
|
||||||
|
|
||||||
if (!showAiMenu) return null;
|
|
||||||
|
|
||||||
return createPortal(
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
zIndex: 199,
|
|
||||||
position: "absolute",
|
|
||||||
top: menuPlacement.top,
|
|
||||||
left: menuPlacement.left,
|
|
||||||
width: menuPlacement.width,
|
|
||||||
pointerEvents: "none",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classes.aiMenu}
|
|
||||||
style={{ pointerEvents: "auto" }}
|
|
||||||
tabIndex={0}
|
|
||||||
ref={containerRef}
|
|
||||||
>
|
|
||||||
<ResultPreview output={output} isLoading={isLoading} />
|
|
||||||
<CommandSelector
|
|
||||||
selectedIndex={selectedIndex}
|
|
||||||
isLoading={isLoading}
|
|
||||||
output={output}
|
|
||||||
currentItems={currentItems}
|
|
||||||
handleCommand={handleCommand}
|
|
||||||
>
|
|
||||||
<TextInput
|
|
||||||
ref={inputRef}
|
|
||||||
className={classes.aiInput}
|
|
||||||
placeholder="Ask AI..."
|
|
||||||
data-autofocus
|
|
||||||
value={prompt}
|
|
||||||
disabled={isLoading}
|
|
||||||
onChange={(e) => setPrompt(e.currentTarget.value)}
|
|
||||||
rightSection={
|
|
||||||
<ActionIcon
|
|
||||||
disabled={!prompt || isLoading}
|
|
||||||
variant="filled"
|
|
||||||
color="blue"
|
|
||||||
radius="xl"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => handleGenerate()}
|
|
||||||
>
|
|
||||||
<IconArrowUp size={14} stroke={2.5} />
|
|
||||||
</ActionIcon>
|
|
||||||
}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
/>
|
|
||||||
</CommandSelector>
|
|
||||||
</div>
|
|
||||||
</div>,
|
|
||||||
document.body,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { EditorAiMenu };
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
import { AiAction } from "@/ee/ai/types/ai.types.ts";
|
|
||||||
import {
|
|
||||||
IconSparkles,
|
|
||||||
IconArrowsMaximize,
|
|
||||||
IconArrowsMinimize,
|
|
||||||
IconWriting,
|
|
||||||
IconHelp,
|
|
||||||
IconList,
|
|
||||||
IconMoodSmile,
|
|
||||||
IconLanguage,
|
|
||||||
IconTrash,
|
|
||||||
IconRefresh,
|
|
||||||
IconChevronLeft,
|
|
||||||
IconCheck,
|
|
||||||
IconArrowDownLeft,
|
|
||||||
IconCopy,
|
|
||||||
IconTextPlus,
|
|
||||||
IconAlignJustified,
|
|
||||||
} from "@tabler/icons-react";
|
|
||||||
|
|
||||||
interface CommandItem {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
icon?: typeof IconSparkles;
|
|
||||||
action?: AiAction;
|
|
||||||
prompt?: string;
|
|
||||||
subCommandSet?: CommandSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandSet = "main" | "tone" | "translate" | "result";
|
|
||||||
|
|
||||||
const mainItems: CommandItem[] = [
|
|
||||||
{
|
|
||||||
id: "improve-writing",
|
|
||||||
name: "Improve writing",
|
|
||||||
icon: IconSparkles,
|
|
||||||
action: AiAction.IMPROVE_WRITING,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "fix-spelling-grammar",
|
|
||||||
name: "Fix spelling & grammar",
|
|
||||||
icon: IconCheck,
|
|
||||||
action: AiAction.FIX_SPELLING_GRAMMAR,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "make-longer",
|
|
||||||
name: "Make longer",
|
|
||||||
icon: IconTextPlus,
|
|
||||||
action: AiAction.MAKE_LONGER,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "make-shorter",
|
|
||||||
name: "Make shorter",
|
|
||||||
icon: IconAlignJustified,
|
|
||||||
action: AiAction.MAKE_SHORTER,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "continue-writing",
|
|
||||||
name: "Continue writing",
|
|
||||||
icon: IconWriting,
|
|
||||||
action: AiAction.CONTINUE_WRITING,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "explain",
|
|
||||||
name: "Explain",
|
|
||||||
icon: IconHelp,
|
|
||||||
action: AiAction.EXPLAIN,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "summarize",
|
|
||||||
name: "Summarize",
|
|
||||||
icon: IconList,
|
|
||||||
action: AiAction.SUMMARIZE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "change-tone",
|
|
||||||
name: "Change tone",
|
|
||||||
icon: IconMoodSmile,
|
|
||||||
subCommandSet: "tone",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate",
|
|
||||||
name: "Translate",
|
|
||||||
icon: IconLanguage,
|
|
||||||
subCommandSet: "translate",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const toneItems: CommandItem[] = [
|
|
||||||
{
|
|
||||||
id: "back",
|
|
||||||
name: "Back",
|
|
||||||
icon: IconChevronLeft,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tone-professional",
|
|
||||||
name: "Professional",
|
|
||||||
icon: IconMoodSmile,
|
|
||||||
action: AiAction.CHANGE_TONE,
|
|
||||||
prompt: "Professional",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tone-casual",
|
|
||||||
name: "Casual",
|
|
||||||
icon: IconMoodSmile,
|
|
||||||
action: AiAction.CHANGE_TONE,
|
|
||||||
prompt: "Casual",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tone-friendly",
|
|
||||||
name: "Friendly",
|
|
||||||
icon: IconMoodSmile,
|
|
||||||
action: AiAction.CHANGE_TONE,
|
|
||||||
prompt: "Friendly",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const translateItems: CommandItem[] = [
|
|
||||||
{
|
|
||||||
id: "back",
|
|
||||||
name: "Back",
|
|
||||||
icon: IconChevronLeft,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-english",
|
|
||||||
name: "English",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "English",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-spanish",
|
|
||||||
name: "Spanish",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Spanish",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-german",
|
|
||||||
name: "German",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "German",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-french",
|
|
||||||
name: "French",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "French",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-dutch",
|
|
||||||
name: "Dutch",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Dutch",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-portuguese",
|
|
||||||
name: "Portuguese",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Portuguese",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-italian",
|
|
||||||
name: "Italian",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Italian",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-japanese",
|
|
||||||
name: "Japanese",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Japanese",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-korean",
|
|
||||||
name: "Korean",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Korean",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-swedish",
|
|
||||||
name: "Swedish",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Swedish",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "translate-chinese",
|
|
||||||
name: "Chinese (Simplified)",
|
|
||||||
icon: IconLanguage,
|
|
||||||
action: AiAction.TRANSLATE,
|
|
||||||
prompt: "Simplified Chinese",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const resultItems: CommandItem[] = [
|
|
||||||
{ id: "result-replace", name: "Replace", icon: IconCheck },
|
|
||||||
{ id: "result-insert-below", name: "Insert below", icon: IconArrowDownLeft },
|
|
||||||
{ id: "result-copy", name: "Copy", icon: IconCopy },
|
|
||||||
{ id: "result-discard", name: "Discard", icon: IconTrash },
|
|
||||||
{
|
|
||||||
id: "result-try-again",
|
|
||||||
name: "Try again",
|
|
||||||
icon: IconRefresh,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const commandItems: Record<CommandSet, CommandItem[]> = {
|
|
||||||
main: mainItems,
|
|
||||||
tone: toneItems,
|
|
||||||
translate: translateItems,
|
|
||||||
result: resultItems,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type { CommandItem, CommandSet };
|
|
||||||
export { commandItems };
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import { Loader, Menu, ScrollArea } from "@mantine/core";
|
|
||||||
import { IconChevronRight } from "@tabler/icons-react";
|
|
||||||
import { ReactNode } from "react";
|
|
||||||
import { CommandItem } from "./command-items.ts";
|
|
||||||
import classes from "./ai-menu.module.css";
|
|
||||||
|
|
||||||
interface CommandSelectorProps {
|
|
||||||
selectedIndex: number;
|
|
||||||
|
|
||||||
isLoading: boolean;
|
|
||||||
output: string;
|
|
||||||
currentItems: CommandItem[];
|
|
||||||
children: ReactNode;
|
|
||||||
handleCommand(item: CommandItem): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CommandSelector = ({
|
|
||||||
selectedIndex,
|
|
||||||
children,
|
|
||||||
isLoading,
|
|
||||||
output,
|
|
||||||
currentItems,
|
|
||||||
handleCommand,
|
|
||||||
}: CommandSelectorProps) => {
|
|
||||||
return (
|
|
||||||
<Menu
|
|
||||||
opened={!isLoading && currentItems.length > 0}
|
|
||||||
middlewares={{ flip: false }}
|
|
||||||
position="bottom-start"
|
|
||||||
offset={4}
|
|
||||||
width={250}
|
|
||||||
trapFocus={false}
|
|
||||||
shadow="lg"
|
|
||||||
>
|
|
||||||
<Menu.Target>{children}</Menu.Target>
|
|
||||||
<Menu.Dropdown>
|
|
||||||
<ScrollArea.Autosize type="scroll" scrollbarSize={5} mah={300}>
|
|
||||||
{currentItems.map((item, index) => {
|
|
||||||
const isSelected = selectedIndex === index;
|
|
||||||
const showLoader =
|
|
||||||
isLoading && output === "" && !item.subCommandSet;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Menu.Item
|
|
||||||
key={item.id}
|
|
||||||
className={isSelected ? classes.menuItemSelected : undefined}
|
|
||||||
leftSection={
|
|
||||||
showLoader ? (
|
|
||||||
<Loader size={14} />
|
|
||||||
) : item.icon ? (
|
|
||||||
<item.icon size={16} />
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
rightSection={
|
|
||||||
item.subCommandSet ? (
|
|
||||||
<IconChevronRight size={14} />
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
onClick={() => handleCommand(item)}
|
|
||||||
disabled={isLoading}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</Menu.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ScrollArea.Autosize>
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { CommandSelector };
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { Loader, Paper, ScrollArea } from "@mantine/core";
|
|
||||||
import DOMPurify from "dompurify";
|
|
||||||
import { marked } from "marked";
|
|
||||||
import { memo } from "react";
|
|
||||||
import classes from "./ai-menu.module.css";
|
|
||||||
|
|
||||||
interface ResultPreviewProps {
|
|
||||||
output: string;
|
|
||||||
isLoading: boolean;
|
|
||||||
}
|
|
||||||
const ResultPreview = memo(({ output, isLoading }: ResultPreviewProps) => {
|
|
||||||
if (!output && !isLoading) return;
|
|
||||||
|
|
||||||
const parsedOutput = `${marked.parse(output)}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Paper mb={4} shadow="lg" radius="md" className={classes.resultPreview}>
|
|
||||||
<ScrollArea.Autosize mah={300} type="scroll" scrollbarSize={5}>
|
|
||||||
<div className={classes.resultPreviewWrapper}>
|
|
||||||
{parsedOutput && (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(parsedOutput) }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isLoading && <Loader size={12} ml="xs" display="inline-block" />}
|
|
||||||
</div>
|
|
||||||
</ScrollArea.Autosize>
|
|
||||||
</Paper>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export { ResultPreview };
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import { Group, Text, Switch, MantineSize, Title } from "@mantine/core";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { isCloud } from "@/lib/config.ts";
|
|
||||||
import useLicense from "@/ee/hooks/use-license.tsx";
|
|
||||||
|
|
||||||
export default function EnableAiSearch() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Group justify="space-between" wrap="nowrap" gap="xl">
|
|
||||||
<div>
|
|
||||||
<Text size="md">{t("AI-powered search (AI Answers)")}</Text>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{t(
|
|
||||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.",
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<AiSearchToggle />
|
|
||||||
</Group>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AiSearchToggleProps {
|
|
||||||
size?: MantineSize;
|
|
||||||
label?: string;
|
|
||||||
}
|
|
||||||
export function AiSearchToggle({ size, label }: AiSearchToggleProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [workspace, setWorkspace] = useAtom(workspaceAtom);
|
|
||||||
const [checked, setChecked] = useState(workspace?.settings?.ai?.search);
|
|
||||||
const { hasLicenseKey } = useLicense();
|
|
||||||
|
|
||||||
const hasAccess = isCloud() || (!isCloud() && hasLicenseKey);
|
|
||||||
|
|
||||||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = event.currentTarget.checked;
|
|
||||||
try {
|
|
||||||
const updatedWorkspace = await updateWorkspace({ aiSearch: value });
|
|
||||||
setChecked(value);
|
|
||||||
setWorkspace(updatedWorkspace);
|
|
||||||
} catch (err) {
|
|
||||||
notifications.show({
|
|
||||||
message: err?.response?.data?.message,
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Switch
|
|
||||||
size={size}
|
|
||||||
label={label}
|
|
||||||
labelPosition="left"
|
|
||||||
defaultChecked={checked}
|
|
||||||
onChange={handleChange}
|
|
||||||
disabled={!hasAccess}
|
|
||||||
aria-label={t("Toggle AI search")}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { Group, Text, Switch } from "@mantine/core";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { useIsCloudEE } from "@/hooks/use-is-cloud-ee.tsx";
|
|
||||||
|
|
||||||
export default function EnableGenerativeAi() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [workspace, setWorkspace] = useAtom(workspaceAtom);
|
|
||||||
const [checked, setChecked] = useState(workspace?.settings?.ai?.generative);
|
|
||||||
const hasAccess = useIsCloudEE();
|
|
||||||
|
|
||||||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = event.currentTarget.checked;
|
|
||||||
try {
|
|
||||||
const updatedWorkspace = await updateWorkspace({ generativeAi: value });
|
|
||||||
setChecked(value);
|
|
||||||
setWorkspace(updatedWorkspace);
|
|
||||||
} catch (err) {
|
|
||||||
notifications.show({
|
|
||||||
message: err?.response?.data?.message,
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Group justify="space-between" wrap="nowrap" gap="xl">
|
|
||||||
<div>
|
|
||||||
<Text size="md">{t("Generative AI (Ask AI)")}</Text>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{t(
|
|
||||||
"Enable AI-powered content generation in the editor. Allows users to generate, improve, translate and transform text.",
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
defaultChecked={checked}
|
|
||||||
onChange={handleChange}
|
|
||||||
disabled={!hasAccess}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
import {
|
|
||||||
Anchor,
|
|
||||||
Group,
|
|
||||||
List,
|
|
||||||
Text,
|
|
||||||
Switch,
|
|
||||||
TextInput,
|
|
||||||
ActionIcon,
|
|
||||||
Tooltip,
|
|
||||||
Stack,
|
|
||||||
Alert,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { useIsCloudEE } from "@/hooks/use-is-cloud-ee.tsx";
|
|
||||||
import { getAppUrl } from "@/lib/config.ts";
|
|
||||||
import { IconCheck, IconCopy, IconInfoCircle } from "@tabler/icons-react";
|
|
||||||
import { CopyButton } from "@/components/common/copy-button.tsx";
|
|
||||||
|
|
||||||
export default function McpSettings() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [workspace, setWorkspace] = useAtom(workspaceAtom);
|
|
||||||
const [checked, setChecked] = useState(workspace?.settings?.ai?.mcp);
|
|
||||||
const hasAccess = useIsCloudEE();
|
|
||||||
|
|
||||||
const mcpUrl = `${getAppUrl()}/mcp`;
|
|
||||||
|
|
||||||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = event.currentTarget.checked;
|
|
||||||
try {
|
|
||||||
const updatedWorkspace = await updateWorkspace({ mcpEnabled: value });
|
|
||||||
setChecked(value);
|
|
||||||
setWorkspace(updatedWorkspace);
|
|
||||||
} catch (err) {
|
|
||||||
notifications.show({
|
|
||||||
message: err?.response?.data?.message,
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack gap="lg">
|
|
||||||
{!hasAccess && (
|
|
||||||
<Alert
|
|
||||||
icon={<IconInfoCircle />}
|
|
||||||
title={t("Enterprise feature")}
|
|
||||||
color="blue"
|
|
||||||
>
|
|
||||||
{t(
|
|
||||||
"MCP is only available in the Docmost enterprise edition. Contact sales@docmost.com.",
|
|
||||||
)}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Group justify="space-between" wrap="nowrap" gap="xl">
|
|
||||||
<div>
|
|
||||||
<Text size="md">{t("Model Context Protocol (MCP)")}</Text>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{t(
|
|
||||||
"Enable the MCP server to allow AI assistants and tools to interact with your workspace content.",
|
|
||||||
)}{" "}
|
|
||||||
{t("View the")}{" "}
|
|
||||||
<Anchor
|
|
||||||
href="https://docmost.com/docs/user-guide/mcp"
|
|
||||||
target="_blank"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
{t("MCP documentation")}
|
|
||||||
</Anchor>
|
|
||||||
.
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
defaultChecked={checked}
|
|
||||||
onChange={handleChange}
|
|
||||||
disabled={!hasAccess}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
{checked && (
|
|
||||||
<div>
|
|
||||||
<Text size="sm" fw={500} mb={4}>
|
|
||||||
{t("MCP Server URL")}
|
|
||||||
</Text>
|
|
||||||
<Group gap="xs">
|
|
||||||
<TextInput
|
|
||||||
value={mcpUrl}
|
|
||||||
readOnly
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
/>
|
|
||||||
<CopyButton value={mcpUrl} timeout={2000}>
|
|
||||||
{({ copied, copy }) => (
|
|
||||||
<Tooltip
|
|
||||||
label={copied ? t("Copied") : t("Copy")}
|
|
||||||
withArrow
|
|
||||||
position="right"
|
|
||||||
>
|
|
||||||
<ActionIcon
|
|
||||||
color={copied ? "teal" : "gray"}
|
|
||||||
variant="subtle"
|
|
||||||
onClick={copy}
|
|
||||||
>
|
|
||||||
{copied ? <IconCheck size={16} /> : <IconCopy size={16} />}
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</CopyButton>
|
|
||||||
</Group>
|
|
||||||
<Text size="sm" c="dimmed" mt="xs">
|
|
||||||
{t(
|
|
||||||
"Use your API key for authentication. You can manage API keys in your account settings.",
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Text size="sm" fw={500} mt="md" mb={4}>
|
|
||||||
{t("Supported tools")}
|
|
||||||
</Text>
|
|
||||||
<List size="sm" spacing={2}>
|
|
||||||
<List.Item><Text size="sm" c="dimmed" span>search_pages, get_page, create_page, update_page</Text></List.Item>
|
|
||||||
<List.Item><Text size="sm" c="dimmed" span>list_pages, list_child_pages, duplicate_page</Text></List.Item>
|
|
||||||
<List.Item><Text size="sm" c="dimmed" span>copy_page_to_space, move_page, move_page_to_space</Text></List.Item>
|
|
||||||
<List.Item><Text size="sm" c="dimmed" span>get_space, list_spaces, create_space, update_space</Text></List.Item>
|
|
||||||
<List.Item><Text size="sm" c="dimmed" span>get_comments, create_comment, update_comment</Text></List.Item>
|
|
||||||
<List.Item><Text size="sm" c="dimmed" span>search_attachments, list_workspace_members, get_current_user</Text></List.Item>
|
|
||||||
</List>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { useMutation, UseMutationResult } from "@tanstack/react-query";
|
|
||||||
import { useState, useCallback } from "react";
|
|
||||||
import { aiAnswers, IAiSearchResponse } from "@/ee/ai/services/ai-search-service.ts";
|
|
||||||
import { IPageSearchParams } from "@/features/search/types/search.types.ts";
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
interface UseAiSearchResult extends UseMutationResult<IAiSearchResponse, Error, IPageSearchParams> {
|
|
||||||
streamingAnswer: string;
|
|
||||||
streamingSources: any[];
|
|
||||||
clearStreaming: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAiSearch(): UseAiSearchResult {
|
|
||||||
const [streamingAnswer, setStreamingAnswer] = useState("");
|
|
||||||
const [streamingSources, setStreamingSources] = useState<any[]>([]);
|
|
||||||
|
|
||||||
const clearStreaming = useCallback(() => {
|
|
||||||
setStreamingAnswer("");
|
|
||||||
setStreamingSources([]);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const mutation = useMutation({
|
|
||||||
mutationFn: async (params: IPageSearchParams & { contentType?: string }) => {
|
|
||||||
setStreamingAnswer("");
|
|
||||||
setStreamingSources([]);
|
|
||||||
|
|
||||||
const { contentType, ...apiParams } = params;
|
|
||||||
|
|
||||||
return await aiAnswers(apiParams, (chunk) => {
|
|
||||||
if (chunk.content) {
|
|
||||||
setStreamingAnswer((prev) => prev + chunk.content);
|
|
||||||
}
|
|
||||||
if (chunk.sources) {
|
|
||||||
setStreamingSources(chunk.sources);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...mutation,
|
|
||||||
streamingAnswer,
|
|
||||||
streamingSources,
|
|
||||||
clearStreaming,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import { useState, useCallback, useRef } from "react";
|
|
||||||
import { useAiGenerateStreamMutation } from "@/ee/ai/queries/ai-query.ts";
|
|
||||||
import { AiGenerateDto } from "@/ee/ai/types/ai.types.ts";
|
|
||||||
|
|
||||||
export function useAiStream() {
|
|
||||||
const [content, setContent] = useState("");
|
|
||||||
const [isStreaming, setIsStreaming] = useState(false);
|
|
||||||
const abortControllerRef = useRef<AbortController | null>(null);
|
|
||||||
const mutation = useAiGenerateStreamMutation();
|
|
||||||
|
|
||||||
const startStream = useCallback(
|
|
||||||
async (data: AiGenerateDto) => {
|
|
||||||
setContent("");
|
|
||||||
setIsStreaming(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const controller = await mutation.mutateAsync({
|
|
||||||
...data,
|
|
||||||
onChunk: (chunk) => {
|
|
||||||
setContent((prev) => prev + chunk.content);
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
console.error("AI stream error:", error);
|
|
||||||
setIsStreaming(false);
|
|
||||||
},
|
|
||||||
onComplete: () => {
|
|
||||||
setIsStreaming(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
abortControllerRef.current = controller;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to start stream:", error);
|
|
||||||
setIsStreaming(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[mutation]
|
|
||||||
);
|
|
||||||
|
|
||||||
const stopStream = useCallback(() => {
|
|
||||||
if (abortControllerRef.current) {
|
|
||||||
abortControllerRef.current.abort();
|
|
||||||
abortControllerRef.current = null;
|
|
||||||
setIsStreaming(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const resetContent = useCallback(() => {
|
|
||||||
setContent("");
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
content,
|
|
||||||
isStreaming,
|
|
||||||
startStream,
|
|
||||||
stopStream,
|
|
||||||
resetContent,
|
|
||||||
isLoading: mutation.isPending,
|
|
||||||
error: mutation.error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
import { Helmet } from "react-helmet-async";
|
|
||||||
import { getAppName } from "@/lib/config.ts";
|
|
||||||
import SettingsTitle from "@/components/settings/settings-title.tsx";
|
|
||||||
import React from "react";
|
|
||||||
import useUserRole from "@/hooks/use-user-role.tsx";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import EnableAiSearch from "@/ee/ai/components/enable-ai-search.tsx";
|
|
||||||
import EnableGenerativeAi from "@/ee/ai/components/enable-generative-ai.tsx";
|
|
||||||
import McpSettings from "@/ee/ai/components/mcp-settings.tsx";
|
|
||||||
import { Alert, Stack, Tabs } from "@mantine/core";
|
|
||||||
import { IconInfoCircle } from "@tabler/icons-react";
|
|
||||||
import { useIsCloudEE } from "@/hooks/use-is-cloud-ee.tsx";
|
|
||||||
import { isCloud } from "@/lib/config.ts";
|
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
|
||||||
|
|
||||||
export default function AiSettings() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { isAdmin } = useUserRole();
|
|
||||||
const hasAccess = useIsCloudEE();
|
|
||||||
const location = useLocation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const activeTab = location.pathname.endsWith("/mcp") ? "mcp" : "ai";
|
|
||||||
|
|
||||||
if (!isAdmin) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTabChange = (value: string | null) => {
|
|
||||||
if (value === "mcp") {
|
|
||||||
navigate("/settings/ai/mcp");
|
|
||||||
} else {
|
|
||||||
navigate("/settings/ai");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>AI settings - {getAppName()}</title>
|
|
||||||
</Helmet>
|
|
||||||
<SettingsTitle title={t("AI settings")} />
|
|
||||||
|
|
||||||
<Tabs color="dark" value={activeTab} onChange={handleTabChange}>
|
|
||||||
<Tabs.List>
|
|
||||||
<Tabs.Tab fw={500} value="ai">
|
|
||||||
{t("AI")}
|
|
||||||
</Tabs.Tab>
|
|
||||||
<Tabs.Tab fw={500} value="mcp">
|
|
||||||
{t("MCP")}
|
|
||||||
</Tabs.Tab>
|
|
||||||
</Tabs.List>
|
|
||||||
|
|
||||||
<Tabs.Panel value="ai" pt="md">
|
|
||||||
{!hasAccess && (
|
|
||||||
<Alert
|
|
||||||
icon={<IconInfoCircle />}
|
|
||||||
title={t("Enterprise feature")}
|
|
||||||
color="blue"
|
|
||||||
mb="lg"
|
|
||||||
>
|
|
||||||
{t(
|
|
||||||
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.",
|
|
||||||
)}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Stack gap="md">
|
|
||||||
{!isCloud() && <EnableAiSearch />}
|
|
||||||
<EnableGenerativeAi />
|
|
||||||
</Stack>
|
|
||||||
</Tabs.Panel>
|
|
||||||
|
|
||||||
<Tabs.Panel value="mcp" pt="md">
|
|
||||||
<McpSettings />
|
|
||||||
</Tabs.Panel>
|
|
||||||
</Tabs>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import {
|
|
||||||
useMutation,
|
|
||||||
UseMutationResult,
|
|
||||||
useQuery,
|
|
||||||
UseQueryResult,
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import {
|
|
||||||
generateAiContent,
|
|
||||||
generateAiContentStream,
|
|
||||||
} from "@/ee/ai/services/ai-service.ts";
|
|
||||||
import {
|
|
||||||
AiConfigResponse,
|
|
||||||
AiContentResponse,
|
|
||||||
AiGenerateDto,
|
|
||||||
AiStreamChunk,
|
|
||||||
AiStreamError,
|
|
||||||
} from "@/ee/ai/types/ai.types.ts";
|
|
||||||
|
|
||||||
export function useAiGenerateMutation(): UseMutationResult<
|
|
||||||
AiContentResponse,
|
|
||||||
Error,
|
|
||||||
AiGenerateDto
|
|
||||||
> {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: AiGenerateDto) => generateAiContent(data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StreamCallbacks {
|
|
||||||
onChunk: (chunk: AiStreamChunk) => void;
|
|
||||||
onError?: (error: AiStreamError) => void;
|
|
||||||
onComplete?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAiGenerateStreamMutation(): UseMutationResult<
|
|
||||||
AbortController,
|
|
||||||
Error,
|
|
||||||
AiGenerateDto & StreamCallbacks
|
|
||||||
> {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ onChunk, onError, onComplete, ...data }) =>
|
|
||||||
generateAiContentStream(data, onChunk, onError, onComplete),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import api from "@/lib/api-client.ts";
|
|
||||||
import { IPageSearchParams } from "@/features/search/types/search.types.ts";
|
|
||||||
|
|
||||||
export interface IAiSearchResponse {
|
|
||||||
answer: string;
|
|
||||||
sources?: Array<{
|
|
||||||
pageId: string;
|
|
||||||
title: string;
|
|
||||||
slugId: string;
|
|
||||||
spaceSlug: string;
|
|
||||||
similarity: number;
|
|
||||||
distance: number;
|
|
||||||
chunkIndex: number;
|
|
||||||
excerpt: string;
|
|
||||||
}>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function aiAnswers(
|
|
||||||
params: IPageSearchParams,
|
|
||||||
onChunk?: (chunk: { content?: string; sources?: any[] }) => void,
|
|
||||||
): Promise<IAiSearchResponse> {
|
|
||||||
const response = await fetch("/api/ai/answers", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
credentials: "include",
|
|
||||||
body: JSON.stringify(params),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = response.body?.getReader();
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
|
|
||||||
let answer = "";
|
|
||||||
let sources: any[] = [];
|
|
||||||
let buffer = "";
|
|
||||||
|
|
||||||
if (reader) {
|
|
||||||
while (true) {
|
|
||||||
const { done, value } = await reader.read();
|
|
||||||
if (done) break;
|
|
||||||
|
|
||||||
buffer += decoder.decode(value, { stream: true });
|
|
||||||
const lines = buffer.split("\n");
|
|
||||||
|
|
||||||
// Keep the last incomplete line in the buffer
|
|
||||||
buffer = lines.pop() || "";
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
if (line.startsWith("data: ")) {
|
|
||||||
const data = line.slice(6);
|
|
||||||
if (data === "[DONE]") break;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(data);
|
|
||||||
if (parsed.error) {
|
|
||||||
throw new Error(parsed.error);
|
|
||||||
}
|
|
||||||
if (parsed.content) {
|
|
||||||
answer += parsed.content;
|
|
||||||
onChunk?.({ content: parsed.content });
|
|
||||||
}
|
|
||||||
if (parsed.sources) {
|
|
||||||
sources = parsed.sources;
|
|
||||||
onChunk?.({ sources: parsed.sources });
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
// Skip invalid JSON
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { answer, sources };
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import api from "@/lib/api-client.ts";
|
|
||||||
import {
|
|
||||||
AiGenerateDto,
|
|
||||||
AiContentResponse,
|
|
||||||
AiStreamChunk,
|
|
||||||
AiStreamError,
|
|
||||||
} from "@/ee/ai/types/ai.types.ts";
|
|
||||||
|
|
||||||
export async function generateAiContent(
|
|
||||||
data: AiGenerateDto,
|
|
||||||
): Promise<AiContentResponse> {
|
|
||||||
const req = await api.post<AiContentResponse>("/ai/generate", data);
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateAiContentStream(
|
|
||||||
data: AiGenerateDto,
|
|
||||||
onChunk: (chunk: AiStreamChunk) => void,
|
|
||||||
onError?: (error: AiStreamError) => void,
|
|
||||||
onComplete?: () => void,
|
|
||||||
): Promise<AbortController> {
|
|
||||||
const abortController = new AbortController();
|
|
||||||
try {
|
|
||||||
const response = await fetch("/api/ai/generate/stream", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
signal: abortController.signal,
|
|
||||||
credentials: "include", // This ensures cookies are sent, matching axios withCredentials
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = response.body?.getReader();
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
|
|
||||||
if (!reader) {
|
|
||||||
throw new Error("Response body is not readable");
|
|
||||||
}
|
|
||||||
|
|
||||||
const processStream = async () => {
|
|
||||||
let buffer = "";
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
const { done, value } = await reader.read();
|
|
||||||
if (done) break;
|
|
||||||
|
|
||||||
buffer += decoder.decode(value, { stream: true });
|
|
||||||
const lines = buffer.split("\n");
|
|
||||||
|
|
||||||
buffer = lines.pop() || "";
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
if (line.startsWith("data: ")) {
|
|
||||||
const data = line.slice(6);
|
|
||||||
if (data === "[DONE]") {
|
|
||||||
onComplete?.();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(data);
|
|
||||||
if (parsed.error) {
|
|
||||||
onError?.(parsed);
|
|
||||||
} else {
|
|
||||||
onChunk(parsed);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Skip invalid JSON
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (error.name !== "AbortError") {
|
|
||||||
onError?.({ error: error.message });
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
reader.releaseLock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
processStream();
|
|
||||||
} catch (error) {
|
|
||||||
onError?.({ error: error.message });
|
|
||||||
}
|
|
||||||
|
|
||||||
return abortController;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
export enum AiAction {
|
|
||||||
IMPROVE_WRITING = "improve_writing",
|
|
||||||
FIX_SPELLING_GRAMMAR = "fix_spelling_grammar",
|
|
||||||
MAKE_SHORTER = "make_shorter",
|
|
||||||
MAKE_LONGER = "make_longer",
|
|
||||||
SIMPLIFY = "simplify",
|
|
||||||
CHANGE_TONE = "change_tone",
|
|
||||||
SUMMARIZE = "summarize",
|
|
||||||
EXPLAIN = "explain",
|
|
||||||
CONTINUE_WRITING = "continue_writing",
|
|
||||||
TRANSLATE = "translate",
|
|
||||||
CUSTOM = "custom",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AiGenerateDto {
|
|
||||||
action?: AiAction;
|
|
||||||
content: string;
|
|
||||||
prompt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AiContentResponse {
|
|
||||||
content: string;
|
|
||||||
usage?: {
|
|
||||||
promptTokens: number;
|
|
||||||
completionTokens: number;
|
|
||||||
totalTokens: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AiConfigResponse {
|
|
||||||
configured: boolean;
|
|
||||||
availableActions: AiAction[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AiStreamChunk {
|
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AiStreamError {
|
|
||||||
error: string;
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import {
|
|
||||||
Modal,
|
|
||||||
Text,
|
|
||||||
Stack,
|
|
||||||
Alert,
|
|
||||||
Group,
|
|
||||||
Button,
|
|
||||||
TextInput,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import { IconAlertTriangle } from "@tabler/icons-react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
import CopyTextButton from "@/components/common/copy.tsx";
|
|
||||||
|
|
||||||
interface ApiKeyCreatedModalProps {
|
|
||||||
opened: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
apiKey: IApiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ApiKeyCreatedModal({
|
|
||||||
opened,
|
|
||||||
onClose,
|
|
||||||
apiKey,
|
|
||||||
}: ApiKeyCreatedModalProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
if (!apiKey) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
opened={opened}
|
|
||||||
onClose={onClose}
|
|
||||||
title={t("API key created")}
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
<Stack gap="md">
|
|
||||||
<Alert
|
|
||||||
icon={<IconAlertTriangle size={16} />}
|
|
||||||
title={t("Important")}
|
|
||||||
color="red"
|
|
||||||
>
|
|
||||||
{t(
|
|
||||||
"Make sure to copy your API key now. You won't be able to see it again!",
|
|
||||||
)}
|
|
||||||
</Alert>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Text size="sm" fw={500} mb="xs">
|
|
||||||
{t("API key")}
|
|
||||||
</Text>
|
|
||||||
<Group gap="xs" wrap="nowrap">
|
|
||||||
<TextInput
|
|
||||||
variant="filled"
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
}}
|
|
||||||
value={apiKey.token}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CopyTextButton text={apiKey.token} />
|
|
||||||
</Group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button fullWidth onClick={onClose} mt="md">
|
|
||||||
{t("I've saved my API key")}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
import { ActionIcon, Group, Menu, Table, Text } from "@mantine/core";
|
|
||||||
import { IconDots, IconEdit, IconTrash } from "@tabler/icons-react";
|
|
||||||
import { format } from "date-fns";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
|
||||||
import React from "react";
|
|
||||||
import NoTableResults from "@/components/common/no-table-results";
|
|
||||||
|
|
||||||
interface ApiKeyTableProps {
|
|
||||||
apiKeys: IApiKey[];
|
|
||||||
isLoading?: boolean;
|
|
||||||
showUserColumn?: boolean;
|
|
||||||
onUpdate?: (apiKey: IApiKey) => void;
|
|
||||||
onRevoke?: (apiKey: IApiKey) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ApiKeyTable({
|
|
||||||
apiKeys,
|
|
||||||
isLoading,
|
|
||||||
showUserColumn = false,
|
|
||||||
onUpdate,
|
|
||||||
onRevoke,
|
|
||||||
}: ApiKeyTableProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const formatDate = (date: Date | string | null) => {
|
|
||||||
if (!date) return t("Never");
|
|
||||||
return format(new Date(date), "MMM dd, yyyy");
|
|
||||||
};
|
|
||||||
|
|
||||||
const isExpired = (expiresAt: string | null) => {
|
|
||||||
if (!expiresAt) return false;
|
|
||||||
return new Date(expiresAt) < new Date();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Table.ScrollContainer minWidth={500}>
|
|
||||||
<Table highlightOnHover verticalSpacing="sm">
|
|
||||||
<Table.Thead>
|
|
||||||
<Table.Tr>
|
|
||||||
<Table.Th>{t("Name")}</Table.Th>
|
|
||||||
{showUserColumn && <Table.Th>{t("User")}</Table.Th>}
|
|
||||||
<Table.Th>{t("Last used")}</Table.Th>
|
|
||||||
<Table.Th>{t("Expires")}</Table.Th>
|
|
||||||
<Table.Th>{t("Created")}</Table.Th>
|
|
||||||
<Table.Th></Table.Th>
|
|
||||||
</Table.Tr>
|
|
||||||
</Table.Thead>
|
|
||||||
|
|
||||||
<Table.Tbody>
|
|
||||||
{apiKeys && apiKeys.length > 0 ? (
|
|
||||||
apiKeys.map((apiKey: IApiKey, index: number) => (
|
|
||||||
<Table.Tr key={index}>
|
|
||||||
<Table.Td>
|
|
||||||
<Text fz="sm" fw={500}>
|
|
||||||
{apiKey.name}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
{showUserColumn && apiKey.creator && (
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="4" wrap="nowrap">
|
|
||||||
<CustomAvatar
|
|
||||||
avatarUrl={apiKey.creator?.avatarUrl}
|
|
||||||
name={apiKey.creator.name}
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
<Text fz="sm" lineClamp={1}>
|
|
||||||
{apiKey.creator.name}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
<Text fz="sm" style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{formatDate(apiKey.lastUsedAt)}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
{apiKey.expiresAt ? (
|
|
||||||
isExpired(apiKey.expiresAt) ? (
|
|
||||||
<Text fz="sm" style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{t("Expired")}
|
|
||||||
</Text>
|
|
||||||
) : (
|
|
||||||
<Text fz="sm" style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{formatDate(apiKey.expiresAt)}
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<Text fz="sm" style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{t("Never")}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
<Text fz="sm" style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{formatDate(apiKey.createdAt)}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
<Menu position="bottom-end" withinPortal>
|
|
||||||
<Menu.Target>
|
|
||||||
<ActionIcon variant="subtle" color="gray">
|
|
||||||
<IconDots size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Menu.Target>
|
|
||||||
<Menu.Dropdown>
|
|
||||||
{onUpdate && (
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconEdit size={16} />}
|
|
||||||
onClick={() => onUpdate(apiKey)}
|
|
||||||
>
|
|
||||||
{t("Rename")}
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
{onRevoke && (
|
|
||||||
<Menu.Item
|
|
||||||
leftSection={<IconTrash size={16} />}
|
|
||||||
color="red"
|
|
||||||
onClick={() => onRevoke(apiKey)}
|
|
||||||
>
|
|
||||||
{t("Revoke")}
|
|
||||||
</Menu.Item>
|
|
||||||
)}
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu>
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<NoTableResults colSpan={showUserColumn ? 6 : 5} />
|
|
||||||
)}
|
|
||||||
</Table.Tbody>
|
|
||||||
</Table>
|
|
||||||
</Table.ScrollContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
import { lazy, Suspense, useState } from "react";
|
|
||||||
import { Modal, TextInput, Button, Group, Stack, Select } from "@mantine/core";
|
|
||||||
import { useForm } from "@mantine/form";
|
|
||||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
|
||||||
import { z } from "zod/v4";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useCreateApiKeyMutation } from "@/ee/api-key/queries/api-key-query";
|
|
||||||
import { IconCalendar } from "@tabler/icons-react";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
|
|
||||||
const DateInput = lazy(() =>
|
|
||||||
import("@mantine/dates").then((module) => ({
|
|
||||||
default: module.DateInput,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
|
|
||||||
interface CreateApiKeyModalProps {
|
|
||||||
opened: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
onSuccess: (response: IApiKey) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
|
||||||
name: z.string().min(1, "Name is required"),
|
|
||||||
expiresAt: z.string().optional(),
|
|
||||||
});
|
|
||||||
type FormValues = z.infer<typeof formSchema>;
|
|
||||||
|
|
||||||
export function CreateApiKeyModal({
|
|
||||||
opened,
|
|
||||||
onClose,
|
|
||||||
onSuccess,
|
|
||||||
}: CreateApiKeyModalProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [expirationOption, setExpirationOption] = useState<string>("30");
|
|
||||||
const createApiKeyMutation = useCreateApiKeyMutation();
|
|
||||||
|
|
||||||
const form = useForm<FormValues>({
|
|
||||||
validate: zod4Resolver(formSchema),
|
|
||||||
initialValues: {
|
|
||||||
name: "",
|
|
||||||
expiresAt: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const getExpirationDate = (): string | undefined => {
|
|
||||||
if (expirationOption === "never") {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (expirationOption === "custom") {
|
|
||||||
return form.values.expiresAt;
|
|
||||||
}
|
|
||||||
const days = parseInt(expirationOption);
|
|
||||||
const date = new Date();
|
|
||||||
date.setDate(date.getDate() + days);
|
|
||||||
return date.toISOString();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getExpirationLabel = (days: number) => {
|
|
||||||
const date = new Date();
|
|
||||||
date.setDate(date.getDate() + days);
|
|
||||||
const formatted = date.toLocaleDateString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
});
|
|
||||||
return `${days} days (${formatted})`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const expirationOptions = [
|
|
||||||
{ value: "30", label: getExpirationLabel(30) },
|
|
||||||
{ value: "60", label: getExpirationLabel(60) },
|
|
||||||
{ value: "90", label: getExpirationLabel(90) },
|
|
||||||
{ value: "365", label: getExpirationLabel(365) },
|
|
||||||
{ value: "custom", label: t("Custom") },
|
|
||||||
{ value: "never", label: t("No expiration") },
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleSubmit = async (data: {
|
|
||||||
name?: string;
|
|
||||||
expiresAt?: string | Date;
|
|
||||||
}) => {
|
|
||||||
const groupData = {
|
|
||||||
name: data.name,
|
|
||||||
expiresAt: getExpirationDate(),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const createdKey = await createApiKeyMutation.mutateAsync(groupData);
|
|
||||||
onSuccess(createdKey);
|
|
||||||
form.reset();
|
|
||||||
onClose();
|
|
||||||
} catch (err) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
form.reset();
|
|
||||||
setExpirationOption("30");
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
opened={opened}
|
|
||||||
onClose={handleClose}
|
|
||||||
title={t("Create API Key")}
|
|
||||||
size="md"
|
|
||||||
>
|
|
||||||
<form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
|
|
||||||
<Stack gap="md">
|
|
||||||
<TextInput
|
|
||||||
label={t("Name")}
|
|
||||||
placeholder={t("Enter a descriptive name")}
|
|
||||||
data-autofocus
|
|
||||||
required
|
|
||||||
{...form.getInputProps("name")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Select
|
|
||||||
label={t("Expiration")}
|
|
||||||
data={expirationOptions}
|
|
||||||
value={expirationOption}
|
|
||||||
onChange={(value) => setExpirationOption(value || "30")}
|
|
||||||
leftSection={<IconCalendar size={16} />}
|
|
||||||
allowDeselect={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{expirationOption === "custom" && (
|
|
||||||
<Suspense fallback={null}>
|
|
||||||
<DateInput
|
|
||||||
label={t("Custom expiration date")}
|
|
||||||
placeholder={t("Select expiration date")}
|
|
||||||
minDate={new Date()}
|
|
||||||
{...form.getInputProps("expiresAt")}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Group justify="flex-end" mt="md">
|
|
||||||
<Button variant="default" onClick={handleClose}>
|
|
||||||
{t("Cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button type="submit" loading={createApiKeyMutation.isPending}>
|
|
||||||
{t("Create")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import { Text, Switch, Tooltip } from "@mantine/core";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import useEnterpriseAccess from "@/ee/hooks/use-enterprise-access.tsx";
|
|
||||||
import {
|
|
||||||
ResponsiveSettingsRow,
|
|
||||||
ResponsiveSettingsContent,
|
|
||||||
ResponsiveSettingsControl,
|
|
||||||
} from "@/components/ui/responsive-settings-row";
|
|
||||||
|
|
||||||
export default function RestrictApiToAdmins() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [workspace, setWorkspace] = useAtom(workspaceAtom);
|
|
||||||
const [checked, setChecked] = useState(
|
|
||||||
workspace?.settings?.api?.restrictToAdmins === true,
|
|
||||||
);
|
|
||||||
const hasAccess = useEnterpriseAccess();
|
|
||||||
|
|
||||||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = event.currentTarget.checked;
|
|
||||||
try {
|
|
||||||
const updatedWorkspace = await updateWorkspace({
|
|
||||||
restrictApiToAdmins: value,
|
|
||||||
});
|
|
||||||
setChecked(value);
|
|
||||||
setWorkspace(updatedWorkspace);
|
|
||||||
} catch (err) {
|
|
||||||
notifications.show({
|
|
||||||
message: err?.response?.data?.message,
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ResponsiveSettingsRow>
|
|
||||||
<ResponsiveSettingsContent>
|
|
||||||
<Text size="md">
|
|
||||||
{t("Restrict API key creation to admins")}
|
|
||||||
</Text>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{t(
|
|
||||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.",
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</ResponsiveSettingsContent>
|
|
||||||
|
|
||||||
<ResponsiveSettingsControl>
|
|
||||||
<Tooltip
|
|
||||||
label={t("Requires an enterprise license")}
|
|
||||||
disabled={hasAccess}
|
|
||||||
refProp="rootRef"
|
|
||||||
>
|
|
||||||
<Switch
|
|
||||||
checked={checked}
|
|
||||||
onChange={handleChange}
|
|
||||||
disabled={!hasAccess}
|
|
||||||
aria-label={t("Toggle restrict API keys to admins")}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</ResponsiveSettingsControl>
|
|
||||||
</ResponsiveSettingsRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import { Modal, Text, Button, Group, Stack } from "@mantine/core";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
import { useRevokeApiKeyMutation } from "@/ee/api-key/queries/api-key-query.ts";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
|
|
||||||
interface RevokeApiKeyModalProps {
|
|
||||||
opened: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
apiKey: IApiKey | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RevokeApiKeyModal({
|
|
||||||
opened,
|
|
||||||
onClose,
|
|
||||||
apiKey,
|
|
||||||
}: RevokeApiKeyModalProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const revokeApiKeyMutation = useRevokeApiKeyMutation();
|
|
||||||
|
|
||||||
const handleRevoke = async () => {
|
|
||||||
if (!apiKey) return;
|
|
||||||
await revokeApiKeyMutation.mutateAsync({
|
|
||||||
apiKeyId: apiKey.id,
|
|
||||||
});
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
opened={opened}
|
|
||||||
onClose={onClose}
|
|
||||||
title={t("Revoke API key")}
|
|
||||||
size="md"
|
|
||||||
>
|
|
||||||
<Stack gap="md">
|
|
||||||
<Text>
|
|
||||||
{t("Are you sure you want to revoke this API key")}{" "}
|
|
||||||
<strong>{apiKey?.name}</strong>?
|
|
||||||
</Text>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{t(
|
|
||||||
"This action cannot be undone. Any applications using this API key will stop working.",
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Group justify="flex-end" mt="md">
|
|
||||||
<Button variant="default" onClick={onClose}>
|
|
||||||
{t("Cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
color="red"
|
|
||||||
onClick={handleRevoke}
|
|
||||||
loading={revokeApiKeyMutation.isPending}
|
|
||||||
>
|
|
||||||
{t("Revoke")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
import { Modal, TextInput, Button, Group, Stack } from "@mantine/core";
|
|
||||||
import { useForm } from "@mantine/form";
|
|
||||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
|
||||||
import { z } from "zod/v4";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useUpdateApiKeyMutation } from "@/ee/api-key/queries/api-key-query";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
|
||||||
name: z.string().min(1, "Name is required"),
|
|
||||||
});
|
|
||||||
type FormValues = z.infer<typeof formSchema>;
|
|
||||||
|
|
||||||
interface UpdateApiKeyModalProps {
|
|
||||||
opened: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
apiKey: IApiKey | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function UpdateApiKeyModal({
|
|
||||||
opened,
|
|
||||||
onClose,
|
|
||||||
apiKey,
|
|
||||||
}: UpdateApiKeyModalProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const updateApiKeyMutation = useUpdateApiKeyMutation();
|
|
||||||
|
|
||||||
const form = useForm<FormValues>({
|
|
||||||
validate: zod4Resolver(formSchema),
|
|
||||||
initialValues: {
|
|
||||||
name: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (opened && apiKey) {
|
|
||||||
form.setValues({ name: apiKey.name });
|
|
||||||
}
|
|
||||||
}, [opened, apiKey]);
|
|
||||||
|
|
||||||
const handleSubmit = async (data: { name?: string }) => {
|
|
||||||
const apiKeyData = {
|
|
||||||
apiKeyId: apiKey.id,
|
|
||||||
name: data.name,
|
|
||||||
};
|
|
||||||
|
|
||||||
await updateApiKeyMutation.mutateAsync(apiKeyData);
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
opened={opened}
|
|
||||||
onClose={onClose}
|
|
||||||
title={t("Update API key")}
|
|
||||||
size="md"
|
|
||||||
>
|
|
||||||
<form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
|
|
||||||
<Stack gap="md">
|
|
||||||
<TextInput
|
|
||||||
label={t("Name")}
|
|
||||||
placeholder={t("Enter a descriptive token name")}
|
|
||||||
required
|
|
||||||
{...form.getInputProps("name")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Group justify="flex-end" mt="md">
|
|
||||||
<Button variant="default" onClick={onClose}>
|
|
||||||
{t("Cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button type="submit" loading={updateApiKeyMutation.isPending}>
|
|
||||||
{t("Update")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export { ApiKeyTable } from "./components/api-key-table";
|
|
||||||
export { CreateApiKeyModal } from "./components/create-api-key-modal";
|
|
||||||
export { ApiKeyCreatedModal } from "./components/api-key-created-modal";
|
|
||||||
export { UpdateApiKeyModal } from "./components/update-api-key-modal";
|
|
||||||
export { RevokeApiKeyModal } from "./components/revoke-api-key-modal";
|
|
||||||
|
|
||||||
// Services
|
|
||||||
export * from "./services/api-key-service";
|
|
||||||
|
|
||||||
// Types
|
|
||||||
export * from "./types/api-key.types";
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { Anchor, Alert, Button, Group, Space, Text } from "@mantine/core";
|
|
||||||
import { IconInfoCircle } from "@tabler/icons-react";
|
|
||||||
import { Helmet } from "react-helmet-async";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import SettingsTitle from "@/components/settings/settings-title";
|
|
||||||
import { getAppName, getAppUrl } from "@/lib/config";
|
|
||||||
import { ApiKeyTable } from "@/ee/api-key/components/api-key-table";
|
|
||||||
import { CreateApiKeyModal } from "@/ee/api-key/components/create-api-key-modal";
|
|
||||||
import { ApiKeyCreatedModal } from "@/ee/api-key/components/api-key-created-modal";
|
|
||||||
import { UpdateApiKeyModal } from "@/ee/api-key/components/update-api-key-modal";
|
|
||||||
import { RevokeApiKeyModal } from "@/ee/api-key/components/revoke-api-key-modal";
|
|
||||||
import Paginate from "@/components/common/paginate";
|
|
||||||
import { useCursorPaginate } from "@/hooks/use-cursor-paginate";
|
|
||||||
import { useGetApiKeysQuery } from "@/ee/api-key/queries/api-key-query.ts";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
|
||||||
import useUserRole from "@/hooks/use-user-role.tsx";
|
|
||||||
|
|
||||||
export default function UserApiKeys() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { cursor, goNext, goPrev } = useCursorPaginate();
|
|
||||||
const [createModalOpened, setCreateModalOpened] = useState(false);
|
|
||||||
const [createdApiKey, setCreatedApiKey] = useState<IApiKey | null>(null);
|
|
||||||
const [updateModalOpened, setUpdateModalOpened] = useState(false);
|
|
||||||
const [revokeModalOpened, setRevokeModalOpened] = useState(false);
|
|
||||||
const [selectedApiKey, setSelectedApiKey] = useState<IApiKey | null>(null);
|
|
||||||
const { data, isLoading } = useGetApiKeysQuery({ cursor });
|
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
|
||||||
const { isAdmin } = useUserRole();
|
|
||||||
const mcpEnabled = workspace?.settings?.ai?.mcp === true;
|
|
||||||
const restrictToAdmins = workspace?.settings?.api?.restrictToAdmins === true;
|
|
||||||
const canCreate = !restrictToAdmins || isAdmin;
|
|
||||||
|
|
||||||
const handleCreateSuccess = (response: IApiKey) => {
|
|
||||||
setCreatedApiKey(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdate = (apiKey: IApiKey) => {
|
|
||||||
setSelectedApiKey(apiKey);
|
|
||||||
setUpdateModalOpened(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRevoke = (apiKey: IApiKey) => {
|
|
||||||
setSelectedApiKey(apiKey);
|
|
||||||
setRevokeModalOpened(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>
|
|
||||||
{t("API keys")} - {getAppName()}
|
|
||||||
</title>
|
|
||||||
</Helmet>
|
|
||||||
|
|
||||||
<SettingsTitle title={t("API keys")} />
|
|
||||||
|
|
||||||
<Text size="sm" c="dimmed" mb="md">
|
|
||||||
{t("View the")}{" "}
|
|
||||||
<Anchor href="https://docmost.com/api-docs" target="_blank" size="sm">
|
|
||||||
{t("API documentation")}
|
|
||||||
</Anchor>{" "}
|
|
||||||
{t("for usage details.")}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{mcpEnabled && canCreate && (
|
|
||||||
<Alert variant="light" color="blue" mb="md" p="sm" icon={<IconInfoCircle />}>
|
|
||||||
<Text size="sm">
|
|
||||||
{t(
|
|
||||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.",
|
|
||||||
)}{" "}
|
|
||||||
<Anchor
|
|
||||||
href="https://docmost.com/docs/user-guide/mcp"
|
|
||||||
target="_blank"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
{t("Learn more")}
|
|
||||||
</Anchor>
|
|
||||||
</Text>
|
|
||||||
<Text size="sm" mt={4}>
|
|
||||||
{t("MCP server URL:")}{" "}
|
|
||||||
<Text size="sm" fw={500} span ff="monospace">
|
|
||||||
{`${getAppUrl()}/mcp`}
|
|
||||||
</Text>
|
|
||||||
</Text>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{canCreate ? (
|
|
||||||
<Group justify="flex-end" mb="md">
|
|
||||||
<Button onClick={() => setCreateModalOpened(true)}>
|
|
||||||
{t("Create API Key")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
) : restrictToAdmins ? (
|
|
||||||
<Alert variant="light" color="yellow" mb="md" p="sm" icon={<IconInfoCircle />}>
|
|
||||||
<Text size="sm">
|
|
||||||
{t("API key creation is restricted to admins by your workspace administrator.")}
|
|
||||||
</Text>
|
|
||||||
</Alert>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<ApiKeyTable
|
|
||||||
apiKeys={data?.items || []}
|
|
||||||
isLoading={isLoading}
|
|
||||||
onUpdate={handleUpdate}
|
|
||||||
onRevoke={handleRevoke}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Space h="md" />
|
|
||||||
|
|
||||||
{data?.items.length > 0 && (
|
|
||||||
<Paginate
|
|
||||||
hasPrevPage={data?.meta?.hasPrevPage}
|
|
||||||
hasNextPage={data?.meta?.hasNextPage}
|
|
||||||
onNext={() => goNext(data?.meta?.nextCursor)}
|
|
||||||
onPrev={goPrev}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<CreateApiKeyModal
|
|
||||||
opened={createModalOpened}
|
|
||||||
onClose={() => setCreateModalOpened(false)}
|
|
||||||
onSuccess={handleCreateSuccess}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ApiKeyCreatedModal
|
|
||||||
opened={!!createdApiKey}
|
|
||||||
onClose={() => setCreatedApiKey(null)}
|
|
||||||
apiKey={createdApiKey}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<UpdateApiKeyModal
|
|
||||||
opened={updateModalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setUpdateModalOpened(false);
|
|
||||||
setSelectedApiKey(null);
|
|
||||||
}}
|
|
||||||
apiKey={selectedApiKey}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<RevokeApiKeyModal
|
|
||||||
opened={revokeModalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setRevokeModalOpened(false);
|
|
||||||
setSelectedApiKey(null);
|
|
||||||
}}
|
|
||||||
apiKey={selectedApiKey}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { Anchor, Button, Divider, Group, Space, Text } from "@mantine/core";
|
|
||||||
import { Helmet } from "react-helmet-async";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import SettingsTitle from "@/components/settings/settings-title";
|
|
||||||
import { getAppName } from "@/lib/config";
|
|
||||||
import { ApiKeyTable } from "@/ee/api-key/components/api-key-table";
|
|
||||||
import { CreateApiKeyModal } from "@/ee/api-key/components/create-api-key-modal";
|
|
||||||
import { ApiKeyCreatedModal } from "@/ee/api-key/components/api-key-created-modal";
|
|
||||||
import { UpdateApiKeyModal } from "@/ee/api-key/components/update-api-key-modal";
|
|
||||||
import { RevokeApiKeyModal } from "@/ee/api-key/components/revoke-api-key-modal";
|
|
||||||
import Paginate from "@/components/common/paginate";
|
|
||||||
import { useCursorPaginate } from "@/hooks/use-cursor-paginate";
|
|
||||||
import { useGetApiKeysQuery } from "@/ee/api-key/queries/api-key-query.ts";
|
|
||||||
import { IApiKey } from "@/ee/api-key";
|
|
||||||
import useUserRole from '@/hooks/use-user-role.tsx';
|
|
||||||
import RestrictApiToAdmins from "@/ee/api-key/components/restrict-api-to-admins";
|
|
||||||
|
|
||||||
export default function WorkspaceApiKeys() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { cursor, goNext, goPrev } = useCursorPaginate();
|
|
||||||
const [createModalOpened, setCreateModalOpened] = useState(false);
|
|
||||||
const [createdApiKey, setCreatedApiKey] = useState<IApiKey | null>(null);
|
|
||||||
const [updateModalOpened, setUpdateModalOpened] = useState(false);
|
|
||||||
const [revokeModalOpened, setRevokeModalOpened] = useState(false);
|
|
||||||
const [selectedApiKey, setSelectedApiKey] = useState<IApiKey | null>(null);
|
|
||||||
const { data, isLoading } = useGetApiKeysQuery({ cursor, adminView: true });
|
|
||||||
const { isAdmin } = useUserRole();
|
|
||||||
|
|
||||||
if (!isAdmin) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCreateSuccess = (response: IApiKey) => {
|
|
||||||
setCreatedApiKey(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdate = (apiKey: IApiKey) => {
|
|
||||||
setSelectedApiKey(apiKey);
|
|
||||||
setUpdateModalOpened(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRevoke = (apiKey: IApiKey) => {
|
|
||||||
setSelectedApiKey(apiKey);
|
|
||||||
setRevokeModalOpened(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>
|
|
||||||
{t("API management")} - {getAppName()}
|
|
||||||
</title>
|
|
||||||
</Helmet>
|
|
||||||
|
|
||||||
<SettingsTitle title={t("API management")} />
|
|
||||||
|
|
||||||
<Text size="sm" c="dimmed" mb="md">
|
|
||||||
{t("Manage API keys for all users in the workspace.")}{" "}
|
|
||||||
{t("View the")}{" "}
|
|
||||||
<Anchor href="https://docmost.com/api-docs" target="_blank" size="sm">
|
|
||||||
{t("API documentation")}
|
|
||||||
</Anchor>{" "}
|
|
||||||
{t("for usage details.")}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<RestrictApiToAdmins />
|
|
||||||
<Divider my="lg" />
|
|
||||||
|
|
||||||
<Group justify="flex-end" mb="md">
|
|
||||||
<Button onClick={() => setCreateModalOpened(true)}>
|
|
||||||
{t("Create API Key")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<ApiKeyTable
|
|
||||||
apiKeys={data?.items}
|
|
||||||
isLoading={isLoading}
|
|
||||||
showUserColumn
|
|
||||||
onUpdate={handleUpdate}
|
|
||||||
onRevoke={handleRevoke}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Space h="md" />
|
|
||||||
|
|
||||||
{data?.items.length > 0 && (
|
|
||||||
<Paginate
|
|
||||||
hasPrevPage={data?.meta?.hasPrevPage}
|
|
||||||
hasNextPage={data?.meta?.hasNextPage}
|
|
||||||
onNext={() => goNext(data?.meta?.nextCursor)}
|
|
||||||
onPrev={goPrev}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<CreateApiKeyModal
|
|
||||||
opened={createModalOpened}
|
|
||||||
onClose={() => setCreateModalOpened(false)}
|
|
||||||
onSuccess={handleCreateSuccess}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ApiKeyCreatedModal
|
|
||||||
opened={!!createdApiKey}
|
|
||||||
onClose={() => setCreatedApiKey(null)}
|
|
||||||
apiKey={createdApiKey}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<UpdateApiKeyModal
|
|
||||||
opened={updateModalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setUpdateModalOpened(false);
|
|
||||||
setSelectedApiKey(null);
|
|
||||||
}}
|
|
||||||
apiKey={selectedApiKey}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<RevokeApiKeyModal
|
|
||||||
opened={revokeModalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setRevokeModalOpened(false);
|
|
||||||
setSelectedApiKey(null);
|
|
||||||
}}
|
|
||||||
apiKey={selectedApiKey}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
import { IPagination, QueryParams } from "@/lib/types.ts";
|
|
||||||
import {
|
|
||||||
keepPreviousData,
|
|
||||||
useMutation,
|
|
||||||
useQuery,
|
|
||||||
useQueryClient,
|
|
||||||
UseQueryResult,
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import {
|
|
||||||
createApiKey,
|
|
||||||
getApiKeys,
|
|
||||||
IApiKey,
|
|
||||||
ICreateApiKeyRequest,
|
|
||||||
IUpdateApiKeyRequest,
|
|
||||||
revokeApiKey,
|
|
||||||
updateApiKey,
|
|
||||||
} from "@/ee/api-key";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
export function useGetApiKeysQuery(
|
|
||||||
params?: QueryParams,
|
|
||||||
): UseQueryResult<IPagination<IApiKey>, Error> {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ["api-key-list", params],
|
|
||||||
queryFn: () => getApiKeys(params),
|
|
||||||
staleTime: 0,
|
|
||||||
gcTime: 0,
|
|
||||||
placeholderData: keepPreviousData,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useRevokeApiKeyMutation() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return useMutation<
|
|
||||||
void,
|
|
||||||
Error,
|
|
||||||
{
|
|
||||||
apiKeyId: string;
|
|
||||||
}
|
|
||||||
>({
|
|
||||||
mutationFn: (data) => revokeApiKey(data),
|
|
||||||
onSuccess: (data, variables) => {
|
|
||||||
notifications.show({ message: t("Revoked successfully") });
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
predicate: (item) =>
|
|
||||||
["api-key-list"].includes(item.queryKey[0] as string),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
const errorMessage = error["response"]?.data?.message;
|
|
||||||
notifications.show({ message: errorMessage, color: "red" });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCreateApiKeyMutation() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return useMutation<IApiKey, Error, ICreateApiKeyRequest>({
|
|
||||||
mutationFn: (data) => createApiKey(data),
|
|
||||||
onSuccess: () => {
|
|
||||||
notifications.show({ message: t("API key created successfully") });
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
predicate: (item) =>
|
|
||||||
["api-key-list"].includes(item.queryKey[0] as string),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
const errorMessage = error["response"]?.data?.message;
|
|
||||||
notifications.show({ message: errorMessage, color: "red" });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateApiKeyMutation() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return useMutation<IApiKey, Error, IUpdateApiKeyRequest>({
|
|
||||||
mutationFn: (data) => updateApiKey(data),
|
|
||||||
onSuccess: (data, variables) => {
|
|
||||||
notifications.show({ message: t("Updated successfully") });
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
predicate: (item) =>
|
|
||||||
["api-key-list"].includes(item.queryKey[0] as string),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
const errorMessage = error["response"]?.data?.message;
|
|
||||||
notifications.show({ message: errorMessage, color: "red" });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import api from "@/lib/api-client";
|
|
||||||
import {
|
|
||||||
ICreateApiKeyRequest,
|
|
||||||
IApiKey,
|
|
||||||
IUpdateApiKeyRequest,
|
|
||||||
} from "@/ee/api-key/types/api-key.types";
|
|
||||||
import { IPagination, QueryParams } from "@/lib/types.ts";
|
|
||||||
|
|
||||||
export async function getApiKeys(
|
|
||||||
params?: QueryParams,
|
|
||||||
): Promise<IPagination<IApiKey>> {
|
|
||||||
const req = await api.post("/api-keys", { ...params });
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createApiKey(
|
|
||||||
data: ICreateApiKeyRequest,
|
|
||||||
): Promise<IApiKey> {
|
|
||||||
const req = await api.post<IApiKey>("/api-keys/create", data);
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateApiKey(
|
|
||||||
data: IUpdateApiKeyRequest,
|
|
||||||
): Promise<IApiKey> {
|
|
||||||
const req = await api.post<IApiKey>("/api-keys/update", data);
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function revokeApiKey(data: { apiKeyId: string }): Promise<void> {
|
|
||||||
await api.post("/api-keys/revoke", data);
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { IUser } from "@/features/user/types/user.types.ts";
|
|
||||||
|
|
||||||
export interface IApiKey {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
token?: string;
|
|
||||||
creatorId: string;
|
|
||||||
workspaceId: string;
|
|
||||||
expiresAt: string | null;
|
|
||||||
lastUsedAt: string | null;
|
|
||||||
createdAt: string;
|
|
||||||
creator: Partial<IUser>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICreateApiKeyRequest {
|
|
||||||
name: string;
|
|
||||||
expiresAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUpdateApiKeyRequest {
|
|
||||||
apiKeyId: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
@@ -1,333 +0,0 @@
|
|||||||
import { Fragment, useState } from "react";
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
Text,
|
|
||||||
Group,
|
|
||||||
Skeleton,
|
|
||||||
Anchor,
|
|
||||||
Collapse,
|
|
||||||
Box,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import {
|
|
||||||
IconChevronRight,
|
|
||||||
IconChevronDown,
|
|
||||||
IconArrowRight,
|
|
||||||
} from "@tabler/icons-react";
|
|
||||||
import { IAuditLog } from "@/ee/audit/types/audit.types";
|
|
||||||
import { CustomAvatar } from "@/components/ui/custom-avatar";
|
|
||||||
import { getEventLabel } from "@/ee/audit/lib/audit-event-labels";
|
|
||||||
import { formattedDate } from "@/lib/time";
|
|
||||||
import NoTableResults from "@/components/common/no-table-results";
|
|
||||||
import classes from "./audit-logs.module.css";
|
|
||||||
|
|
||||||
type AuditLogsTableProps = {
|
|
||||||
items?: IAuditLog[];
|
|
||||||
isLoading: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
function hasDetails(entry: IAuditLog): boolean {
|
|
||||||
return !!(entry.changes?.before || entry.changes?.after || entry.metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getResourceUrl(entry: IAuditLog): string | null {
|
|
||||||
if (!entry.resource) return null;
|
|
||||||
|
|
||||||
switch (entry.resourceType) {
|
|
||||||
case "group":
|
|
||||||
return `/settings/groups/${entry.resource.id}`;
|
|
||||||
case "space":
|
|
||||||
case "space_member":
|
|
||||||
return entry.resource.slug ? `/s/${entry.resource.slug}` : null;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatValue(value: unknown): string {
|
|
||||||
if (value === null || value === undefined) return "—";
|
|
||||||
if (typeof value === "boolean") return value ? "true" : "false";
|
|
||||||
if (typeof value === "object") return JSON.stringify(value);
|
|
||||||
return String(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ChangesDiff({ changes }: { changes: IAuditLog["changes"] }) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
if (!changes) return null;
|
|
||||||
|
|
||||||
const { before, after } = changes;
|
|
||||||
const allKeys = new Set([
|
|
||||||
...Object.keys(before ?? {}),
|
|
||||||
...Object.keys(after ?? {}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (allKeys.size === 0) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Text fz="xs" fw={600} mb={4}>
|
|
||||||
{t("Changes")}
|
|
||||||
</Text>
|
|
||||||
{[...allKeys].map((key) => {
|
|
||||||
const hasBefore = before && key in before;
|
|
||||||
const hasAfter = after && key in after;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Group key={key} gap={6} mb={2} wrap="nowrap" align="center">
|
|
||||||
<Text
|
|
||||||
fz="xs"
|
|
||||||
c="dimmed"
|
|
||||||
fw={500}
|
|
||||||
style={{ minWidth: "fit-content" }}
|
|
||||||
>
|
|
||||||
{key}:
|
|
||||||
</Text>
|
|
||||||
{hasBefore && (
|
|
||||||
<Text fz="xs" component="span">
|
|
||||||
{formatValue(before[key])}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{hasBefore && hasAfter && (
|
|
||||||
<IconArrowRight size={10} color="var(--mantine-color-dimmed)" />
|
|
||||||
)}
|
|
||||||
{hasAfter && (
|
|
||||||
<Text fz="xs" component="span">
|
|
||||||
{formatValue(after[key])}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function MetadataDisplay({ metadata }: { metadata: Record<string, any> }) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const entries = Object.entries(metadata);
|
|
||||||
if (entries.length === 0) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Text fz="xs" fw={600} mb={4}>
|
|
||||||
{t("Metadata")}
|
|
||||||
</Text>
|
|
||||||
{entries.map(([key, value]) => (
|
|
||||||
<Group key={key} gap={6} mb={2} wrap="nowrap">
|
|
||||||
<Text fz="xs" c="dimmed" fw={500}>
|
|
||||||
{key}:
|
|
||||||
</Text>
|
|
||||||
<Text fz="xs">{formatValue(value)}</Text>
|
|
||||||
</Group>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function TableSkeleton() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{Array.from({ length: 8 }).map((_, i) => (
|
|
||||||
<Table.Tr key={i}>
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="sm" wrap="nowrap">
|
|
||||||
<Skeleton circle height={36} />
|
|
||||||
<div>
|
|
||||||
<Skeleton height={14} width={120} mb={4} />
|
|
||||||
<Skeleton height={10} width={160} />
|
|
||||||
</div>
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Skeleton height={14} width={140} />
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Skeleton height={14} width={120} />
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>
|
|
||||||
<Skeleton height={14} width={120} />
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ResourceCell({ entry }: { entry: IAuditLog }) {
|
|
||||||
if (!entry.resource?.name) {
|
|
||||||
return (
|
|
||||||
<Text fz="sm" c="dimmed">
|
|
||||||
—
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = getResourceUrl(entry);
|
|
||||||
|
|
||||||
if (url) {
|
|
||||||
return (
|
|
||||||
<Anchor
|
|
||||||
size="sm"
|
|
||||||
underline="never"
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
color: "var(--mantine-color-text)",
|
|
||||||
}}
|
|
||||||
component={Link}
|
|
||||||
to={url}
|
|
||||||
>
|
|
||||||
<div className={classes.resourceLinkText}>
|
|
||||||
<Text fz="sm" fw={500} lineClamp={1}>
|
|
||||||
{entry.resource.name}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</Anchor>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Text fz="sm" lineClamp={1}>
|
|
||||||
{entry.resource.name}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AuditLogsTable({
|
|
||||||
items,
|
|
||||||
isLoading,
|
|
||||||
}: AuditLogsTableProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
|
||||||
|
|
||||||
const toggleExpanded = (id: string) => {
|
|
||||||
setExpanded((prev) => {
|
|
||||||
const next = new Set(prev);
|
|
||||||
if (next.has(id)) {
|
|
||||||
next.delete(id);
|
|
||||||
} else {
|
|
||||||
next.add(id);
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Table.ScrollContainer minWidth={700}>
|
|
||||||
<Table highlightOnHover verticalSpacing="xs" className={classes.table}>
|
|
||||||
<Table.Thead>
|
|
||||||
<Table.Tr>
|
|
||||||
<Table.Th>{t("Actor")}</Table.Th>
|
|
||||||
<Table.Th>{t("Event")}</Table.Th>
|
|
||||||
<Table.Th>{t("Resource")}</Table.Th>
|
|
||||||
<Table.Th>{t("Date")}</Table.Th>
|
|
||||||
</Table.Tr>
|
|
||||||
</Table.Thead>
|
|
||||||
|
|
||||||
<Table.Tbody>
|
|
||||||
{isLoading ? (
|
|
||||||
<TableSkeleton />
|
|
||||||
) : items && items.length > 0 ? (
|
|
||||||
items.map((entry) => {
|
|
||||||
const expandable = hasDetails(entry);
|
|
||||||
const isExpanded = expanded.has(entry.id);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment key={entry.id}>
|
|
||||||
<Table.Tr
|
|
||||||
onClick={
|
|
||||||
expandable ? () => toggleExpanded(entry.id) : undefined
|
|
||||||
}
|
|
||||||
style={{ cursor: expandable ? "pointer" : undefined }}
|
|
||||||
>
|
|
||||||
<Table.Td>
|
|
||||||
<Group gap="sm" wrap="nowrap">
|
|
||||||
{expandable ? (
|
|
||||||
isExpanded ? (
|
|
||||||
<IconChevronDown
|
|
||||||
size={16}
|
|
||||||
color="var(--mantine-color-dimmed)"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<IconChevronRight
|
|
||||||
size={16}
|
|
||||||
color="var(--mantine-color-dimmed)"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<Box w={16} />
|
|
||||||
)}
|
|
||||||
{entry.actor ? (
|
|
||||||
<Group gap="sm" wrap="nowrap">
|
|
||||||
<CustomAvatar
|
|
||||||
avatarUrl={entry.actor.avatarUrl}
|
|
||||||
name={entry.actor.name}
|
|
||||||
size={36}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<Text fz="sm" fw={500} lineClamp={1}>
|
|
||||||
{entry.actor.name}
|
|
||||||
</Text>
|
|
||||||
<Text fz="xs" c="dimmed">
|
|
||||||
{entry.actor.email}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</Group>
|
|
||||||
) : (
|
|
||||||
<Text fz="sm" c="dimmed" fs="italic">
|
|
||||||
{entry.actorType === "system"
|
|
||||||
? t("System")
|
|
||||||
: t("System")}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
<Text fz="sm">{t(getEventLabel(entry.event))}</Text>
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
<ResourceCell entry={entry} />
|
|
||||||
</Table.Td>
|
|
||||||
|
|
||||||
<Table.Td>
|
|
||||||
<Text fz="sm" style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{formattedDate(new Date(entry.createdAt))}
|
|
||||||
</Text>
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
|
|
||||||
{expandable && (
|
|
||||||
<Table.Tr className={classes.detailRow}>
|
|
||||||
<Table.Td colSpan={4} p={0}>
|
|
||||||
<Collapse in={isExpanded}>
|
|
||||||
<Box
|
|
||||||
px="md"
|
|
||||||
py="sm"
|
|
||||||
className={classes.detailContent}
|
|
||||||
>
|
|
||||||
<Group gap="xl" align="flex-start">
|
|
||||||
{entry.changes && (
|
|
||||||
<ChangesDiff changes={entry.changes} />
|
|
||||||
)}
|
|
||||||
{entry.metadata && (
|
|
||||||
<MetadataDisplay metadata={entry.metadata} />
|
|
||||||
)}
|
|
||||||
</Group>
|
|
||||||
</Box>
|
|
||||||
</Collapse>
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
) : (
|
|
||||||
<NoTableResults colSpan={4} />
|
|
||||||
)}
|
|
||||||
</Table.Tbody>
|
|
||||||
</Table>
|
|
||||||
</Table.ScrollContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
.table {
|
|
||||||
--table-border-color: var(--mantine-color-gray-2);
|
|
||||||
|
|
||||||
@mixin dark {
|
|
||||||
--table-border-color: var(--mantine-color-dark-5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.resourceLinkText {
|
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
@mixin light {
|
|
||||||
border-bottom: 0.05em solid var(--mantine-color-dark-0);
|
|
||||||
}
|
|
||||||
@mixin dark {
|
|
||||||
border-bottom: 0.05em solid var(--mantine-color-dark-2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailRow {
|
|
||||||
&:hover {
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailContent {
|
|
||||||
@mixin light {
|
|
||||||
background: var(--mantine-color-gray-0);
|
|
||||||
}
|
|
||||||
@mixin dark {
|
|
||||||
background: var(--mantine-color-dark-7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
type EventOption = {
|
|
||||||
value: string;
|
|
||||||
label: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type EventGroup = {
|
|
||||||
group: string;
|
|
||||||
items: EventOption[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const auditEventLabels: Record<string, string> = {
|
|
||||||
"workspace.created": "Created workspace",
|
|
||||||
"workspace.updated": "Updated workspace",
|
|
||||||
"workspace.invite_created": "Created invitation",
|
|
||||||
"workspace.invite_resent": "Resent invitation",
|
|
||||||
"workspace.invite_revoked": "Revoked invitation",
|
|
||||||
|
|
||||||
"user.created": "Created user",
|
|
||||||
"user.deleted": "Deleted user",
|
|
||||||
"user.login": "Logged in",
|
|
||||||
"user.logout": "Logged out",
|
|
||||||
"user.role_changed": "Changed user role",
|
|
||||||
"user.password_changed": "Changed password",
|
|
||||||
"user.password_reset": "Reset password",
|
|
||||||
"user.updated": "Updated user",
|
|
||||||
"user.deactivated": "Deactivated user",
|
|
||||||
"user.activated": "Activated user",
|
|
||||||
"user.mfa_enabled": "Enabled MFA",
|
|
||||||
"user.mfa_disabled": "Disabled MFA",
|
|
||||||
"user.mfa_backup_code_generated": "Generated MFA backup codes",
|
|
||||||
|
|
||||||
"api_key.created": "Created API key",
|
|
||||||
"api_key.updated": "Updated API key",
|
|
||||||
"api_key.deleted": "Deleted API key",
|
|
||||||
|
|
||||||
"space.created": "Created space",
|
|
||||||
"space.updated": "Updated space",
|
|
||||||
"space.deleted": "Deleted space",
|
|
||||||
"space.member_added": "Added space member",
|
|
||||||
"space.member_removed": "Removed space member",
|
|
||||||
"space.member_role_changed": "Changed space member role",
|
|
||||||
"space.exported": "Exported space",
|
|
||||||
|
|
||||||
"group.created": "Created group",
|
|
||||||
"group.updated": "Updated group",
|
|
||||||
"group.deleted": "Deleted group",
|
|
||||||
"group.member_added": "Added group member",
|
|
||||||
"group.member_removed": "Removed group member",
|
|
||||||
|
|
||||||
"comment.deleted": "Deleted comment",
|
|
||||||
|
|
||||||
"page.trashed": "Trashed page",
|
|
||||||
"page.deleted": "Deleted page",
|
|
||||||
"page.restored": "Restored page",
|
|
||||||
"page.imported": "Imported page",
|
|
||||||
"page.exported": "Exported page",
|
|
||||||
"page.restricted": "Restricted page",
|
|
||||||
"page.restriction_removed": "Removed page restriction",
|
|
||||||
"page.permission_added": "Added page permission",
|
|
||||||
"page.permission_removed": "Removed page permission",
|
|
||||||
|
|
||||||
"share.created": "Created share link",
|
|
||||||
"share.deleted": "Deleted share link",
|
|
||||||
|
|
||||||
"sso.provider_created": "Created SSO provider",
|
|
||||||
"sso.provider_updated": "Updated SSO provider",
|
|
||||||
"sso.provider_deleted": "Deleted SSO provider",
|
|
||||||
|
|
||||||
"license.activated": "Activated license",
|
|
||||||
"license.removed": "Removed license",
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getEventLabel(event: string): string {
|
|
||||||
return auditEventLabels[event] ?? event;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const eventFilterOptions: EventGroup[] = [
|
|
||||||
{
|
|
||||||
group: "Workspace",
|
|
||||||
items: [
|
|
||||||
{ value: "workspace.updated", label: "Updated workspace" },
|
|
||||||
{ value: "workspace.invite_created", label: "Created invitation" },
|
|
||||||
{ value: "workspace.invite_revoked", label: "Revoked invitation" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "User",
|
|
||||||
items: [
|
|
||||||
{ value: "user.login", label: "Logged in" },
|
|
||||||
{ value: "user.logout", label: "Logged out" },
|
|
||||||
{ value: "user.created", label: "Created user" },
|
|
||||||
{ value: "user.deleted", label: "Deleted user" },
|
|
||||||
{ value: "user.deactivated", label: "Deactivated user" },
|
|
||||||
{ value: "user.activated", label: "Activated user" },
|
|
||||||
{ value: "user.role_changed", label: "Changed user role" },
|
|
||||||
{ value: "user.password_changed", label: "Changed password" },
|
|
||||||
{ value: "user.mfa_enabled", label: "Enabled MFA" },
|
|
||||||
{ value: "user.mfa_disabled", label: "Disabled MFA" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "Space",
|
|
||||||
items: [
|
|
||||||
{ value: "space.created", label: "Created space" },
|
|
||||||
{ value: "space.updated", label: "Updated space" },
|
|
||||||
{ value: "space.deleted", label: "Deleted space" },
|
|
||||||
{ value: "space.member_added", label: "Added space member" },
|
|
||||||
{ value: "space.member_removed", label: "Removed space member" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "Group",
|
|
||||||
items: [
|
|
||||||
{ value: "group.created", label: "Created group" },
|
|
||||||
{ value: "group.updated", label: "Updated group" },
|
|
||||||
{ value: "group.deleted", label: "Deleted group" },
|
|
||||||
{ value: "group.member_added", label: "Added group member" },
|
|
||||||
{ value: "group.member_removed", label: "Removed group member" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "Comment",
|
|
||||||
items: [
|
|
||||||
{ value: "comment.deleted", label: "Deleted comment" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "Page",
|
|
||||||
items: [
|
|
||||||
{ value: "page.trashed", label: "Trashed page" },
|
|
||||||
{ value: "page.deleted", label: "Deleted page" },
|
|
||||||
{ value: "page.restored", label: "Restored page" },
|
|
||||||
{ value: "page.imported", label: "Imported page" },
|
|
||||||
{ value: "page.exported", label: "Exported page" },
|
|
||||||
{ value: "page.restricted", label: "Restricted page" },
|
|
||||||
{ value: "page.restriction_removed", label: "Removed page restriction" },
|
|
||||||
{ value: "page.permission_added", label: "Added page permission" },
|
|
||||||
{ value: "page.permission_removed", label: "Removed page permission" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "Share",
|
|
||||||
items: [
|
|
||||||
{ value: "share.created", label: "Created share link" },
|
|
||||||
{ value: "share.deleted", label: "Deleted share link" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "SSO",
|
|
||||||
items: [
|
|
||||||
{ value: "sso.provider_created", label: "Created SSO provider" },
|
|
||||||
{ value: "sso.provider_updated", label: "Updated SSO provider" },
|
|
||||||
{ value: "sso.provider_deleted", label: "Deleted SSO provider" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "API key",
|
|
||||||
items: [
|
|
||||||
{ value: "api_key.created", label: "Created API key" },
|
|
||||||
{ value: "api_key.deleted", label: "Deleted API key" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group: "License",
|
|
||||||
items: [
|
|
||||||
{ value: "license.activated", label: "Activated license" },
|
|
||||||
{ value: "license.removed", label: "Removed license" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
import { useState, useMemo, useEffect } from "react";
|
|
||||||
import {
|
|
||||||
ActionIcon,
|
|
||||||
Button,
|
|
||||||
Group,
|
|
||||||
NumberInput,
|
|
||||||
Popover,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Text,
|
|
||||||
Tooltip,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import { Helmet } from "react-helmet-async";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { IconSettings } from "@tabler/icons-react";
|
|
||||||
import SettingsTitle from "@/components/settings/settings-title";
|
|
||||||
import { getAppName } from "@/lib/config";
|
|
||||||
import Paginate from "@/components/common/paginate";
|
|
||||||
import { useCursorPaginate } from "@/hooks/use-cursor-paginate";
|
|
||||||
import {
|
|
||||||
useAuditLogsQuery,
|
|
||||||
useAuditRetentionQuery,
|
|
||||||
useUpdateAuditRetentionMutation,
|
|
||||||
} from "@/ee/audit/queries/audit-query";
|
|
||||||
import { IAuditLogParams } from "@/ee/audit/types/audit.types";
|
|
||||||
import { eventFilterOptions } from "@/ee/audit/lib/audit-event-labels";
|
|
||||||
import AuditLogsTable from "@/ee/audit/components/audit-logs-table";
|
|
||||||
import useUserRole from "@/hooks/use-user-role";
|
|
||||||
|
|
||||||
type RetentionUnit = "days" | "months" | "years";
|
|
||||||
|
|
||||||
function daysToRetention(days: number): { amount: number; unit: RetentionUnit } {
|
|
||||||
if (days >= 365 && days % 365 === 0) {
|
|
||||||
return { amount: days / 365, unit: "years" };
|
|
||||||
}
|
|
||||||
if (days >= 30 && days % 30 === 0) {
|
|
||||||
return { amount: days / 30, unit: "months" };
|
|
||||||
}
|
|
||||||
return { amount: days, unit: "days" };
|
|
||||||
}
|
|
||||||
|
|
||||||
function retentionToDays(amount: number, unit: RetentionUnit): number {
|
|
||||||
if (unit === "years") return amount * 365;
|
|
||||||
if (unit === "months") return amount * 30;
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AuditLogs() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { isOwner } = useUserRole();
|
|
||||||
const { cursor, goNext, goPrev, resetCursor } = useCursorPaginate();
|
|
||||||
|
|
||||||
const [eventFilter, setEventFilter] = useState<string | null>(null);
|
|
||||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
||||||
|
|
||||||
const { data: retentionData } = useAuditRetentionQuery();
|
|
||||||
const updateRetention = useUpdateAuditRetentionMutation();
|
|
||||||
|
|
||||||
const currentDays = retentionData?.retentionDays ?? 365;
|
|
||||||
const parsed = daysToRetention(currentDays);
|
|
||||||
const [retentionAmount, setRetentionAmount] = useState<number | string>(parsed.amount);
|
|
||||||
const [retentionUnit, setRetentionUnit] = useState<RetentionUnit>(parsed.unit);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (retentionData) {
|
|
||||||
const { amount, unit } = daysToRetention(retentionData.retentionDays);
|
|
||||||
setRetentionAmount(amount);
|
|
||||||
setRetentionUnit(unit);
|
|
||||||
}
|
|
||||||
}, [retentionData?.retentionDays]);
|
|
||||||
|
|
||||||
const resetRetentionForm = () => {
|
|
||||||
const { amount, unit } = daysToRetention(currentDays);
|
|
||||||
setRetentionAmount(amount);
|
|
||||||
setRetentionUnit(unit);
|
|
||||||
};
|
|
||||||
|
|
||||||
const params: IAuditLogParams = useMemo(
|
|
||||||
() => ({
|
|
||||||
cursor,
|
|
||||||
limit: 50,
|
|
||||||
event: eventFilter ?? undefined,
|
|
||||||
}),
|
|
||||||
[cursor, eventFilter],
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data, isLoading } = useAuditLogsQuery(params);
|
|
||||||
|
|
||||||
if (!isOwner) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleEventChange = (value: string | null) => {
|
|
||||||
setEventFilter(value);
|
|
||||||
resetCursor();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>
|
|
||||||
{t("Audit log")} - {getAppName()}
|
|
||||||
</title>
|
|
||||||
</Helmet>
|
|
||||||
|
|
||||||
<SettingsTitle title={t("Audit log")} />
|
|
||||||
|
|
||||||
<Group mb="md" gap="sm">
|
|
||||||
<Select
|
|
||||||
placeholder={t("Filter by event")}
|
|
||||||
data={eventFilterOptions.map((group) => ({
|
|
||||||
group: t(group.group),
|
|
||||||
items: group.items.map((item) => ({
|
|
||||||
value: item.value,
|
|
||||||
label: t(item.label),
|
|
||||||
})),
|
|
||||||
}))}
|
|
||||||
value={eventFilter}
|
|
||||||
onChange={handleEventChange}
|
|
||||||
clearable
|
|
||||||
searchable
|
|
||||||
w={220}
|
|
||||||
size="sm"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Popover
|
|
||||||
position="bottom-end"
|
|
||||||
shadow="md"
|
|
||||||
width={260}
|
|
||||||
withArrow
|
|
||||||
opened={settingsOpen}
|
|
||||||
onChange={(opened) => {
|
|
||||||
if (!opened) resetRetentionForm();
|
|
||||||
setSettingsOpen(opened);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Popover.Target>
|
|
||||||
<Tooltip label={t("Audit settings")}>
|
|
||||||
<ActionIcon variant="default" size="input-sm" ml="auto" onClick={() => setSettingsOpen((o) => !o)}>
|
|
||||||
<IconSettings size={16} />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
</Popover.Target>
|
|
||||||
<Popover.Dropdown>
|
|
||||||
<Text fz="sm" fw={500} mb={4}>
|
|
||||||
{t("Retention")}
|
|
||||||
</Text>
|
|
||||||
<Text fz="xs" c="dimmed" mb="sm">
|
|
||||||
{t("Logs older than this period are automatically deleted.")}
|
|
||||||
</Text>
|
|
||||||
<Group gap="xs" wrap="nowrap" mb="sm">
|
|
||||||
<NumberInput
|
|
||||||
value={retentionAmount}
|
|
||||||
onChange={(val) => setRetentionAmount(val)}
|
|
||||||
min={1}
|
|
||||||
hideControls
|
|
||||||
size="sm"
|
|
||||||
w={60}
|
|
||||||
/>
|
|
||||||
<Select
|
|
||||||
data={[
|
|
||||||
{ value: "days", label: t("days") },
|
|
||||||
{ value: "months", label: t("months") },
|
|
||||||
{ value: "years", label: t("years") },
|
|
||||||
]}
|
|
||||||
value={retentionUnit}
|
|
||||||
onChange={(value) => {
|
|
||||||
if (value === "days" || value === "months" || value === "years") {
|
|
||||||
setRetentionUnit(value);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
size="sm"
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
comboboxProps={{ withinPortal: false }}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
<Group gap="xs" grow>
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant="default"
|
|
||||||
onClick={() => {
|
|
||||||
resetRetentionForm();
|
|
||||||
setSettingsOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("Cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
onClick={() => {
|
|
||||||
const num = typeof retentionAmount === "number" ? retentionAmount : 1;
|
|
||||||
const clamped = Math.max(1, num);
|
|
||||||
setRetentionAmount(clamped);
|
|
||||||
const days = retentionToDays(clamped, retentionUnit);
|
|
||||||
if (days !== currentDays) {
|
|
||||||
updateRetention.mutate({ auditRetentionDays: days });
|
|
||||||
}
|
|
||||||
setSettingsOpen(false);
|
|
||||||
}}
|
|
||||||
loading={updateRetention.isPending}
|
|
||||||
>
|
|
||||||
{t("Save")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Popover.Dropdown>
|
|
||||||
</Popover>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<AuditLogsTable items={data?.items} isLoading={isLoading} />
|
|
||||||
|
|
||||||
<Space h="md" />
|
|
||||||
|
|
||||||
{data?.items && data.items.length > 0 && (
|
|
||||||
<Paginate
|
|
||||||
hasPrevPage={data?.meta?.hasPrevPage}
|
|
||||||
hasNextPage={data?.meta?.hasNextPage}
|
|
||||||
onNext={() => goNext(data?.meta?.nextCursor)}
|
|
||||||
onPrev={goPrev}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import {
|
|
||||||
keepPreviousData,
|
|
||||||
useMutation,
|
|
||||||
useQuery,
|
|
||||||
useQueryClient,
|
|
||||||
UseQueryResult,
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import {
|
|
||||||
getAuditLogs,
|
|
||||||
getAuditRetention,
|
|
||||||
updateAuditRetention,
|
|
||||||
} from "@/ee/audit/services/audit-service";
|
|
||||||
import { IAuditLog, IAuditLogParams } from "@/ee/audit/types/audit.types";
|
|
||||||
import { IPagination } from "@/lib/types";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
export function useAuditLogsQuery(
|
|
||||||
params?: IAuditLogParams,
|
|
||||||
): UseQueryResult<IPagination<IAuditLog>, Error> {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ["audit-logs", params],
|
|
||||||
queryFn: () => getAuditLogs(params),
|
|
||||||
placeholderData: keepPreviousData,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAuditRetentionQuery() {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ["audit-retention"],
|
|
||||||
queryFn: () => getAuditRetention(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateAuditRetentionMutation() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: { auditRetentionDays: number }) =>
|
|
||||||
updateAuditRetention(data),
|
|
||||||
onSuccess: () => {
|
|
||||||
notifications.show({ message: t("Audit retention updated") });
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["audit-retention"] });
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
const errorMessage = error["response"]?.data?.message;
|
|
||||||
notifications.show({ message: errorMessage, color: "red" });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import api from "@/lib/api-client";
|
|
||||||
import { IAuditLog, IAuditLogParams } from "@/ee/audit/types/audit.types";
|
|
||||||
import { IPagination } from "@/lib/types";
|
|
||||||
|
|
||||||
export async function getAuditLogs(
|
|
||||||
params?: IAuditLogParams,
|
|
||||||
): Promise<IPagination<IAuditLog>> {
|
|
||||||
const req = await api.post("/audit", { ...params });
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAuditRetention(): Promise<{ retentionDays: number }> {
|
|
||||||
const req = await api.post("/audit/retention");
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateAuditRetention(data: {
|
|
||||||
auditRetentionDays: number;
|
|
||||||
}): Promise<{ retentionDays: number }> {
|
|
||||||
const req = await api.post("/audit/retention/update", data);
|
|
||||||
return req.data;
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
export type IAuditLog = {
|
|
||||||
id: string;
|
|
||||||
workspaceId: string;
|
|
||||||
actorId?: string;
|
|
||||||
actorType: string;
|
|
||||||
event: string;
|
|
||||||
resourceType: string;
|
|
||||||
resourceId?: string;
|
|
||||||
spaceId?: string;
|
|
||||||
changes?: {
|
|
||||||
before?: Record<string, any>;
|
|
||||||
after?: Record<string, any>;
|
|
||||||
};
|
|
||||||
metadata?: Record<string, any>;
|
|
||||||
ipAddress?: string;
|
|
||||||
createdAt: string;
|
|
||||||
actor?: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
avatarUrl?: string;
|
|
||||||
};
|
|
||||||
resource?: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
slug?: string;
|
|
||||||
slugId?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type IAuditLogParams = {
|
|
||||||
event?: string;
|
|
||||||
resourceType?: string;
|
|
||||||
actorId?: string;
|
|
||||||
spaceId?: string;
|
|
||||||
startDate?: string;
|
|
||||||
endDate?: string;
|
|
||||||
cursor?: string;
|
|
||||||
limit?: number;
|
|
||||||
};
|
|
||||||
@@ -30,12 +30,12 @@ export default function BillingDetails() {
|
|||||||
>
|
>
|
||||||
Plan
|
Plan
|
||||||
</Text>
|
</Text>
|
||||||
<Text fw={700} fz="lg" tt="capitalize">
|
<Text fw={700} fz="lg">
|
||||||
{plans.find(
|
{
|
||||||
(plan) => plan.productId === billing.stripeProductId,
|
plans.find(
|
||||||
)?.name ||
|
(plan) => plan.productId === billing.stripeProductId,
|
||||||
billing.planName ||
|
)?.name
|
||||||
"Standard"}
|
}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -112,59 +112,18 @@ export default function BillingDetails() {
|
|||||||
fz="xs"
|
fz="xs"
|
||||||
className={classes.label}
|
className={classes.label}
|
||||||
>
|
>
|
||||||
Cost
|
Total
|
||||||
|
</Text>
|
||||||
|
<Text fw={700} fz="lg">
|
||||||
|
{(billing.amount / 100) * billing.quantity}{" "}
|
||||||
|
{billing.currency.toUpperCase()}
|
||||||
|
</Text>
|
||||||
|
<Text c="dimmed" fz="sm">
|
||||||
|
${billing.amount / 100} /user/{billing.interval}
|
||||||
</Text>
|
</Text>
|
||||||
{billing.billingScheme === "tiered" && (
|
|
||||||
<>
|
|
||||||
<Text fw={700} fz="lg">
|
|
||||||
${billing.amount / 100} {billing.currency.toUpperCase()} /{" "}
|
|
||||||
{billing.interval}
|
|
||||||
</Text>
|
|
||||||
<Text c="dimmed" fz="sm">
|
|
||||||
per {billing.interval}
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{billing.billingScheme !== "tiered" && (
|
|
||||||
<>
|
|
||||||
<Text fw={700} fz="lg">
|
|
||||||
{(billing.amount / 100) * billing.quantity}{" "}
|
|
||||||
{billing.currency.toUpperCase()} / {billing.interval}
|
|
||||||
</Text>
|
|
||||||
<Text c="dimmed" fz="sm">
|
|
||||||
${billing.amount / 100} /user/{billing.interval}
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{billing.billingScheme === "tiered" && billing.tieredUpTo && (
|
|
||||||
<Paper p="md" radius="md">
|
|
||||||
<Group justify="apart">
|
|
||||||
<div>
|
|
||||||
<Text
|
|
||||||
c="dimmed"
|
|
||||||
tt="uppercase"
|
|
||||||
fw={700}
|
|
||||||
fz="xs"
|
|
||||||
className={classes.label}
|
|
||||||
>
|
|
||||||
Current Tier
|
|
||||||
</Text>
|
|
||||||
<Text fw={700} fz="lg">
|
|
||||||
For {billing.tieredUpTo} users
|
|
||||||
</Text>
|
|
||||||
{/*billing.tieredFlatAmount && (
|
|
||||||
<Text c="dimmed" fz="sm">
|
|
||||||
</Text>
|
|
||||||
)*/}
|
|
||||||
</div>
|
|
||||||
</Group>
|
|
||||||
</Paper>
|
|
||||||
)}
|
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,32 +2,24 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
List,
|
List,
|
||||||
|
SegmentedControl,
|
||||||
ThemeIcon,
|
ThemeIcon,
|
||||||
Title,
|
Title,
|
||||||
Text,
|
Text,
|
||||||
Group,
|
Group,
|
||||||
Select,
|
|
||||||
Container,
|
|
||||||
Stack,
|
|
||||||
Badge,
|
|
||||||
Flex,
|
|
||||||
Switch,
|
|
||||||
Alert,
|
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { IconCheck, IconInfoCircle } from "@tabler/icons-react";
|
import { IconCheck } from "@tabler/icons-react";
|
||||||
import { getCheckoutLink } from "@/ee/billing/services/billing-service.ts";
|
|
||||||
import { useBillingPlans } from "@/ee/billing/queries/billing-query.ts";
|
import { useBillingPlans } from "@/ee/billing/queries/billing-query.ts";
|
||||||
import { useAtomValue } from "jotai";
|
import { getCheckoutLink } from "@/ee/billing/services/billing-service.ts";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom";
|
|
||||||
|
|
||||||
export default function BillingPlans() {
|
export default function BillingPlans() {
|
||||||
const { data: plans } = useBillingPlans();
|
const { data: plans } = useBillingPlans();
|
||||||
const workspace = useAtomValue(workspaceAtom);
|
const [interval, setInterval] = useState("yearly");
|
||||||
const [isAnnual, setIsAnnual] = useState(true);
|
|
||||||
const [selectedTierValue, setSelectedTierValue] = useState<string | null>(
|
if (!plans) {
|
||||||
null,
|
return null;
|
||||||
);
|
}
|
||||||
|
|
||||||
const handleCheckout = async (priceId: string) => {
|
const handleCheckout = async (priceId: string) => {
|
||||||
try {
|
try {
|
||||||
@@ -40,194 +32,84 @@ export default function BillingPlans() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remove by July 30.
|
|
||||||
// Check if workspace was created between June 28 and July 14, 2025
|
|
||||||
const showTieredPricingNotice = (() => {
|
|
||||||
if (!workspace?.createdAt) return false;
|
|
||||||
const createdDate = new Date(workspace.createdAt);
|
|
||||||
const startDate = new Date('2025-06-20');
|
|
||||||
const endDate = new Date('2025-07-14');
|
|
||||||
return createdDate >= startDate && createdDate <= endDate;
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (!plans || plans.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any plan is tiered
|
|
||||||
const hasTieredPlans = plans.some(plan => plan.billingScheme === 'tiered' && plan.pricingTiers?.length > 0);
|
|
||||||
const firstTieredPlan = plans.find(plan => plan.billingScheme === 'tiered' && plan.pricingTiers?.length > 0);
|
|
||||||
|
|
||||||
// Set initial tier value if not set and we have tiered plans
|
|
||||||
if (hasTieredPlans && !selectedTierValue && firstTieredPlan) {
|
|
||||||
setSelectedTierValue(firstTieredPlan.pricingTiers[0].upTo.toString());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For tiered plans, ensure we have a selected tier
|
|
||||||
if (hasTieredPlans && !selectedTierValue) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectData = firstTieredPlan?.pricingTiers
|
|
||||||
?.filter((tier) => !tier.custom)
|
|
||||||
.map((tier, index) => {
|
|
||||||
const prevMaxUsers =
|
|
||||||
index > 0 ? firstTieredPlan.pricingTiers[index - 1].upTo : 0;
|
|
||||||
return {
|
|
||||||
value: tier.upTo.toString(),
|
|
||||||
label: `${prevMaxUsers + 1}-${tier.upTo} users`,
|
|
||||||
};
|
|
||||||
}) || [];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container size="xl" py="xl">
|
<Group justify="center" p="xl">
|
||||||
{/* Tiered pricing notice for eligible workspaces */}
|
{plans.map((plan) => {
|
||||||
{showTieredPricingNotice && !hasTieredPlans && (
|
const price =
|
||||||
<Alert
|
interval === "monthly" ? plan.price.monthly : plan.price.yearly;
|
||||||
icon={<IconInfoCircle size={16} />}
|
const priceId = interval === "monthly" ? plan.monthlyId : plan.yearlyId;
|
||||||
title="Want the old tiered pricing?"
|
const yearlyMonthPrice = parseInt(plan.price.yearly) / 12;
|
||||||
color="blue"
|
|
||||||
mb="lg"
|
|
||||||
>
|
|
||||||
Contact support to switch back to our tiered pricing model.
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Controls Section */}
|
return (
|
||||||
<Stack gap="xl" mb="md">
|
<Card
|
||||||
{/* Team Size and Billing Controls */}
|
key={plan.name}
|
||||||
<Group justify="center" align="center" gap="sm">
|
withBorder
|
||||||
{hasTieredPlans && (
|
radius="md"
|
||||||
<Select
|
shadow="sm"
|
||||||
label="Team size"
|
p="xl"
|
||||||
description="Select the number of users"
|
w={300}
|
||||||
value={selectedTierValue}
|
>
|
||||||
onChange={setSelectedTierValue}
|
<SegmentedControl
|
||||||
data={selectData}
|
value={interval}
|
||||||
w={250}
|
onChange={setInterval}
|
||||||
size="md"
|
fullWidth
|
||||||
allowDeselect={false}
|
data={[
|
||||||
|
{ label: "Monthly", value: "monthly" },
|
||||||
|
{ label: "Yearly (25% OFF)", value: "yearly" },
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
|
|
||||||
<Group justify="center" align="start">
|
<Title order={3} ta="center" mt="sm" mb="xs">
|
||||||
<Flex justify="center" gap="md" align="center">
|
{plan.name}
|
||||||
<Text size="md">Monthly</Text>
|
</Title>
|
||||||
<Switch
|
<Text ta="center" size="lg" fw={700}>
|
||||||
defaultChecked={isAnnual}
|
{interval === "monthly" && (
|
||||||
onChange={(event) => setIsAnnual(event.target.checked)}
|
<>
|
||||||
size="sm"
|
${price}{" "}
|
||||||
/>
|
<Text span size="sm" fw={500} c="dimmed">
|
||||||
<Text size="md">
|
/user/month
|
||||||
Annually
|
|
||||||
<Badge component="span" variant="light" color="blue">
|
|
||||||
15% OFF
|
|
||||||
</Badge>
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{/* Plans Grid */}
|
|
||||||
<Group justify="center" gap="lg" align="stretch">
|
|
||||||
{plans.map((plan, index) => {
|
|
||||||
let price;
|
|
||||||
let displayPrice;
|
|
||||||
const priceId = isAnnual ? plan.yearlyId : plan.monthlyId;
|
|
||||||
|
|
||||||
if (plan.billingScheme === 'tiered' && plan.pricingTiers?.length > 0) {
|
|
||||||
// Tiered billing logic
|
|
||||||
const planSelectedTier =
|
|
||||||
plan.pricingTiers.find(
|
|
||||||
(tier) => tier.upTo.toString() === selectedTierValue,
|
|
||||||
) || plan.pricingTiers[0];
|
|
||||||
|
|
||||||
price = isAnnual
|
|
||||||
? planSelectedTier.yearly
|
|
||||||
: planSelectedTier.monthly;
|
|
||||||
displayPrice = isAnnual ? (price / 12).toFixed(0) : price;
|
|
||||||
} else {
|
|
||||||
// Per-unit billing logic
|
|
||||||
const monthlyPrice = parseFloat(plan.price?.monthly || '0');
|
|
||||||
const yearlyPrice = parseFloat(plan.price?.yearly || '0');
|
|
||||||
price = isAnnual ? yearlyPrice : monthlyPrice;
|
|
||||||
displayPrice = isAnnual ? (yearlyPrice / 12).toFixed(0) : monthlyPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
key={plan.name}
|
|
||||||
withBorder
|
|
||||||
radius="lg"
|
|
||||||
shadow="sm"
|
|
||||||
p="xl"
|
|
||||||
w={350}
|
|
||||||
miw={300}
|
|
||||||
style={{
|
|
||||||
position: "relative",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack gap="lg">
|
|
||||||
{/* Plan Header */}
|
|
||||||
<Stack gap="xs">
|
|
||||||
<Title order={3} size="h4">
|
|
||||||
{plan.name}
|
|
||||||
</Title>
|
|
||||||
{plan.description && (
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{plan.description}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{/* Pricing */}
|
|
||||||
<Stack gap="xs">
|
|
||||||
<Group align="baseline" gap="xs">
|
|
||||||
<Title order={1} size="h1">
|
|
||||||
${displayPrice}
|
|
||||||
</Title>
|
|
||||||
<Text size="lg" c="dimmed">
|
|
||||||
{plan.billingScheme === 'per_unit'
|
|
||||||
? `per user/month`
|
|
||||||
: `per month`}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
{isAnnual ? "Billed annually" : "Billed monthly"}
|
|
||||||
</Text>
|
</Text>
|
||||||
{plan.billingScheme === 'tiered' && plan.pricingTiers && (
|
</>
|
||||||
<Text size="md" fw={500}>
|
)}
|
||||||
For {plan.pricingTiers.find(tier => tier.upTo.toString() === selectedTierValue)?.upTo || plan.pricingTiers[0].upTo} users
|
{interval === "yearly" && (
|
||||||
</Text>
|
<>
|
||||||
)}
|
${yearlyMonthPrice}{" "}
|
||||||
</Stack>
|
<Text span size="sm" fw={500} c="dimmed">
|
||||||
|
/user/month
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<br/>
|
||||||
|
<Text span ta="center" size="md" fw={500} c="dimmed">
|
||||||
|
billed {interval}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
|
||||||
{/* CTA Button */}
|
<Card.Section mt="lg">
|
||||||
<Button onClick={() => handleCheckout(priceId)} fullWidth>
|
<Button onClick={() => handleCheckout(priceId)} fullWidth>
|
||||||
Subscribe
|
Subscribe
|
||||||
</Button>
|
</Button>
|
||||||
|
</Card.Section>
|
||||||
|
|
||||||
{/* Features */}
|
<Card.Section mt="md">
|
||||||
<List
|
<List
|
||||||
spacing="xs"
|
spacing="xs"
|
||||||
size="sm"
|
size="sm"
|
||||||
icon={
|
center
|
||||||
<ThemeIcon size={20} radius="xl">
|
icon={
|
||||||
<IconCheck size={14} />
|
<ThemeIcon variant="light" size={24} radius="xl">
|
||||||
</ThemeIcon>
|
<IconCheck size={16} />
|
||||||
}
|
</ThemeIcon>
|
||||||
>
|
}
|
||||||
{plan.features.map((feature, featureIndex) => (
|
>
|
||||||
<List.Item key={featureIndex}>{feature}</List.Item>
|
{plan.features.map((feature, index) => (
|
||||||
))}
|
<List.Item key={index}>{feature}</List.Item>
|
||||||
</List>
|
))}
|
||||||
</Stack>
|
</List>
|
||||||
</Card>
|
</Card.Section>
|
||||||
);
|
</Card>
|
||||||
})}
|
);
|
||||||
</Group>
|
})}
|
||||||
</Container>
|
</Group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export enum BillingPlan {
|
export enum BillingPlan {
|
||||||
STANDARD = "standard",
|
STANDARD = "standard",
|
||||||
BUSINESS = "business",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBilling {
|
export interface IBilling {
|
||||||
@@ -25,11 +24,6 @@ export interface IBilling {
|
|||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
deletedAt: Date;
|
deletedAt: Date;
|
||||||
billingScheme: string | null;
|
|
||||||
tieredUpTo: string | null;
|
|
||||||
tieredFlatAmount: number | null;
|
|
||||||
tieredUnitAmount: number | null;
|
|
||||||
planName: string | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICheckoutLink {
|
export interface ICheckoutLink {
|
||||||
@@ -47,18 +41,9 @@ export interface IBillingPlan {
|
|||||||
monthlyId: string;
|
monthlyId: string;
|
||||||
yearlyId: string;
|
yearlyId: string;
|
||||||
currency: string;
|
currency: string;
|
||||||
price?: {
|
price: {
|
||||||
monthly: string;
|
monthly: string;
|
||||||
yearly: string;
|
yearly: string;
|
||||||
};
|
};
|
||||||
features: string[];
|
features: string[];
|
||||||
billingScheme: string | null;
|
|
||||||
pricingTiers?: PricingTier[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PricingTier {
|
|
||||||
upTo: number;
|
|
||||||
monthly?: number;
|
|
||||||
yearly?: number;
|
|
||||||
custom?: boolean;
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import { ActionIcon, Tooltip } from "@mantine/core";
|
|
||||||
import { IconCircleCheck, IconCircleCheckFilled } from "@tabler/icons-react";
|
|
||||||
import { useResolveCommentMutation } from "@/ee/comment/queries/comment-query";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Editor } from "@tiptap/react";
|
|
||||||
|
|
||||||
interface ResolveCommentProps {
|
|
||||||
editor: Editor;
|
|
||||||
commentId: string;
|
|
||||||
pageId: string;
|
|
||||||
resolvedAt?: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ResolveComment({
|
|
||||||
editor,
|
|
||||||
commentId,
|
|
||||||
pageId,
|
|
||||||
resolvedAt,
|
|
||||||
}: ResolveCommentProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const resolveCommentMutation = useResolveCommentMutation();
|
|
||||||
|
|
||||||
const isResolved = resolvedAt != null;
|
|
||||||
const iconColor = isResolved ? "green" : "gray";
|
|
||||||
|
|
||||||
const handleResolveToggle = async () => {
|
|
||||||
try {
|
|
||||||
await resolveCommentMutation.mutateAsync({
|
|
||||||
commentId,
|
|
||||||
pageId,
|
|
||||||
resolved: !isResolved,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (editor) {
|
|
||||||
editor.commands.setCommentResolved(commentId, !isResolved);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to toggle resolved state:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
label={isResolved ? t("Re-Open comment") : t("Resolve comment")}
|
|
||||||
position="top"
|
|
||||||
>
|
|
||||||
<ActionIcon
|
|
||||||
onClick={handleResolveToggle}
|
|
||||||
variant="subtle"
|
|
||||||
color={isResolved ? "green" : "gray"}
|
|
||||||
size="sm"
|
|
||||||
loading={resolveCommentMutation.isPending}
|
|
||||||
disabled={resolveCommentMutation.isPending}
|
|
||||||
>
|
|
||||||
{isResolved ? (
|
|
||||||
<IconCircleCheckFilled size={18} />
|
|
||||||
) : (
|
|
||||||
<IconCircleCheck size={18} />
|
|
||||||
)}
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ResolveComment;
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import {
|
|
||||||
useMutation,
|
|
||||||
useQueryClient,
|
|
||||||
InfiniteData,
|
|
||||||
} from "@tanstack/react-query";
|
|
||||||
import { resolveComment } from "@/features/comment/services/comment-service";
|
|
||||||
import {
|
|
||||||
IComment,
|
|
||||||
IResolveComment,
|
|
||||||
} from "@/features/comment/types/comment.types";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { IPagination } from "@/lib/types.ts";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { RQ_KEY } from "@/features/comment/queries/comment-query";
|
|
||||||
|
|
||||||
function updateCommentInCache(
|
|
||||||
cache: InfiniteData<IPagination<IComment>>,
|
|
||||||
commentId: string,
|
|
||||||
updater: (comment: IComment) => IComment,
|
|
||||||
): InfiniteData<IPagination<IComment>> {
|
|
||||||
return {
|
|
||||||
...cache,
|
|
||||||
pages: cache.pages.map((page) => ({
|
|
||||||
...page,
|
|
||||||
items: page.items.map((comment) =>
|
|
||||||
comment.id === commentId ? updater(comment) : comment,
|
|
||||||
),
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useResolveCommentMutation() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: IResolveComment) => resolveComment(data),
|
|
||||||
onMutate: async (variables) => {
|
|
||||||
await queryClient.cancelQueries({ queryKey: RQ_KEY(variables.pageId) });
|
|
||||||
const previousCache = queryClient.getQueryData(RQ_KEY(variables.pageId));
|
|
||||||
|
|
||||||
const cache = previousCache as InfiniteData<IPagination<IComment>> | undefined;
|
|
||||||
if (cache) {
|
|
||||||
queryClient.setQueryData(
|
|
||||||
RQ_KEY(variables.pageId),
|
|
||||||
updateCommentInCache(cache, variables.commentId, (comment) => ({
|
|
||||||
...comment,
|
|
||||||
resolvedAt: variables.resolved ? new Date() : null,
|
|
||||||
resolvedById: variables.resolved ? "optimistic" : null,
|
|
||||||
resolvedBy: variables.resolved
|
|
||||||
? ({ id: "optimistic", name: "", avatarUrl: null } as IComment["resolvedBy"])
|
|
||||||
: null,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { previousCache };
|
|
||||||
},
|
|
||||||
onError: (_err, variables, context) => {
|
|
||||||
if (context?.previousCache) {
|
|
||||||
queryClient.setQueryData(RQ_KEY(variables.pageId), context.previousCache);
|
|
||||||
}
|
|
||||||
notifications.show({
|
|
||||||
message: t("Failed to resolve comment"),
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSuccess: (data: IComment, variables) => {
|
|
||||||
const cache = queryClient.getQueryData(
|
|
||||||
RQ_KEY(data.pageId),
|
|
||||||
) as InfiniteData<IPagination<IComment>> | undefined;
|
|
||||||
|
|
||||||
if (cache) {
|
|
||||||
queryClient.setQueryData(
|
|
||||||
RQ_KEY(data.pageId),
|
|
||||||
updateCommentInCache(cache, variables.commentId, (comment) => ({
|
|
||||||
...comment,
|
|
||||||
resolvedAt: data.resolvedAt,
|
|
||||||
resolvedById: data.resolvedById,
|
|
||||||
resolvedBy: data.resolvedBy,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifications.show({
|
|
||||||
message: variables.resolved
|
|
||||||
? t("Comment resolved successfully")
|
|
||||||
: t("Comment re-opened successfully"),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { z } from "zod/v4";
|
import * as z from "zod";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm, zodResolver } from "@mantine/form";
|
||||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
Title,
|
Title,
|
||||||
@@ -31,7 +30,7 @@ export function CloudLoginForm() {
|
|||||||
const { data: joinedWorkspaces } = useJoinedWorkspacesQuery();
|
const { data: joinedWorkspaces } = useJoinedWorkspacesQuery();
|
||||||
|
|
||||||
const form = useForm<any>({
|
const form = useForm<any>({
|
||||||
validate: zod4Resolver(formSchema),
|
validate: zodResolver(formSchema),
|
||||||
initialValues: {
|
initialValues: {
|
||||||
hostname: "",
|
hostname: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { Modal, TextInput, PasswordInput, Button, Stack } from "@mantine/core";
|
|
||||||
import { useForm } from "@mantine/form";
|
|
||||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
|
||||||
import { z } from "zod/v4";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { IAuthProvider } from "@/ee/security/types/security.types";
|
|
||||||
import APP_ROUTE, { getPostLoginRedirect } from "@/lib/app-route";
|
|
||||||
import { ldapLogin } from "@/ee/security/services/ldap-auth-service";
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
|
||||||
username: z.string().min(1, { message: "Username is required" }),
|
|
||||||
password: z.string().min(1, { message: "Password is required" }),
|
|
||||||
});
|
|
||||||
|
|
||||||
interface LdapLoginModalProps {
|
|
||||||
opened: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
provider: IAuthProvider;
|
|
||||||
workspaceId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LdapLoginModal({
|
|
||||||
opened,
|
|
||||||
onClose,
|
|
||||||
provider,
|
|
||||||
workspaceId,
|
|
||||||
}: LdapLoginModalProps) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const form = useForm({
|
|
||||||
validate: zod4Resolver(formSchema),
|
|
||||||
initialValues: {
|
|
||||||
username: "",
|
|
||||||
password: "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleSubmit = async (values: {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
}) => {
|
|
||||||
setIsLoading(true);
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await ldapLogin({
|
|
||||||
username: values.username,
|
|
||||||
password: values.password,
|
|
||||||
providerId: provider.id,
|
|
||||||
workspaceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle MFA like the regular login
|
|
||||||
if (response?.userHasMfa) {
|
|
||||||
onClose();
|
|
||||||
navigate(APP_ROUTE.AUTH.MFA_CHALLENGE + window.location.search);
|
|
||||||
} else if (response?.requiresMfaSetup) {
|
|
||||||
onClose();
|
|
||||||
navigate(APP_ROUTE.AUTH.MFA_SETUP_REQUIRED + window.location.search);
|
|
||||||
} else {
|
|
||||||
onClose();
|
|
||||||
navigate(getPostLoginRedirect());
|
|
||||||
}
|
|
||||||
} catch (err: any) {
|
|
||||||
setIsLoading(false);
|
|
||||||
const errorMessage =
|
|
||||||
err.response?.data?.message || "Authentication failed";
|
|
||||||
setError(errorMessage);
|
|
||||||
|
|
||||||
notifications.show({
|
|
||||||
message: errorMessage,
|
|
||||||
color: "red",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
form.reset();
|
|
||||||
setError(null);
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
opened={opened}
|
|
||||||
onClose={handleClose}
|
|
||||||
title={`LDAP Login - ${provider.name}`}
|
|
||||||
size="md"
|
|
||||||
>
|
|
||||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
|
||||||
<Stack>
|
|
||||||
<TextInput
|
|
||||||
id="ldap-username"
|
|
||||||
type="text"
|
|
||||||
label={t("LDAP username")}
|
|
||||||
placeholder="Enter your LDAP username"
|
|
||||||
variant="filled"
|
|
||||||
disabled={isLoading}
|
|
||||||
data-autofocus
|
|
||||||
{...form.getInputProps("username")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<PasswordInput
|
|
||||||
label={t("LDAP password")}
|
|
||||||
placeholder={t("Enter your LDAP password")}
|
|
||||||
variant="filled"
|
|
||||||
disabled={isLoading}
|
|
||||||
{...form.getInputProps("password")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button type="submit" fullWidth mt="md" loading={isLoading}>
|
|
||||||
{t("Sign in with LDAP")}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
import { Button, Group, Text, Modal, TextInput } from "@mantine/core";
|
import { Button, Group, Text, Modal, TextInput } from "@mantine/core";
|
||||||
import { z } from "zod/v4";
|
import * as z from "zod";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm, zodResolver } from "@mantine/form";
|
||||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getSubdomainHost } from "@/lib/config.ts";
|
import { getSubdomainHost } from "@/lib/config.ts";
|
||||||
import { IWorkspace } from "@/features/workspace/types/workspace.types.ts";
|
import { IWorkspace } from "@/features/workspace/types/workspace.types.ts";
|
||||||
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
||||||
import { getHostnameUrl } from "@/ee/utils.ts";
|
import { getHostnameUrl } from "@/ee/utils.ts";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai/index";
|
||||||
import {
|
import {
|
||||||
currentUserAtom,
|
currentUserAtom,
|
||||||
workspaceAtom,
|
workspaceAtom,
|
||||||
@@ -67,7 +66,7 @@ function ChangeHostnameForm({ onClose }: ChangeHostnameFormProps) {
|
|||||||
const [currentUser, setCurrentUser] = useAtom(currentUserAtom);
|
const [currentUser, setCurrentUser] = useAtom(currentUserAtom);
|
||||||
|
|
||||||
const form = useForm<FormValues>({
|
const form = useForm<FormValues>({
|
||||||
validate: zod4Resolver(formSchema),
|
validate: zodResolver(formSchema),
|
||||||
initialValues: {
|
initialValues: {
|
||||||
hostname: currentUser?.workspace?.hostname,
|
hostname: currentUser?.workspace?.hostname,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { usePostHog } from "posthog-js/react";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useAtom } from "jotai";
|
|
||||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
|
|
||||||
|
|
||||||
export function PosthogUser() {
|
|
||||||
const posthog = usePostHog();
|
|
||||||
const [currentUser] = useAtom(currentUserAtom);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (currentUser) {
|
|
||||||
const user = currentUser?.user;
|
|
||||||
const workspace = currentUser?.workspace;
|
|
||||||
if (!user || !workspace) return;
|
|
||||||
|
|
||||||
posthog?.identify(user.id, {
|
|
||||||
name: user.name,
|
|
||||||
email: user.email,
|
|
||||||
workspaceId: user.workspaceId,
|
|
||||||
workspaceHostname: workspace.hostname,
|
|
||||||
lastActiveAt: new Date().toISOString(),
|
|
||||||
createdAt: user.createdAt,
|
|
||||||
source: "docmost-app",
|
|
||||||
});
|
|
||||||
posthog?.group("workspace", workspace.id, {
|
|
||||||
name: workspace.name,
|
|
||||||
hostname: workspace.hostname,
|
|
||||||
plan: workspace?.plan,
|
|
||||||
status: workspace.status,
|
|
||||||
isOnTrial: !!workspace.trialEndAt,
|
|
||||||
hasStripeCustomerId: !!workspace.stripeCustomerId,
|
|
||||||
memberCount: workspace.memberCount,
|
|
||||||
lastActiveAt: new Date().toISOString(),
|
|
||||||
createdAt: workspace.createdAt,
|
|
||||||
source: "docmost-app",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [posthog, currentUser]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@@ -1,62 +1,29 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { useWorkspacePublicDataQuery } from "@/features/workspace/queries/workspace-query.ts";
|
import { useWorkspacePublicDataQuery } from "@/features/workspace/queries/workspace-query.ts";
|
||||||
import { Button, Divider, Stack } from "@mantine/core";
|
import { Button, Divider, Stack } from "@mantine/core";
|
||||||
import { IconLock, IconServer } from "@tabler/icons-react";
|
import { IconLock } from "@tabler/icons-react";
|
||||||
import { IAuthProvider } from "@/ee/security/types/security.types.ts";
|
import { IAuthProvider } from "@/ee/security/types/security.types.ts";
|
||||||
import { buildSsoLoginUrl } from "@/ee/security/sso.utils.ts";
|
import { buildSsoLoginUrl } from "@/ee/security/sso.utils.ts";
|
||||||
import { SSO_PROVIDER } from "@/ee/security/contants.ts";
|
import { SSO_PROVIDER } from "@/ee/security/contants.ts";
|
||||||
import { GoogleIcon } from "@/components/icons/google-icon.tsx";
|
import { GoogleIcon } from "@/components/icons/google-icon.tsx";
|
||||||
import { isCloud } from "@/lib/config.ts";
|
import { isCloud } from "@/lib/config.ts";
|
||||||
import { LdapLoginModal } from "@/ee/components/ldap-login-modal.tsx";
|
|
||||||
|
|
||||||
export default function SsoLogin() {
|
export default function SsoLogin() {
|
||||||
const { data, isLoading } = useWorkspacePublicDataQuery();
|
const { data, isLoading } = useWorkspacePublicDataQuery();
|
||||||
const [ldapModalOpened, setLdapModalOpened] = useState(false);
|
|
||||||
const [selectedLdapProvider, setSelectedLdapProvider] = useState<IAuthProvider | null>(null);
|
|
||||||
|
|
||||||
if (!data?.authProviders || data?.authProviders?.length === 0) {
|
if (!data?.authProviders || data?.authProviders?.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSsoLogin = (provider: IAuthProvider) => {
|
const handleSsoLogin = (provider: IAuthProvider) => {
|
||||||
if (provider.type === SSO_PROVIDER.LDAP) {
|
window.location.href = buildSsoLoginUrl({
|
||||||
// Open modal for LDAP instead of redirecting
|
providerId: provider.id,
|
||||||
setSelectedLdapProvider(provider);
|
type: provider.type,
|
||||||
setLdapModalOpened(true);
|
workspaceId: data.id,
|
||||||
} else {
|
});
|
||||||
// Redirect for other SSO providers
|
|
||||||
window.location.href = buildSsoLoginUrl({
|
|
||||||
providerId: provider.id,
|
|
||||||
type: provider.type,
|
|
||||||
workspaceId: data.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProviderIcon = (provider: IAuthProvider) => {
|
|
||||||
if (provider.type === SSO_PROVIDER.GOOGLE) {
|
|
||||||
return <GoogleIcon size={16} />;
|
|
||||||
} else if (provider.type === SSO_PROVIDER.LDAP) {
|
|
||||||
return <IconServer size={16} />;
|
|
||||||
} else {
|
|
||||||
return <IconLock size={16} />;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectedLdapProvider && (
|
|
||||||
<LdapLoginModal
|
|
||||||
opened={ldapModalOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setLdapModalOpened(false);
|
|
||||||
setSelectedLdapProvider(null);
|
|
||||||
}}
|
|
||||||
provider={selectedLdapProvider}
|
|
||||||
workspaceId={data.id}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(isCloud() || data.hasLicenseKey) && (
|
{(isCloud() || data.hasLicenseKey) && (
|
||||||
<>
|
<>
|
||||||
<Stack align="stretch" justify="center" gap="sm">
|
<Stack align="stretch" justify="center" gap="sm">
|
||||||
@@ -64,7 +31,13 @@ export default function SsoLogin() {
|
|||||||
<div key={provider.id}>
|
<div key={provider.id}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleSsoLogin(provider)}
|
onClick={() => handleSsoLogin(provider)}
|
||||||
leftSection={getProviderIcon(provider)}
|
leftSection={
|
||||||
|
provider.type === SSO_PROVIDER.GOOGLE ? (
|
||||||
|
<GoogleIcon size={16} />
|
||||||
|
) : (
|
||||||
|
<IconLock size={16} />
|
||||||
|
)
|
||||||
|
}
|
||||||
variant="default"
|
variant="default"
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import { isCloud } from "@/lib/config";
|
|
||||||
import useLicense from "@/ee/hooks/use-license";
|
|
||||||
import usePlan from "@/ee/hooks/use-plan";
|
|
||||||
|
|
||||||
const useEnterpriseAccess = () => {
|
|
||||||
const { hasLicenseKey } = useLicense();
|
|
||||||
const { isBusiness } = usePlan();
|
|
||||||
|
|
||||||
return (isCloud() && isBusiness) || (!isCloud() && hasLicenseKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useEnterpriseAccess;
|
|
||||||
@@ -2,18 +2,14 @@ import { useAtom } from "jotai";
|
|||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||||
import { BillingPlan } from "@/ee/billing/types/billing.types.ts";
|
import { BillingPlan } from "@/ee/billing/types/billing.types.ts";
|
||||||
|
|
||||||
const usePlan = () => {
|
export const usePlan = () => {
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [workspace] = useAtom(workspaceAtom);
|
||||||
|
|
||||||
const isStandard =
|
const isStandard =
|
||||||
typeof workspace?.plan === "string" &&
|
typeof workspace?.plan === "string" &&
|
||||||
workspace?.plan.toLowerCase() === BillingPlan.STANDARD.toLowerCase();
|
workspace?.plan.toLowerCase() === BillingPlan.STANDARD.toLowerCase();
|
||||||
|
|
||||||
const isBusiness =
|
return { isStandard };
|
||||||
typeof workspace?.plan === "string" &&
|
|
||||||
workspace?.plan.toLowerCase() === BillingPlan.BUSINESS.toLowerCase();
|
|
||||||
|
|
||||||
return { isStandard, isBusiness };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default usePlan;
|
export default usePlan;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { z } from "zod/v4";
|
import * as z from "zod";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, Group, Modal, Textarea } from "@mantine/core";
|
import { Button, Group, Modal, Textarea } from "@mantine/core";
|
||||||
import { useForm } from "@mantine/form";
|
import { useForm, zodResolver } from "@mantine/form";
|
||||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useActivateMutation } from "@/ee/licence/queries/license-query.ts";
|
import { useActivateMutation } from "@/ee/licence/queries/license-query.ts";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
@@ -50,7 +49,7 @@ export function ActivateLicenseForm({ onClose }: ActivateLicenseFormProps) {
|
|||||||
const activateLicenseMutation = useActivateMutation();
|
const activateLicenseMutation = useActivateMutation();
|
||||||
|
|
||||||
const form = useForm<FormValues>({
|
const form = useForm<FormValues>({
|
||||||
validate: zod4Resolver(formSchema),
|
validate: zodResolver(formSchema),
|
||||||
initialValues: {
|
initialValues: {
|
||||||
licenseKey: "",
|
licenseKey: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,76 +1,39 @@
|
|||||||
import { Group, List, Stack, Table, Text, ThemeIcon } from "@mantine/core";
|
import { Group, Table, ThemeIcon } from "@mantine/core";
|
||||||
import { IconCheck } from "@tabler/icons-react";
|
import { IconCheck } from "@tabler/icons-react";
|
||||||
|
|
||||||
const enterpriseFeatures = [
|
|
||||||
"SSO (SAML, OIDC, LDAP)",
|
|
||||||
"AI Integration (Search & Assistant)",
|
|
||||||
"Page-level Permissions",
|
|
||||||
"Audit Logs",
|
|
||||||
"API Keys",
|
|
||||||
"MCP Support",
|
|
||||||
"Multi-factor Authentication (2FA)",
|
|
||||||
"Enterprise Controls",
|
|
||||||
"Advanced Search Engine Support",
|
|
||||||
"Full-text Search in Attachments (PDF, DOCX)",
|
|
||||||
"Resolve Comments",
|
|
||||||
"Confluence Import",
|
|
||||||
"DOCX Import",
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function OssDetails() {
|
export default function OssDetails() {
|
||||||
return (
|
return (
|
||||||
<Stack gap="lg">
|
<Table.ScrollContainer minWidth={500} py="md">
|
||||||
<Table.ScrollContainer minWidth={500} py="md">
|
<Table
|
||||||
<Table
|
variant="vertical"
|
||||||
variant="vertical"
|
verticalSpacing="sm"
|
||||||
verticalSpacing="sm"
|
layout="fixed"
|
||||||
layout="fixed"
|
withTableBorder
|
||||||
withTableBorder
|
>
|
||||||
>
|
<Table.Caption>
|
||||||
<Table.Tbody>
|
To unlock enterprise features like SSO, contact sales@docmost.com.
|
||||||
<Table.Tr>
|
</Table.Caption>
|
||||||
<Table.Th w={160}>Edition</Table.Th>
|
<Table.Tbody>
|
||||||
<Table.Td>
|
<Table.Tr>
|
||||||
<Group wrap="nowrap">
|
<Table.Th w={160}>Edition</Table.Th>
|
||||||
Open Source
|
<Table.Td>
|
||||||
<div>
|
<Group wrap="nowrap">
|
||||||
<ThemeIcon
|
Open Source
|
||||||
color="green"
|
<div>
|
||||||
variant="light"
|
<ThemeIcon
|
||||||
size={24}
|
color="green"
|
||||||
radius="xl"
|
variant="light"
|
||||||
>
|
size={24}
|
||||||
<IconCheck size={16} />
|
radius="xl"
|
||||||
</ThemeIcon>
|
>
|
||||||
</div>
|
<IconCheck size={16} />
|
||||||
</Group>
|
</ThemeIcon>
|
||||||
</Table.Td>
|
</div>
|
||||||
</Table.Tr>
|
</Group>
|
||||||
</Table.Tbody>
|
</Table.Td>
|
||||||
</Table>
|
</Table.Tr>
|
||||||
</Table.ScrollContainer>
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
<Stack gap="md">
|
</Table.ScrollContainer>
|
||||||
<Text fw={500}>Upgrade to the Enterprise Edition to unlock:</Text>
|
|
||||||
|
|
||||||
<List
|
|
||||||
spacing={4}
|
|
||||||
size="sm"
|
|
||||||
icon={
|
|
||||||
<ThemeIcon size={20} color={"gray"} radius="xl">
|
|
||||||
<IconCheck size={14} />
|
|
||||||
</ThemeIcon>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{enterpriseFeatures.map((feature) => (
|
|
||||||
<List.Item key={feature}>{feature}</List.Item>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
|
|
||||||
<Text size="sm" c="dimmed">
|
|
||||||
Contact <a href="mailto:sales@docmost.com?subject=Enterprise%20License%20Inquiry">sales@docmost.com </a> to purchase an enterprise license.
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user