diff --git a/.dockerignore b/.dockerignore index 6528bce76..f828e1f65 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ -node_modules -.git -dist +**/node_modules +**/.git +**/dist /data -.env* -.nx +**/.env* +**/.nx diff --git a/.env.example b/.env.example index e97dacccb..6c5756fad 100644 --- a/.env.example +++ b/.env.example @@ -22,7 +22,6 @@ AWS_S3_ENDPOINT= AWS_S3_FORCE_PATH_STYLE= # Azure Blob Storage driver config -STORAGE_DRIVER=azure AZURE_STORAGE_ACCOUNT_NAME= AZURE_STORAGE_ACCOUNT_KEY= AZURE_STORAGE_CONTAINER= diff --git a/.gitignore b/.gitignore index 862c9e2c8..883b23ffb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ .env.prod data # compiled output -/dist +dist /node_modules # Logs diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 9bf9395dd..000000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -shamefully-hoist = true diff --git a/Dockerfile b/Dockerfile index d665e254b..242532634 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM node:22-slim AS base +FROM node:26-slim AS base LABEL org.opencontainers.image.source="https://github.com/docmost/docmost" -RUN npm install -g pnpm@10.4.0 +RUN npm install -g pnpm@11.15.1 FROM base AS builder @@ -28,11 +28,12 @@ COPY --from=builder /app/apps/server/package.json /app/apps/server/package.json # Copy packages COPY --from=builder /app/packages/editor-ext/dist /app/packages/editor-ext/dist COPY --from=builder /app/packages/editor-ext/package.json /app/packages/editor-ext/package.json +COPY --from=builder /app/packages/base-formula/dist /app/packages/base-formula/dist +COPY --from=builder /app/packages/base-formula/package.json /app/packages/base-formula/package.json # Copy root package files COPY --from=builder /app/package.json /app/package.json COPY --from=builder /app/pnpm*.yaml /app/ -COPY --from=builder /app/.npmrc /app/.npmrc # Copy patches COPY --from=builder /app/patches /app/patches diff --git a/apps/client/package.json b/apps/client/package.json index c938bc448..4e00721eb 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,7 +1,7 @@ { "name": "client", "private": true, - "version": "0.90.0", + "version": "0.95.0", "scripts": { "dev": "vite", "build": "tsc && vite build", @@ -18,47 +18,50 @@ "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0", "@atlaskit/pragmatic-drag-and-drop-live-region": "1.3.4", "@casl/react": "5.0.1", + "@docmost/base-formula": "workspace:*", "@docmost/editor-ext": "workspace:*", "@excalidraw/excalidraw": "0.18.0-3a5ef40", - "@mantine/core": "8.3.18", - "@mantine/dates": "8.3.18", - "@mantine/form": "8.3.18", - "@mantine/hooks": "8.3.18", - "@mantine/modals": "8.3.18", - "@mantine/notifications": "8.3.18", - "@mantine/spotlight": "8.3.18", + "@mantine/core": "9.3.2", + "@mantine/dates": "9.3.2", + "@mantine/form": "9.3.2", + "@mantine/hooks": "9.3.2", + "@mantine/modals": "9.3.2", + "@mantine/notifications": "9.3.2", + "@mantine/spotlight": "9.3.2", "@slidoapp/emoji-mart": "5.8.7", "@slidoapp/emoji-mart-data": "1.2.4", "@slidoapp/emoji-mart-react": "1.1.5", "@tabler/icons-react": "3.40.0", "@tanstack/react-query": "5.90.17", - "@tanstack/react-virtual": "3.13.24", + "@tanstack/react-table": "8.21.3", + "@tanstack/react-virtual": "3.14.3", "alfaaz": "1.1.0", - "axios": "1.16.0", + "axios": "1.18.1", "blueimp-load-image": "5.16.0", "clsx": "2.1.1", "file-saver": "2.0.5", "highlightjs-sap-abap": "0.3.0", "i18next": "25.10.1", "i18next-http-backend": "3.0.6", - "jotai": "2.18.1", + "jotai": "2.20.1", "jotai-optics": "0.4.0", - "js-cookie": "3.0.5", + "js-cookie": "3.0.7", "jwt-decode": "4.0.0", "katex": "0.16.40", "lowlight": "3.3.0", "mantine-form-zod-resolver": "1.3.0", "mermaid": "11.15.0", "mitt": "3.0.1", - "posthog-js": "1.372.2", - "react": "18.3.1", + "nanoid": "3.3.8", + "posthog-js": "1.391.2", + "react": "19.2.7", "react-clear-modal": "^2.0.18", - "react-dom": "^18.3.1", + "react-dom": "19.2.7", "react-drawio": "1.0.7", "react-error-boundary": "6.1.1", "react-helmet-async": "3.0.0", "react-i18next": "16.5.8", - "react-router-dom": "7.13.1", + "react-router-dom": "7.18.2", "semver": "7.7.4", "socket.io-client": "4.8.3", "zod": "4.3.6" @@ -73,8 +76,8 @@ "@types/js-cookie": "3.0.6", "@types/katex": "0.16.8", "@types/node": "22.19.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", "@vitejs/plugin-react": "6.0.1", "eslint": "9.28.0", "eslint-plugin-react": "7.37.5", @@ -83,13 +86,13 @@ "globals": "15.13.0", "jsdom": "25.0.0", "optics-ts": "2.4.1", - "postcss": "8.5.14", + "postcss": "8.5.25", "postcss-preset-mantine": "1.18.0", "postcss-simple-vars": "7.0.1", "prettier": "3.8.1", "typescript": "5.9.3", "typescript-eslint": "8.57.1", - "vite": "8.0.5", + "vite": "8.0.16", "vitest": "4.1.6" } } diff --git a/apps/client/public/locales/de-DE/translation.json b/apps/client/public/locales/de-DE/translation.json index 0368ad429..f067ecc27 100644 --- a/apps/client/public/locales/de-DE/translation.json +++ b/apps/client/public/locales/de-DE/translation.json @@ -41,6 +41,8 @@ "Dark": "Dunkel", "Date": "Datum", "Delete": "Löschen", + "Remove from page": "Von Seite entfernen", + "Base options": "Basisoptionen", "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.", "Description": "Beschreibung", @@ -76,6 +78,24 @@ "Failed to import pages": "Import der Seiten fehlgeschlagen", "Failed to load page. An error occurred.": "Seite konnte nicht geladen werden. Es ist ein Fehler aufgetreten.", "Failed to update data": "Aktualisierung der Daten fehlgeschlagen", + "Failed to create base": "Basis konnte nicht erstellt werden", + "Failed to update base": "Basis konnte nicht aktualisiert werden", + "Failed to delete base": "Basis konnte nicht gelöscht werden", + "Failed to create property": "Eigenschaft konnte nicht erstellt werden", + "Failed to update property": "Eigenschaft konnte nicht aktualisiert werden", + "Failed to delete property": "Eigenschaft konnte nicht gelöscht werden", + "Failed to reorder property": "Eigenschaft konnte nicht neu angeordnet werden", + "Failed to create view": "Ansicht konnte nicht erstellt werden", + "Failed to update view": "Ansicht konnte nicht aktualisiert werden", + "Failed to delete view": "Ansicht konnte nicht gelöscht werden", + "Failed to create row": "Zeile konnte nicht erstellt werden", + "Failed to update row": "Zeile konnte nicht aktualisiert werden", + "Failed to delete row": "Zeile konnte nicht gelöscht werden", + "Failed to delete rows": "Zeilen konnten nicht gelöscht werden", + "Failed to reorder row": "Zeile konnte nicht neu angeordnet werden", + "Failed to move card": "Karte konnte nicht verschoben werden", + "Failed to add card": "Karte konnte nicht hinzugefügt werden", + "Failed to export CSV": "CSV konnte nicht exportiert werden", "Favorite spaces": "Favorisierte Bereiche", "Favorite spaces appear here": "Favorisierte Bereiche werden hier angezeigt", "Favorites": "Favoriten", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Mermaid-Diagramm einfügen", "Insert and design Drawio diagrams": "Drawio-Diagramme einfügen und gestalten", "Insert current date": "Aktuelles Datum einfügen", + "Time": "Uhrzeit", + "Insert current time": "Aktuelle Uhrzeit einfügen", "Draw and sketch excalidraw diagrams": "Excalidraw-Diagramme zeichnen und skizzieren", "Multiple": "Mehrfach", "Turn into": "In verwandeln", @@ -424,6 +446,7 @@ "Names do not match": "Namen stimmen nicht überein", "Today, {{time}}": "Heute, {{time}}", "Yesterday, {{time}}": "Gestern, {{time}}", + "now": "jetzt", "Space created successfully": "Bereich erfolgreich erstellt", "Space updated successfully": "Bereich erfolgreich aktualisiert", "Space deleted successfully": "Bereich erfolgreich gelöscht", @@ -596,6 +619,8 @@ "Deleted by": "Gelöscht von", "Deleted at": "Gelöscht am", "Preview": "Vorschau", + "Base preview unavailable": "Basisvorschau nicht verfügbar", + "Restore this base to view its contents.": "Stelle diese Basis wieder her, um ihren Inhalt anzuzeigen.", "Subpages": "Unterseiten", "Failed to load subpages": "Unterseiten konnten nicht geladen werden", "No subpages": "Keine Unterseiten", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Sind Sie sicher, dass Sie diese Vorlage löschen möchten?", "Template scope updated": "Vorlagenbereich aktualisiert", "Choose which space this template belongs to": "Wählen Sie den Bereich aus, zu dem diese Vorlage gehört", + "Only workspace admins can create global templates.": "Nur Workspace-Admins können globale Vorlagen erstellen.", + "You need edit access to this space to create templates.": "Sie benötigen Bearbeitungszugriff auf diesen Space, um Vorlagen zu erstellen.", "Scope": "Bereich", "Select scope": "Bereich auswählen", "Title": "Titel", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Seiten und Bereiche suchen...", "No results found": "Keine Ergebnisse gefunden", "You don't have permission to create pages here": "Sie haben hier keine Berechtigung, Seiten zu erstellen", - "Chat menu": "Chatmenü", + "Chat menu for {{title}}": "Chat-Menü für {{title}}", "API key menu": "API-Schlüssel-Menü", "Jump to comment selection": "Zur Kommentarauswahl springen", "Slash commands": "Slash-Befehle", @@ -1063,7 +1090,7 @@ "Filter": "Filter", "Page title": "Seitentitel", "Page content": "Seiteninhalt", - "Member actions": "Mitgliederaktionen", + "Member actions for {{name}}": "Mitgliederaktionen für {{name}}", "Toggle password visibility": "Passwortsichtbarkeit umschalten", "Send comment": "Kommentar senden", "Token actions": "Token-Aktionen", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} zu Favoriten hinzugefügt", "Removed {{name}} from favorites": "{{name}} aus Favoriten entfernt", "Page menu for {{name}}": "Seitenmenü für {{name}}", - "Create subpage of {{name}}": "Unterseite von {{name}} erstellen" + "Create subpage of {{name}}": "Unterseite von {{name}} erstellen", + "Allow personal spaces": "Persönliche Bereiche erlauben", + "Members can create their own personal space.": "Mitglieder können ihren eigenen persönlichen Bereich erstellen.", + "Toggle allow personal spaces": "Persönliche Bereiche erlauben umschalten", + "Create personal space": "Persönlichen Bereich erstellen", + "Personal space": "Persönlicher Bereich", + "{{name}}'s space": "Bereich von {{name}}", + "Apply": "Anwenden", + "Cells that aren't already a page reference will be cleared.": "Zellen, die noch keine Seitenreferenz sind, werden geleert.", + "Cells that aren't a valid URL will be cleared.": "Zellen, die keine gültige URL sind, werden geleert.", + "Cells that aren't a valid email address will be cleared.": "Zellen, die keine gültige E-Mail-Adresse sind, werden geleert.", + "Cells that can't be parsed as a date will be cleared.": "Zellen, die nicht als Datum geparst werden können, werden geleert.", + "Cells that can't be parsed as a number will be cleared.": "Zellen, die nicht als Zahl geparst werden können, werden geleert.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Zellen werden umgewandelt (yes/true/1 werden als ausgewählt markiert; alles andere wird als nicht ausgewählt markiert oder geleert).", + "Cells will be reinterpreted under the new type.": "Zellen werden unter dem neuen Typ neu interpretiert.", + "Cells will be replaced with a comma-separated list of file names.": "Zellen werden durch eine kommagetrennte Liste von Dateinamen ersetzt.", + "Cells will be replaced with a comma-separated list of option names.": "Zellen werden durch eine kommagetrennte Liste von Optionsnamen ersetzt.", + "Cells will be replaced with the option name.": "Zellen werden durch den Optionsnamen ersetzt.", + "Cells will be replaced with the page title.": "Zellen werden durch den Seitentitel ersetzt.", + "Cells will be replaced with the person's name.": "Zellen werden durch den Namen der Person ersetzt.", + "Change type": "Typ ändern", + "Change type to {{label}}?": "Typ in {{label}} ändern?", + "Converting…": "Wird umgewandelt…", + "Existing values become single-item lists. No data is lost.": "Vorhandene Werte werden zu Einzellisten. Es gehen keine Daten verloren.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Nur das erste ausgewählte Element pro Zeile wird beibehalten; der Rest wird verworfen.", + "Previous record": "Vorheriger Datensatz", + "Next record": "Nächster Datensatz", + "Record actions": "Datensatzaktionen", + "Delete record": "Datensatz löschen", + "Delete record?": "Datensatz löschen?", + "This action cannot be undone.": "Diese Aktion kann nicht rückgängig gemacht werden.", + "to navigate": "zum Navigieren", + "to close": "zum Schließen", + "Expand row {{number}}": "Zeile {{number}} erweitern", + "Saving…": "Wird gespeichert…", + "Read-only": "Schreibgeschützt", + "Loading…": "Wird geladen…", + "Updated {{when}}": "Aktualisiert {{when}}", + "Add property": "Eigenschaft hinzufügen", + "Create property": "Eigenschaft erstellen", + "Hide properties": "Eigenschaften ausblenden", + "Find a property type": "Einen Eigenschaftstyp finden", + "Properties": "Eigenschaften", + "A property with this name already exists": "Eine Eigenschaft mit diesem Namen existiert bereits", + "Add card": "Karte hinzufügen", + "Add filter": "Filter hinzufügen", + "Add option": "Option hinzufügen", + "Add sort": "Sortierung hinzufügen", + "Add view": "Ansicht hinzufügen", + "All data in this column will be lost.": "Alle Daten in dieser Spalte gehen verloren.", + "Allow multiple people": "Mehrere Personen zulassen", + "Alphabetize": "Alphabetisch sortieren", + "Are you sure you want to delete": "Sind Sie sicher, dass Sie löschen möchten", + "Ascending": "Aufsteigend", + "Base deleted": "Base gelöscht", + "Base name": "Base-Name", + "Base table": "Base-Tabelle", + "Card properties": "Karteneigenschaften", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Zellen, die das Textlimit überschreiten, werden abgeschnitten und der zusätzliche Inhalt geht dauerhaft verloren.", + "Checkbox": "Kontrollkästchen", + "Checked by default": "Standardmäßig aktiviert", + "Choose a property": "Wählen Sie eine Eigenschaft", + "Clear selection": "Auswahl aufheben", + "Column options": "Spaltenoptionen", + "Comma, period": "Komma, Punkt", + "Complete": "Abgeschlossen", + "Contains": "Enthält", + "Copy link to view": "Link zur Ansicht kopieren", + "Create a status property": "Eine Statuseigenschaft erstellen", + "Created at": "Erstellt am", + "Currency": "Währung", + "Decimal places": "Dezimalstellen", + "Default value": "Standardwert", + "Delete property": "Eigenschaft löschen", + "Delete view": "Ansicht löschen", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "Absteigend", + "Discard": "Verwerfen", + "Doesn't contain": "Enthält nicht", + "Done": "Fertig", + "Edit formula": "Formel bearbeiten", + "Edit property": "Eigenschaft bearbeiten", + "Export CSV": "CSV exportieren", + "Failed to load base": "Base konnte nicht geladen werden", + "False": "Falsch", + "File": "Datei", + "Filter and sort changes are visible only to you": "Änderungen an Filtern und Sortierungen sind nur für Sie sichtbar", + "Filter by": "Filtern nach", + "Formula": "Formel", + "Get started with": "Erste Schritte mit", + "Greater than": "Größer als", + "Group by": "Gruppieren nach", + "Group this board by a select or status property.": "Gruppieren Sie dieses Board nach einer Auswahl- oder Statuseigenschaft.", + "Hide all": "Alle ausblenden", + "Hide group": "Gruppe ausblenden", + "In Progress": "In Bearbeitung", + "In progress": "In Bearbeitung", + "Include time": "Uhrzeit einschließen", + "Insert a kanban board on this page": "Fügen Sie ein Kanban-Board auf dieser Seite ein", + "Insert an inline base on this page": "Fügen Sie eine Inline-Base auf dieser Seite ein", + "Is": "Ist", + "Is after": "Ist nach", + "Is any of": "Ist eines von", + "Is before": "Ist vor", + "Is empty": "Ist leer", + "Is none of": "Ist keines von", + "Is not": "Ist nicht", + "Is not empty": "Ist nicht leer", + "Is on or after": "Ist am oder nach", + "Is on or before": "Ist am oder vor", + "Is within": "Ist innerhalb von", + "Keep editing": "Weiter bearbeiten", + "Last edited at": "Zuletzt bearbeitet am", + "Last edited by": "Zuletzt bearbeitet von", + "Less than": "Kleiner als", + "Link copied to clipboard": "Link in die Zwischenablage kopiert", + "Local": "Lokal", + "Long text": "Langer Text", + "Moved card to {{column}}": "Karte nach {{column}} verschoben", + "Moved column to {{column}}": "Spalte nach {{column}} verschoben", + "Multi-select": "Mehrfachauswahl", + "New row": "Neue Zeile", + "Next month": "Nächster Monat", + "Next week": "Nächste Woche", + "Next year": "Nächstes Jahr", + "No filters applied": "Keine Filter angewendet", + "No match": "Keine Übereinstimmung", + "No options for this property type": "Keine Optionen für diesen Eigenschaftstyp", + "No sorts applied": "Keine Sortierungen angewendet", + "No value": "Kein Wert", + "None": "Keine", + "Not started": "Nicht begonnen", + "Number": "Zahl", + "One month ago": "Vor einem Monat", + "One month from now": "In einem Monat", + "One week ago": "Vor einer Woche", + "One week from now": "In einer Woche", + "Open as page": "Als Seite öffnen", + "Options": "Optionen", + "Past month": "Letzter Monat", + "Past week": "Letzte Woche", + "Past year": "Letztes Jahr", + "Percent": "Prozent", + "Period, comma": "Punkt, Komma", + "Person": "Person", + "Please enter a valid email": "Bitte geben Sie eine gültige E-Mail-Adresse ein", + "Progress": "Fortschritt", + "Property options": "Eigenschaftsoptionen", + "Relative": "Relativ", + "Rename property": "Eigenschaft umbenennen", + "Reset": "Zurücksetzen", + "Save for everyone": "Für alle speichern", + "Select": "Auswahl", + "Select a property": "Eigenschaft auswählen", + "Select all loaded rows": "Alle geladenen Zeilen auswählen", + "Show all": "Alle anzeigen", + "Sort": "Sortieren", + "Sort by": "Sortieren nach", + "Space, comma": "Leerzeichen, Komma", + "Space, period": "Leerzeichen, Punkt", + "This board has no grouping property yet.": "Dieses Board hat noch keine Gruppierungseigenschaft.", + "This month": "Diesen Monat", + "This year": "Dieses Jahr", + "Thousands and decimal separators": "Tausender- und Dezimaltrennzeichen", + "Time format": "Zeitformat", + "To Do": "Zu erledigen", + "Tomorrow": "Morgen", + "True": "Wahr", + "Unsaved changes": "Nicht gespeicherte Änderungen", + "Untitled base": "Unbenannte Base", + "URL": "URL", + "Value": "Wert", + "View updated for everyone": "Ansicht für alle aktualisiert", + "You have unsaved changes. Do you want to discard them?": "Sie haben nicht gespeicherte Änderungen. Möchten Sie sie verwerfen?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index ec40a1967..18c981434 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -41,6 +41,8 @@ "Dark": "Dark", "Date": "Date", "Delete": "Delete", + "Remove from page": "Remove from page", + "Base options": "Base options", "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", @@ -76,6 +78,24 @@ "Failed to import pages": "Failed to import pages", "Failed to load page. An error occurred.": "Failed to load page. An error occurred.", "Failed to update data": "Failed to update data", + "Failed to create base": "Failed to create base", + "Failed to update base": "Failed to update base", + "Failed to delete base": "Failed to delete base", + "Failed to create property": "Failed to create property", + "Failed to update property": "Failed to update property", + "Failed to delete property": "Failed to delete property", + "Failed to reorder property": "Failed to reorder property", + "Failed to create view": "Failed to create view", + "Failed to update view": "Failed to update view", + "Failed to delete view": "Failed to delete view", + "Failed to create row": "Failed to create row", + "Failed to update row": "Failed to update row", + "Failed to delete row": "Failed to delete row", + "Failed to delete rows": "Failed to delete rows", + "Failed to reorder row": "Failed to reorder row", + "Failed to move card": "Failed to move card", + "Failed to add card": "Failed to add card", + "Failed to export CSV": "Failed to export CSV", "Favorite spaces": "Favorite spaces", "Favorite spaces appear here": "Favorite spaces appear here", "Favorites": "Favorites", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Insert mermaid diagram", "Insert and design Drawio diagrams": "Insert and design Drawio diagrams", "Insert current date": "Insert current date", + "Time": "Time", + "Insert current time": "Insert current time", "Draw and sketch excalidraw diagrams": "Draw and sketch excalidraw diagrams", "Multiple": "Multiple", "Turn into": "Turn into", @@ -424,6 +446,7 @@ "Names do not match": "Names do not match", "Today, {{time}}": "Today, {{time}}", "Yesterday, {{time}}": "Yesterday, {{time}}", + "now": "now", "Space created successfully": "Space created successfully", "Space updated successfully": "Space updated successfully", "Space deleted successfully": "Space deleted successfully", @@ -596,6 +619,8 @@ "Deleted by": "Deleted by", "Deleted at": "Deleted at", "Preview": "Preview", + "Base preview unavailable": "Base preview unavailable", + "Restore this base to view its contents.": "Restore this base to view its contents.", "Subpages": "Subpages", "Failed to load subpages": "Failed to load subpages", "No subpages": "No subpages", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Are you sure you want to delete this template?", "Template scope updated": "Template scope updated", "Choose which space this template belongs to": "Choose which space this template belongs to", + "Only workspace admins can create global templates.": "Only workspace admins can create global templates.", + "You need edit access to this space to create templates.": "You need edit access to this space to create templates.", "Scope": "Scope", "Select scope": "Select scope", "Title": "Title", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Search pages and spaces...", "No results found": "No results found", "You don't have permission to create pages here": "You don't have permission to create pages here", - "Chat menu": "Chat menu", + "Chat menu for {{title}}": "Chat menu for {{title}}", "API key menu": "API key menu", "Jump to comment selection": "Jump to comment selection", "Slash commands": "Slash commands", @@ -1063,7 +1090,7 @@ "Filter": "Filter", "Page title": "Page title", "Page content": "Page content", - "Member actions": "Member actions", + "Member actions for {{name}}": "Member actions for {{name}}", "Toggle password visibility": "Toggle password visibility", "Send comment": "Send comment", "Token actions": "Token actions", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "Added {{name}} to favorites", "Removed {{name}} from favorites": "Removed {{name}} from favorites", "Page menu for {{name}}": "Page menu for {{name}}", - "Create subpage of {{name}}": "Create subpage of {{name}}" + "Create subpage of {{name}}": "Create subpage of {{name}}", + "Allow personal spaces": "Allow personal spaces", + "Members can create their own personal space.": "Members can create their own personal space.", + "Toggle allow personal spaces": "Toggle allow personal spaces", + "Create personal space": "Create personal space", + "Personal space": "Personal space", + "{{name}}'s space": "{{name}}'s space", + "Apply": "Apply", + "Cells that aren't already a page reference will be cleared.": "Cells that aren't already a page reference will be cleared.", + "Cells that aren't a valid URL will be cleared.": "Cells that aren't a valid URL will be cleared.", + "Cells that aren't a valid email address will be cleared.": "Cells that aren't a valid email address will be cleared.", + "Cells that can't be parsed as a date will be cleared.": "Cells that can't be parsed as a date will be cleared.", + "Cells that can't be parsed as a number will be cleared.": "Cells that can't be parsed as a number will be cleared.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).", + "Cells will be reinterpreted under the new type.": "Cells will be reinterpreted under the new type.", + "Cells will be replaced with a comma-separated list of file names.": "Cells will be replaced with a comma-separated list of file names.", + "Cells will be replaced with a comma-separated list of option names.": "Cells will be replaced with a comma-separated list of option names.", + "Cells will be replaced with the option name.": "Cells will be replaced with the option name.", + "Cells will be replaced with the page title.": "Cells will be replaced with the page title.", + "Cells will be replaced with the person's name.": "Cells will be replaced with the person's name.", + "Change type": "Change type", + "Change type to {{label}}?": "Change type to {{label}}?", + "Converting…": "Converting…", + "Existing values become single-item lists. No data is lost.": "Existing values become single-item lists. No data is lost.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Only the first selected item per row will be kept; the rest will be discarded.", + "Previous record": "Previous record", + "Next record": "Next record", + "Record actions": "Record actions", + "Delete record": "Delete record", + "Delete record?": "Delete record?", + "This action cannot be undone.": "This action cannot be undone.", + "to navigate": "to navigate", + "to close": "to close", + "Expand row {{number}}": "Expand row {{number}}", + "Saving…": "Saving…", + "Read-only": "Read-only", + "Loading…": "Loading…", + "Updated {{when}}": "Updated {{when}}", + "Add property": "Add property", + "Create property": "Create property", + "Hide properties": "Hide properties", + "Find a property type": "Find a property type", + "Properties": "Properties", + "A property with this name already exists": "A property with this name already exists", + "Add card": "Add card", + "Add filter": "Add filter", + "Add option": "Add option", + "Add sort": "Add sort", + "Add view": "Add view", + "All data in this column will be lost.": "All data in this column will be lost.", + "Allow multiple people": "Allow multiple people", + "Alphabetize": "Alphabetize", + "Are you sure you want to delete": "Are you sure you want to delete", + "Ascending": "Ascending", + "Base deleted": "Base deleted", + "Base name": "Base name", + "Base table": "Base table", + "Card properties": "Card properties", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Cells longer than the Text limit will be truncated and the extra content permanently lost.", + "Checkbox": "Checkbox", + "Checked by default": "Checked by default", + "Choose a property": "Choose a property", + "Clear selection": "Clear selection", + "Column options": "Column options", + "Comma, period": "Comma, period", + "Complete": "Complete", + "Contains": "Contains", + "Copy link to view": "Copy link to view", + "Create a status property": "Create a status property", + "Created at": "Created at", + "Currency": "Currency", + "Decimal places": "Decimal places", + "Default value": "Default value", + "Delete property": "Delete property", + "Delete view": "Delete view", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "Descending", + "Discard": "Discard", + "Doesn't contain": "Doesn't contain", + "Done": "Done", + "Edit formula": "Edit formula", + "Edit property": "Edit property", + "Export CSV": "Export CSV", + "Failed to load base": "Failed to load base", + "False": "False", + "File": "File", + "Filter and sort changes are visible only to you": "Filter and sort changes are visible only to you", + "Filter by": "Filter by", + "Formula": "Formula", + "Get started with": "Get started with", + "Greater than": "Greater than", + "Group by": "Group by", + "Group this board by a select or status property.": "Group this board by a select or status property.", + "Hide all": "Hide all", + "Hide group": "Hide group", + "In Progress": "In Progress", + "In progress": "In progress", + "Include time": "Include time", + "Insert a kanban board on this page": "Insert a kanban board on this page", + "Insert an inline base on this page": "Insert an inline base on this page", + "Is": "Is", + "Is after": "Is after", + "Is any of": "Is any of", + "Is before": "Is before", + "Is empty": "Is empty", + "Is none of": "Is none of", + "Is not": "Is not", + "Is not empty": "Is not empty", + "Is on or after": "Is on or after", + "Is on or before": "Is on or before", + "Is within": "Is within", + "Keep editing": "Keep editing", + "Last edited at": "Last edited at", + "Last edited by": "Last edited by", + "Less than": "Less than", + "Link copied to clipboard": "Link copied to clipboard", + "Local": "Local", + "Long text": "Long text", + "Moved card to {{column}}": "Moved card to {{column}}", + "Moved column to {{column}}": "Moved column to {{column}}", + "Multi-select": "Multi-select", + "New row": "New row", + "Next month": "Next month", + "Next week": "Next week", + "Next year": "Next year", + "No filters applied": "No filters applied", + "No match": "No match", + "No options for this property type": "No options for this property type", + "No sorts applied": "No sorts applied", + "No value": "No value", + "None": "None", + "Not started": "Not started", + "Number": "Number", + "One month ago": "One month ago", + "One month from now": "One month from now", + "One week ago": "One week ago", + "One week from now": "One week from now", + "Open as page": "Open as page", + "Options": "Options", + "Past month": "Past month", + "Past week": "Past week", + "Past year": "Past year", + "Percent": "Percent", + "Period, comma": "Period, comma", + "Person": "Person", + "Please enter a valid email": "Please enter a valid email", + "Progress": "Progress", + "Property options": "Property options", + "Relative": "Relative", + "Rename property": "Rename property", + "Reset": "Reset", + "Save for everyone": "Save for everyone", + "Select": "Select", + "Select a property": "Select a property", + "Select all loaded rows": "Select all loaded rows", + "Show all": "Show all", + "Sort": "Sort", + "Sort by": "Sort by", + "Space, comma": "Space, comma", + "Space, period": "Space, period", + "This board has no grouping property yet.": "This board has no grouping property yet.", + "This month": "This month", + "This year": "This year", + "Thousands and decimal separators": "Thousands and decimal separators", + "Time format": "Time format", + "To Do": "To Do", + "Tomorrow": "Tomorrow", + "True": "True", + "Unsaved changes": "Unsaved changes", + "Untitled base": "Untitled base", + "URL": "URL", + "Value": "Value", + "View updated for everyone": "View updated for everyone", + "You have unsaved changes. Do you want to discard them?": "You have unsaved changes. Do you want to discard them?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/es-ES/translation.json b/apps/client/public/locales/es-ES/translation.json index 131977738..fd834a2c6 100644 --- a/apps/client/public/locales/es-ES/translation.json +++ b/apps/client/public/locales/es-ES/translation.json @@ -41,6 +41,8 @@ "Dark": "Oscuro", "Date": "Fecha", "Delete": "Eliminar", + "Remove from page": "Quitar de la página", + "Base options": "Opciones de la base", "Delete group": "Eliminar grupo", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "¿Está seguro de que desea eliminar esta página? Esto eliminará sus dependientes y el historial de la página. Esta acción es irreversible.", "Description": "Descripción", @@ -76,6 +78,24 @@ "Failed to import pages": "No se pudieron importar las páginas", "Failed to load page. An error occurred.": "Error al cargar la página. Se produjo un error.", "Failed to update data": "No se pudo actualizar los datos", + "Failed to create base": "No se pudo crear la base", + "Failed to update base": "No se pudo actualizar la base", + "Failed to delete base": "No se pudo eliminar la base", + "Failed to create property": "No se pudo crear la propiedad", + "Failed to update property": "No se pudo actualizar la propiedad", + "Failed to delete property": "No se pudo eliminar la propiedad", + "Failed to reorder property": "No se pudo reordenar la propiedad", + "Failed to create view": "No se pudo crear la vista", + "Failed to update view": "No se pudo actualizar la vista", + "Failed to delete view": "No se pudo eliminar la vista", + "Failed to create row": "No se pudo crear la fila", + "Failed to update row": "No se pudo actualizar la fila", + "Failed to delete row": "No se pudo eliminar la fila", + "Failed to delete rows": "No se pudieron eliminar las filas", + "Failed to reorder row": "No se pudo reordenar la fila", + "Failed to move card": "No se pudo mover la tarjeta", + "Failed to add card": "No se pudo añadir la tarjeta", + "Failed to export CSV": "No se pudo exportar el CSV", "Favorite spaces": "Espacios favoritos", "Favorite spaces appear here": "Los espacios favoritos aparecen aquí", "Favorites": "Favoritos", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Insertar diagrama Mermaid", "Insert and design Drawio diagrams": "Insertar y diseñar diagramas de Drawio", "Insert current date": "Insertar fecha actual", + "Time": "Hora", + "Insert current time": "Insertar hora actual", "Draw and sketch excalidraw diagrams": "Dibujar y crear bocetos de diagramas de Excalidraw", "Multiple": "Múltiple", "Turn into": "Convertir en", @@ -424,6 +446,7 @@ "Names do not match": "Los nombres no coinciden", "Today, {{time}}": "Hoy, {{time}}", "Yesterday, {{time}}": "Ayer, {{time}}", + "now": "ahora", "Space created successfully": "Espacio creado correctamente", "Space updated successfully": "Espacio actualizado correctamente", "Space deleted successfully": "Espacio eliminado correctamente", @@ -596,6 +619,8 @@ "Deleted by": "Eliminado por", "Deleted at": "Eliminado el", "Preview": "Vista previa", + "Base preview unavailable": "Vista previa de la base no disponible", + "Restore this base to view its contents.": "Restaura esta base para ver su contenido.", "Subpages": "Subpáginas", "Failed to load subpages": "No se pudieron cargar las subpáginas", "No subpages": "No hay subpáginas", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "¿Seguro que quieres eliminar esta plantilla?", "Template scope updated": "Alcance de la plantilla actualizado", "Choose which space this template belongs to": "Elige a qué espacio pertenece esta plantilla", + "Only workspace admins can create global templates.": "Solo los administradores del espacio de trabajo pueden crear plantillas globales.", + "You need edit access to this space to create templates.": "Necesitas acceso de edición a este espacio para crear plantillas.", "Scope": "Alcance", "Select scope": "Seleccionar alcance", "Title": "Título", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Buscar páginas y espacios...", "No results found": "No se encontraron resultados", "You don't have permission to create pages here": "No tienes permiso para crear páginas aquí", - "Chat menu": "Menú del chat", + "Chat menu for {{title}}": "Menú del chat de {{title}}", "API key menu": "Menú de la clave API", "Jump to comment selection": "Ir a la selección de comentarios", "Slash commands": "Comandos de barra", @@ -1063,7 +1090,7 @@ "Filter": "Filtrar", "Page title": "Título de la página", "Page content": "Contenido de la página", - "Member actions": "Acciones de miembro", + "Member actions for {{name}}": "Acciones de miembro para {{name}}", "Toggle password visibility": "Alternar visibilidad de la contraseña", "Send comment": "Enviar comentario", "Token actions": "Acciones de token", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "Se agregó {{name}} a favoritos", "Removed {{name}} from favorites": "Se quitó {{name}} de favoritos", "Page menu for {{name}}": "Menú de página para {{name}}", - "Create subpage of {{name}}": "Crear subpágina de {{name}}" + "Create subpage of {{name}}": "Crear subpágina de {{name}}", + "Allow personal spaces": "Permitir espacios personales", + "Members can create their own personal space.": "Los miembros pueden crear su propio espacio personal.", + "Toggle allow personal spaces": "Alternar permitir espacios personales", + "Create personal space": "Crear espacio personal", + "Personal space": "Espacio personal", + "{{name}}'s space": "Espacio de {{name}}", + "Apply": "Aplicar", + "Cells that aren't already a page reference will be cleared.": "Las celdas que aún no sean una referencia de página se borrarán.", + "Cells that aren't a valid URL will be cleared.": "Las celdas que no sean una URL válida se borrarán.", + "Cells that aren't a valid email address will be cleared.": "Las celdas que no sean una dirección de correo electrónico válida se borrarán.", + "Cells that can't be parsed as a date will be cleared.": "Las celdas que no puedan interpretarse como una fecha se borrarán.", + "Cells that can't be parsed as a number will be cleared.": "Las celdas que no puedan interpretarse como un número se borrarán.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Las celdas se convertirán de forma forzada (yes/true/1 pasarán a estar marcadas; todo lo demás pasará a estar desmarcado o se borrará).", + "Cells will be reinterpreted under the new type.": "Las celdas se reinterpretarán según el nuevo tipo.", + "Cells will be replaced with a comma-separated list of file names.": "Las celdas se reemplazarán por una lista de nombres de archivo separados por comas.", + "Cells will be replaced with a comma-separated list of option names.": "Las celdas se reemplazarán por una lista de nombres de opciones separados por comas.", + "Cells will be replaced with the option name.": "Las celdas se reemplazarán por el nombre de la opción.", + "Cells will be replaced with the page title.": "Las celdas se reemplazarán por el título de la página.", + "Cells will be replaced with the person's name.": "Las celdas se reemplazarán por el nombre de la persona.", + "Change type": "Cambiar tipo", + "Change type to {{label}}?": "¿Cambiar el tipo a {{label}}?", + "Converting…": "Convirtiendo…", + "Existing values become single-item lists. No data is lost.": "Los valores existentes se convierten en listas de un solo elemento. No se pierde ningún dato.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Solo se conservará el primer elemento seleccionado por fila; el resto se descartará.", + "Previous record": "Registro anterior", + "Next record": "Siguiente registro", + "Record actions": "Acciones del registro", + "Delete record": "Eliminar registro", + "Delete record?": "¿Eliminar registro?", + "This action cannot be undone.": "Esta acción no se puede deshacer.", + "to navigate": "para navegar", + "to close": "para cerrar", + "Expand row {{number}}": "Expandir fila {{number}}", + "Saving…": "Guardando…", + "Read-only": "Solo lectura", + "Loading…": "Cargando…", + "Updated {{when}}": "Actualizado {{when}}", + "Add property": "Añadir propiedad", + "Create property": "Crear propiedad", + "Hide properties": "Ocultar propiedades", + "Find a property type": "Buscar un tipo de propiedad", + "Properties": "Propiedades", + "A property with this name already exists": "Ya existe una propiedad con este nombre", + "Add card": "Agregar tarjeta", + "Add filter": "Agregar filtro", + "Add option": "Agregar opción", + "Add sort": "Agregar orden", + "Add view": "Agregar vista", + "All data in this column will be lost.": "Todos los datos de esta columna se perderán.", + "Allow multiple people": "Permitir varias personas", + "Alphabetize": "Ordenar alfabéticamente", + "Are you sure you want to delete": "¿Está seguro de que desea eliminar", + "Ascending": "Ascendente", + "Base deleted": "Base eliminada", + "Base name": "Nombre de la base", + "Base table": "Tabla base", + "Card properties": "Propiedades de la tarjeta", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Las celdas más largas que el límite de texto se truncarán y el contenido adicional se perderá permanentemente.", + "Checkbox": "Casilla de verificación", + "Checked by default": "Marcado por defecto", + "Choose a property": "Seleccione una propiedad", + "Clear selection": "Borrar selección", + "Column options": "Opciones de columna", + "Comma, period": "Coma, punto", + "Complete": "Completo", + "Contains": "Contiene", + "Copy link to view": "Copiar enlace a la vista", + "Create a status property": "Crear una propiedad de estado", + "Created at": "Creado el", + "Currency": "Moneda", + "Decimal places": "Decimales", + "Default value": "Valor predeterminado", + "Delete property": "Eliminar propiedad", + "Delete view": "Eliminar vista", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "Descendente", + "Discard": "Descartar", + "Doesn't contain": "No contiene", + "Done": "Hecho", + "Edit formula": "Editar fórmula", + "Edit property": "Editar propiedad", + "Export CSV": "Exportar CSV", + "Failed to load base": "No se pudo cargar la base", + "False": "Falso", + "File": "Archivo", + "Filter and sort changes are visible only to you": "Los cambios de filtro y ordenación solo son visibles para usted", + "Filter by": "Filtrar por", + "Formula": "Fórmula", + "Get started with": "Comenzar con", + "Greater than": "Mayor que", + "Group by": "Agrupar por", + "Group this board by a select or status property.": "Agrupe este tablero por una propiedad de selección o estado.", + "Hide all": "Ocultar todo", + "Hide group": "Ocultar grupo", + "In Progress": "En curso", + "In progress": "En curso", + "Include time": "Incluir hora", + "Insert a kanban board on this page": "Insertar un tablero kanban en esta página", + "Insert an inline base on this page": "Insertar una base integrada en esta página", + "Is": "Es", + "Is after": "Es posterior a", + "Is any of": "Es cualquiera de", + "Is before": "Es anterior a", + "Is empty": "Está vacío", + "Is none of": "No es ninguno de", + "Is not": "No es", + "Is not empty": "No está vacío", + "Is on or after": "Es en o después de", + "Is on or before": "Es en o antes de", + "Is within": "Está dentro de", + "Keep editing": "Seguir editando", + "Last edited at": "Última edición el", + "Last edited by": "Última edición por", + "Less than": "Menor que", + "Link copied to clipboard": "Enlace copiado al portapapeles", + "Local": "Local", + "Long text": "Texto largo", + "Moved card to {{column}}": "Tarjeta movida a {{column}}", + "Moved column to {{column}}": "Columna movida a {{column}}", + "Multi-select": "Selección múltiple", + "New row": "Nueva fila", + "Next month": "Próximo mes", + "Next week": "Próxima semana", + "Next year": "Próximo año", + "No filters applied": "No hay filtros aplicados", + "No match": "Sin coincidencias", + "No options for this property type": "No hay opciones para este tipo de propiedad", + "No sorts applied": "No hay ordenaciones aplicadas", + "No value": "Sin valor", + "None": "Ninguno", + "Not started": "No iniciado", + "Number": "Número", + "One month ago": "Hace un mes", + "One month from now": "Dentro de un mes", + "One week ago": "Hace una semana", + "One week from now": "Dentro de una semana", + "Open as page": "Abrir como página", + "Options": "Opciones", + "Past month": "Último mes", + "Past week": "Última semana", + "Past year": "Último año", + "Percent": "Porcentaje", + "Period, comma": "Punto, coma", + "Person": "Persona", + "Please enter a valid email": "Por favor, introduzca un correo electrónico válido", + "Progress": "Progreso", + "Property options": "Opciones de propiedad", + "Relative": "Relativo", + "Rename property": "Renombrar propiedad", + "Reset": "Restablecer", + "Save for everyone": "Guardar para todos", + "Select": "Selección", + "Select a property": "Seleccionar una propiedad", + "Select all loaded rows": "Seleccionar todas las filas cargadas", + "Show all": "Mostrar todo", + "Sort": "Ordenar", + "Sort by": "Ordenar por", + "Space, comma": "Espacio, coma", + "Space, period": "Espacio, punto", + "This board has no grouping property yet.": "Este tablero aún no tiene una propiedad de agrupación.", + "This month": "Este mes", + "This year": "Este año", + "Thousands and decimal separators": "Separadores de miles y decimales", + "Time format": "Formato de hora", + "To Do": "Por hacer", + "Tomorrow": "Mañana", + "True": "Verdadero", + "Unsaved changes": "Cambios no guardados", + "Untitled base": "Base sin título", + "URL": "URL", + "Value": "Valor", + "View updated for everyone": "Vista actualizada para todos", + "You have unsaved changes. Do you want to discard them?": "Tiene cambios no guardados. ¿Quiere descartarlos?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/fr-FR/translation.json b/apps/client/public/locales/fr-FR/translation.json index 20f354421..04ebbc6ad 100644 --- a/apps/client/public/locales/fr-FR/translation.json +++ b/apps/client/public/locales/fr-FR/translation.json @@ -41,6 +41,8 @@ "Dark": "Sombre", "Date": "Date", "Delete": "Supprimer", + "Remove from page": "Supprimer de la page", + "Base options": "Options de la base", "Delete group": "Supprimer groupe", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Êtes-vous sûr de vouloir supprimer cette page ? Cela supprimera ses enfants et l'historique de la page. Cette action est irréversible.", "Description": "Description", @@ -76,6 +78,24 @@ "Failed to import pages": "Échec de l'importation des pages", "Failed to load page. An error occurred.": "Échec du chargement de la page. Une erreur s'est produite.", "Failed to update data": "Échec de la mise à jour des données", + "Failed to create base": "Échec de la création de la base", + "Failed to update base": "Échec de la mise à jour de la base", + "Failed to delete base": "Échec de la suppression de la base", + "Failed to create property": "Échec de la création de la propriété", + "Failed to update property": "Échec de la mise à jour de la propriété", + "Failed to delete property": "Échec de la suppression de la propriété", + "Failed to reorder property": "Échec de la réorganisation de la propriété", + "Failed to create view": "Échec de la création de la vue", + "Failed to update view": "Échec de la mise à jour de la vue", + "Failed to delete view": "Échec de la suppression de la vue", + "Failed to create row": "Échec de la création de la ligne", + "Failed to update row": "Échec de la mise à jour de la ligne", + "Failed to delete row": "Échec de la suppression de la ligne", + "Failed to delete rows": "Échec de la suppression des lignes", + "Failed to reorder row": "Échec de la réorganisation de la ligne", + "Failed to move card": "Échec du déplacement de la carte", + "Failed to add card": "Échec de l'ajout de la carte", + "Failed to export CSV": "Échec de l'exportation du CSV", "Favorite spaces": "Espaces favoris", "Favorite spaces appear here": "Les espaces favoris apparaissent ici", "Favorites": "Favoris", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Insérer un diagramme Mermaid", "Insert and design Drawio diagrams": "Insérer et concevoir des diagrammes Drawio", "Insert current date": "Insérer la date actuelle", + "Time": "Heure", + "Insert current time": "Insérer l'heure actuelle", "Draw and sketch excalidraw diagrams": "Dessiner et esquisser des diagrammes Excalidraw", "Multiple": "Multiple", "Turn into": "Transformer en", @@ -424,6 +446,7 @@ "Names do not match": "Les noms ne correspondent pas", "Today, {{time}}": "Aujourd’hui, {{time}}", "Yesterday, {{time}}": "Hier, {{time}}", + "now": "maintenant", "Space created successfully": "Espace créé avec succès", "Space updated successfully": "Espace mis à jour avec succès", "Space deleted successfully": "Espace supprimé avec succès", @@ -596,6 +619,8 @@ "Deleted by": "Supprimé par", "Deleted at": "Supprimé le", "Preview": "Aperçu", + "Base preview unavailable": "Aperçu de la base indisponible", + "Restore this base to view its contents.": "Restaurez cette base pour afficher son contenu.", "Subpages": "Sous-pages", "Failed to load subpages": "Échec du chargement des sous-pages", "No subpages": "Aucune sous-page", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Êtes-vous sûr de vouloir supprimer ce modèle ?", "Template scope updated": "Portée du modèle mise à jour", "Choose which space this template belongs to": "Choisissez à quel espace appartient ce modèle", + "Only workspace admins can create global templates.": "Seuls les administrateurs de l’espace de travail peuvent créer des modèles globaux.", + "You need edit access to this space to create templates.": "Vous devez disposer d’un accès en modification à cet espace pour créer des modèles.", "Scope": "Portée", "Select scope": "Sélectionner la portée", "Title": "Titre", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Rechercher des pages et des espaces...", "No results found": "Aucun résultat trouvé", "You don't have permission to create pages here": "Vous n’avez pas l’autorisation de créer des pages ici", - "Chat menu": "Menu du chat", + "Chat menu for {{title}}": "Menu de discussion pour {{title}}", "API key menu": "Menu de la clé API", "Jump to comment selection": "Aller à la sélection de commentaires", "Slash commands": "Commandes slash", @@ -1063,7 +1090,7 @@ "Filter": "Filtrer", "Page title": "Titre de la page", "Page content": "Contenu de la page", - "Member actions": "Actions des membres", + "Member actions for {{name}}": "Actions du membre pour {{name}}", "Toggle password visibility": "Afficher/masquer le mot de passe", "Send comment": "Envoyer le commentaire", "Token actions": "Actions du jeton", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} a été ajouté aux favoris", "Removed {{name}} from favorites": "{{name}} a été retiré des favoris", "Page menu for {{name}}": "Menu de la page pour {{name}}", - "Create subpage of {{name}}": "Créer une sous-page de {{name}}" + "Create subpage of {{name}}": "Créer une sous-page de {{name}}", + "Allow personal spaces": "Autoriser les espaces personnels", + "Members can create their own personal space.": "Les membres peuvent créer leur propre espace personnel.", + "Toggle allow personal spaces": "Activer/désactiver l'autorisation des espaces personnels", + "Create personal space": "Créer un espace personnel", + "Personal space": "Espace personnel", + "{{name}}'s space": "Espace de {{name}}", + "Apply": "Appliquer", + "Cells that aren't already a page reference will be cleared.": "Les cellules qui ne sont pas déjà une référence de page seront effacées.", + "Cells that aren't a valid URL will be cleared.": "Les cellules qui ne sont pas une URL valide seront effacées.", + "Cells that aren't a valid email address will be cleared.": "Les cellules qui ne sont pas une adresse e-mail valide seront effacées.", + "Cells that can't be parsed as a date will be cleared.": "Les cellules qui ne peuvent pas être interprétées comme une date seront effacées.", + "Cells that can't be parsed as a number will be cleared.": "Les cellules qui ne peuvent pas être interprétées comme un nombre seront effacées.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Les cellules seront converties (yes/true/1 deviendront cochées ; tout le reste deviendra décoché ou sera effacé).", + "Cells will be reinterpreted under the new type.": "Les cellules seront réinterprétées selon le nouveau type.", + "Cells will be replaced with a comma-separated list of file names.": "Les cellules seront remplacées par une liste de noms de fichiers séparés par des virgules.", + "Cells will be replaced with a comma-separated list of option names.": "Les cellules seront remplacées par une liste de noms d'options séparés par des virgules.", + "Cells will be replaced with the option name.": "Les cellules seront remplacées par le nom de l'option.", + "Cells will be replaced with the page title.": "Les cellules seront remplacées par le titre de la page.", + "Cells will be replaced with the person's name.": "Les cellules seront remplacées par le nom de la personne.", + "Change type": "Changer le type", + "Change type to {{label}}?": "Changer le type en {{label}} ?", + "Converting…": "Conversion…", + "Existing values become single-item lists. No data is lost.": "Les valeurs existantes deviennent des listes à un seul élément. Aucune donnée n'est perdue.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Seul le premier élément sélectionné par ligne sera conservé ; les autres seront ignorés.", + "Previous record": "Enregistrement précédent", + "Next record": "Enregistrement suivant", + "Record actions": "Actions de l'enregistrement", + "Delete record": "Supprimer l'enregistrement", + "Delete record?": "Supprimer l'enregistrement ?", + "This action cannot be undone.": "Cette action ne peut pas être annulée.", + "to navigate": "pour naviguer", + "to close": "pour fermer", + "Expand row {{number}}": "Développer la ligne {{number}}", + "Saving…": "Enregistrement…", + "Read-only": "Lecture seule", + "Loading…": "Chargement…", + "Updated {{when}}": "Mis à jour {{when}}", + "Add property": "Ajouter une propriété", + "Create property": "Créer une propriété", + "Hide properties": "Masquer les propriétés", + "Find a property type": "Rechercher un type de propriété", + "Properties": "Propriétés", + "A property with this name already exists": "Une propriété portant ce nom existe déjà", + "Add card": "Ajouter une carte", + "Add filter": "Ajouter un filtre", + "Add option": "Ajouter une option", + "Add sort": "Ajouter un tri", + "Add view": "Ajouter une vue", + "All data in this column will be lost.": "Toutes les données de cette colonne seront perdues.", + "Allow multiple people": "Autoriser plusieurs personnes", + "Alphabetize": "Trier par ordre alphabétique", + "Are you sure you want to delete": "Êtes-vous sûr de vouloir supprimer", + "Ascending": "Croissant", + "Base deleted": "Base supprimée", + "Base name": "Nom de la base", + "Base table": "Table de base", + "Card properties": "Propriétés de la carte", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Les cellules dépassant la limite de texte seront tronquées et le contenu supplémentaire sera définitivement perdu.", + "Checkbox": "Case à cocher", + "Checked by default": "Coché par défaut", + "Choose a property": "Choisir une propriété", + "Clear selection": "Effacer la sélection", + "Column options": "Options de la colonne", + "Comma, period": "Virgule, point", + "Complete": "Terminé", + "Contains": "Contient", + "Copy link to view": "Copier le lien vers la vue", + "Create a status property": "Créer une propriété de statut", + "Created at": "Créé le", + "Currency": "Devise", + "Decimal places": "Décimales", + "Default value": "Valeur par défaut", + "Delete property": "Supprimer la propriété", + "Delete view": "Supprimer la vue", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "Décroissant", + "Discard": "Ignorer", + "Doesn't contain": "Ne contient pas", + "Done": "Terminé", + "Edit formula": "Modifier la formule", + "Edit property": "Modifier la propriété", + "Export CSV": "Exporter en CSV", + "Failed to load base": "Échec du chargement de la base", + "False": "Faux", + "File": "Fichier", + "Filter and sort changes are visible only to you": "Les modifications de filtre et de tri ne sont visibles que par vous", + "Filter by": "Filtrer par", + "Formula": "Formule", + "Get started with": "Commencer avec", + "Greater than": "Supérieur à", + "Group by": "Grouper par", + "Group this board by a select or status property.": "Groupez ce tableau par une propriété de sélection ou de statut.", + "Hide all": "Tout masquer", + "Hide group": "Masquer le groupe", + "In Progress": "En cours", + "In progress": "En cours", + "Include time": "Inclure l'heure", + "Insert a kanban board on this page": "Insérer un tableau kanban sur cette page", + "Insert an inline base on this page": "Insérer une base intégrée sur cette page", + "Is": "Est", + "Is after": "Est après", + "Is any of": "Est l'un de", + "Is before": "Est avant", + "Is empty": "Est vide", + "Is none of": "N'est aucun de", + "Is not": "N'est pas", + "Is not empty": "N'est pas vide", + "Is on or after": "Est le ou après le", + "Is on or before": "Est le ou avant le", + "Is within": "Est dans la plage", + "Keep editing": "Continuer la modification", + "Last edited at": "Dernière modification le", + "Last edited by": "Dernière modification par", + "Less than": "Inférieur à", + "Link copied to clipboard": "Lien copié dans le presse-papiers", + "Local": "Local", + "Long text": "Texte long", + "Moved card to {{column}}": "Carte déplacée vers {{column}}", + "Moved column to {{column}}": "Colonne déplacée vers {{column}}", + "Multi-select": "Sélection multiple", + "New row": "Nouvelle ligne", + "Next month": "Le mois prochain", + "Next week": "La semaine prochaine", + "Next year": "L'année prochaine", + "No filters applied": "Aucun filtre appliqué", + "No match": "Aucune correspondance", + "No options for this property type": "Aucune option pour ce type de propriété", + "No sorts applied": "Aucun tri appliqué", + "No value": "Aucune valeur", + "None": "Aucun", + "Not started": "Non commencé", + "Number": "Nombre", + "One month ago": "Il y a un mois", + "One month from now": "Dans un mois", + "One week ago": "Il y a une semaine", + "One week from now": "Dans une semaine", + "Open as page": "Ouvrir comme page", + "Options": "Options", + "Past month": "Le mois dernier", + "Past week": "La semaine dernière", + "Past year": "L'année dernière", + "Percent": "Pourcentage", + "Period, comma": "Point, virgule", + "Person": "Personne", + "Please enter a valid email": "Veuillez entrer une adresse e-mail valide", + "Progress": "Progression", + "Property options": "Options de la propriété", + "Relative": "Relatif", + "Rename property": "Renommer la propriété", + "Reset": "Réinitialiser", + "Save for everyone": "Enregistrer pour tout le monde", + "Select": "Sélection", + "Select a property": "Sélectionner une propriété", + "Select all loaded rows": "Sélectionner toutes les lignes chargées", + "Show all": "Tout afficher", + "Sort": "Trier", + "Sort by": "Trier par", + "Space, comma": "Espace, virgule", + "Space, period": "Espace, point", + "This board has no grouping property yet.": "Ce tableau n'a pas encore de propriété de groupement.", + "This month": "Ce mois-ci", + "This year": "Cette année", + "Thousands and decimal separators": "Séparateurs des milliers et des décimales", + "Time format": "Format de l'heure", + "To Do": "À faire", + "Tomorrow": "Demain", + "True": "Vrai", + "Unsaved changes": "Modifications non enregistrées", + "Untitled base": "Base sans titre", + "URL": "URL", + "Value": "Valeur", + "View updated for everyone": "Vue mise à jour pour tout le monde", + "You have unsaved changes. Do you want to discard them?": "Vous avez des modifications non enregistrées. Voulez-vous les ignorer ?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/it-IT/translation.json b/apps/client/public/locales/it-IT/translation.json index 441c90f69..e3aaa82ce 100644 --- a/apps/client/public/locales/it-IT/translation.json +++ b/apps/client/public/locales/it-IT/translation.json @@ -41,6 +41,8 @@ "Dark": "Scuro", "Date": "Data", "Delete": "Elimina", + "Remove from page": "Rimuovi dalla pagina", + "Base options": "Opzioni della base", "Delete group": "Elimina gruppo", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Sei sicuro di voler eliminare questa pagina? Verranno cancellate anche le sue sottopagine e la cronologia. Questa azione è irreversibile.", "Description": "Descrizione", @@ -76,6 +78,24 @@ "Failed to import pages": "Impossibile importare le pagine", "Failed to load page. An error occurred.": "Il caricamento della pagina è fallito. Si è verificato un errore.", "Failed to update data": "Impossibile aggiornare i dati", + "Failed to create base": "Impossibile creare la base", + "Failed to update base": "Impossibile aggiornare la base", + "Failed to delete base": "Impossibile eliminare la base", + "Failed to create property": "Impossibile creare la proprietà", + "Failed to update property": "Impossibile aggiornare la proprietà", + "Failed to delete property": "Impossibile eliminare la proprietà", + "Failed to reorder property": "Impossibile riordinare la proprietà", + "Failed to create view": "Impossibile creare la vista", + "Failed to update view": "Impossibile aggiornare la vista", + "Failed to delete view": "Impossibile eliminare la vista", + "Failed to create row": "Impossibile creare la riga", + "Failed to update row": "Impossibile aggiornare la riga", + "Failed to delete row": "Impossibile eliminare la riga", + "Failed to delete rows": "Impossibile eliminare le righe", + "Failed to reorder row": "Impossibile riordinare la riga", + "Failed to move card": "Impossibile spostare la scheda", + "Failed to add card": "Impossibile aggiungere la scheda", + "Failed to export CSV": "Impossibile esportare il CSV", "Favorite spaces": "Spazi preferiti", "Favorite spaces appear here": "Gli spazi preferiti appariranno qui", "Favorites": "Preferiti", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Inserisci diagramma Mermaid", "Insert and design Drawio diagrams": "Inserisci e progetta diagrammi Drawio", "Insert current date": "Inserisci data corrente", + "Time": "Ora", + "Insert current time": "Inserisci ora corrente", "Draw and sketch excalidraw diagrams": "Disegna e abbozza diagrammi Excalidraw", "Multiple": "Multiplo", "Turn into": "Trasforma in", @@ -424,6 +446,7 @@ "Names do not match": "I nomi non corrispondono", "Today, {{time}}": "Oggi, {{time}}", "Yesterday, {{time}}": "Ieri, {{time}}", + "now": "ora", "Space created successfully": "Spazio creato con successo", "Space updated successfully": "Spazio aggiornato con successo", "Space deleted successfully": "Spazio eliminato con successo", @@ -596,6 +619,8 @@ "Deleted by": "Eliminato da", "Deleted at": "Eliminato il", "Preview": "Anteprima", + "Base preview unavailable": "Anteprima della base non disponibile", + "Restore this base to view its contents.": "Ripristina questa base per visualizzarne i contenuti.", "Subpages": "Sottopagine", "Failed to load subpages": "Caricamento delle sottopagine non riuscito", "No subpages": "Nessuna sottopagina", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Sei sicuro di voler eliminare questo modello?", "Template scope updated": "Ambito del modello aggiornato", "Choose which space this template belongs to": "Scegli a quale spazio appartiene questo modello", + "Only workspace admins can create global templates.": "Solo gli amministratori dell'area di lavoro possono creare modelli globali.", + "You need edit access to this space to create templates.": "Hai bisogno dell'accesso in modifica a questo spazio per creare modelli.", "Scope": "Ambito", "Select scope": "Seleziona ambito", "Title": "Titolo", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Cerca pagine e spazi...", "No results found": "Nessun risultato trovato", "You don't have permission to create pages here": "Non hai l'autorizzazione per creare pagine qui", - "Chat menu": "Menu della chat", + "Chat menu for {{title}}": "Menu chat per {{title}}", "API key menu": "Menu della chiave API", "Jump to comment selection": "Vai alla selezione dei commenti", "Slash commands": "Comandi slash", @@ -1063,7 +1090,7 @@ "Filter": "Filtro", "Page title": "Titolo pagina", "Page content": "Contenuto della pagina", - "Member actions": "Azioni membro", + "Member actions for {{name}}": "Azioni membro per {{name}}", "Toggle password visibility": "Attiva/disattiva visibilità password", "Send comment": "Invia commento", "Token actions": "Azioni token", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} aggiunto ai preferiti", "Removed {{name}} from favorites": "{{name}} rimosso dai preferiti", "Page menu for {{name}}": "Menu della pagina per {{name}}", - "Create subpage of {{name}}": "Crea sottopagina di {{name}}" + "Create subpage of {{name}}": "Crea sottopagina di {{name}}", + "Allow personal spaces": "Consenti spazi personali", + "Members can create their own personal space.": "I membri possono creare il proprio spazio personale.", + "Toggle allow personal spaces": "Attiva/disattiva spazi personali", + "Create personal space": "Crea spazio personale", + "Personal space": "Spazio personale", + "{{name}}'s space": "Spazio di {{name}}", + "Apply": "Applica", + "Cells that aren't already a page reference will be cleared.": "Le celle che non sono già un riferimento a una pagina verranno svuotate.", + "Cells that aren't a valid URL will be cleared.": "Le celle che non contengono un URL valido verranno svuotate.", + "Cells that aren't a valid email address will be cleared.": "Le celle che non contengono un indirizzo email valido verranno svuotate.", + "Cells that can't be parsed as a date will be cleared.": "Le celle che non possono essere interpretate come una data verranno svuotate.", + "Cells that can't be parsed as a number will be cleared.": "Le celle che non possono essere interpretate come un numero verranno svuotate.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Le celle verranno convertite forzatamente (yes/true/1 diventeranno selezionate; tutto il resto diventerà non selezionato o verrà svuotato).", + "Cells will be reinterpreted under the new type.": "Le celle verranno reinterpretate con il nuovo tipo.", + "Cells will be replaced with a comma-separated list of file names.": "Le celle verranno sostituite con un elenco di nomi file separati da virgole.", + "Cells will be replaced with a comma-separated list of option names.": "Le celle verranno sostituite con un elenco di nomi di opzioni separati da virgole.", + "Cells will be replaced with the option name.": "Le celle verranno sostituite con il nome dell'opzione.", + "Cells will be replaced with the page title.": "Le celle verranno sostituite con il titolo della pagina.", + "Cells will be replaced with the person's name.": "Le celle verranno sostituite con il nome della persona.", + "Change type": "Cambia tipo", + "Change type to {{label}}?": "Cambiare tipo in {{label}}?", + "Converting…": "Conversione…", + "Existing values become single-item lists. No data is lost.": "I valori esistenti diventano elenchi con un solo elemento. Nessun dato andrà perso.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Verrà mantenuto solo il primo elemento selezionato per riga; gli altri verranno scartati.", + "Previous record": "Record precedente", + "Next record": "Record successivo", + "Record actions": "Azioni record", + "Delete record": "Elimina record", + "Delete record?": "Eliminare il record?", + "This action cannot be undone.": "Questa azione non può essere annullata.", + "to navigate": "per navigare", + "to close": "per chiudere", + "Expand row {{number}}": "Espandi riga {{number}}", + "Saving…": "Salvataggio…", + "Read-only": "Sola lettura", + "Loading…": "Caricamento…", + "Updated {{when}}": "Aggiornato {{when}}", + "Add property": "Aggiungi proprietà", + "Create property": "Crea proprietà", + "Hide properties": "Nascondi proprietà", + "Find a property type": "Trova un tipo di proprietà", + "Properties": "Proprietà", + "A property with this name already exists": "Esiste già una proprietà con questo nome", + "Add card": "Aggiungi scheda", + "Add filter": "Aggiungi filtro", + "Add option": "Aggiungi opzione", + "Add sort": "Aggiungi ordinamento", + "Add view": "Aggiungi vista", + "All data in this column will be lost.": "Tutti i dati in questa colonna andranno persi.", + "Allow multiple people": "Consenti più persone", + "Alphabetize": "Ordina alfabeticamente", + "Are you sure you want to delete": "Sei sicuro di voler eliminare", + "Ascending": "Crescente", + "Base deleted": "Base eliminata", + "Base name": "Nome della base", + "Base table": "Tabella della base", + "Card properties": "Proprietà della scheda", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Le celle più lunghe del limite del testo verranno troncate e il contenuto aggiuntivo andrà perso in modo permanente.", + "Checkbox": "Casella di controllo", + "Checked by default": "Selezionata per impostazione predefinita", + "Choose a property": "Scegli una proprietà", + "Clear selection": "Cancella selezione", + "Column options": "Opzioni della colonna", + "Comma, period": "Virgola, punto", + "Complete": "Completato", + "Contains": "Contiene", + "Copy link to view": "Copia link alla vista", + "Create a status property": "Crea una proprietà di stato", + "Created at": "Creato il", + "Currency": "Valuta", + "Decimal places": "Posizioni decimali", + "Default value": "Valore predefinito", + "Delete property": "Elimina proprietà", + "Delete view": "Elimina vista", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "Decrescente", + "Discard": "Ignora", + "Doesn't contain": "Non contiene", + "Done": "Fatto", + "Edit formula": "Modifica formula", + "Edit property": "Modifica proprietà", + "Export CSV": "Esporta CSV", + "Failed to load base": "Impossibile caricare la base", + "False": "Falso", + "File": "File", + "Filter and sort changes are visible only to you": "Le modifiche a filtri e ordinamenti sono visibili solo a te", + "Filter by": "Filtra per", + "Formula": "Formula", + "Get started with": "Inizia con", + "Greater than": "Maggiore di", + "Group by": "Raggruppa per", + "Group this board by a select or status property.": "Raggruppa questa bacheca per una proprietà di selezione o di stato.", + "Hide all": "Nascondi tutto", + "Hide group": "Nascondi gruppo", + "In Progress": "In corso", + "In progress": "In corso", + "Include time": "Includi ora", + "Insert a kanban board on this page": "Inserisci una bacheca kanban in questa pagina", + "Insert an inline base on this page": "Inserisci una base in linea in questa pagina", + "Is": "È", + "Is after": "È dopo", + "Is any of": "È uno tra", + "Is before": "È prima", + "Is empty": "È vuoto", + "Is none of": "Non è nessuno di", + "Is not": "Non è", + "Is not empty": "Non è vuoto", + "Is on or after": "È il o dopo il", + "Is on or before": "È il o prima del", + "Is within": "È entro", + "Keep editing": "Continua a modificare", + "Last edited at": "Ultima modifica il", + "Last edited by": "Ultima modifica di", + "Less than": "Minore di", + "Link copied to clipboard": "Link copiato negli appunti", + "Local": "Locale", + "Long text": "Testo lungo", + "Moved card to {{column}}": "Scheda spostata in {{column}}", + "Moved column to {{column}}": "Colonna spostata in {{column}}", + "Multi-select": "Selezione multipla", + "New row": "Nuova riga", + "Next month": "Prossimo mese", + "Next week": "Prossima settimana", + "Next year": "Prossimo anno", + "No filters applied": "Nessun filtro applicato", + "No match": "Nessuna corrispondenza", + "No options for this property type": "Nessuna opzione per questo tipo di proprietà", + "No sorts applied": "Nessun ordinamento applicato", + "No value": "Nessun valore", + "None": "Nessuno", + "Not started": "Non iniziato", + "Number": "Numero", + "One month ago": "Un mese fa", + "One month from now": "Tra un mese", + "One week ago": "Una settimana fa", + "One week from now": "Tra una settimana", + "Open as page": "Apri come pagina", + "Options": "Opzioni", + "Past month": "Mese scorso", + "Past week": "Settimana scorsa", + "Past year": "Anno scorso", + "Percent": "Percentuale", + "Period, comma": "Punto, virgola", + "Person": "Persona", + "Please enter a valid email": "Inserisci un indirizzo email valido", + "Progress": "Avanzamento", + "Property options": "Opzioni della proprietà", + "Relative": "Relativo", + "Rename property": "Rinomina proprietà", + "Reset": "Reimposta", + "Save for everyone": "Salva per tutti", + "Select": "Seleziona", + "Select a property": "Seleziona una proprietà", + "Select all loaded rows": "Seleziona tutte le righe caricate", + "Show all": "Mostra tutto", + "Sort": "Ordina", + "Sort by": "Ordina per", + "Space, comma": "Spazio, virgola", + "Space, period": "Spazio, punto", + "This board has no grouping property yet.": "Questa bacheca non ha ancora una proprietà di raggruppamento.", + "This month": "Questo mese", + "This year": "Quest'anno", + "Thousands and decimal separators": "Separatori delle migliaia e dei decimali", + "Time format": "Formato ora", + "To Do": "Da fare", + "Tomorrow": "Domani", + "True": "Vero", + "Unsaved changes": "Modifiche non salvate", + "Untitled base": "Base senza titolo", + "URL": "URL", + "Value": "Valore", + "View updated for everyone": "Vista aggiornata per tutti", + "You have unsaved changes. Do you want to discard them?": "Hai modifiche non salvate. Vuoi ignorarle?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/ja-JP/translation.json b/apps/client/public/locales/ja-JP/translation.json index 492868cf2..e408bfda8 100644 --- a/apps/client/public/locales/ja-JP/translation.json +++ b/apps/client/public/locales/ja-JP/translation.json @@ -41,6 +41,8 @@ "Dark": "ダーク", "Date": "日付", "Delete": "削除", + "Remove from page": "ページから削除", + "Base options": "ベースのオプション", "Delete group": "グループを削除", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "このページを削除してもよろしいですか?子ページとページ履歴も削除されます。この操作は取り消せません。", "Description": "説明", @@ -76,6 +78,24 @@ "Failed to import pages": "ページのインポートに失敗しました", "Failed to load page. An error occurred.": "ページの読み込みに失敗しました。エラーが発生しました。", "Failed to update data": "データの更新に失敗しました", + "Failed to create base": "ベースの作成に失敗しました", + "Failed to update base": "ベースの更新に失敗しました", + "Failed to delete base": "ベースの削除に失敗しました", + "Failed to create property": "プロパティの作成に失敗しました", + "Failed to update property": "プロパティの更新に失敗しました", + "Failed to delete property": "プロパティの削除に失敗しました", + "Failed to reorder property": "プロパティの並べ替えに失敗しました", + "Failed to create view": "ビューの作成に失敗しました", + "Failed to update view": "ビューの更新に失敗しました", + "Failed to delete view": "ビューの削除に失敗しました", + "Failed to create row": "行の作成に失敗しました", + "Failed to update row": "行の更新に失敗しました", + "Failed to delete row": "行の削除に失敗しました", + "Failed to delete rows": "行の削除に失敗しました", + "Failed to reorder row": "行の並べ替えに失敗しました", + "Failed to move card": "カードの移動に失敗しました", + "Failed to add card": "カードの追加に失敗しました", + "Failed to export CSV": "CSV のエクスポートに失敗しました", "Favorite spaces": "お気に入りのスペース", "Favorite spaces appear here": "お気に入りのスペースがここに表示されます", "Favorites": "お気に入り", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Mermaid ダイアグラムを挿入", "Insert and design Drawio diagrams": "Drawio ダイアグラムを挿入して作成", "Insert current date": "現在の日付を挿入", + "Time": "時刻", + "Insert current time": "現在の時刻を挿入", "Draw and sketch excalidraw diagrams": "Excalidraw ダイアグラムを描画・スケッチ", "Multiple": "複数", "Turn into": "変換する", @@ -424,6 +446,7 @@ "Names do not match": "名前が一致しません", "Today, {{time}}": "今日 {{time}}", "Yesterday, {{time}}": "昨日 {{time}}", + "now": "今すぐ", "Space created successfully": "スペースが正常に作成されました", "Space updated successfully": "スペースが正常に更新されました", "Space deleted successfully": "スペースが正常に削除されました", @@ -596,6 +619,8 @@ "Deleted by": "削除者", "Deleted at": "削除日時", "Preview": "プレビュー", + "Base preview unavailable": "ベースのプレビューを利用できません", + "Restore this base to view its contents.": "内容を表示するには、このベースを復元してください。", "Subpages": "サブページ", "Failed to load subpages": "サブページの読み込みに失敗しました", "No subpages": "サブページはありません", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "このテンプレートを削除してもよろしいですか?", "Template scope updated": "テンプレートのスコープを更新しました", "Choose which space this template belongs to": "このテンプレートを所属させるスペースを選択", + "Only workspace admins can create global templates.": "グローバルテンプレートを作成できるのは、ワークスペース管理者のみです。", + "You need edit access to this space to create templates.": "テンプレートを作成するには、このスペースへの編集アクセス権が必要です。", "Scope": "スコープ", "Select scope": "スコープを選択", "Title": "タイトル", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "ページとスペースを検索…", "No results found": "結果が見つかりません", "You don't have permission to create pages here": "ここにページを作成する権限がありません", - "Chat menu": "チャットメニュー", + "Chat menu for {{title}}": "{{title}} のチャットメニュー", "API key menu": "API キーメニュー", "Jump to comment selection": "コメント選択に移動", "Slash commands": "スラッシュコマンド", @@ -1063,7 +1090,7 @@ "Filter": "フィルター", "Page title": "ページタイトル", "Page content": "ページ内容", - "Member actions": "メンバーの操作", + "Member actions for {{name}}": "{{name}} のメンバー操作", "Toggle password visibility": "パスワードの表示を切り替え", "Send comment": "コメントを送信", "Token actions": "トークンの操作", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} をお気に入りに追加しました", "Removed {{name}} from favorites": "{{name}} をお気に入りから削除しました", "Page menu for {{name}}": "{{name}} のページメニュー", - "Create subpage of {{name}}": "{{name}} のサブページを作成" + "Create subpage of {{name}}": "{{name}} のサブページを作成", + "Allow personal spaces": "パーソナルスペースを許可", + "Members can create their own personal space.": "メンバーは自分専用のパーソナルスペースを作成できます。", + "Toggle allow personal spaces": "パーソナルスペースの許可を切り替える", + "Create personal space": "パーソナルスペースを作成", + "Personal space": "パーソナルスペース", + "{{name}}'s space": "{{name}} のスペース", + "Apply": "適用", + "Cells that aren't already a page reference will be cleared.": "すでにページ参照になっているセル以外は消去されます。", + "Cells that aren't a valid URL will be cleared.": "有効な URL ではないセルは消去されます。", + "Cells that aren't a valid email address will be cleared.": "有効なメールアドレスではないセルは消去されます。", + "Cells that can't be parsed as a date will be cleared.": "日付として解析できないセルは消去されます。", + "Cells that can't be parsed as a number will be cleared.": "数値として解析できないセルは消去されます。", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "セルは強制変換されます(yes/true/1 はチェック済みになり、それ以外は未チェックまたは空になります)。", + "Cells will be reinterpreted under the new type.": "セルは新しい型で再解釈されます。", + "Cells will be replaced with a comma-separated list of file names.": "セルは、ファイル名のカンマ区切りリストに置き換えられます。", + "Cells will be replaced with a comma-separated list of option names.": "セルは、オプション名のカンマ区切りリストに置き換えられます。", + "Cells will be replaced with the option name.": "セルはオプション名に置き換えられます。", + "Cells will be replaced with the page title.": "セルはページタイトルに置き換えられます。", + "Cells will be replaced with the person's name.": "セルはその人の名前に置き換えられます。", + "Change type": "型を変更", + "Change type to {{label}}?": "型を {{label}} に変更しますか?", + "Converting…": "変換中…", + "Existing values become single-item lists. No data is lost.": "既存の値は単一項目のリストになります。データは失われません。", + "Only the first selected item per row will be kept; the rest will be discarded.": "各行で最初に選択された項目のみ保持され、残りは破棄されます。", + "Previous record": "前のレコード", + "Next record": "次のレコード", + "Record actions": "レコード操作", + "Delete record": "レコードを削除", + "Delete record?": "レコードを削除しますか?", + "This action cannot be undone.": "この操作は元に戻せません。", + "to navigate": "移動するには", + "to close": "閉じるには", + "Expand row {{number}}": "行 {{number}} を展開", + "Saving…": "保存中…", + "Read-only": "読み取り専用", + "Loading…": "読み込み中…", + "Updated {{when}}": "{{when}} に更新", + "Add property": "プロパティを追加", + "Create property": "プロパティを作成", + "Hide properties": "プロパティを非表示", + "Find a property type": "プロパティの種類を検索", + "Properties": "プロパティ", + "A property with this name already exists": "この名前のプロパティはすでに存在します", + "Add card": "カードを追加", + "Add filter": "フィルターを追加", + "Add option": "オプションを追加", + "Add sort": "並べ替えを追加", + "Add view": "ビューを追加", + "All data in this column will be lost.": "この列内のすべてのデータは失われます。", + "Allow multiple people": "複数のユーザーを許可", + "Alphabetize": "アルファベット順", + "Are you sure you want to delete": "削除してもよろしいですか", + "Ascending": "昇順", + "Base deleted": "ベースを削除しました", + "Base name": "ベース名", + "Base table": "ベーステーブル", + "Card properties": "カードのプロパティ", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "テキストの制限を超える長さのセルは切り詰められ、超過分の内容は完全に失われます。", + "Checkbox": "チェックボックス", + "Checked by default": "デフォルトでチェックを入れる", + "Choose a property": "プロパティを選択", + "Clear selection": "選択をクリア", + "Column options": "列のオプション", + "Comma, period": "カンマ、小数点", + "Complete": "完了", + "Contains": "含む", + "Copy link to view": "ビューへのリンクをコピー", + "Create a status property": "ステータスプロパティを作成", + "Created at": "作成日時", + "Currency": "通貨", + "Decimal places": "小数点以下の桁数", + "Default value": "デフォルト値", + "Delete property": "プロパティを削除", + "Delete view": "ビューを削除", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "降順", + "Discard": "破棄", + "Doesn't contain": "含まない", + "Done": "完了", + "Edit formula": "数式を編集", + "Edit property": "プロパティを編集", + "Export CSV": "CSVをエクスポート", + "Failed to load base": "ベースの読み込みに失敗しました", + "False": "偽", + "File": "ファイル", + "Filter and sort changes are visible only to you": "フィルターと並べ替えの変更は自分にのみ表示されます", + "Filter by": "条件", + "Formula": "数式", + "Get started with": "次から始める", + "Greater than": "より大きい", + "Group by": "グループ化", + "Group this board by a select or status property.": "このボードをセレクトまたはステータスのプロパティでグループ化します。", + "Hide all": "すべて非表示", + "Hide group": "グループを非表示", + "In Progress": "進行中", + "In progress": "進行中", + "Include time": "時刻を含める", + "Insert a kanban board on this page": "このページにカンバンボードを挿入", + "Insert an inline base on this page": "このページにインラインベースを挿入", + "Is": "次に等しい", + "Is after": "次より後", + "Is any of": "次のいずれか", + "Is before": "次より前", + "Is empty": "空である", + "Is none of": "次のいずれでもない", + "Is not": "次に等しくない", + "Is not empty": "空ではない", + "Is on or after": "次以降", + "Is on or before": "次以前", + "Is within": "次の期間内", + "Keep editing": "編集を続ける", + "Last edited at": "最終編集日時", + "Last edited by": "最終編集者", + "Less than": "より小さい", + "Link copied to clipboard": "リンクをクリップボードにコピーしました", + "Local": "ローカル", + "Long text": "長いテキスト", + "Moved card to {{column}}": "カードを{{column}}に移動しました", + "Moved column to {{column}}": "列を{{column}}に移動しました", + "Multi-select": "複数選択", + "New row": "新規行", + "Next month": "来月", + "Next week": "来週", + "Next year": "来年", + "No filters applied": "フィルターは適用されていません", + "No match": "一致なし", + "No options for this property type": "このプロパティタイプにはオプションがありません", + "No sorts applied": "並べ替えは適用されていません", + "No value": "値なし", + "None": "なし", + "Not started": "未着手", + "Number": "数値", + "One month ago": "1か月前", + "One month from now": "1か月後", + "One week ago": "1週間前", + "One week from now": "1週間後", + "Open as page": "ページとして開く", + "Options": "オプション", + "Past month": "先月", + "Past week": "先週", + "Past year": "昨年", + "Percent": "パーセント", + "Period, comma": "小数点、カンマ", + "Person": "ユーザー", + "Please enter a valid email": "有効なメールアドレスを入力してください", + "Progress": "進捗", + "Property options": "プロパティのオプション", + "Relative": "相対", + "Rename property": "プロパティ名を変更", + "Reset": "リセット", + "Save for everyone": "全員に保存", + "Select": "選択", + "Select a property": "プロパティを選択", + "Select all loaded rows": "読み込まれているすべての行を選択", + "Show all": "すべて表示", + "Sort": "並べ替え", + "Sort by": "並べ替え条件", + "Space, comma": "スペース、カンマ", + "Space, period": "スペース、小数点", + "This board has no grouping property yet.": "このボードにはまだグループ化プロパティがありません。", + "This month": "今月", + "This year": "今年", + "Thousands and decimal separators": "桁区切りと小数点区切り", + "Time format": "時刻形式", + "To Do": "To Do", + "Tomorrow": "明日", + "True": "真", + "Unsaved changes": "未保存の変更", + "Untitled base": "無題のベース", + "URL": "URL", + "Value": "値", + "View updated for everyone": "ビューが全員向けに更新されました", + "You have unsaved changes. Do you want to discard them?": "未保存の変更があります。破棄しますか?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/ko-KR/translation.json b/apps/client/public/locales/ko-KR/translation.json index 5847ab19a..fb8e9884a 100644 --- a/apps/client/public/locales/ko-KR/translation.json +++ b/apps/client/public/locales/ko-KR/translation.json @@ -41,6 +41,8 @@ "Dark": "어두운", "Date": "날짜", "Delete": "삭제", + "Remove from page": "페이지에서 제거", + "Base options": "베이스 옵션", "Delete group": "팀 삭제", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "이 페이지를 삭제하시겠습니까? 하위 페이지와 페이지 기록이 모두 삭제됩니다. 이 작업은 되돌릴 수 없습니다.", "Description": "설명", @@ -76,6 +78,24 @@ "Failed to import pages": "페이지 가져오기 실패", "Failed to load page. An error occurred.": "페이지 불러오기 실패. 오류가 발생했습니다.", "Failed to update data": "데이터 갱신 실패", + "Failed to create base": "베이스를 만들지 못했습니다", + "Failed to update base": "베이스를 업데이트하지 못했습니다", + "Failed to delete base": "베이스를 삭제하지 못했습니다", + "Failed to create property": "속성을 만들지 못했습니다", + "Failed to update property": "속성을 업데이트하지 못했습니다", + "Failed to delete property": "속성을 삭제하지 못했습니다", + "Failed to reorder property": "속성 순서를 변경하지 못했습니다", + "Failed to create view": "보기를 만들지 못했습니다", + "Failed to update view": "보기를 업데이트하지 못했습니다", + "Failed to delete view": "보기를 삭제하지 못했습니다", + "Failed to create row": "행을 만들지 못했습니다", + "Failed to update row": "행을 업데이트하지 못했습니다", + "Failed to delete row": "행을 삭제하지 못했습니다", + "Failed to delete rows": "행을 삭제하지 못했습니다", + "Failed to reorder row": "행 순서를 변경하지 못했습니다", + "Failed to move card": "카드를 이동하지 못했습니다", + "Failed to add card": "카드를 추가하지 못했습니다", + "Failed to export CSV": "CSV를 내보내지 못했습니다", "Favorite spaces": "즐겨찾는 스페이스", "Favorite spaces appear here": "즐겨찾는 스페이스가 여기에 표시됩니다", "Favorites": "즐겨찾기", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Mermaid 다이어그램 삽입", "Insert and design Drawio diagrams": "Drawio 다이어그램 삽입 및 편집", "Insert current date": "현재 날짜 삽입", + "Time": "시간", + "Insert current time": "현재 시간 삽입", "Draw and sketch excalidraw diagrams": "Excalidraw 다이어그램 그리기 및 스케치", "Multiple": "다중", "Turn into": "변경하기", @@ -424,6 +446,7 @@ "Names do not match": "이름이 일치하지 않습니다", "Today, {{time}}": "오늘, {{time}}", "Yesterday, {{time}}": "어제, {{time}}", + "now": "지금", "Space created successfully": "스페이스가 성공적으로 생성되었습니다", "Space updated successfully": "스페이스가 성공적으로 업데이트되었습니다", "Space deleted successfully": "스페이스가 성공적으로 삭제되었습니다", @@ -596,6 +619,8 @@ "Deleted by": "삭제한 사람", "Deleted at": "삭제 시간", "Preview": "미리보기", + "Base preview unavailable": "베이스 미리보기를 사용할 수 없음", + "Restore this base to view its contents.": "이 베이스를 복원하여 내용을 보세요.", "Subpages": "하위 페이지", "Failed to load subpages": "하위 페이지를 불러오지 못했습니다", "No subpages": "하위 페이지가 없습니다", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "이 템플릿을 삭제하시겠습니까?", "Template scope updated": "템플릿 범위가 업데이트되었습니다", "Choose which space this template belongs to": "이 템플릿이 속할 스페이스를 선택하세요", + "Only workspace admins can create global templates.": "전역 템플릿은 워크스페이스 관리자만 만들 수 있습니다.", + "You need edit access to this space to create templates.": "템플릿을 만들려면 이 스페이스에 대한 편집 권한이 있어야 합니다.", "Scope": "범위", "Select scope": "범위 선택", "Title": "제목", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "페이지와 스페이스 검색...", "No results found": "결과를 찾을 수 없습니다", "You don't have permission to create pages here": "여기에서 페이지를 만들 권한이 없습니다", - "Chat menu": "채팅 메뉴", + "Chat menu for {{title}}": "{{title}}의 채팅 메뉴", "API key menu": "API 키 메뉴", "Jump to comment selection": "댓글 선택으로 이동", "Slash commands": "슬래시 명령어", @@ -1063,7 +1090,7 @@ "Filter": "필터", "Page title": "페이지 제목", "Page content": "페이지 내용", - "Member actions": "멤버 작업", + "Member actions for {{name}}": "{{name}}에 대한 멤버 작업", "Toggle password visibility": "비밀번호 표시 전환", "Send comment": "댓글 보내기", "Token actions": "토큰 작업", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} 즐겨찾기에 추가됨", "Removed {{name}} from favorites": "{{name}} 즐겨찾기에서 제거됨", "Page menu for {{name}}": "{{name}}의 페이지 메뉴", - "Create subpage of {{name}}": "{{name}}의 하위 페이지 만들기" + "Create subpage of {{name}}": "{{name}}의 하위 페이지 만들기", + "Allow personal spaces": "개인 공간 허용", + "Members can create their own personal space.": "멤버는 자신만의 개인 공간을 만들 수 있습니다.", + "Toggle allow personal spaces": "개인 공간 허용 전환", + "Create personal space": "개인 공간 만들기", + "Personal space": "개인 공간", + "{{name}}'s space": "{{name}}의 공간", + "Apply": "적용", + "Cells that aren't already a page reference will be cleared.": "이미 페이지 참조인 셀이 아닌 경우 지워집니다.", + "Cells that aren't a valid URL will be cleared.": "유효한 URL이 아닌 셀은 지워집니다.", + "Cells that aren't a valid email address will be cleared.": "유효한 이메일 주소가 아닌 셀은 지워집니다.", + "Cells that can't be parsed as a date will be cleared.": "날짜로 해석할 수 없는 셀은 지워집니다.", + "Cells that can't be parsed as a number will be cleared.": "숫자로 해석할 수 없는 셀은 지워집니다.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "셀 값은 강제로 변환됩니다(yes/true/1은 선택됨이 되고, 그 외의 모든 값은 선택 해제되거나 지워집니다).", + "Cells will be reinterpreted under the new type.": "셀은 새 유형에 따라 다시 해석됩니다.", + "Cells will be replaced with a comma-separated list of file names.": "셀은 쉼표로 구분된 파일 이름 목록으로 대체됩니다.", + "Cells will be replaced with a comma-separated list of option names.": "셀은 쉼표로 구분된 옵션 이름 목록으로 대체됩니다.", + "Cells will be replaced with the option name.": "셀은 옵션 이름으로 대체됩니다.", + "Cells will be replaced with the page title.": "셀은 페이지 제목으로 대체됩니다.", + "Cells will be replaced with the person's name.": "셀은 사람 이름으로 대체됩니다.", + "Change type": "유형 변경", + "Change type to {{label}}?": "유형을 {{label}}로 변경할까요?", + "Converting…": "변환 중…", + "Existing values become single-item lists. No data is lost.": "기존 값은 단일 항목 목록이 됩니다. 데이터는 손실되지 않습니다.", + "Only the first selected item per row will be kept; the rest will be discarded.": "각 행에서 처음 선택된 항목만 유지되며 나머지는 삭제됩니다.", + "Previous record": "이전 레코드", + "Next record": "다음 레코드", + "Record actions": "레코드 작업", + "Delete record": "레코드 삭제", + "Delete record?": "레코드를 삭제할까요?", + "This action cannot be undone.": "이 작업은 되돌릴 수 없습니다.", + "to navigate": "탐색하려면", + "to close": "닫으려면", + "Expand row {{number}}": "행 {{number}} 펼치기", + "Saving…": "저장 중…", + "Read-only": "읽기 전용", + "Loading…": "불러오는 중…", + "Updated {{when}}": "{{when}}에 업데이트됨", + "Add property": "속성 추가", + "Create property": "속성 만들기", + "Hide properties": "속성 숨기기", + "Find a property type": "속성 유형 찾기", + "Properties": "속성", + "A property with this name already exists": "이 이름의 속성이 이미 있습니다", + "Add card": "카드 추가", + "Add filter": "필터 추가", + "Add option": "옵션 추가", + "Add sort": "정렬 추가", + "Add view": "보기 추가", + "All data in this column will be lost.": "이 열의 모든 데이터가 손실됩니다.", + "Allow multiple people": "여러 사람 허용", + "Alphabetize": "가나다순", + "Are you sure you want to delete": "삭제하시겠습니까", + "Ascending": "오름차순", + "Base deleted": "베이스가 삭제됨", + "Base name": "베이스 이름", + "Base table": "베이스 테이블", + "Card properties": "카드 속성", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "텍스트 제한보다 긴 셀은 잘리며, 초과된 콘텐츠는 영구적으로 손실됩니다.", + "Checkbox": "체크박스", + "Checked by default": "기본적으로 선택됨", + "Choose a property": "속성 선택", + "Clear selection": "선택 지우기", + "Column options": "열 옵션", + "Comma, period": "쉼표, 마침표", + "Complete": "완료", + "Contains": "포함", + "Copy link to view": "보기 링크 복사", + "Create a status property": "상태 속성 만들기", + "Created at": "작성 시간", + "Currency": "통화", + "Decimal places": "소수 자릿수", + "Default value": "기본값", + "Delete property": "속성 삭제", + "Delete view": "보기 삭제", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "내림차순", + "Discard": "삭제", + "Doesn't contain": "포함하지 않음", + "Done": "완료", + "Edit formula": "수식 편집", + "Edit property": "속성 편집", + "Export CSV": "CSV 내보내기", + "Failed to load base": "베이스를 불러오지 못했습니다", + "False": "거짓", + "File": "파일", + "Filter and sort changes are visible only to you": "필터 및 정렬 변경 사항은 나에게만 표시됩니다", + "Filter by": "필터 기준", + "Formula": "수식", + "Get started with": "시작하기", + "Greater than": "보다 큼", + "Group by": "그룹화 기준", + "Group this board by a select or status property.": "선택 또는 상태 속성으로 이 보드를 그룹화하세요.", + "Hide all": "모두 숨기기", + "Hide group": "그룹 숨기기", + "In Progress": "진행 중", + "In progress": "진행 중", + "Include time": "시간 포함", + "Insert a kanban board on this page": "이 페이지에 칸반 보드 삽입", + "Insert an inline base on this page": "이 페이지에 인라인 베이스 삽입", + "Is": "같음", + "Is after": "이후", + "Is any of": "다음 중 하나와 같음", + "Is before": "이전", + "Is empty": "비어 있음", + "Is none of": "다음 중 어느 것과도 같지 않음", + "Is not": "같지 않음", + "Is not empty": "비어 있지 않음", + "Is on or after": "해당 날짜 또는 이후", + "Is on or before": "해당 날짜 또는 이전", + "Is within": "다음 범위 내", + "Keep editing": "계속 편집", + "Last edited at": "마지막 편집 시간", + "Last edited by": "마지막 편집자", + "Less than": "보다 작음", + "Link copied to clipboard": "링크가 클립보드에 복사됨", + "Local": "로컬", + "Long text": "긴 텍스트", + "Moved card to {{column}}": "카드를 {{column}}(으)로 이동함", + "Moved column to {{column}}": "열을 {{column}}(으)로 이동함", + "Multi-select": "다중 선택", + "New row": "새 행", + "Next month": "다음 달", + "Next week": "다음 주", + "Next year": "내년", + "No filters applied": "적용된 필터 없음", + "No match": "일치하는 항목 없음", + "No options for this property type": "이 속성 유형에는 옵션이 없습니다", + "No sorts applied": "적용된 정렬 없음", + "No value": "값 없음", + "None": "없음", + "Not started": "시작 전", + "Number": "숫자", + "One month ago": "한 달 전", + "One month from now": "한 달 후", + "One week ago": "일주일 전", + "One week from now": "일주일 후", + "Open as page": "페이지로 열기", + "Options": "옵션", + "Past month": "지난달", + "Past week": "지난주", + "Past year": "작년", + "Percent": "백분율", + "Period, comma": "마침표, 쉼표", + "Person": "사람", + "Please enter a valid email": "유효한 이메일을 입력하세요", + "Progress": "진행률", + "Property options": "속성 옵션", + "Relative": "상대값", + "Rename property": "속성 이름 변경", + "Reset": "재설정", + "Save for everyone": "모든 사용자에게 저장", + "Select": "선택", + "Select a property": "속성 선택", + "Select all loaded rows": "불러온 모든 행 선택", + "Show all": "모두 보기", + "Sort": "정렬", + "Sort by": "정렬 기준", + "Space, comma": "공백, 쉼표", + "Space, period": "공백, 마침표", + "This board has no grouping property yet.": "이 보드에는 아직 그룹화 속성이 없습니다.", + "This month": "이번 달", + "This year": "올해", + "Thousands and decimal separators": "천 단위 및 소수 구분 기호", + "Time format": "시간 형식", + "To Do": "할 일", + "Tomorrow": "내일", + "True": "참", + "Unsaved changes": "저장되지 않은 변경 사항", + "Untitled base": "제목 없는 베이스", + "URL": "URL", + "Value": "값", + "View updated for everyone": "보기가 모두에게 업데이트되었습니다", + "You have unsaved changes. Do you want to discard them?": "저장되지 않은 변경 사항이 있습니다. 버리시겠습니까?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/nl-NL/translation.json b/apps/client/public/locales/nl-NL/translation.json index 591c96746..59c1d7a73 100644 --- a/apps/client/public/locales/nl-NL/translation.json +++ b/apps/client/public/locales/nl-NL/translation.json @@ -41,6 +41,8 @@ "Dark": "Donker", "Date": "Datum", "Delete": "Verwijderen", + "Remove from page": "Van pagina verwijderen", + "Base options": "Basisopties", "Delete group": "Groep verwijderen", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Weet u zeker dat u deze pagina wilt verwijderen? Dit zal de subpagina's en paginageschiedenis verwijderen. Deze actie kan niet ongedaan gemaakt worden.", "Description": "Beschrijving", @@ -76,6 +78,24 @@ "Failed to import pages": "Pagina's importeren mislukt", "Failed to load page. An error occurred.": "Laden van pagina mislukt. Er is een fout opgetreden.", "Failed to update data": "Bijwerken van gegevens mislukt", + "Failed to create base": "Kan basis niet aanmaken", + "Failed to update base": "Kan basis niet bijwerken", + "Failed to delete base": "Kan basis niet verwijderen", + "Failed to create property": "Kan eigenschap niet aanmaken", + "Failed to update property": "Kan eigenschap niet bijwerken", + "Failed to delete property": "Kan eigenschap niet verwijderen", + "Failed to reorder property": "Kan eigenschap niet opnieuw ordenen", + "Failed to create view": "Kan weergave niet aanmaken", + "Failed to update view": "Kan weergave niet bijwerken", + "Failed to delete view": "Kan weergave niet verwijderen", + "Failed to create row": "Kan rij niet aanmaken", + "Failed to update row": "Kan rij niet bijwerken", + "Failed to delete row": "Kan rij niet verwijderen", + "Failed to delete rows": "Kan rijen niet verwijderen", + "Failed to reorder row": "Kan rij niet opnieuw ordenen", + "Failed to move card": "Kan kaart niet verplaatsen", + "Failed to add card": "Kan kaart niet toevoegen", + "Failed to export CSV": "Kan CSV niet exporteren", "Favorite spaces": "Favoriete ruimtes", "Favorite spaces appear here": "Favoriete ruimtes verschijnen hier", "Favorites": "Favorieten", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Mermaid-diagram invoegen", "Insert and design Drawio diagrams": "Drawio-diagrammen invoegen en ontwerpen", "Insert current date": "Huidige datum invoegen", + "Time": "Tijd", + "Insert current time": "Huidige tijd invoegen", "Draw and sketch excalidraw diagrams": "Excalidraw-diagrammen tekenen en schetsen", "Multiple": "Meerdere", "Turn into": "Omzetten naar", @@ -424,6 +446,7 @@ "Names do not match": "Namen komen niet overeen", "Today, {{time}}": "Vandaag, {{time}}", "Yesterday, {{time}}": "Gisteren, {{time}}", + "now": "nu", "Space created successfully": "Ruimte succesvol aangemaakt", "Space updated successfully": "Ruimte succesvol bijgewerkt", "Space deleted successfully": "Ruimte succesvol verwijderd", @@ -596,6 +619,8 @@ "Deleted by": "Verwijderd door", "Deleted at": "Verwijderd op", "Preview": "Voorbeeld", + "Base preview unavailable": "Voorbeeld van basis niet beschikbaar", + "Restore this base to view its contents.": "Herstel deze basis om de inhoud te bekijken.", "Subpages": "Subpagina's", "Failed to load subpages": "Subpagina's laden mislukt", "No subpages": "Geen subpagina's", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Weet je zeker dat je dit sjabloon wilt verwijderen?", "Template scope updated": "Bereik van sjabloon bijgewerkt", "Choose which space this template belongs to": "Kies bij welke werkruimte dit sjabloon hoort", + "Only workspace admins can create global templates.": "Alleen workspace-beheerders kunnen globale sjablonen maken.", + "You need edit access to this space to create templates.": "Je hebt bewerkingstoegang tot deze ruimte nodig om sjablonen te maken.", "Scope": "Bereik", "Select scope": "Bereik selecteren", "Title": "Titel", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Pagina's en werkruimtes zoeken...", "No results found": "Geen resultaten gevonden", "You don't have permission to create pages here": "Je hebt geen toestemming om hier pagina's te maken", - "Chat menu": "Chatmenu", + "Chat menu for {{title}}": "Chatmenu voor {{title}}", "API key menu": "API-sleutelmenu", "Jump to comment selection": "Naar reactieselectie springen", "Slash commands": "Slash-opdrachten", @@ -1063,7 +1090,7 @@ "Filter": "Filter", "Page title": "Paginatitel", "Page content": "Pagina-inhoud", - "Member actions": "Lidacties", + "Member actions for {{name}}": "Lidacties voor {{name}}", "Toggle password visibility": "Wachtwoordzichtbaarheid in-/uitschakelen", "Send comment": "Reactie verzenden", "Token actions": "Tokenacties", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} toegevoegd aan favorieten", "Removed {{name}} from favorites": "{{name}} verwijderd uit favorieten", "Page menu for {{name}}": "Paginamenu voor {{name}}", - "Create subpage of {{name}}": "Subpagina van {{name}} maken" + "Create subpage of {{name}}": "Subpagina van {{name}} maken", + "Allow personal spaces": "Persoonlijke ruimtes toestaan", + "Members can create their own personal space.": "Leden kunnen hun eigen persoonlijke ruimte aanmaken.", + "Toggle allow personal spaces": "Persoonlijke ruimtes toestaan in- of uitschakelen", + "Create personal space": "Persoonlijke ruimte aanmaken", + "Personal space": "Persoonlijke ruimte", + "{{name}}'s space": "ruimte van {{name}}", + "Apply": "Toepassen", + "Cells that aren't already a page reference will be cleared.": "Cellen die nog geen paginaverwijzing zijn, worden leeggemaakt.", + "Cells that aren't a valid URL will be cleared.": "Cellen die geen geldige URL zijn, worden leeggemaakt.", + "Cells that aren't a valid email address will be cleared.": "Cellen die geen geldig e-mailadres zijn, worden leeggemaakt.", + "Cells that can't be parsed as a date will be cleared.": "Cellen die niet als een datum kunnen worden geïnterpreteerd, worden leeggemaakt.", + "Cells that can't be parsed as a number will be cleared.": "Cellen die niet als een getal kunnen worden geïnterpreteerd, worden leeggemaakt.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Cellen worden geconverteerd (yes/true/1 worden aangevinkt; al het andere wordt uitgevinkt of leeggemaakt).", + "Cells will be reinterpreted under the new type.": "Cellen worden opnieuw geïnterpreteerd volgens het nieuwe type.", + "Cells will be replaced with a comma-separated list of file names.": "Cellen worden vervangen door een door komma's gescheiden lijst met bestandsnamen.", + "Cells will be replaced with a comma-separated list of option names.": "Cellen worden vervangen door een door komma's gescheiden lijst met optienamen.", + "Cells will be replaced with the option name.": "Cellen worden vervangen door de optienaam.", + "Cells will be replaced with the page title.": "Cellen worden vervangen door de paginatitel.", + "Cells will be replaced with the person's name.": "Cellen worden vervangen door de naam van de persoon.", + "Change type": "Type wijzigen", + "Change type to {{label}}?": "Type wijzigen naar {{label}}?", + "Converting…": "Converteren…", + "Existing values become single-item lists. No data is lost.": "Bestaande waarden worden lijsten met één item. Er gaan geen gegevens verloren.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Alleen het eerste geselecteerde item per rij blijft behouden; de rest wordt verwijderd.", + "Previous record": "Vorige record", + "Next record": "Volgende record", + "Record actions": "Recordacties", + "Delete record": "Record verwijderen", + "Delete record?": "Record verwijderen?", + "This action cannot be undone.": "Deze actie kan niet ongedaan worden gemaakt.", + "to navigate": "om te navigeren", + "to close": "om te sluiten", + "Expand row {{number}}": "Rij {{number}} uitvouwen", + "Saving…": "Opslaan…", + "Read-only": "Alleen-lezen", + "Loading…": "Laden…", + "Updated {{when}}": "Bijgewerkt {{when}}", + "Add property": "Eigenschap toevoegen", + "Create property": "Eigenschap aanmaken", + "Hide properties": "Eigenschappen verbergen", + "Find a property type": "Een eigenschapstype zoeken", + "Properties": "Eigenschappen", + "A property with this name already exists": "Er bestaat al een eigenschap met deze naam", + "Add card": "Kaart toevoegen", + "Add filter": "Filter toevoegen", + "Add option": "Optie toevoegen", + "Add sort": "Sortering toevoegen", + "Add view": "Weergave toevoegen", + "All data in this column will be lost.": "Alle gegevens in deze kolom gaan verloren.", + "Allow multiple people": "Meerdere personen toestaan", + "Alphabetize": "Alfabetisch sorteren", + "Are you sure you want to delete": "Weet je zeker dat je wilt verwijderen", + "Ascending": "Oplopend", + "Base deleted": "Base verwijderd", + "Base name": "Basenaam", + "Base table": "Basistabel", + "Card properties": "Kaarteigenschappen", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Cellen die langer zijn dan de tekstlimiet worden afgekapt en de extra inhoud gaat permanent verloren.", + "Checkbox": "Selectievakje", + "Checked by default": "Standaard aangevinkt", + "Choose a property": "Kies een eigenschap", + "Clear selection": "Selectie wissen", + "Column options": "Kolomopties", + "Comma, period": "Komma, punt", + "Complete": "Voltooid", + "Contains": "Bevat", + "Copy link to view": "Link naar weergave kopiëren", + "Create a status property": "Een statuseigenschap maken", + "Created at": "Aangemaakt op", + "Currency": "Valuta", + "Decimal places": "Decimalen", + "Default value": "Standaardwaarde", + "Delete property": "Eigenschap verwijderen", + "Delete view": "Weergave verwijderen", + "Delete {{count}} rows?_one": "1 rij verwijderen?", + "Delete {{count}} rows?_other": "{{count}} rijen verwijderen?", + "Descending": "Aflopend", + "Discard": "Negeren", + "Doesn't contain": "Bevat niet", + "Done": "Klaar", + "Edit formula": "Formule bewerken", + "Edit property": "Eigenschap bewerken", + "Export CSV": "CSV exporteren", + "Failed to load base": "Base laden mislukt", + "False": "Onwaar", + "File": "Bestand", + "Filter and sort changes are visible only to you": "Wijzigingen in filters en sortering zijn alleen zichtbaar voor jou", + "Filter by": "Filteren op", + "Formula": "Formule", + "Get started with": "Aan de slag met", + "Greater than": "Groter dan", + "Group by": "Groeperen op", + "Group this board by a select or status property.": "Groepeer dit bord op een selectie- of statuseigenschap.", + "Hide all": "Alles verbergen", + "Hide group": "Groep verbergen", + "In Progress": "In uitvoering", + "In progress": "In uitvoering", + "Include time": "Tijd opnemen", + "Insert a kanban board on this page": "Voeg een kanbanbord in op deze pagina", + "Insert an inline base on this page": "Voeg een inline base in op deze pagina", + "Is": "Is", + "Is after": "Is na", + "Is any of": "Is een van", + "Is before": "Is vóór", + "Is empty": "Is leeg", + "Is none of": "Is geen van", + "Is not": "Is niet", + "Is not empty": "Is niet leeg", + "Is on or after": "Is op of na", + "Is on or before": "Is op of vóór", + "Is within": "Is binnen", + "Keep editing": "Doorgaan met bewerken", + "Last edited at": "Laatst bewerkt op", + "Last edited by": "Laatst bewerkt door", + "Less than": "Kleiner dan", + "Link copied to clipboard": "Link gekopieerd naar klembord", + "Local": "Lokaal", + "Long text": "Lange tekst", + "Moved card to {{column}}": "Kaart verplaatst naar {{column}}", + "Moved column to {{column}}": "Kolom verplaatst naar {{column}}", + "Multi-select": "Meervoudige selectie", + "New row": "Nieuwe rij", + "Next month": "Volgende maand", + "Next week": "Volgende week", + "Next year": "Volgend jaar", + "No filters applied": "Geen filters toegepast", + "No match": "Geen overeenkomst", + "No options for this property type": "Geen opties voor dit eigenschapstype", + "No sorts applied": "Geen sorteringen toegepast", + "No value": "Geen waarde", + "None": "Geen", + "Not started": "Niet gestart", + "Number": "Getal", + "One month ago": "Een maand geleden", + "One month from now": "Over een maand", + "One week ago": "Een week geleden", + "One week from now": "Over een week", + "Open as page": "Openen als pagina", + "Options": "Opties", + "Past month": "Afgelopen maand", + "Past week": "Afgelopen week", + "Past year": "Afgelopen jaar", + "Percent": "Procent", + "Period, comma": "Punt, komma", + "Person": "Persoon", + "Please enter a valid email": "Voer een geldig e-mailadres in", + "Progress": "Voortgang", + "Property options": "Eigenschapopties", + "Relative": "Relatief", + "Rename property": "Eigenschap hernoemen", + "Reset": "Opnieuw instellen", + "Save for everyone": "Opslaan voor iedereen", + "Select": "Selecteren", + "Select a property": "Selecteer een eigenschap", + "Select all loaded rows": "Alle geladen rijen selecteren", + "Show all": "Alles tonen", + "Sort": "Sorteren", + "Sort by": "Sorteren op", + "Space, comma": "Spatie, komma", + "Space, period": "Spatie, punt", + "This board has no grouping property yet.": "Dit bord heeft nog geen groeperingseigenschap.", + "This month": "Deze maand", + "This year": "Dit jaar", + "Thousands and decimal separators": "Scheidingstekens voor duizendtallen en decimalen", + "Time format": "Tijdnotatie", + "To Do": "Te doen", + "Tomorrow": "Morgen", + "True": "Waar", + "Unsaved changes": "Niet-opgeslagen wijzigingen", + "Untitled base": "Base zonder titel", + "URL": "URL", + "Value": "Waarde", + "View updated for everyone": "Weergave bijgewerkt voor iedereen", + "You have unsaved changes. Do you want to discard them?": "Je hebt niet-opgeslagen wijzigingen. Wil je deze negeren?", + "{{count}} rows deleted_one": "1 rij verwijderd", + "{{count}} rows deleted_other": "{{count}} rijen verwijderd", + "{{count}} selected_one": "1 geselecteerd", + "{{count}} selected_other": "{{count}} geselecteerd" } diff --git a/apps/client/public/locales/pt-BR/translation.json b/apps/client/public/locales/pt-BR/translation.json index e2788f1fe..2e4cd89ef 100644 --- a/apps/client/public/locales/pt-BR/translation.json +++ b/apps/client/public/locales/pt-BR/translation.json @@ -41,6 +41,8 @@ "Dark": "Escuro", "Date": "Data", "Delete": "Excluir", + "Remove from page": "Remover da página", + "Base options": "Opções da base", "Delete group": "Excluir grupo", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Você tem certeza que quer deletar essa página? Isso irá deletar todas as páginas filhas e to o histórico. Esta ação é irreversível.", "Description": "Descrição", @@ -76,6 +78,24 @@ "Failed to import pages": "Falha ao importar páginas", "Failed to load page. An error occurred.": "Falha ao carregar página. Ocorreu um erro.", "Failed to update data": "Falha ao atualizar dados", + "Failed to create base": "Falha ao criar base", + "Failed to update base": "Falha ao atualizar base", + "Failed to delete base": "Falha ao excluir base", + "Failed to create property": "Falha ao criar propriedade", + "Failed to update property": "Falha ao atualizar propriedade", + "Failed to delete property": "Falha ao excluir propriedade", + "Failed to reorder property": "Falha ao reordenar propriedade", + "Failed to create view": "Falha ao criar visualização", + "Failed to update view": "Falha ao atualizar visualização", + "Failed to delete view": "Falha ao excluir visualização", + "Failed to create row": "Falha ao criar linha", + "Failed to update row": "Falha ao atualizar linha", + "Failed to delete row": "Falha ao excluir linha", + "Failed to delete rows": "Falha ao excluir linhas", + "Failed to reorder row": "Falha ao reordenar linha", + "Failed to move card": "Falha ao mover cartão", + "Failed to add card": "Falha ao adicionar cartão", + "Failed to export CSV": "Falha ao exportar CSV", "Favorite spaces": "Espaços favoritos", "Favorite spaces appear here": "Os espaços favoritos aparecem aqui", "Favorites": "Favoritos", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Inserir diagrama Mermaid", "Insert and design Drawio diagrams": "Inserir e criar diagramas Drawio", "Insert current date": "Inserir data atual", + "Time": "Horário", + "Insert current time": "Inserir horário atual", "Draw and sketch excalidraw diagrams": "Desenhar e esboçar diagramas Excalidraw", "Multiple": "Múltiplo", "Turn into": "Transformar em", @@ -424,6 +446,7 @@ "Names do not match": "Os nomes não correspondem", "Today, {{time}}": "Hoje, {{time}}", "Yesterday, {{time}}": "Ontem, {{time}}", + "now": "agora", "Space created successfully": "Espaço criado com sucesso", "Space updated successfully": "Espaço atualizado com sucesso", "Space deleted successfully": "Espaço excluído com sucesso", @@ -596,6 +619,8 @@ "Deleted by": "Excluído por", "Deleted at": "Excluído em", "Preview": "Visualização", + "Base preview unavailable": "Pré-visualização da base indisponível", + "Restore this base to view its contents.": "Restaure esta base para visualizar seu conteúdo.", "Subpages": "Subpáginas", "Failed to load subpages": "Falha ao carregar as subpáginas", "No subpages": "Nenhuma subpágina", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Tem certeza de que deseja excluir este modelo?", "Template scope updated": "Escopo do modelo atualizado", "Choose which space this template belongs to": "Escolha a qual espaço este modelo pertence", + "Only workspace admins can create global templates.": "Somente administradores do espaço de trabalho podem criar modelos globais.", + "You need edit access to this space to create templates.": "Você precisa de acesso de edição a este espaço para criar modelos.", "Scope": "Escopo", "Select scope": "Selecionar escopo", "Title": "Título", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Pesquisar páginas e espaços...", "No results found": "Nenhum resultado encontrado", "You don't have permission to create pages here": "Você não tem permissão para criar páginas aqui", - "Chat menu": "Menu do chat", + "Chat menu for {{title}}": "Menu do chat para {{title}}", "API key menu": "Menu da chave de API", "Jump to comment selection": "Ir para a seleção de comentários", "Slash commands": "Comandos de barra", @@ -1063,7 +1090,7 @@ "Filter": "Filtrar", "Page title": "Título da página", "Page content": "Conteúdo da página", - "Member actions": "Ações do membro", + "Member actions for {{name}}": "Ações do membro para {{name}}", "Toggle password visibility": "Alternar visibilidade da senha", "Send comment": "Enviar comentário", "Token actions": "Ações do token", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} adicionado aos favoritos", "Removed {{name}} from favorites": "{{name}} removido dos favoritos", "Page menu for {{name}}": "Menu da página de {{name}}", - "Create subpage of {{name}}": "Criar subpágina de {{name}}" + "Create subpage of {{name}}": "Criar subpágina de {{name}}", + "Allow personal spaces": "Permitir espaços pessoais", + "Members can create their own personal space.": "Os membros podem criar seu próprio espaço pessoal.", + "Toggle allow personal spaces": "Ativar/desativar permissão para espaços pessoais", + "Create personal space": "Criar espaço pessoal", + "Personal space": "Espaço pessoal", + "{{name}}'s space": "Espaço de {{name}}", + "Apply": "Aplicar", + "Cells that aren't already a page reference will be cleared.": "As células que ainda não forem uma referência de página serão limpas.", + "Cells that aren't a valid URL will be cleared.": "As células que não forem uma URL válida serão limpas.", + "Cells that aren't a valid email address will be cleared.": "As células que não forem um endereço de e-mail válido serão limpas.", + "Cells that can't be parsed as a date will be cleared.": "As células que não puderem ser interpretadas como uma data serão limpas.", + "Cells that can't be parsed as a number will be cleared.": "As células que não puderem ser interpretadas como um número serão limpas.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "As células serão convertidas (yes/true/1 se tornam marcadas; todo o resto se torna desmarcado ou limpo).", + "Cells will be reinterpreted under the new type.": "As células serão reinterpretadas com o novo tipo.", + "Cells will be replaced with a comma-separated list of file names.": "As células serão substituídas por uma lista de nomes de arquivos separados por vírgula.", + "Cells will be replaced with a comma-separated list of option names.": "As células serão substituídas por uma lista de nomes de opções separados por vírgula.", + "Cells will be replaced with the option name.": "As células serão substituídas pelo nome da opção.", + "Cells will be replaced with the page title.": "As células serão substituídas pelo título da página.", + "Cells will be replaced with the person's name.": "As células serão substituídas pelo nome da pessoa.", + "Change type": "Alterar tipo", + "Change type to {{label}}?": "Alterar tipo para {{label}}?", + "Converting…": "Convertendo…", + "Existing values become single-item lists. No data is lost.": "Os valores existentes se tornam listas de item único. Nenhum dado é perdido.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Apenas o primeiro item selecionado por linha será mantido; o restante será descartado.", + "Previous record": "Registro anterior", + "Next record": "Próximo registro", + "Record actions": "Ações do registro", + "Delete record": "Excluir registro", + "Delete record?": "Excluir registro?", + "This action cannot be undone.": "Esta ação não pode ser desfeita.", + "to navigate": "para navegar", + "to close": "para fechar", + "Expand row {{number}}": "Expandir linha {{number}}", + "Saving…": "Salvando…", + "Read-only": "Somente leitura", + "Loading…": "Carregando…", + "Updated {{when}}": "Atualizado {{when}}", + "Add property": "Adicionar propriedade", + "Create property": "Criar propriedade", + "Hide properties": "Ocultar propriedades", + "Find a property type": "Encontrar um tipo de propriedade", + "Properties": "Propriedades", + "A property with this name already exists": "Já existe uma propriedade com este nome", + "Add card": "Adicionar cartão", + "Add filter": "Adicionar filtro", + "Add option": "Adicionar opção", + "Add sort": "Adicionar ordenação", + "Add view": "Adicionar visualização", + "All data in this column will be lost.": "Todos os dados nesta coluna serão perdidos.", + "Allow multiple people": "Permitir várias pessoas", + "Alphabetize": "Ordenar alfabeticamente", + "Are you sure you want to delete": "Tem certeza de que deseja excluir", + "Ascending": "Crescente", + "Base deleted": "Base excluída", + "Base name": "Nome da base", + "Base table": "Tabela da base", + "Card properties": "Propriedades do cartão", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Células maiores do que o limite de Texto serão truncadas e o conteúdo extra será perdido permanentemente.", + "Checkbox": "Caixa de seleção", + "Checked by default": "Marcado por padrão", + "Choose a property": "Escolha uma propriedade", + "Clear selection": "Limpar seleção", + "Column options": "Opções da coluna", + "Comma, period": "Vírgula, ponto", + "Complete": "Concluído", + "Contains": "Contém", + "Copy link to view": "Copiar link da visualização", + "Create a status property": "Criar uma propriedade de status", + "Created at": "Criado em", + "Currency": "Moeda", + "Decimal places": "Casas decimais", + "Default value": "Valor padrão", + "Delete property": "Excluir propriedade", + "Delete view": "Excluir visualização", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "Decrescente", + "Discard": "Descartar", + "Doesn't contain": "Não contém", + "Done": "Concluído", + "Edit formula": "Editar fórmula", + "Edit property": "Editar propriedade", + "Export CSV": "Exportar CSV", + "Failed to load base": "Falha ao carregar a base", + "False": "Falso", + "File": "Arquivo", + "Filter and sort changes are visible only to you": "As alterações de filtro e ordenação são visíveis somente para você", + "Filter by": "Filtrar por", + "Formula": "Fórmula", + "Get started with": "Começar com", + "Greater than": "Maior que", + "Group by": "Agrupar por", + "Group this board by a select or status property.": "Agrupe este quadro por uma propriedade de seleção ou status.", + "Hide all": "Ocultar tudo", + "Hide group": "Ocultar grupo", + "In Progress": "Em andamento", + "In progress": "Em andamento", + "Include time": "Incluir hora", + "Insert a kanban board on this page": "Inserir um quadro kanban nesta página", + "Insert an inline base on this page": "Inserir uma base inline nesta página", + "Is": "É", + "Is after": "É depois de", + "Is any of": "É qualquer um de", + "Is before": "É antes de", + "Is empty": "Está vazio", + "Is none of": "Não é nenhum de", + "Is not": "Não é", + "Is not empty": "Não está vazio", + "Is on or after": "É em ou depois de", + "Is on or before": "É em ou antes de", + "Is within": "Está dentro de", + "Keep editing": "Continuar editando", + "Last edited at": "Última edição em", + "Last edited by": "Última edição por", + "Less than": "Menor que", + "Link copied to clipboard": "Link copiado para a área de transferência", + "Local": "Local", + "Long text": "Texto longo", + "Moved card to {{column}}": "Cartão movido para {{column}}", + "Moved column to {{column}}": "Coluna movida para {{column}}", + "Multi-select": "Seleção múltipla", + "New row": "Nova linha", + "Next month": "Próximo mês", + "Next week": "Próxima semana", + "Next year": "Próximo ano", + "No filters applied": "Nenhum filtro aplicado", + "No match": "Sem correspondência", + "No options for this property type": "Sem opções para este tipo de propriedade", + "No sorts applied": "Nenhuma ordenação aplicada", + "No value": "Sem valor", + "None": "Nenhum", + "Not started": "Não iniciado", + "Number": "Número", + "One month ago": "Há um mês", + "One month from now": "Daqui a um mês", + "One week ago": "Há uma semana", + "One week from now": "Daqui a uma semana", + "Open as page": "Abrir como página", + "Options": "Opções", + "Past month": "Mês passado", + "Past week": "Semana passada", + "Past year": "Ano passado", + "Percent": "Porcentagem", + "Period, comma": "Ponto, vírgula", + "Person": "Pessoa", + "Please enter a valid email": "Por favor, insira um e-mail válido", + "Progress": "Progresso", + "Property options": "Opções da propriedade", + "Relative": "Relativo", + "Rename property": "Renomear propriedade", + "Reset": "Redefinir", + "Save for everyone": "Salvar para todos", + "Select": "Seleção", + "Select a property": "Selecione uma propriedade", + "Select all loaded rows": "Selecionar todas as linhas carregadas", + "Show all": "Mostrar tudo", + "Sort": "Ordenar", + "Sort by": "Ordenar por", + "Space, comma": "Espaço, vírgula", + "Space, period": "Espaço, ponto", + "This board has no grouping property yet.": "Este quadro ainda não tem uma propriedade de agrupamento.", + "This month": "Este mês", + "This year": "Este ano", + "Thousands and decimal separators": "Separadores de milhares e decimais", + "Time format": "Formato de hora", + "To Do": "A fazer", + "Tomorrow": "Amanhã", + "True": "Verdadeiro", + "Unsaved changes": "Alterações não salvas", + "Untitled base": "Base sem título", + "URL": "URL", + "Value": "Valor", + "View updated for everyone": "Visualização atualizada para todos", + "You have unsaved changes. Do you want to discard them?": "Você tem alterações não salvas. Deseja descartá-las?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/ru-RU/translation.json b/apps/client/public/locales/ru-RU/translation.json index 3d93ec67d..bae44d133 100644 --- a/apps/client/public/locales/ru-RU/translation.json +++ b/apps/client/public/locales/ru-RU/translation.json @@ -41,6 +41,8 @@ "Dark": "Темная", "Date": "Дата", "Delete": "Удалить", + "Remove from page": "Удалить со страницы", + "Base options": "Параметры базы", "Delete group": "Удалить группу", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Вы уверены, что хотите удалить эту страницу? Это удалит её дочерние страницы, а также историю страницы. Это действие необратимо.", "Description": "Описание", @@ -76,6 +78,24 @@ "Failed to import pages": "Не удалось импортировать страницы", "Failed to load page. An error occurred.": "Не удалось загрузить страницу. Произошла ошибка.", "Failed to update data": "Не удалось обновить данные", + "Failed to create base": "Не удалось создать базу", + "Failed to update base": "Не удалось обновить базу", + "Failed to delete base": "Не удалось удалить базу", + "Failed to create property": "Не удалось создать свойство", + "Failed to update property": "Не удалось обновить свойство", + "Failed to delete property": "Не удалось удалить свойство", + "Failed to reorder property": "Не удалось изменить порядок свойств", + "Failed to create view": "Не удалось создать представление", + "Failed to update view": "Не удалось обновить представление", + "Failed to delete view": "Не удалось удалить представление", + "Failed to create row": "Не удалось создать строку", + "Failed to update row": "Не удалось обновить строку", + "Failed to delete row": "Не удалось удалить строку", + "Failed to delete rows": "Не удалось удалить строки", + "Failed to reorder row": "Не удалось изменить порядок строки", + "Failed to move card": "Не удалось переместить карточку", + "Failed to add card": "Не удалось добавить карточку", + "Failed to export CSV": "Не удалось экспортировать CSV", "Favorite spaces": "Избранные пространства", "Favorite spaces appear here": "Здесь отображаются избранные пространства", "Favorites": "Избранное", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Вставить диаграмму Mermaid", "Insert and design Drawio diagrams": "Вставляйте и редактируйте диаграммы Drawio", "Insert current date": "Вставить текущую дату", + "Time": "Время", + "Insert current time": "Вставить текущее время", "Draw and sketch excalidraw diagrams": "Рисуйте и создавайте диаграммы Excalidraw", "Multiple": "Несколько", "Turn into": "Преобразовать в", @@ -424,6 +446,7 @@ "Names do not match": "Названия не совпадают", "Today, {{time}}": "Сегодня, {{time}}", "Yesterday, {{time}}": "Вчера, {{time}}", + "now": "сейчас", "Space created successfully": "Пространство успешно создано", "Space updated successfully": "Пространство успешно обновлено", "Space deleted successfully": "Пространство успешно удалено", @@ -596,6 +619,8 @@ "Deleted by": "Удалено пользователем", "Deleted at": "Удалено", "Preview": "Предпросмотр", + "Base preview unavailable": "Предпросмотр базы недоступен", + "Restore this base to view its contents.": "Восстановите эту базу, чтобы просмотреть её содержимое.", "Subpages": "Подстраницы", "Failed to load subpages": "Не удалось загрузить подстраницы", "No subpages": "Нет подстраниц", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Вы уверены, что хотите удалить этот шаблон?", "Template scope updated": "Область действия шаблона обновлена", "Choose which space this template belongs to": "Выберите, к какому пространству относится этот шаблон", + "Only workspace admins can create global templates.": "Только администраторы рабочего пространства могут создавать глобальные шаблоны.", + "You need edit access to this space to create templates.": "Чтобы создавать шаблоны, вам нужен доступ на редактирование этого пространства.", "Scope": "Область действия", "Select scope": "Выберите область действия", "Title": "Заголовок", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Поиск страниц и пространств...", "No results found": "Результаты не найдены", "You don't have permission to create pages here": "У вас нет прав на создание страниц здесь", - "Chat menu": "Меню чата", + "Chat menu for {{title}}": "Меню чата для {{title}}", "API key menu": "Меню API-ключа", "Jump to comment selection": "Перейти к выбору комментария", "Slash commands": "Команды со слешем", @@ -1063,7 +1090,7 @@ "Filter": "Фильтр", "Page title": "Заголовок страницы", "Page content": "Содержимое страницы", - "Member actions": "Действия с участником", + "Member actions for {{name}}": "Действия с участниками для {{name}}", "Toggle password visibility": "Переключить видимость пароля", "Send comment": "Отправить комментарий", "Token actions": "Действия с токеном", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} добавлено в избранное", "Removed {{name}} from favorites": "{{name}} удалено из избранного", "Page menu for {{name}}": "Меню страницы для {{name}}", - "Create subpage of {{name}}": "Создать подстраницу для {{name}}" + "Create subpage of {{name}}": "Создать подстраницу для {{name}}", + "Allow personal spaces": "Разрешить личные пространства", + "Members can create their own personal space.": "Участники могут создавать свои собственные личные пространства.", + "Toggle allow personal spaces": "Переключить разрешение личных пространств", + "Create personal space": "Создать личное пространство", + "Personal space": "Личное пространство", + "{{name}}'s space": "Пространство {{name}}", + "Apply": "Применить", + "Cells that aren't already a page reference will be cleared.": "Ячейки, которые ещё не являются ссылкой на страницу, будут очищены.", + "Cells that aren't a valid URL will be cleared.": "Ячейки, которые не содержат допустимый URL, будут очищены.", + "Cells that aren't a valid email address will be cleared.": "Ячейки, которые не содержат допустимый адрес электронной почты, будут очищены.", + "Cells that can't be parsed as a date will be cleared.": "Ячейки, которые нельзя распознать как дату, будут очищены.", + "Cells that can't be parsed as a number will be cleared.": "Ячейки, которые нельзя распознать как число, будут очищены.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Значения в ячейках будут приведены к типу (yes/true/1 станут отмеченными; всё остальное станет неотмеченным или будет очищено).", + "Cells will be reinterpreted under the new type.": "Значения в ячейках будут заново интерпретированы в соответствии с новым типом.", + "Cells will be replaced with a comma-separated list of file names.": "Ячейки будут заменены списком имён файлов, разделённых запятыми.", + "Cells will be replaced with a comma-separated list of option names.": "Ячейки будут заменены списком названий параметров, разделённых запятыми.", + "Cells will be replaced with the option name.": "Ячейки будут заменены названием параметра.", + "Cells will be replaced with the page title.": "Ячейки будут заменены заголовком страницы.", + "Cells will be replaced with the person's name.": "Ячейки будут заменены именем человека.", + "Change type": "Изменить тип", + "Change type to {{label}}?": "Изменить тип на {{label}}?", + "Converting…": "Преобразование…", + "Existing values become single-item lists. No data is lost.": "Существующие значения станут одноэлементными списками. Данные не будут потеряны.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Для каждой строки будет сохранён только первый выбранный элемент; остальные будут отброшены.", + "Previous record": "Предыдущая запись", + "Next record": "Следующая запись", + "Record actions": "Действия с записью", + "Delete record": "Удалить запись", + "Delete record?": "Удалить запись?", + "This action cannot be undone.": "Это действие нельзя отменить.", + "to navigate": "для навигации", + "to close": "для закрытия", + "Expand row {{number}}": "Развернуть строку {{number}}", + "Saving…": "Сохранение…", + "Read-only": "Только для чтения", + "Loading…": "Загрузка…", + "Updated {{when}}": "Обновлено {{when}}", + "Add property": "Добавить свойство", + "Create property": "Создать свойство", + "Hide properties": "Скрыть свойства", + "Find a property type": "Найти тип свойства", + "Properties": "Свойства", + "A property with this name already exists": "Свойство с таким именем уже существует", + "Add card": "Добавить карточку", + "Add filter": "Добавить фильтр", + "Add option": "Добавить вариант", + "Add sort": "Добавить сортировку", + "Add view": "Добавить представление", + "All data in this column will be lost.": "Все данные в этом столбце будут потеряны.", + "Allow multiple people": "Разрешить нескольких пользователей", + "Alphabetize": "По алфавиту", + "Are you sure you want to delete": "Вы уверены, что хотите удалить", + "Ascending": "По возрастанию", + "Base deleted": "База удалена", + "Base name": "Название базы", + "Base table": "Таблица базы", + "Card properties": "Свойства карточки", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Ячейки, длина которых превышает ограничение для текста, будут обрезаны, а лишнее содержимое будет безвозвратно потеряно.", + "Checkbox": "Флажок", + "Checked by default": "Отмечено по умолчанию", + "Choose a property": "Выберите свойство", + "Clear selection": "Очистить выбор", + "Column options": "Параметры столбца", + "Comma, period": "Запятая, точка", + "Complete": "Завершено", + "Contains": "Содержит", + "Copy link to view": "Скопировать ссылку на представление", + "Create a status property": "Создать свойство статуса", + "Created at": "Создано", + "Currency": "Валюта", + "Decimal places": "Десятичные знаки", + "Default value": "Значение по умолчанию", + "Delete property": "Удалить свойство", + "Delete view": "Удалить представление", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "По убыванию", + "Discard": "Отменить", + "Doesn't contain": "Не содержит", + "Done": "Готово", + "Edit formula": "Редактировать формулу", + "Edit property": "Редактировать свойство", + "Export CSV": "Экспорт CSV", + "Failed to load base": "Не удалось загрузить базу", + "False": "Ложь", + "File": "Файл", + "Filter and sort changes are visible only to you": "Изменения фильтра и сортировки видны только вам", + "Filter by": "Фильтр по", + "Formula": "Формула", + "Get started with": "Начать работу с", + "Greater than": "Больше чем", + "Group by": "Группировать по", + "Group this board by a select or status property.": "Сгруппируйте эту доску по свойству выбора или статуса.", + "Hide all": "Скрыть все", + "Hide group": "Скрыть группу", + "In Progress": "В процессе", + "In progress": "В процессе", + "Include time": "Включить время", + "Insert a kanban board on this page": "Вставить канбан-доску на эту страницу", + "Insert an inline base on this page": "Вставить встроенную базу на эту страницу", + "Is": "Равно", + "Is after": "После", + "Is any of": "Совпадает с любым из", + "Is before": "До", + "Is empty": "Пусто", + "Is none of": "Не совпадает ни с одним из", + "Is not": "Не равно", + "Is not empty": "Не пусто", + "Is on or after": "В этот день или позже", + "Is on or before": "В этот день или раньше", + "Is within": "Находится в пределах", + "Keep editing": "Продолжить редактирование", + "Last edited at": "Последнее изменение", + "Last edited by": "Последний изменивший", + "Less than": "Меньше чем", + "Link copied to clipboard": "Ссылка скопирована в буфер обмена", + "Local": "Локальный", + "Long text": "Длинный текст", + "Moved card to {{column}}": "Карточка перемещена в {{column}}", + "Moved column to {{column}}": "Столбец перемещён в {{column}}", + "Multi-select": "Множественный выбор", + "New row": "Новая строка", + "Next month": "Следующий месяц", + "Next week": "Следующая неделя", + "Next year": "Следующий год", + "No filters applied": "Фильтры не применены", + "No match": "Нет совпадений", + "No options for this property type": "Для этого типа свойства нет параметров", + "No sorts applied": "Сортировка не применена", + "No value": "Нет значения", + "None": "Нет", + "Not started": "Не начато", + "Number": "Число", + "One month ago": "Месяц назад", + "One month from now": "Через месяц", + "One week ago": "Неделю назад", + "One week from now": "Через неделю", + "Open as page": "Открыть как страницу", + "Options": "Параметры", + "Past month": "Прошлый месяц", + "Past week": "Прошлая неделя", + "Past year": "Прошлый год", + "Percent": "Процент", + "Period, comma": "Точка, запятая", + "Person": "Пользователь", + "Please enter a valid email": "Пожалуйста, введите корректный адрес электронной почты", + "Progress": "Прогресс", + "Property options": "Параметры свойства", + "Relative": "Относительный", + "Rename property": "Переименовать свойство", + "Reset": "Сбросить", + "Save for everyone": "Сохранить для всех", + "Select": "Выбор", + "Select a property": "Выберите свойство", + "Select all loaded rows": "Выбрать все загруженные строки", + "Show all": "Показать все", + "Sort": "Сортировка", + "Sort by": "Сортировать по", + "Space, comma": "Пробел, запятая", + "Space, period": "Пробел, точка", + "This board has no grouping property yet.": "У этой доски пока нет свойства для группировки.", + "This month": "Этот месяц", + "This year": "Этот год", + "Thousands and decimal separators": "Разделители тысяч и десятичных знаков", + "Time format": "Формат времени", + "To Do": "К выполнению", + "Tomorrow": "Завтра", + "True": "Истина", + "Unsaved changes": "Несохранённые изменения", + "Untitled base": "База без названия", + "URL": "URL", + "Value": "Значение", + "View updated for everyone": "Представление обновлено для всех", + "You have unsaved changes. Do you want to discard them?": "У вас есть несохранённые изменения. Хотите их отменить?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/uk-UA/translation.json b/apps/client/public/locales/uk-UA/translation.json index 6144df469..d3dd687ea 100644 --- a/apps/client/public/locales/uk-UA/translation.json +++ b/apps/client/public/locales/uk-UA/translation.json @@ -41,6 +41,8 @@ "Dark": "Темна", "Date": "Дата", "Delete": "Видалити", + "Remove from page": "Видалити зі сторінки", + "Base options": "Параметри бази", "Delete group": "Видалити групу", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Ви впевнені, що хочете видалити цю сторінку? Це видалить її дочірні сторінки, а також історію сторінки. Ця дія необоротна.", "Description": "Опис", @@ -76,6 +78,24 @@ "Failed to import pages": "Не вдалося імпортувати сторінки", "Failed to load page. An error occurred.": "Не вдалося завантажити сторінку. Сталася помилка.", "Failed to update data": "Не вдалося оновити дані", + "Failed to create base": "Не вдалося створити базу", + "Failed to update base": "Не вдалося оновити базу", + "Failed to delete base": "Не вдалося видалити базу", + "Failed to create property": "Не вдалося створити властивість", + "Failed to update property": "Не вдалося оновити властивість", + "Failed to delete property": "Не вдалося видалити властивість", + "Failed to reorder property": "Не вдалося змінити порядок властивості", + "Failed to create view": "Не вдалося створити подання", + "Failed to update view": "Не вдалося оновити подання", + "Failed to delete view": "Не вдалося видалити подання", + "Failed to create row": "Не вдалося створити рядок", + "Failed to update row": "Не вдалося оновити рядок", + "Failed to delete row": "Не вдалося видалити рядок", + "Failed to delete rows": "Не вдалося видалити рядки", + "Failed to reorder row": "Не вдалося змінити порядок рядка", + "Failed to move card": "Не вдалося перемістити картку", + "Failed to add card": "Не вдалося додати картку", + "Failed to export CSV": "Не вдалося експортувати CSV", "Favorite spaces": "Обрані простори", "Favorite spaces appear here": "Тут відображаються обрані простори", "Favorites": "Обране", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "Вставити діаграму Mermaid", "Insert and design Drawio diagrams": "Вставляйте та створюйте діаграми Drawio", "Insert current date": "Вставити поточну дату", + "Time": "Час", + "Insert current time": "Вставити поточний час", "Draw and sketch excalidraw diagrams": "Створюйте та кресліть діаграми Excalidraw", "Multiple": "Кілька", "Turn into": "Перетворити", @@ -424,6 +446,7 @@ "Names do not match": "Назви не збігаються", "Today, {{time}}": "Сьогодні, {{time}}", "Yesterday, {{time}}": "Вчора, {{time}}", + "now": "зараз", "Space created successfully": "Простір успішно створено", "Space updated successfully": "Простір успішно оновлено", "Space deleted successfully": "Простір успішно видалено", @@ -596,6 +619,8 @@ "Deleted by": "Видалив", "Deleted at": "Видалено", "Preview": "Попередній перегляд", + "Base preview unavailable": "Попередній перегляд бази недоступний", + "Restore this base to view its contents.": "Відновіть цю базу, щоб переглянути її вміст.", "Subpages": "Підсторінки", "Failed to load subpages": "Не вдалося завантажити підсторінки", "No subpages": "Немає підсторінок", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "Ви впевнені, що хочете видалити цей шаблон?", "Template scope updated": "Область дії шаблону оновлено", "Choose which space this template belongs to": "Виберіть, до якого простору належить цей шаблон", + "Only workspace admins can create global templates.": "Лише адміністратори робочого простору можуть створювати глобальні шаблони.", + "You need edit access to this space to create templates.": "Щоб створювати шаблони, вам потрібен доступ до редагування цього простору.", "Scope": "Область дії", "Select scope": "Вибрати область дії", "Title": "Назва", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "Шукати сторінки та простори...", "No results found": "Результати не знайдено", "You don't have permission to create pages here": "У вас немає дозволу на створення сторінок тут", - "Chat menu": "Меню чату", + "Chat menu for {{title}}": "Меню чату для {{title}}", "API key menu": "Меню ключа API", "Jump to comment selection": "Перейти до вибору коментаря", "Slash commands": "Слеш-команди", @@ -1063,7 +1090,7 @@ "Filter": "Фільтр", "Page title": "Назва сторінки", "Page content": "Вміст сторінки", - "Member actions": "Дії з учасником", + "Member actions for {{name}}": "Дії учасника для {{name}}", "Toggle password visibility": "Перемкнути видимість пароля", "Send comment": "Надіслати коментар", "Token actions": "Дії з токеном", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "{{name}} додано до обраного", "Removed {{name}} from favorites": "{{name}} видалено з обраного", "Page menu for {{name}}": "Меню сторінки для {{name}}", - "Create subpage of {{name}}": "Створити підсторінку для {{name}}" + "Create subpage of {{name}}": "Створити підсторінку для {{name}}", + "Allow personal spaces": "Дозволити особисті простори", + "Members can create their own personal space.": "Учасники можуть створювати власний особистий простір.", + "Toggle allow personal spaces": "Перемкнути дозвіл на особисті простори", + "Create personal space": "Створити особистий простір", + "Personal space": "Особистий простір", + "{{name}}'s space": "Простір {{name}}", + "Apply": "Застосувати", + "Cells that aren't already a page reference will be cleared.": "Клітинки, які ще не є посиланням на сторінку, буде очищено.", + "Cells that aren't a valid URL will be cleared.": "Клітинки, які не є дійсною URL-адресою, буде очищено.", + "Cells that aren't a valid email address will be cleared.": "Клітинки, які не є дійсною електронною адресою, буде очищено.", + "Cells that can't be parsed as a date will be cleared.": "Клітинки, які не вдається розпізнати як дату, буде очищено.", + "Cells that can't be parsed as a number will be cleared.": "Клітинки, які не вдається розпізнати як число, буде очищено.", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "Клітинки буде приведено до потрібного формату (yes/true/1 стануть позначеними; усе інше стане непозначеним або буде очищено).", + "Cells will be reinterpreted under the new type.": "Клітинки буде повторно інтерпретовано відповідно до нового типу.", + "Cells will be replaced with a comma-separated list of file names.": "Клітинки буде замінено списком імен файлів, розділених комами.", + "Cells will be replaced with a comma-separated list of option names.": "Клітинки буде замінено списком назв параметрів, розділених комами.", + "Cells will be replaced with the option name.": "Клітинки буде замінено назвою параметра.", + "Cells will be replaced with the page title.": "Клітинки буде замінено заголовком сторінки.", + "Cells will be replaced with the person's name.": "Клітинки буде замінено іменем особи.", + "Change type": "Змінити тип", + "Change type to {{label}}?": "Змінити тип на {{label}}?", + "Converting…": "Перетворення…", + "Existing values become single-item lists. No data is lost.": "Наявні значення стануть одноелементними списками. Дані не буде втрачено.", + "Only the first selected item per row will be kept; the rest will be discarded.": "Для кожного рядка буде збережено лише перший вибраний елемент; решту буде відкинуто.", + "Previous record": "Попередній запис", + "Next record": "Наступний запис", + "Record actions": "Дії із записом", + "Delete record": "Видалити запис", + "Delete record?": "Видалити запис?", + "This action cannot be undone.": "Цю дію неможливо скасувати.", + "to navigate": "для навігації", + "to close": "для закриття", + "Expand row {{number}}": "Розгорнути рядок {{number}}", + "Saving…": "Збереження…", + "Read-only": "Лише читання", + "Loading…": "Завантаження…", + "Updated {{when}}": "Оновлено {{when}}", + "Add property": "Додати властивість", + "Create property": "Створити властивість", + "Hide properties": "Приховати властивості", + "Find a property type": "Знайти тип властивості", + "Properties": "Властивості", + "A property with this name already exists": "Властивість із такою назвою вже існує", + "Add card": "Додати картку", + "Add filter": "Додати фільтр", + "Add option": "Додати опцію", + "Add sort": "Додати сортування", + "Add view": "Додати подання", + "All data in this column will be lost.": "Усі дані в цьому стовпці буде втрачено.", + "Allow multiple people": "Дозволити кількох людей", + "Alphabetize": "За алфавітом", + "Are you sure you want to delete": "Ви впевнені, що хочете видалити", + "Ascending": "За зростанням", + "Base deleted": "Базу видалено", + "Base name": "Назва бази", + "Base table": "Таблиця бази", + "Card properties": "Властивості картки", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "Клітинки, довші за обмеження для тексту, буде обрізано, а зайвий вміст буде безповоротно втрачено.", + "Checkbox": "Прапорець", + "Checked by default": "Позначено за замовчуванням", + "Choose a property": "Оберіть властивість", + "Clear selection": "Очистити вибір", + "Column options": "Параметри стовпця", + "Comma, period": "Кома, крапка", + "Complete": "Завершено", + "Contains": "Містить", + "Copy link to view": "Скопіювати посилання на подання", + "Create a status property": "Створити властивість статусу", + "Created at": "Створено", + "Currency": "Валюта", + "Decimal places": "Десяткові знаки", + "Default value": "Значення за замовчуванням", + "Delete property": "Видалити властивість", + "Delete view": "Видалити подання", + "Delete {{count}} rows?_one": "Delete 1 row?", + "Delete {{count}} rows?_other": "Delete {{count}} rows?", + "Descending": "За спаданням", + "Discard": "Скасувати", + "Doesn't contain": "Не містить", + "Done": "Готово", + "Edit formula": "Редагувати формулу", + "Edit property": "Редагувати властивість", + "Export CSV": "Експорт CSV", + "Failed to load base": "Не вдалося завантажити базу", + "False": "Хибність", + "File": "Файл", + "Filter and sort changes are visible only to you": "Зміни фільтрів і сортування видимі лише вам", + "Filter by": "Фільтрувати за", + "Formula": "Формула", + "Get started with": "Почніть із", + "Greater than": "Більше ніж", + "Group by": "Групувати за", + "Group this board by a select or status property.": "Згрупуйте цю дошку за властивістю вибору або статусу.", + "Hide all": "Приховати все", + "Hide group": "Приховати групу", + "In Progress": "У процесі", + "In progress": "У процесі", + "Include time": "Включити час", + "Insert a kanban board on this page": "Вставити канбан-дошку на цю сторінку", + "Insert an inline base on this page": "Вставити вбудовану базу на цю сторінку", + "Is": "Є", + "Is after": "Після", + "Is any of": "Є одним із", + "Is before": "До", + "Is empty": "Порожнє", + "Is none of": "Не є жодним із", + "Is not": "Не є", + "Is not empty": "Не порожнє", + "Is on or after": "У цей день або пізніше", + "Is on or before": "У цей день або раніше", + "Is within": "У межах", + "Keep editing": "Продовжити редагування", + "Last edited at": "Востаннє відредаговано", + "Last edited by": "Востаннє відредагував", + "Less than": "Менше ніж", + "Link copied to clipboard": "Посилання скопійовано в буфер обміну", + "Local": "Локальний", + "Long text": "Довгий текст", + "Moved card to {{column}}": "Картку переміщено до {{column}}", + "Moved column to {{column}}": "Стовпець переміщено до {{column}}", + "Multi-select": "Мультивибір", + "New row": "Новий рядок", + "Next month": "Наступного місяця", + "Next week": "Наступного тижня", + "Next year": "Наступного року", + "No filters applied": "Фільтри не застосовано", + "No match": "Немає збігів", + "No options for this property type": "Немає опцій для цього типу властивості", + "No sorts applied": "Сортування не застосовано", + "No value": "Немає значення", + "None": "Немає", + "Not started": "Не розпочато", + "Number": "Число", + "One month ago": "Місяць тому", + "One month from now": "Через місяць", + "One week ago": "Тиждень тому", + "One week from now": "Через тиждень", + "Open as page": "Відкрити як сторінку", + "Options": "Опції", + "Past month": "За минулий місяць", + "Past week": "За минулий тиждень", + "Past year": "За минулий рік", + "Percent": "Відсоток", + "Period, comma": "Крапка, кома", + "Person": "Особа", + "Please enter a valid email": "Будь ласка, введіть коректну електронну адресу", + "Progress": "Прогрес", + "Property options": "Параметри властивості", + "Relative": "Відносний", + "Rename property": "Перейменувати властивість", + "Reset": "Скинути", + "Save for everyone": "Зберегти для всіх", + "Select": "Вибір", + "Select a property": "Виберіть властивість", + "Select all loaded rows": "Вибрати всі завантажені рядки", + "Show all": "Показати все", + "Sort": "Сортування", + "Sort by": "Сортувати за", + "Space, comma": "Пробіл, кома", + "Space, period": "Пробіл, крапка", + "This board has no grouping property yet.": "Ця дошка ще не має властивості групування.", + "This month": "Цього місяця", + "This year": "Цього року", + "Thousands and decimal separators": "Роздільники тисяч і десяткових знаків", + "Time format": "Формат часу", + "To Do": "До виконання", + "Tomorrow": "Завтра", + "True": "Істина", + "Unsaved changes": "Незбережені зміни", + "Untitled base": "База без назви", + "URL": "URL", + "Value": "Значення", + "View updated for everyone": "Подання оновлено для всіх", + "You have unsaved changes. Do you want to discard them?": "У вас є незбережені зміни. Хочете їх скасувати?", + "{{count}} rows deleted_one": "1 row deleted", + "{{count}} rows deleted_other": "{{count}} rows deleted", + "{{count}} selected_one": "1 selected", + "{{count}} selected_other": "{{count}} selected" } diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json index 40cd5c1ba..97ff9ce85 100644 --- a/apps/client/public/locales/zh-CN/translation.json +++ b/apps/client/public/locales/zh-CN/translation.json @@ -41,6 +41,8 @@ "Dark": "深色", "Date": "日期", "Delete": "删除", + "Remove from page": "从页面中移除", + "Base options": "数据库选项", "Delete group": "删除群组", "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "您确定要删除这个页面吗?这将删除其子页面和页面历史记录。此操作不可逆。", "Description": "描述", @@ -76,6 +78,24 @@ "Failed to import pages": "导入页面失败", "Failed to load page. An error occurred.": "页面加载失败。发生了一个错误。", "Failed to update data": "数据更新失败", + "Failed to create base": "创建数据库失败", + "Failed to update base": "更新数据库失败", + "Failed to delete base": "删除数据库失败", + "Failed to create property": "创建属性失败", + "Failed to update property": "更新属性失败", + "Failed to delete property": "删除属性失败", + "Failed to reorder property": "重新排序属性失败", + "Failed to create view": "创建视图失败", + "Failed to update view": "更新视图失败", + "Failed to delete view": "删除视图失败", + "Failed to create row": "创建记录失败", + "Failed to update row": "更新记录失败", + "Failed to delete row": "删除记录失败", + "Failed to delete rows": "删除记录失败", + "Failed to reorder row": "重新排序记录失败", + "Failed to move card": "移动卡片失败", + "Failed to add card": "添加卡片失败", + "Failed to export CSV": "导出 CSV 失败", "Favorite spaces": "收藏的空间", "Favorite spaces appear here": "收藏的空间会显示在这里", "Favorites": "收藏", @@ -398,6 +418,8 @@ "Insert mermaid diagram": "插入 Mermaid 图表", "Insert and design Drawio diagrams": "插入并设计 Drawio 图表", "Insert current date": "插入当前日期", + "Time": "时间", + "Insert current time": "插入当前时间", "Draw and sketch excalidraw diagrams": "绘制和草绘 Excalidraw 图表", "Multiple": "多个", "Turn into": "变成", @@ -424,6 +446,7 @@ "Names do not match": "名称不匹配", "Today, {{time}}": "今天,{{time}}", "Yesterday, {{time}}": "昨天,{{time}}", + "now": "现在", "Space created successfully": "空间创建成功", "Space updated successfully": "空间更新成功", "Space deleted successfully": "空间删除成功", @@ -596,6 +619,8 @@ "Deleted by": "删除者", "Deleted at": "删除于", "Preview": "预览", + "Base preview unavailable": "无法预览数据库", + "Restore this base to view its contents.": "恢复此数据库以查看其内容。", "Subpages": "子页面", "Failed to load subpages": "加载子页面失败", "No subpages": "没有子页面", @@ -965,6 +990,8 @@ "Are you sure you want to delete this template?": "你确定要删除此模板吗?", "Template scope updated": "模板范围已更新", "Choose which space this template belongs to": "选择此模板所属的空间", + "Only workspace admins can create global templates.": "只有工作区管理员才能创建全局模板。", + "You need edit access to this space to create templates.": "您需要拥有此空间的编辑权限才能创建模板。", "Scope": "范围", "Select scope": "选择范围", "Title": "标题", @@ -977,7 +1004,7 @@ "Search pages and spaces...": "搜索页面和空间……", "No results found": "未找到结果", "You don't have permission to create pages here": "你无权在此处创建页面", - "Chat menu": "聊天菜单", + "Chat menu for {{title}}": "{{title}} 的聊天菜单", "API key menu": "API 密钥菜单", "Jump to comment selection": "跳转到评论选择", "Slash commands": "斜杠命令", @@ -1063,7 +1090,7 @@ "Filter": "筛选", "Page title": "页面标题", "Page content": "页面内容", - "Member actions": "成员操作", + "Member actions for {{name}}": "{{name}} 的成员操作", "Toggle password visibility": "切换密码可见性", "Send comment": "发送评论", "Token actions": "令牌操作", @@ -1084,5 +1111,183 @@ "Added {{name}} to favorites": "已将 {{name}} 添加到收藏", "Removed {{name}} from favorites": "已将 {{name}} 从收藏中移除", "Page menu for {{name}}": "{{name}} 的页面菜单", - "Create subpage of {{name}}": "创建 {{name}} 的子页面" + "Create subpage of {{name}}": "创建 {{name}} 的子页面", + "Allow personal spaces": "允许个人空间", + "Members can create their own personal space.": "成员可以创建自己的个人空间。", + "Toggle allow personal spaces": "切换是否允许个人空间", + "Create personal space": "创建个人空间", + "Personal space": "个人空间", + "{{name}}'s space": "{{name}} 的空间", + "Apply": "应用", + "Cells that aren't already a page reference will be cleared.": "尚未是页面引用的单元格将被清空。", + "Cells that aren't a valid URL will be cleared.": "不是有效 URL 的单元格将被清空。", + "Cells that aren't a valid email address will be cleared.": "不是有效电子邮件地址的单元格将被清空。", + "Cells that can't be parsed as a date will be cleared.": "无法解析为日期的单元格将被清空。", + "Cells that can't be parsed as a number will be cleared.": "无法解析为数字的单元格将被清空。", + "Cells will be coerced (yes/true/1 become checked; everything else becomes unchecked or cleared).": "单元格将被强制转换(yes/true/1 将变为选中;其他所有值将变为未选中或被清空)。", + "Cells will be reinterpreted under the new type.": "单元格将在新类型下重新解释。", + "Cells will be replaced with a comma-separated list of file names.": "单元格将被替换为以逗号分隔的文件名列表。", + "Cells will be replaced with a comma-separated list of option names.": "单元格将被替换为以逗号分隔的选项名称列表。", + "Cells will be replaced with the option name.": "单元格将被替换为选项名称。", + "Cells will be replaced with the page title.": "单元格将被替换为页面标题。", + "Cells will be replaced with the person's name.": "单元格将被替换为此人的姓名。", + "Change type": "更改类型", + "Change type to {{label}}?": "将类型更改为 {{label}}?", + "Converting…": "正在转换…", + "Existing values become single-item lists. No data is lost.": "现有值将变为只包含一项的列表。不会丢失数据。", + "Only the first selected item per row will be kept; the rest will be discarded.": "每行仅保留第一个已选项目;其余项目将被丢弃。", + "Previous record": "上一条记录", + "Next record": "下一条记录", + "Record actions": "记录操作", + "Delete record": "删除记录", + "Delete record?": "删除记录?", + "This action cannot be undone.": "此操作无法撤销。", + "to navigate": "用于导航", + "to close": "用于关闭", + "Expand row {{number}}": "展开第 {{number}} 行", + "Saving…": "正在保存…", + "Read-only": "只读", + "Loading…": "正在加载…", + "Updated {{when}}": "更新于 {{when}}", + "Add property": "添加属性", + "Create property": "创建属性", + "Hide properties": "隐藏属性", + "Find a property type": "查找属性类型", + "Properties": "属性", + "A property with this name already exists": "已存在同名属性", + "Add card": "添加卡片", + "Add filter": "添加筛选", + "Add option": "添加选项", + "Add sort": "添加排序", + "Add view": "添加视图", + "All data in this column will be lost.": "此列中的所有数据都将丢失。", + "Allow multiple people": "允许多人", + "Alphabetize": "按字母顺序", + "Are you sure you want to delete": "您确定要删除", + "Ascending": "升序", + "Base deleted": "资料库已删除", + "Base name": "资料库名称", + "Base table": "资料库表", + "Card properties": "卡片属性", + "Cells longer than the Text limit will be truncated and the extra content permanently lost.": "超出文本长度限制的单元格内容将被截断,额外内容将永久丢失。", + "Checkbox": "复选框", + "Checked by default": "默认选中", + "Choose a property": "选择一个属性", + "Clear selection": "清除选择", + "Column options": "列选项", + "Comma, period": "逗号、句点", + "Complete": "完成", + "Contains": "包含", + "Copy link to view": "复制视图链接", + "Create a status property": "创建状态属性", + "Created at": "创建于", + "Currency": "货币", + "Decimal places": "小数位数", + "Default value": "默认值", + "Delete property": "删除属性", + "Delete view": "删除视图", + "Delete {{count}} rows?_one": "删除 1 行?", + "Delete {{count}} rows?_other": "删除 {{count}} 行?", + "Descending": "降序", + "Discard": "放弃", + "Doesn't contain": "不包含", + "Done": "完成", + "Edit formula": "编辑公式", + "Edit property": "编辑属性", + "Export CSV": "导出 CSV", + "Failed to load base": "加载资料库失败", + "False": "假", + "File": "文件", + "Filter and sort changes are visible only to you": "筛选和排序更改仅对您可见", + "Filter by": "筛选条件", + "Formula": "公式", + "Get started with": "开始使用", + "Greater than": "大于", + "Group by": "分组依据", + "Group this board by a select or status property.": "按选择或状态属性对此看板进行分组。", + "Hide all": "全部隐藏", + "Hide group": "隐藏分组", + "In Progress": "进行中", + "In progress": "进行中", + "Include time": "包含时间", + "Insert a kanban board on this page": "在此页面插入一个看板", + "Insert an inline base on this page": "在此页面插入一个内联资料库", + "Is": "是", + "Is after": "在此之后", + "Is any of": "是其中之一", + "Is before": "在此之前", + "Is empty": "为空", + "Is none of": "都不是", + "Is not": "不是", + "Is not empty": "不为空", + "Is on or after": "在此日期或之后", + "Is on or before": "在此日期或之前", + "Is within": "在范围内", + "Keep editing": "继续编辑", + "Last edited at": "最后编辑于", + "Last edited by": "最后编辑者", + "Less than": "小于", + "Link copied to clipboard": "链接已复制到剪贴板", + "Local": "本地", + "Long text": "长文本", + "Moved card to {{column}}": "已将卡片移动到 {{column}}", + "Moved column to {{column}}": "已将列移动到 {{column}}", + "Multi-select": "多选", + "New row": "新行", + "Next month": "下个月", + "Next week": "下周", + "Next year": "明年", + "No filters applied": "未应用筛选", + "No match": "无匹配项", + "No options for this property type": "此属性类型没有可用选项", + "No sorts applied": "未应用排序", + "No value": "无值", + "None": "无", + "Not started": "未开始", + "Number": "数字", + "One month ago": "一个月前", + "One month from now": "从现在起一个月后", + "One week ago": "一周前", + "One week from now": "从现在起一周后", + "Open as page": "作为页面打开", + "Options": "选项", + "Past month": "过去一个月", + "Past week": "过去一周", + "Past year": "过去一年", + "Percent": "百分比", + "Period, comma": "句点、逗号", + "Person": "人员", + "Please enter a valid email": "请输入有效的电子邮件地址", + "Progress": "进度", + "Property options": "属性选项", + "Relative": "相对", + "Rename property": "重命名属性", + "Reset": "重置", + "Save for everyone": "保存给所有人", + "Select": "选择", + "Select a property": "选择一个属性", + "Select all loaded rows": "选择所有已加载的行", + "Show all": "显示全部", + "Sort": "排序", + "Sort by": "排序依据", + "Space, comma": "空格、逗号", + "Space, period": "空格、句点", + "This board has no grouping property yet.": "此看板尚无分组属性。", + "This month": "本月", + "This year": "今年", + "Thousands and decimal separators": "千位分隔符和小数分隔符", + "Time format": "时间格式", + "To Do": "待办", + "Tomorrow": "明天", + "True": "真", + "Unsaved changes": "未保存的更改", + "Untitled base": "未命名资料库", + "URL": "网址", + "Value": "值", + "View updated for everyone": "已为所有人更新视图", + "You have unsaved changes. Do you want to discard them?": "您有未保存的更改。要放弃这些更改吗?", + "{{count}} rows deleted_one": "已删除 1 行", + "{{count}} rows deleted_other": "已删除 {{count}} 行", + "{{count}} selected_one": "已选择 1 项", + "{{count}} selected_other": "已选择 {{count}} 项" } diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx index ff36f0f52..8200414bd 100644 --- a/apps/client/src/App.tsx +++ b/apps/client/src/App.tsx @@ -41,6 +41,7 @@ import AiSettings from "@/ee/ai/pages/ai-settings.tsx"; import Integrations from "@/features/integration/pages/integrations.tsx"; import Connections from "@/features/integration/pages/connections.tsx"; import SlackLinkPage from "@/features/integration/pages/slack-link.tsx"; +import BasePage from "@/ee/base/pages/base-page.tsx"; import AuditLogs from "@/ee/audit/pages/audit-logs.tsx"; import VerifiedPages from "@/ee/page-verification/pages/verified-pages.tsx"; import TemplateList from "@/ee/template/pages/template-list"; @@ -110,6 +111,8 @@ export default function App() { element={} /> + } /> + } /> (false); const [isExporting, setIsExporting] = useState(false); const { t } = useTranslation(); + const upgradeLabel = useUpgradeLabel(); + const isDocx = format === ExportFormat.Docx; + const docxEntitled = useHasFeature(Feature.DOCX_EXPORT); + const blockedByLicense = isDocx && !docxEntitled; const handleExport = async () => { setIsExporting(true); try { if (type === "page") { - await exportPage({ - pageId: id, - format, - includeChildren, - includeAttachments, - }); + if (format === ExportFormat.Docx) { + await exportPageToDocx({ pageId: id }); + } else { + await exportPage({ + pageId: id, + format, + includeChildren, + includeAttachments, + }); + } } if (type === "space") { await exportSpace({ spaceId: id, format, includeAttachments }); @@ -88,10 +104,15 @@ export default function ExportModal({
{t("Format")}
- + - {type === "page" && ( + {type === "page" && !isDocx && ( <> @@ -143,7 +164,16 @@ export default function ExportModal({ - + + + @@ -154,23 +184,49 @@ export default function ExportModal({ interface ExportFormatSelection { format: ExportFormat; onChange: (value: string) => void; + includeDocx?: boolean; + docxEntitled?: boolean; } -function ExportFormatSelection({ format, onChange }: ExportFormatSelection) { +function ExportFormatSelection({ + format, + onChange, + includeDocx, + docxEntitled, +}: ExportFormatSelection) { const { t } = useTranslation(); + const data = [ + { value: "markdown", label: "Markdown" }, + { value: "html", label: "HTML" }, + ...(includeDocx + ? [{ value: "docx", label: "Word (.docx)", disabled: !docxEntitled }] + : []), + ]; + return ( { + setValue(e.currentTarget.value); + debouncedCommit(); + }} + onFocus={() => { + focusedRef.current = true; + }} + onBlur={() => { + focusedRef.current = false; + commit(); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + e.currentTarget.blur(); + } + if (e.key === "Escape") { + setValue(page?.title ?? ""); + e.currentTarget.blur(); + } + }} + /> + ); +} diff --git a/apps/client/src/ee/base/components/base-table-skeleton.tsx b/apps/client/src/ee/base/components/base-table-skeleton.tsx new file mode 100644 index 000000000..cd7dfc6fd --- /dev/null +++ b/apps/client/src/ee/base/components/base-table-skeleton.tsx @@ -0,0 +1,92 @@ +import { Skeleton } from "@mantine/core"; +import gridClasses from "@/ee/base/styles/grid.module.css"; +import classes from "@/ee/base/styles/base-table-skeleton.module.css"; + +const ROW_NUMBER_WIDTH = 64; +const COLUMN_WIDTH = 180; +const DEFAULT_COLUMN_COUNT = 6; +const DEFAULT_ROW_COUNT = 10; + +// Deterministic widths prevent flicker between renders. +const CELL_WIDTH_RATIOS = [0.78, 0.62, 0.84, 0.55, 0.71, 0.66]; +const HEADER_WIDTH_RATIOS = [0.42, 0.58, 0.5, 0.64, 0.46, 0.54]; + +type BaseTableSkeletonProps = { + // Match the eventual content shape to avoid a jarring size jump on swap. + rows?: number; + columns?: number; +}; + +export function BaseTableSkeleton({ + rows = DEFAULT_ROW_COUNT, + columns = DEFAULT_COLUMN_COUNT, +}: BaseTableSkeletonProps = {}) { + const gridTemplateColumns = [ + `${ROW_NUMBER_WIDTH}px`, + ...Array.from({ length: columns }, () => `${COLUMN_WIDTH}px`), + ].join(" "); + + return ( +
+
+
+ + + +
+
+ + + + +
+
+ +
+
+
+
+ +
+
+ {Array.from({ length: columns }).map((_, colIndex) => ( +
+
+ + +
+
+ ))} + + {Array.from({ length: rows }).map((_, rowIndex) => ( +
+
+
+ +
+
+ {Array.from({ length: columns }).map((_, colIndex) => ( +
+
+ +
+
+ ))} +
+ ))} +
+
+
+ ); +} diff --git a/apps/client/src/ee/base/components/base-table.tsx b/apps/client/src/ee/base/components/base-table.tsx new file mode 100644 index 000000000..be449c3f9 --- /dev/null +++ b/apps/client/src/ee/base/components/base-table.tsx @@ -0,0 +1,70 @@ +import { GridContainer } from "@/ee/base/components/grid/grid-container"; +import { Table } from "@tanstack/react-table"; +import { + IBase, + IBaseRow, + IBaseView, +} from "@/ee/base/types/base.types"; + +type BaseTableProps = { + base: IBase; + rows: IBaseRow[]; + effectiveView: IBaseView | undefined; + table: Table; + pageId: string; + embedded?: boolean; + isFiltered: boolean; + hasNextPage: boolean; + isFetchingNextPage: boolean; + onFetchNextPage: () => void; + onCellUpdate: (rowId: string, propertyId: string, value: unknown) => void; + onAddRow: (afterRowId?: string, focusPropertyId?: string) => void; + onColumnReorder: (columnId: string, finishIndex: number) => void; + onResizeEnd: () => void; + onRowReorder: ( + rowId: string, + targetRowId: string, + dropPosition: "above" | "below", + ) => void; + persistViewConfig: () => void; + scrollportRef: React.RefObject; + aboveBand?: React.ReactNode; +}; + +export function BaseTable({ + base, + rows: _rows, + table, + pageId, + embedded, + isFiltered, + hasNextPage, + isFetchingNextPage, + onFetchNextPage, + onCellUpdate, + onAddRow, + onColumnReorder, + onResizeEnd, + onRowReorder, + scrollportRef, + aboveBand, +}: BaseTableProps) { + return ( + + ); +} diff --git a/apps/client/src/ee/base/components/base-toolbar.tsx b/apps/client/src/ee/base/components/base-toolbar.tsx new file mode 100644 index 000000000..213ce5874 --- /dev/null +++ b/apps/client/src/ee/base/components/base-toolbar.tsx @@ -0,0 +1,295 @@ +import { useState, useCallback, useMemo } from "react"; +import { ActionIcon, Tooltip, Badge } from "@mantine/core"; +import { Table } from "@tanstack/react-table"; +import { + IconSortAscending, + IconFilter, + IconEye, + IconDownload, + IconArrowsDiagonal, + IconLayoutColumns, + IconAdjustments, +} from "@tabler/icons-react"; +import { notifications } from "@mantine/notifications"; +import { + IBase, + IBaseRow, + IBaseView, + ViewSortConfig, + FilterCondition, + FilterGroup, +} from "@/ee/base/types/base.types"; +import { exportBaseToCsv } from "@/ee/base/services/base-service"; +import { getApiErrorMessage } from "@/lib/api-error"; +import { ViewTabs } from "@/ee/base/components/views/view-tabs"; +import { ViewSortConfigPopover } from "@/ee/base/components/views/view-sort-config"; +import { ViewFilterConfigPopover } from "@/ee/base/components/views/view-filter-config"; +import { ViewPropertyVisibility } from "@/ee/base/components/views/view-property-visibility"; +import { KanbanGroupByPicker } from "@/ee/base/components/kanban/kanban-group-by-picker"; +import { KanbanCardProperties } from "@/ee/base/components/kanban/kanban-card-properties"; +import { useTranslation } from "react-i18next"; +import classes from "@/ee/base/styles/grid.module.css"; +import toolbarClasses from "@/ee/base/styles/base-toolbar.module.css"; + +type BaseToolbarProps = { + base: IBase; + activeView: IBaseView | undefined; + views: IBaseView[]; + table?: Table; + onViewChange: (viewId: string) => void; + onAddView?: () => void; + canAddView?: boolean; + onPersistViewConfig: () => void; + onDraftSortsChange: (sorts: ViewSortConfig[] | undefined) => void; + onDraftFiltersChange: (filter: FilterGroup | undefined) => void; + onExpand?: () => void; + getViewShareUrl?: (viewId: string) => string | null; +}; + +export function BaseToolbar({ + base, + activeView, + views, + table, + onViewChange, + onAddView, + canAddView, + onPersistViewConfig, + onDraftSortsChange, + onDraftFiltersChange, + onExpand, + getViewShareUrl, +}: BaseToolbarProps) { + const { t } = useTranslation(); + const [sortOpened, setSortOpened] = useState(false); + const [filterOpened, setFilterOpened] = useState(false); + const [propertiesOpened, setPropertiesOpened] = useState(false); + const [cardPropertiesOpened, setCardPropertiesOpened] = useState(false); + const [exporting, setExporting] = useState(false); + + const isKanban = activeView?.type === "kanban"; + + const handleExport = useCallback(async () => { + if (exporting) return; + setExporting(true); + try { + await exportBaseToCsv(base.id); + } catch (err) { + notifications.show({ + color: "red", + message: getApiErrorMessage(err, t("Failed to export CSV")), + }); + } finally { + setExporting(false); + } + }, [base.id, exporting, t]); + + const openToolbar = useCallback((panel: "sort" | "filter" | "properties") => { + setSortOpened(panel === "sort" ? (v) => !v : false); + setFilterOpened(panel === "filter" ? (v) => !v : false); + setPropertiesOpened(panel === "properties" ? (v) => !v : false); + }, []); + + const sorts = activeView?.config?.sorts ?? []; + const conditions = useMemo(() => { + const filter = activeView?.config?.filter; + if (!filter || filter.op !== "and") return []; + return filter.children.filter( + (c): c is FilterCondition => !("children" in c), + ); + }, [activeView?.config?.filter]); + + const hiddenPropertyCount = useMemo(() => { + if (!table) return 0; + const cols = table.getAllLeafColumns().filter((col) => col.id !== "__row_number"); + return cols.filter((col) => col.getCanHide() && !col.getIsVisible()).length; + }, [table, table?.getState().columnVisibility]); + + const handleSortsChange = useCallback( + (newSorts: ViewSortConfig[]) => { + onDraftSortsChange(newSorts.length > 0 ? newSorts : undefined); + }, + [onDraftSortsChange], + ); + + const handleFiltersChange = useCallback( + (newConditions: FilterCondition[]) => { + const filter: FilterGroup | undefined = + newConditions.length > 0 + ? { op: "and", children: newConditions } + : undefined; + onDraftFiltersChange(filter); + }, + [onDraftFiltersChange], + ); + + return ( +
+ + +
+ + + + + + + setFilterOpened(false)} + conditions={conditions} + properties={base.properties} + onChange={handleFiltersChange} + > + + 0 ? "blue" : "gray"} + onClick={() => openToolbar("filter")} + > + + {conditions.length > 0 && ( + + {conditions.length} + + )} + + + + + {isKanban && activeView && ( + <> + + + + + + + + + setCardPropertiesOpened(false)} + base={base} + view={activeView} + pageId={base.id} + > + + setCardPropertiesOpened((v) => !v)} + > + + + + + + )} + + {!isKanban && ( + <> + setSortOpened(false)} + sorts={sorts} + properties={base.properties} + onChange={handleSortsChange} + > + + 0 ? "blue" : "gray"} + onClick={() => openToolbar("sort")} + > + + {sorts.length > 0 && ( + + {sorts.length} + + )} + + + + + {table && ( + setPropertiesOpened(false)} + table={table} + properties={base.properties} + onPersist={onPersistViewConfig} + > + + 0 ? "blue" : "gray"} + onClick={() => openToolbar("properties")} + > + + {hiddenPropertyCount > 0 && ( + + {hiddenPropertyCount} + + )} + + + + )} + + )} + + {onExpand && ( + + + + + + )} +
+
+ ); +} diff --git a/apps/client/src/ee/base/components/base-view-draft-banner.tsx b/apps/client/src/ee/base/components/base-view-draft-banner.tsx new file mode 100644 index 000000000..cda3c9f15 --- /dev/null +++ b/apps/client/src/ee/base/components/base-view-draft-banner.tsx @@ -0,0 +1,45 @@ +import { Group, Button, Tooltip } from "@mantine/core"; +import { useTranslation } from "react-i18next"; + +type BaseViewDraftBannerProps = { + isDirty: boolean; + canSave: boolean; + onReset: () => void; + onSave: () => void; + saving: boolean; +}; + +export function BaseViewDraftBanner({ + isDirty, + canSave, + onReset, + onSave, + saving, +}: BaseViewDraftBannerProps) { + const { t } = useTranslation(); + if (!isDirty) return null; + return ( + + + {canSave && ( + + + + )} + + ); +} diff --git a/apps/client/src/ee/base/components/base-view.tsx b/apps/client/src/ee/base/components/base-view.tsx new file mode 100644 index 000000000..22612f265 --- /dev/null +++ b/apps/client/src/ee/base/components/base-view.tsx @@ -0,0 +1,541 @@ +import { useCallback, useEffect, useMemo, useRef } from "react"; +import { Text, Stack } from "@mantine/core"; +import { useAtom } from "jotai"; +import { IconTable } from "@tabler/icons-react"; +import { useTranslation } from "react-i18next"; +import { notifications } from "@mantine/notifications"; +import { reorder } from "@atlaskit/pragmatic-drag-and-drop/reorder"; +import { generateJitteredKeyBetween } from "fractional-indexing-jittered"; +import { useBaseQuery } from "@/ee/base/queries/base-query"; +import { useBaseSocket } from "@/ee/base/hooks/use-base-socket"; +import { + FilterGroup, + ViewSortConfig, + EditingCell, + FocusedCell, + IBaseProperty, +} from "@/ee/base/types/base.types"; +import { + useBaseRowsQuery, + flattenRows, + useCreateRowMutation, + useUpdateRowMutation, + useReorderRowMutation, +} from "@/ee/base/queries/base-row-query"; +import { useUpdateViewMutation } from "@/ee/base/queries/base-view-query"; +import { + activeViewIdAtomFamily, + editingCellAtomFamily, + focusedCellAtomFamily, +} from "@/ee/base/atoms/base-atoms"; +import { useBaseTable } from "@/ee/base/hooks/use-base-table"; +import { isSystemPropertyType } from "@/ee/base/property-types/property-type.registry"; +import { useRowSelection } from "@/ee/base/hooks/use-row-selection"; +import useCurrentUser from "@/features/user/hooks/use-current-user"; +import { useHydrateCurrentUser } from "@/ee/base/reference/reference-store"; +import { useViewDraft } from "@/ee/base/hooks/use-view-draft"; +import { BaseToolbar } from "@/ee/base/components/base-toolbar"; +import { BaseViewDraftBanner } from "@/ee/base/components/base-view-draft-banner"; +import { BaseEmbedTitle } from "@/ee/base/components/base-embed-title"; +import { BaseTableSkeleton } from "@/ee/base/components/base-table-skeleton"; +import { ViewRenderer } from "@/ee/base/components/views/view-renderer"; +import { RowDetailModal } from "@/ee/base/components/row-detail-modal/row-detail-modal"; +import { useRowDetailModal } from "@/ee/base/hooks/use-row-detail-modal"; +import { BaseEditableProvider } from "@/ee/base/context/base-editable"; +import { RowExpandProvider } from "@/ee/base/context/row-expand"; +import { usePageQuery } from "@/features/page/queries/page-query"; +import { buildPageUrl } from "@/features/page/page.utils"; +import { getAppUrl } from "@/lib/config.ts"; +import { useNavigate } from "react-router-dom"; +import classes from "@/ee/base/styles/grid.module.css"; +import viewClasses from "@/ee/base/styles/base-view.module.css"; +import kanbanClasses from "@/ee/base/styles/kanban.module.css"; + +type BaseViewProps = { + pageId: string; + embedded?: boolean; + /** False makes the view read-only. Standalone passes page.permissions.canEdit; + * embedded ANDs that with the host editor's editability. */ + editable?: boolean; + titleSlot?: React.ReactNode; +}; + +export function BaseView({ pageId, embedded, editable = true, titleSlot }: BaseViewProps) { + const { t } = useTranslation(); + // Subscribe so other clients' edits, schema changes, and async-job completions reconcile into cache. + useBaseSocket(pageId); + const { data: base, isLoading: baseLoading, error: baseError } = + useBaseQuery(pageId); + + const navigate = useNavigate(); + const { data: page } = usePageQuery({ pageId }); + const handleExpand = useCallback(() => { + if (!page) return; + navigate(buildPageUrl(page.space?.slug, page.slugId, page.title)); + }, [navigate, page]); + + // Share URL for a specific view; always points at the standalone page where ?view= is honored. + const getViewShareUrl = useCallback( + (viewId: string) => + page + ? `${getAppUrl()}${buildPageUrl(page.space?.slug, page.slugId, page.title)}?view=${encodeURIComponent(viewId)}` + : null, + [page], + ); + + const [activeViewId, setActiveViewId] = useAtom( + activeViewIdAtomFamily(pageId), + ) as unknown as [string | null, (val: string | null) => void]; + + const [, setEditingCell] = useAtom( + editingCellAtomFamily(pageId), + ) as unknown as [EditingCell, (val: EditingCell) => void]; + + const [, setFocusedCell] = useAtom( + focusedCellAtomFamily(pageId), + ) as unknown as [FocusedCell, (val: FocusedCell) => void]; + + const views = useMemo( + () => + [...(base?.views ?? [])].sort((a, b) => + a.position < b.position ? -1 : a.position > b.position ? 1 : 0, + ), + [base?.views], + ); + const activeView = useMemo(() => { + if (!views.length) return undefined; + return views.find((v) => v.id === activeViewId) ?? views[0]; + }, [views, activeViewId]); + + const { data: currentUser } = useCurrentUser(); + useHydrateCurrentUser(pageId); + const { + effectiveFilter, + effectiveSorts, + isDirty, + setFilter: setDraftFilter, + setSorts: setDraftSorts, + reset: resetDraft, + buildPromotedConfig, + } = useViewDraft({ + userId: currentUser?.user.id, + pageId, + viewId: activeView?.id, + baselineFilter: activeView?.config?.filter, + baselineSorts: activeView?.config?.sorts, + }); + + // Baseline merged with local draft. Used for table state and toolbar badge counts. + // The real activeView remains the auto-persist baseline so drafts can't leak into layout writes. + const effectiveView = useMemo( + () => + activeView + ? { + ...activeView, + config: { + ...activeView.config, + filter: effectiveFilter, + sorts: effectiveSorts, + }, + } + : undefined, + [activeView, effectiveFilter, effectiveSorts], + ); + + const activeFilter = effectiveFilter; + const activeSorts = effectiveSorts; + + const canSave = editable; + + // Gate on base to avoid a "bland" list request before the active view's + // config resolves, which would double network traffic for sorted/filtered views. + const isKanban = activeView?.type === "kanban"; + + const { + data: rowsData, + isLoading: rowsLoading, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + } = useBaseRowsQuery(base && !isKanban ? pageId : undefined, activeFilter, activeSorts); + + const updateRowMutation = useUpdateRowMutation(); + const createRowMutation = useCreateRowMutation(); + const reorderRowMutation = useReorderRowMutation(); + const updateViewMutation = useUpdateViewMutation(); + + useEffect(() => { + if (activeView && activeViewId !== activeView.id) { + setActiveViewId(activeView.id); + } + }, [activeView, activeViewId, setActiveViewId]); + + // Deep link: apply ?view= once after views load; skip if the id is + // unrecognised so we fall back to the default without fighting a later tab switch. + const appliedViewParamRef = useRef(false); + useEffect(() => { + if (appliedViewParamRef.current || views.length === 0) return; + const viewParam = new URLSearchParams(window.location.search).get("view"); + if (viewParam && views.some((v) => v.id === viewParam)) { + setActiveViewId(viewParam); + } + appliedViewParamRef.current = true; + }, [views, setActiveViewId]); + + const { clear: clearSelection } = useRowSelection(pageId); + useEffect(() => { + clearSelection(); + }, [pageId, activeView?.id, clearSelection]); + + const scrollportRef = useRef(null); + + const rows = useMemo(() => { + const flat = flattenRows(rowsData); + // With an active sort the server returns rows in sort order via keyset + // pagination; re-sorting by position on the client would break it as more + // pages load. Position sort only applies when no view sort is active. + if (activeSorts && activeSorts.length > 0) { + return flat; + } + return flat.sort((a, b) => + a.position < b.position ? -1 : a.position > b.position ? 1 : 0, + ); + }, [rowsData, activeSorts]); + const rowsRef = useRef(rows); + rowsRef.current = rows; + + const { table, persistViewConfig } = useBaseTable(base, rows, effectiveView); + + const guardedPersistViewConfig = useCallback(() => { + if (!editable) return; + persistViewConfig(); + }, [editable, persistViewConfig]); + + // Mutation result objects change identity every render; only .mutate is + // stable. Rows are memoized on these callbacks' identities, so they must + // not churn with unrelated re-renders. + const updateRow = updateRowMutation.mutate; + const handleCellUpdate = useCallback( + (rowId: string, propertyId: string, value: unknown) => { + if (!editable) return; + updateRow({ + rowId, + pageId, + cells: { [propertyId]: value }, + }); + }, + [editable, pageId, updateRow], + ); + + const handleAddRow = useCallback( + (afterRowId?: string, focusPropertyId?: string) => { + if (!editable) return; + createRowMutation.mutate( + { pageId, ...(afterRowId ? { afterRowId } : {}) }, + { + onSuccess: (newRow) => { + let propertyId = focusPropertyId; + if (!propertyId) { + const firstEditable = table.getVisibleLeafColumns().find((col) => { + if (col.id === "__row_number") return false; + const prop = col.columnDef.meta?.property as + | IBaseProperty + | undefined; + return ( + !!prop && + prop.type !== "checkbox" && + !isSystemPropertyType(prop.type) + ); + }); + propertyId = ( + firstEditable?.columnDef.meta?.property as + | IBaseProperty + | undefined + )?.id; + } + if (propertyId) { + setEditingCell({ rowId: newRow.id, propertyId }); + setFocusedCell({ rowId: newRow.id, propertyId }); + } + }, + }, + ); + }, + [editable, pageId, createRowMutation, table, setEditingCell, setFocusedCell], + ); + + const handleViewChange = useCallback( + (viewId: string) => { + setActiveViewId(viewId); + }, + [setActiveViewId], + ); + + const handleColumnReorder = useCallback( + (columnId: string, finishIndex: number) => { + const order = table.getState().columnOrder; + const startIndex = order.indexOf(columnId); + if (startIndex === -1 || startIndex === finishIndex) return; + table.setColumnOrder(reorder({ list: order, startIndex, finishIndex })); + guardedPersistViewConfig(); + }, + [table, guardedPersistViewConfig], + ); + + const handleResizeEnd = useCallback(() => { + guardedPersistViewConfig(); + }, [guardedPersistViewConfig]); + + const handleDraftSortsChange = useCallback( + (sorts: ViewSortConfig[] | undefined) => { + setDraftSorts(sorts && sorts.length > 0 ? sorts : undefined); + }, + [setDraftSorts], + ); + + const handleDraftFiltersChange = useCallback( + (filter: FilterGroup | undefined) => { + setDraftFilter(filter); + }, + [setDraftFilter], + ); + + const handleSaveDraft = useCallback(async () => { + if (!activeView || !base) return; + // Preserves non-draft baseline fields (widths/order/visibility), overwrites only filter/sorts. + const config = buildPromotedConfig(activeView.config); + try { + await updateViewMutation.mutateAsync({ + viewId: activeView.id, + pageId: base.id, + config, + }); + resetDraft(); + notifications.show({ message: t("View updated for everyone") }); + } catch { + // useUpdateViewMutation shows a toast and rolls back; keep the draft so the user can retry. + } + }, [ + activeView, + base, + buildPromotedConfig, + resetDraft, + t, + updateViewMutation, + ]); + + const { openRowId, openRow, closeRow } = useRowDetailModal(pageId); + // openRow's identity tracks searchParams; rows subscribe to the expand + // context, so hand them a stable wrapper instead. + const openRowRef = useRef(openRow); + openRowRef.current = openRow; + const handleExpandRow = useCallback((rowId: string) => { + openRowRef.current(rowId); + }, []); + const handleRowNavigate = useCallback((rowId: string) => { + openRowRef.current(rowId, { replace: true }); + }, []); + + const reorderRow = reorderRowMutation.mutate; + const handleRowReorder = useCallback( + (rowId: string, targetRowId: string, dropPosition: "above" | "below") => { + if (!editable) return; + const remainingRows = rowsRef.current.filter((r) => r.id !== rowId); + const targetIndex = remainingRows.findIndex((r) => r.id === targetRowId); + if (targetIndex === -1) return; + + let lowerPos: string | null = null; + let upperPos: string | null = null; + if (dropPosition === "above") { + lowerPos = + targetIndex > 0 ? remainingRows[targetIndex - 1]?.position : null; + upperPos = remainingRows[targetIndex]?.position ?? null; + } else { + lowerPos = remainingRows[targetIndex]?.position ?? null; + upperPos = + targetIndex < remainingRows.length - 1 + ? remainingRows[targetIndex + 1]?.position + : null; + } + + try { + let newPosition: string; + if (lowerPos && upperPos && lowerPos === upperPos) { + newPosition = generateJitteredKeyBetween(lowerPos, null); + } else { + newPosition = generateJitteredKeyBetween(lowerPos, upperPos); + } + reorderRow({ rowId, pageId, position: newPosition }); + } catch { + // Position computation failed; skip silently. + } + }, + [editable, pageId, reorderRow], + ); + + if (baseLoading || (!isKanban && rowsLoading)) { + return ; + } + if (baseError) { + return ( + + + {t("Failed to load base")} + + ); + } + if (!base) return null; + + // Ghost rows are an "empty base" affordance, not a "filter matched nothing" state. + const isFiltered = (activeFilter?.children?.length ?? 0) > 0; + + const banner = ( + + ); + + const toolbar = ( + + ); + + const kanbanBand = ( +
+ {embedded ? null : titleSlot} + {banner} + {toolbar} + {embedded ? : null} +
+ ); + + const viewRenderer = (folded: React.ReactNode) => ( + + ); + + if (embedded) { + if (isKanban) { + return ( + + + {kanbanBand} + {viewRenderer(null)} + + + + ); + } + + // Banner and toolbar go into aboveBand so they scroll with the host document; + // only the column-header row stays pinned (via --sticky-band-top). + return ( + + + {viewRenderer( + <> + {banner} + {toolbar} + + , + )} + + + + ); + } + + if (isKanban) { + return ( + +
+ + {kanbanBand} + {viewRenderer(null)} + +
+ +
+ ); + } + + // Standalone: title, banner, and toolbar go in aboveBand inside the scroll + // container so they scroll away; only the column-header row stays pinned. + return ( + +
+
+ + {viewRenderer( + <> + {titleSlot} + {banner} + {toolbar} + , + )} + +
+
+ +
+ ); +} diff --git a/apps/client/src/ee/base/components/cells/badge-overflow.tsx b/apps/client/src/ee/base/components/cells/badge-overflow.tsx new file mode 100644 index 000000000..278b84472 --- /dev/null +++ b/apps/client/src/ee/base/components/cells/badge-overflow.tsx @@ -0,0 +1,100 @@ +import { ReactElement, useLayoutEffect, useRef, useState } from "react"; +import { Tooltip } from "@mantine/core"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +export function computeVisibleBadgeCount( + itemWidths: number[], + gap: number, + available: number, + badgeWidth: number, +): number { + const count = itemWidths.length; + if (count === 0) return 0; + if (available <= 0) return count; + + let lineWidth = 0; + for (let i = 0; i < count; i++) { + lineWidth += itemWidths[i] + (i > 0 ? gap : 0); + } + if (lineWidth <= available) return count; + + let used = 0; + let fit = 0; + for (let i = 0; i < count; i++) { + const advance = itemWidths[i] + (i > 0 ? gap : 0); + if (used + advance + gap + badgeWidth <= available) { + used += advance; + fit = i + 1; + } else { + break; + } + } + return Math.max(fit, 1); +} + +const BADGE_GAP = 4; + +type BadgeOverflowListProps = { + chips: ReactElement[]; + measureKey: string; + tooltipLabel?: string; +}; + +export function BadgeOverflowList({ + chips, + measureKey, + tooltipLabel, +}: BadgeOverflowListProps) { + const containerRef = useRef(null); + const measureRef = useRef(null); + const [visibleCount, setVisibleCount] = useState(chips.length); + + useLayoutEffect(() => { + const container = containerRef.current; + const measure = measureRef.current; + if (!container || !measure) return; + + const recompute = () => { + const nodes = Array.from(measure.children) as HTMLElement[]; + const chipWidths = nodes.slice(0, -1).map((n) => n.offsetWidth); + const badgeWidth = nodes[nodes.length - 1]?.offsetWidth ?? 0; + setVisibleCount( + computeVisibleBadgeCount( + chipWidths, + BADGE_GAP, + container.clientWidth, + badgeWidth, + ), + ); + }; + + recompute(); + const observer = new ResizeObserver(recompute); + observer.observe(container); + return () => observer.disconnect(); + }, [measureKey]); + + const visible = chips.slice(0, visibleCount); + const overflow = chips.length - visibleCount; + + return ( + +
+
+ {chips} + +{chips.length} +
+ {visible} + {overflow > 0 && ( + +{overflow} + )} +
+
+ ); +} diff --git a/apps/client/src/ee/base/components/cells/cell-checkbox.tsx b/apps/client/src/ee/base/components/cells/cell-checkbox.tsx new file mode 100644 index 000000000..163359dbd --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-checkbox.tsx @@ -0,0 +1,44 @@ +import { useCallback } from "react"; +import { Checkbox } from "@mantine/core"; +import { IBaseProperty } from "@/ee/base/types/base.types"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellCheckboxProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + readOnly?: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +export function CellCheckbox({ value, readOnly, onCommit }: CellCheckboxProps) { + const checked = value === true; + + const handleChange = useCallback(() => { + if (readOnly) return; + onCommit(!checked); + }, [readOnly, checked, onCommit]); + + return ( +
+ {}} + size="xs" + tabIndex={-1} + styles={{ + input: { + cursor: readOnly ? "default" : "pointer", + pointerEvents: "none", + }, + }} + /> +
+ ); +} diff --git a/apps/client/src/ee/base/components/cells/cell-created-at.tsx b/apps/client/src/ee/base/components/cells/cell-created-at.tsx new file mode 100644 index 000000000..21286843c --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-created-at.tsx @@ -0,0 +1,22 @@ +import { IBaseProperty } from "@/ee/base/types/base.types"; +import { formatTimestamp } from "@/ee/base/formatters/cell-formatters"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellCreatedAtProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +export function CellCreatedAt({ value }: CellCreatedAtProps) { + const formatted = formatTimestamp(typeof value === "string" ? value : null); + + if (!formatted) { + return ; + } + + return {formatted}; +} diff --git a/apps/client/src/ee/base/components/cells/cell-date.tsx b/apps/client/src/ee/base/components/cells/cell-date.tsx new file mode 100644 index 000000000..a4af25a15 --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-date.tsx @@ -0,0 +1,146 @@ +import { useCallback } from "react"; +import { Popover } from "@mantine/core"; +import { DatePicker } from "@mantine/dates"; +import { + IBaseProperty, + DateTypeOptions, +} from "@/ee/base/types/base.types"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellDateProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +export function formatDateDisplay( + dateStr: string | null | undefined, + options: DateTypeOptions | undefined, +): string { + if (!dateStr) return ""; + try { + const date = new Date(dateStr); + if (isNaN(date.getTime())) return ""; + + const months = [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + ]; + const month = months[date.getMonth()]; + const day = date.getDate(); + const year = date.getFullYear(); + + let result = `${month} ${day}, ${year}`; + + if (options?.includeTime) { + if (options.timeFormat === "24h") { + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); + result += ` ${hours}:${minutes}`; + } else { + let hours = date.getHours(); + const ampm = hours >= 12 ? "PM" : "AM"; + hours = hours % 12 || 12; + const minutes = String(date.getMinutes()).padStart(2, "0"); + result += ` ${hours}:${minutes} ${ampm}`; + } + } + + return result; + } catch { + return ""; + } +} + +function toISODateString(dateStr: string | null): string | null { + if (!dateStr) return null; + try { + const date = new Date(dateStr); + if (isNaN(date.getTime())) return null; + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; + } catch { + return null; + } +} + +export function CellDate({ + value, + property, + isEditing, + onCommit, + onCancel, +}: CellDateProps) { + const typeOptions = property.typeOptions as DateTypeOptions | undefined; + const dateStr = typeof value === "string" ? value : null; + const pickerValue = toISODateString(dateStr); + + const handleChange = useCallback( + (selected: string | null) => { + if (selected) { + const date = new Date(selected); + onCommit(date.toISOString()); + } else { + onCommit(null); + } + }, + [onCommit], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Escape") { + e.preventDefault(); + onCancel(); + } + }, + [onCancel], + ); + + if (isEditing) { + return ( + { + if (!o) onCancel(); + }} + onClose={onCancel} + position="bottom-start" + width="auto" + trapFocus + closeOnClickOutside + closeOnEscape + > + +
+ + {formatDateDisplay(dateStr, typeOptions)} + +
+
+ + + +
+ ); + } + + if (!dateStr) { + return ; + } + + return ( + + {formatDateDisplay(dateStr, typeOptions)} + + ); +} diff --git a/apps/client/src/ee/base/components/cells/cell-email.tsx b/apps/client/src/ee/base/components/cells/cell-email.tsx new file mode 100644 index 000000000..0d93f69fa --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-email.tsx @@ -0,0 +1,61 @@ +import { IBaseProperty } from "@/ee/base/types/base.types"; +import { Tooltip } from "@mantine/core"; +import { useEditableTextCell } from "@/ee/base/hooks/use-editable-text-cell"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellEmailProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +const toDraft = (value: unknown) => (typeof value === "string" ? value : ""); +const parse = (draft: string) => draft || null; + +export function CellEmail({ value, property, rowId, isEditing, onCommit, onCancel }: CellEmailProps) { + const { draft, setDraft, inputRef, handleKeyDown, handleBlur } = + useEditableTextCell({ + value, + isEditing, + onCommit, + onCancel, + toDraft, + parse, + rowId, + propertyId: property.id, + }); + + if (isEditing) { + return ( + setDraft(e.target.value)} + onKeyDown={handleKeyDown} + onBlur={handleBlur} + /> + ); + } + + const displayValue = toDraft(value); + if (!displayValue) { + return ; + } + return ( + + e.stopPropagation()} + > + {displayValue} + + + ); +} diff --git a/apps/client/src/ee/base/components/cells/cell-file.tsx b/apps/client/src/ee/base/components/cells/cell-file.tsx new file mode 100644 index 000000000..3d3bcd247 --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-file.tsx @@ -0,0 +1,236 @@ +import { useState, useRef, useCallback } from "react"; +import { Popover, ActionIcon, Text, UnstyledButton } from "@mantine/core"; +import { + IconPaperclip, + IconUpload, + IconFile, + IconX, +} from "@tabler/icons-react"; +import { IBaseProperty } from "@/ee/base/types/base.types"; +import cellClasses from "@/ee/base/styles/cells.module.css"; +import { uploadFile } from "@/features/page/services/page-service"; +import { getFileUrl } from "@/lib/config"; + +export type FileValue = { + id: string; + fileName: string; + mimeType?: string; + fileSize?: number; + url?: string; +}; + +function buildFileUrl(file: Pick): string { + return file.url ?? `/api/files/${file.id}/${encodeURIComponent(file.fileName)}`; +} + +type CellFileProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + readOnly?: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +function formatFileSize(bytes?: number): string { + if (!bytes) return ""; + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; +} + +function parseFiles(value: unknown): FileValue[] { + if (!Array.isArray(value)) return []; + return value.filter( + (f): f is FileValue => + f && typeof f === "object" && "id" in f && "fileName" in f, + ); +} + +export function CellFile({ + value, + property, + isEditing, + readOnly, + onCommit, + onCancel, +}: CellFileProps) { + const files = parseFiles(value); + const fileInputRef = useRef(null); + const [uploading, setUploading] = useState(false); + + const handleRemove = useCallback( + (fileId: string) => { + if (readOnly) return; + const updated = files.filter((f) => f.id !== fileId); + onCommit(updated.length > 0 ? updated : null); + }, + [readOnly, files, onCommit], + ); + + const handleUpload = useCallback( + async (fileList: FileList | null) => { + if (!fileList || fileList.length === 0) return; + setUploading(true); + + const newFiles: FileValue[] = [...files]; + + // Reuse the page-attachment upload pipeline: the base's pageId is passed + // to the standard /files/upload endpoint, which enforces the same edit + // access check as any other page attachment. + for (const file of Array.from(fileList)) { + try { + const attachment = await uploadFile(file, property.pageId); + newFiles.push({ + id: attachment.id, + fileName: attachment.fileName, + mimeType: attachment.mimeType, + fileSize: attachment.fileSize, + url: `/api/files/${attachment.id}/${encodeURIComponent(attachment.fileName)}`, + }); + } catch (err) { + console.error("File upload failed:", err); + } + } + + setUploading(false); + onCommit(newFiles.length > 0 ? newFiles : null); + }, + [files, property.pageId, onCommit], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Escape") { + e.preventDefault(); + onCancel(); + } + }, + [onCancel], + ); + + const MAX_VISIBLE = 2; + + if (isEditing) { + return ( + { + if (!o) onCancel(); + }} + onClose={onCancel} + position="bottom-start" + width={280} + trapFocus + closeOnClickOutside + closeOnEscape + hideDetached={false} + > + +
+ +
+
+ + {!readOnly && files.length === 0 && !uploading && ( + + No files attached + + )} + + {files.map((file) => ( + + ))} + + {!readOnly && ( + <> + { + handleUpload(e.target.files); + e.target.value = ""; + }} + /> + + fileInputRef.current?.click()} + disabled={uploading} + className={cellClasses.fileUploadBtn} + style={{ + color: uploading + ? "var(--mantine-color-gray-5)" + : "var(--mantine-color-blue-6)", + }} + > + + {uploading ? "Uploading..." : "Add file"} + + + )} + +
+ ); + } + + if (files.length === 0) { + return ; + } + + return ; +} + +function FileList({ + files, + maxVisible, +}: { + files: FileValue[]; + maxVisible: number; +}) { + const visible = files.slice(0, maxVisible); + const overflow = files.length - maxVisible; + + return ( +
+ {visible.map((file) => ( + + + {file.fileName} + + ))} + {overflow > 0 && ( + +{overflow} + )} +
+ ); +} diff --git a/apps/client/src/ee/base/components/cells/cell-formula.tsx b/apps/client/src/ee/base/components/cells/cell-formula.tsx new file mode 100644 index 000000000..bdaaf11cf --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-formula.tsx @@ -0,0 +1,38 @@ +import { Badge, Tooltip } from "@mantine/core"; +import { + IBaseProperty, + isFormulaErrorCell, +} from "@/ee/base/types/base.types"; +import { CellText } from "./cell-text"; +import { CellNumber } from "./cell-number"; +import { CellCheckbox } from "./cell-checkbox"; +import { CellDate } from "./cell-date"; + +type Props = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +export function CellFormula(props: Props) { + const { value, property } = props; + if (isFormulaErrorCell(value)) { + return ( + + + #ERROR + + + ); + } + const opts = (property.typeOptions ?? {}) as { resultType?: string }; + const resultType = opts.resultType ?? "null"; + const readOnlyProps = { ...props, isEditing: false }; + if (resultType === "number") return ; + if (resultType === "boolean") return ; + if (resultType === "date") return ; + return ; +} diff --git a/apps/client/src/ee/base/components/cells/cell-last-edited-at.tsx b/apps/client/src/ee/base/components/cells/cell-last-edited-at.tsx new file mode 100644 index 000000000..efad990de --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-last-edited-at.tsx @@ -0,0 +1,22 @@ +import { IBaseProperty } from "@/ee/base/types/base.types"; +import { formatTimestamp } from "@/ee/base/formatters/cell-formatters"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellLastEditedAtProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +export function CellLastEditedAt({ value }: CellLastEditedAtProps) { + const formatted = formatTimestamp(typeof value === "string" ? value : null); + + if (!formatted) { + return ; + } + + return {formatted}; +} diff --git a/apps/client/src/ee/base/components/cells/cell-last-edited-by.tsx b/apps/client/src/ee/base/components/cells/cell-last-edited-by.tsx new file mode 100644 index 000000000..b6dc90c52 --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-last-edited-by.tsx @@ -0,0 +1,41 @@ +import { Group, Tooltip } from "@mantine/core"; +import { IBaseProperty } from "@/ee/base/types/base.types"; +import { useReferenceStore } from "@/ee/base/reference/reference-store"; +import { CustomAvatar } from "@/components/ui/custom-avatar"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellLastEditedByProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onCancel: () => void; +}; + +export function CellLastEditedBy({ value, property }: CellLastEditedByProps) { + const userId = typeof value === "string" ? value : null; + + const store = useReferenceStore(property.pageId); + const user = userId ? store.users[userId] ?? null : null; + + if (!userId) { + return ; + } + + const name = user?.name ?? userId.substring(0, 8); + + return ( + + + + {name} + + + ); +} diff --git a/apps/client/src/ee/base/components/cells/cell-long-text.tsx b/apps/client/src/ee/base/components/cells/cell-long-text.tsx new file mode 100644 index 000000000..2c3900562 --- /dev/null +++ b/apps/client/src/ee/base/components/cells/cell-long-text.tsx @@ -0,0 +1,151 @@ +import { useEffect, useRef, useState } from "react"; +import { Popover, Textarea, Group, CloseButton, Tooltip } from "@mantine/core"; +import { useDebouncedCallback } from "@mantine/hooks"; +import { IBaseProperty } from "@/ee/base/types/base.types"; +import { formatLongTextPreview } from "@/ee/base/formatters/cell-formatters"; +import cellClasses from "@/ee/base/styles/cells.module.css"; + +type CellLongTextProps = { + value: unknown; + property: IBaseProperty; + rowId: string; + isEditing: boolean; + onCommit: (value: unknown) => void; + onValueChange: (value: unknown) => void; + onCancel: () => void; + onTabNavigate?: (shiftKey: boolean) => void; +}; + +const toText = (value: unknown) => (typeof value === "string" ? value : ""); +const normalize = (s: string) => { + const trimmed = s.trim(); + return trimmed.length ? trimmed : null; +}; + +export function CellLongText({ + value, + isEditing, + onCommit, + onValueChange, + onCancel, + onTabNavigate, +}: CellLongTextProps) { + const [draft, setDraft] = useState(() => toText(value)); + const cancelledRef = useRef(false); + const committedRef = useRef(false); + const wasEditingRef = useRef(false); + const textareaRef = useRef(null); + + // Seed draft and focus on the false->true editing transition only; ignore + // value changes mid-edit so the user's typing is not clobbered. + useEffect(() => { + if (isEditing && !wasEditingRef.current) { + cancelledRef.current = false; + committedRef.current = false; + setDraft(toText(value)); + requestAnimationFrame(() => { + const el = textareaRef.current; + if (!el) return; + el.focus(); + el.setSelectionRange(el.value.length, el.value.length); + }); + } + wasEditingRef.current = isEditing; + }, [isEditing, value]); + + // Autosave after a typing pause; commit/cancel clear the pending fire so + // a closed editor can never write a stale or discarded draft. + const debouncedAutosave = useDebouncedCallback(() => { + onValueChange(normalize(draft)); + }, 10_000); + + const commit = () => { + if (committedRef.current) return; + committedRef.current = true; + debouncedAutosave.cancel(); + onCommit(normalize(draft)); + }; + const cancel = () => { + cancelledRef.current = true; + debouncedAutosave.cancel(); + onCancel(); + }; + + const preview = formatLongTextPreview(toText(value)); + + return ( + { + if (opened) return; + // Programmatic close after cancel must not re-commit. + if (cancelledRef.current) { + cancelledRef.current = false; + return; + } + commit(); + }} + position="bottom-start" + width={320} + shadow="md" + withinPortal + closeOnClickOutside + closeOnEscape={false} + trapFocus + > + +
+ {preview ? ( + + {preview} + + ) : ( + + )} +
+
+ e.stopPropagation()} + className={cellClasses.longTextDropdown} + > + {isEditing && ( + <> + + + +