Compare commits

...

56 Commits

Author SHA1 Message Date
renovate[bot]
2c4fb6c0d0 chore(deps): update node.js to v24.13.0 2026-01-14 01:02:53 +00:00
Elian Doran
ed1bf17add feat(i18n): add workflow to check translation coverage (#8376) 2026-01-13 23:06:10 +02:00
Elian Doran
4800f2a172 chore(ci/i18n): add permissions 2026-01-13 22:56:27 +02:00
Elian Doran
e7ff364c01 chore(i18n): trigger on workflow change 2026-01-13 22:52:51 +02:00
Elian Doran
79ca299726 feat(i18n): add workflow to check translation coverage 2026-01-13 22:49:46 +02:00
Elian Doran
9d7ba48a6a Translations update from Hosted Weblate (#8375) 2026-01-13 22:28:17 +02:00
Gishky
9329665919 Translated using Weblate (English (United Kingdom))
Currently translated at 1.9% (34 of 1759 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/en_GB/
2026-01-13 21:23:46 +01:00
Gishky
f6821bce03 Translated using Weblate (German)
Currently translated at 100.0% (1759 of 1759 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2026-01-13 21:23:45 +01:00
Gishky
a7aedf93ab Translated using Weblate (German)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/de/
2026-01-13 21:23:45 +01:00
Elian Doran
4ffcf01452 fix: mac alt shortcuts (#8369) 2026-01-13 22:23:38 +02:00
Elian Doran
618459d353 feat(flake): provide .#edit-docs as a standalone docs editor (#8350) 2026-01-13 22:22:58 +02:00
Elian Doran
6436c16449 Fix race condition in edit-docs Electron ready event (#8344) 2026-01-13 22:20:22 +02:00
Elian Doran
1bec457004 Translations update from Hosted Weblate (#8374) 2026-01-13 21:58:13 +02:00
Hosted Weblate
3e541e37fe Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2026-01-13 20:44:40 +01:00
Elian Doran
a41b78d36f feat(ux): show more helpful output when users encounter permissions issues within the data directory (#8273) 2026-01-13 21:44:30 +02:00
Elian Doran
79c50f3b4c fix(deps): update dependency react-i18next to v16.5.2 (#8348) 2026-01-13 13:38:55 +02:00
Elian Doran
0f54b01cdd chore(deps): update dependency @smithy/middleware-retry to v4.4.20 (#8362) 2026-01-13 10:45:41 +02:00
Elian Doran
41f2b03711 chore(deps): update dependency @redocly/cli to v2.14.5 (#8361) 2026-01-13 10:33:06 +02:00
Elian Doran
0be76f982c Merge branch 'main' into renovate/smithy-middleware-retry-4.x 2026-01-13 10:33:02 +02:00
Elian Doran
5deb277672 chore(deps): update vitest monorepo to v4.0.17 (#8363) 2026-01-13 10:32:25 +02:00
Elian Doran
3d15c9e94c Translations update from Hosted Weblate (#8370) 2026-01-13 10:22:31 +02:00
noobhjy
1363f94621 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1759 of 1759 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2026-01-13 08:14:58 +00:00
Kim Nøglegaard
abdcd6cc0c Translated using Weblate (Norwegian Bokmål)
Currently translated at 6.4% (25 of 388 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/nb_NO/
2026-01-13 08:14:58 +00:00
nvno
dc8abed2f3 Translated using Weblate (Portuguese)
Currently translated at 99.6% (1753 of 1759 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pt/
2026-01-13 08:14:57 +00:00
Kim Nøglegaard
892c2cd838 Translated using Weblate (Norwegian Bokmål)
Currently translated at 2.3% (41 of 1759 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/nb_NO/
2026-01-13 08:14:56 +00:00
Hosted Weblate
2796b29138 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2026-01-13 08:14:55 +00:00
Elian Doran
05620a129f chore(deps): update electron-forge monorepo to v7.11.1 (#8366) 2026-01-13 10:14:48 +02:00
renovate[bot]
cb11955a44 chore(deps): update vitest monorepo to v4.0.17 2026-01-13 08:12:19 +00:00
Elian Doran
c3623a15fb fix(ci): website workflow failing due to postinstall scripts 2026-01-13 10:09:51 +02:00
Wael Nasreddine
0273c64bbf Build edit-docs as standalone package using makeApp
Changed edit-docs from a simple wrapper script to a properly built Nix
package using makeApp, similar to how desktop and server are built.

Changes:
- Added build script to apps/edit-docs/package.json
- Created apps/edit-docs/scripts/build.ts based on desktop's build script
- Added edit-docs:build task to root package.json
- Changed flake.nix to use makeApp which:
  - Builds edit-docs with all dependencies bundled
  - Creates a standalone trilium-edit-docs executable
  - Can be installed with 'nix profile install' and run from any directory

This makes edit-docs truly reusable - it can now be installed and run
from any project without requiring the Trilium source tree.
2026-01-12 22:08:27 -08:00
Wael Nasreddine
5b37140ffa Fix race condition in edit-docs Electron ready event
The edit-docs tool would hang on startup when the Electron 'ready' event
fired before the event listener was registered. This race condition occurred
because:

1. startElectron() creates a deferred promise and registers a 'ready' listener
2. The 'ready' event fires asynchronously at some point during app initialization
3. If async work (like config loading) delays the listener registration,
   Electron may already be ready when app.on('ready', ...) is called
4. Once fired, the 'ready' event doesn't fire again, leaving the listener
   waiting forever

The fix checks electron.app.isReady() before registering the listener:
- If already ready: execute the handler immediately
- If not ready: register the listener as before

This ensures the initialization sequence completes regardless of timing.

The issue became apparent while working on making edit-docs reusable from
other projects (see #8343), where config loading added enough async delay
to consistently trigger the race condition.

Related: https://github.com/TriliumNext/Trilium/issues/8343
2026-01-12 22:08:27 -08:00
Wael Nasreddine
fb4d63b049 Add --config, --help, and --version flags to edit-docs
- Implement --config (-c) flag to allow custom configuration file paths.
- Add --help (-h) flag to display tool usage and available options.
- Add --version (-v) flag to display the current Trilium version.
- Update electron-start.mts to correctly pass command-line arguments to Electron.
- Synchronize edit-docs version with the root package.json via update-version.ts.
- Resolve config paths relative to the configuration file's directory.

This makes edit-docs more robust and easier to use from external projects
and immutable environments like Nix.
2026-01-12 22:08:27 -08:00
Wael Nasreddine
015e41e792 fix(edit-docs): Minify meta for format==share 2026-01-12 22:08:27 -08:00
Wael Nasreddine
8e47f33329 Refactor edit-docs to use edit-docs-config.yaml
This removes hardcoded configuration from edit-docs.ts and replaces
it with dynamic loading from edit-docs-config.yaml.

Changes:
- Removed BASE_URL and NOTE_MAPPINGS constants
- Removed DOCS_ROOT and USER_GUIDE_ROOT environment variable dependencies
- Added js-yaml for YAML parsing
- Config paths are resolved relative to repository root

The tool now reads configuration from edit-docs-config.yaml, making it
easier to customize without code changes. The pnpm script is simplified
since it no longer needs to pass complex environment variables.
2026-01-12 22:08:27 -08:00
Elian Doran
ad4a8ec5f4 chore(deps): use pinned versions 2026-01-13 07:40:20 +02:00
renovate[bot]
56356f9c61 fix(deps): update dependency react-i18next to v16.5.2 2026-01-13 05:38:17 +00:00
Elian Doran
abda0f9111 chore(deps): update dependency happy-dom to v20.1.0 (#8307) 2026-01-13 07:35:35 +02:00
Elian Doran
c2a9d21198 fix(deps): update dependency i18next to v25.7.4 (#8305) 2026-01-13 07:34:54 +02:00
Elian Doran
59ffa1fa93 fix(deps): update dependency diff to v8.0.3 (#8364) 2026-01-13 07:33:16 +02:00
Elian Doran
d056185368 chore(deps): update dependency eslint-plugin-playwright to v2.5.0 (#8365) 2026-01-13 07:32:37 +02:00
Elian Doran
251c1f6471 chore(deps): update typescript-eslint monorepo to v8.53.0 (#8367) 2026-01-13 07:32:15 +02:00
Chloe Lee
9efca9827e Merge branch 'main' into fix/mac-alt-shortcuts 2026-01-13 10:54:30 +08:00
renovate[bot]
f5e2129ad4 chore(deps): update typescript-eslint monorepo to v8.53.0 2026-01-13 01:17:33 +00:00
renovate[bot]
6c8e6f2429 chore(deps): update electron-forge monorepo to v7.11.1 2026-01-13 01:16:59 +00:00
renovate[bot]
9b4b1a393e chore(deps): update dependency eslint-plugin-playwright to v2.5.0 2026-01-13 01:16:28 +00:00
renovate[bot]
028334407c fix(deps): update dependency diff to v8.0.3 2026-01-13 01:15:54 +00:00
renovate[bot]
b93540b40d chore(deps): update dependency @smithy/middleware-retry to v4.4.20 2026-01-13 01:14:27 +00:00
renovate[bot]
9e7eba5eab chore(deps): update dependency @redocly/cli to v2.14.5 2026-01-13 01:13:45 +00:00
chloelee767
a5e8c8f573 add tests 2026-01-13 00:05:07 +08:00
chloelee767
644cc27fa7 fix alt shortcuts on mac not triggering 2026-01-12 23:05:42 +08:00
renovate[bot]
72d9e846b7 fix(deps): update dependency i18next to v25.7.4 2026-01-12 05:55:15 +00:00
renovate[bot]
6595fd9c10 chore(deps): update dependency happy-dom to v20.1.0 2026-01-11 14:43:06 +00:00
perfectra1n
2dd541e1d0 fix(tests): update data_dir tests for new EEXIST graceful handling 2026-01-05 14:34:52 -08:00
Elian Doran
8157ef5e74 Merge branch 'main' into feat/show-helpful-permission-error-output 2026-01-05 23:43:20 +02:00
perfectra1n
0185dd0d18 feat(ux): implement suggestions from gemini just to make sure 2026-01-05 11:55:14 -08:00
perfectra1n
142ed42d90 feat(ux): show more helpful output when users encounter permissions issues within the data directory 2026-01-05 11:38:18 -08:00
42 changed files with 1625 additions and 931 deletions

30
.github/workflows/i18n.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Internationalization
on:
push:
branches:
- "weblate:*"
workflow_dispatch:
pull_request:
paths:
- "apps/client/src/translations/**"
- ".github/workflows/i18n.yml"
permissions:
contents: read
jobs:
i18n-check:
name: Check i18n translations
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Check translations
run: pnpm tsx scripts/translation/check-translation-coverage.ts

View File

@@ -34,7 +34,7 @@ jobs:
cache: "pnpm"
- name: Install dependencies
run: pnpm install --filter website --frozen-lockfile
run: pnpm install --filter website --frozen-lockfile --ignore-scripts
- name: Build the website
run: pnpm website:build

2
.nvmrc
View File

@@ -1 +1 @@
24.12.0
24.13.0

View File

@@ -165,6 +165,17 @@ pnpm install
pnpm edit-docs:edit-docs
```
Alternatively, if you have Nix installed:
```shell
# Run directly
nix run .#edit-docs
# Or install to your profile
nix profile install .#edit-docs
trilium-edit-docs
```
### Building the Executable
Download the repository, install dependencies using `pnpm` and then build the desktop app for Windows:
```shell

View File

@@ -11,7 +11,7 @@
"license": "AGPL-3.0-only",
"packageManager": "pnpm@10.28.0",
"devDependencies": {
"@redocly/cli": "2.14.4",
"@redocly/cli": "2.14.5",
"archiver": "7.0.1",
"fs-extra": "11.3.3",
"react": "19.2.3",

View File

@@ -44,7 +44,7 @@
"draggabilly": "3.0.0",
"force-graph": "1.51.0",
"globals": "17.0.0",
"i18next": "25.7.3",
"i18next": "25.7.4",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery.fancytree": "2.38.5",
@@ -60,7 +60,7 @@
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.28.2",
"react-i18next": "16.5.1",
"react-i18next": "16.5.2",
"react-window": "2.2.5",
"reveal.js": "5.2.1",
"svg-pan-zoom": "3.6.2",
@@ -78,7 +78,7 @@
"@types/reveal.js": "5.2.2",
"@types/tabulator-tables": "6.3.1",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "20.0.11",
"happy-dom": "20.1.0",
"lightningcss": "1.30.2",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.4"

View File

@@ -100,6 +100,20 @@ describe("shortcuts", () => {
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
it("should match letter keys using code when key is a special character (macOS Alt behavior)", () => {
// On macOS, pressing Option/Alt + A produces 'å' as the key, but code is still 'KeyA'
const macOSAltAEvent = createKeyboardEvent("å", "KeyA");
expect(keyMatches(macOSAltAEvent, "a")).toBe(true);
// Option + H produces '˙'
const macOSAltHEvent = createKeyboardEvent("˙", "KeyH");
expect(keyMatches(macOSAltHEvent, "h")).toBe(true);
// Option + S produces 'ß'
const macOSAltSEvent = createKeyboardEvent("ß", "KeyS");
expect(keyMatches(macOSAltSEvent, "s")).toBe(true);
});
});
describe("matchesShortcut", () => {
@@ -200,6 +214,33 @@ describe("shortcuts", () => {
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
it("should match Alt+letter shortcuts on macOS where key is a special character", () => {
// On macOS, pressing Option/Alt + A produces 'å' but code remains 'KeyA'
const macOSAltAEvent = createKeyboardEvent({
key: "å",
code: "KeyA",
altKey: true
});
expect(matchesShortcut(macOSAltAEvent, "alt+a")).toBe(true);
// Option/Alt + H produces '˙'
const macOSAltHEvent = createKeyboardEvent({
key: "˙",
code: "KeyH",
altKey: true
});
expect(matchesShortcut(macOSAltHEvent, "alt+h")).toBe(true);
// Combined with Ctrl: Ctrl+Alt+S where Alt produces 'ß'
const macOSCtrlAltSEvent = createKeyboardEvent({
key: "ß",
code: "KeyS",
ctrlKey: true,
altKey: true
});
expect(matchesShortcut(macOSCtrlAltSEvent, "ctrl+alt+s")).toBe(true);
});
});
describe("bindGlobalShortcut", () => {

View File

@@ -213,8 +213,11 @@ export function keyMatches(e: KeyboardEvent, key: string): boolean {
}
// For letter keys, use the physical key code for consistency
// On macOS, Option/Alt key produces special characters, so we must use e.code
if (key.length === 1 && key >= 'a' && key <= 'z') {
return e.key.toLowerCase() === key.toLowerCase();
// e.code is like "KeyA", "KeyB", etc.
const expectedCode = `Key${key.toUpperCase()}`;
return e.code === expectedCode || e.key.toLowerCase() === key.toLowerCase();
}
// For regular keys, check both key and code as fallback

View File

@@ -1604,7 +1604,9 @@
"clone-indicator-tooltip": "此笔记有 {{- count}} 个父级: {{- parents}}",
"clone-indicator-tooltip-single": "此笔记已克隆1 个额外的父级:{{- parent}}",
"subtree-hidden-tooltip_other": "从树中隐藏的 {{count}} 篇子笔记",
"subtree-hidden-moved-title": "已添加到 {{title}}"
"subtree-hidden-moved-title": "已添加到 {{title}}",
"subtree-hidden-moved-description-collection": "此集合隐藏其树中的子笔记。",
"subtree-hidden-moved-description-other": "子笔记隐藏于此笔记的树中。"
},
"title_bar_buttons": {
"window-on-top": "保持此窗口置顶"

View File

@@ -1,6 +1,6 @@
{
"about": {
"title": "Über Trilium Notes",
"title": "Über Trilium Notizen",
"homepage": "Startseite:",
"app_version": "App-Version:",
"db_version": "DB-Version:",
@@ -26,7 +26,12 @@
"widget-list-error": {
"title": "Abruf der Liste von Widgets vom Server ist fehlgeschlagen"
},
"open-script-note": "Script-Notiz öffnen"
"open-script-note": "Script-Notiz öffnen",
"widget-render-error": {
"title": "Eine externe React Integration konnte nicht dargestellt werden"
},
"widget-missing-parent": "Der externen Integration fehlt die erforderliche Eigenschaft '{{property}}'\n\nFalls dieses Skript ohne UI-Element ausgeführt werden soll, benutze stattdessen '#run=frontendStartup'.",
"scripting-error": "Benutzerdefinierter Skriptfehler: {{title}}"
},
"add_link": {
"add_link": "Link hinzufügen",
@@ -210,7 +215,7 @@
"modalTitle": "Infonachricht",
"closeButton": "Schließen",
"okButton": "OK",
"copy_to_clipboard": "In die Zwischenablage kopieren"
"copy_to_clipboard": "In Zwischenablage kopieren"
},
"jump_to_note": {
"search_button": "Suche im Volltext",
@@ -698,8 +703,8 @@
"export_as_image_png": "PNG (Raster)",
"export_as_image_svg": "SVG (Vektor)",
"note_map": "Notizen Karte",
"view_revisions": "Notizrevisionen",
"advanced": "Erweitert"
"view_revisions": "Änderungshistorie...",
"advanced": "Fortgeschritten"
},
"onclick_button": {
"no_click_handler": "Das Schaltflächen-Widget „{{componentId}}“ hat keinen definierten Klick-Handler"
@@ -792,7 +797,8 @@
"expand_all_levels": "Alle Ebenen erweitern",
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
"expand_first_level": "Direkte Unterelemente erweitern",
"expand_nth_level": "{{depth}} Ebenen erweitern"
"expand_nth_level": "{{depth}} Ebenen erweitern",
"hide_child_notes": "Unterknoten im Baum ausblenden"
},
"edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@@ -805,7 +811,7 @@
"file_type": "Dateityp",
"file_size": "Dateigröße",
"download": "Herunterladen",
"open": "Offen",
"open": "Extern öffnen",
"upload_new_revision": "Neue Revision hochladen",
"upload_success": "Neue Dateirevision wurde hochgeladen.",
"upload_failed": "Das Hochladen einer neuen Dateirevision ist fehlgeschlagen.",
@@ -903,7 +909,7 @@
"unknown_search_option": "Unbekannte Suchoption {{searchOptionName}}",
"search_note_saved": "Suchnotiz wurde in {{-notePathTitle}} gespeichert",
"actions_executed": "Aktionen wurden ausgeführt.",
"view_options": "Anzeigeoptionen:"
"view_options": "Optionen anzeigen:"
},
"similar_notes": {
"title": "Ähnliche Notizen",
@@ -1009,9 +1015,9 @@
"auto-detect-language": "Automatisch erkannt",
"keeps-crashing": "Die Bearbeitungskomponente stürzt immer wieder ab. Bitte starten Sie Trilium neu. Wenn das Problem weiterhin besteht, erstellen Sie einen Fehlerbericht.",
"editor_crashed_title": "Der Text Editor ist abgestürzt",
"editor_crashed_content": "Ihr Inhalt wurde erfolgreich wiederhergestellt, aber einzelne Ihrer letzten Änderungen waren möglicherweise noch nicht gespeichert.",
"editor_crashed_details_button": "Zeige mehr Details",
"editor_crashed_details_intro": "Falls Sie diesen Fehler mehrmals sehen, melden Sie dies auf GitHub mit den folgenden Informationen.",
"editor_crashed_content": "Ihr Inhalt wurde erfolgreich wiederhergestellt, aber kürzlich gemachte Änderungen wurden unter Umständen nicht gespeichert.",
"editor_crashed_details_button": "Mehr Details anzeigen...",
"editor_crashed_details_intro": "Falls dieser Fehler häufiger auftritt, ziehen Sie in Betracht uns diesen über GitHub zu melden, indem Sie die folgenden Informationen bereitstellen.",
"editor_crashed_details_title": "Technische Informationen"
},
"empty": {
@@ -1412,7 +1418,7 @@
"will_be_deleted_in": "Dieser Anhang wird in {{time}} automatisch gelöscht",
"will_be_deleted_soon": "Dieser Anhang wird bald automatisch gelöscht",
"deletion_reason": ", da der Anhang nicht im Inhalt der Notiz verlinkt ist. Um das Löschen zu verhindern, füge den Anhangslink wieder in den Inhalt ein oder wandel den Anhang in eine Notiz um.",
"role_and_size": "Rolle: {{role}}, Größe: {{size}}",
"role_and_size": "Rolle: {{role}}, Größe: {{size}}, MIME: {{- mimeType}}",
"link_copied": "Anhangslink in die Zwischenablage kopiert.",
"unrecognized_role": "Unbekannte Anhangsrolle „{{role}}“."
},
@@ -1463,10 +1469,13 @@
"import-into-note": "In Notiz importieren",
"apply-bulk-actions": "Massenaktionen anwenden",
"converted-to-attachments": "{{count}} Notizen wurden als Anhang konvertiert.",
"convert-to-attachment-confirm": "Bist du sicher, dass du die ausgewählten Notizen in Anhänge ihrer übergeordneten Notizen umwandeln möchtest?",
"convert-to-attachment-confirm": "Bist du sicher, dass du die ausgewählten Notizen in Anhänge ihrer übergeordneten Notizen umwandeln möchtest? Diese Operation wird nur auf Bildnotizes angewandt. Andere Notizen werden übersprungen.",
"open-in-popup": "Schnellbearbeitung",
"archive": "Archiviere",
"unarchive": "Entarchivieren"
"unarchive": "Entarchivieren",
"open-in-a-new-window": "In neuem Fenster öffnen",
"hide-subtree": "Teilbaum ausblenden",
"show-subtree": "Teilbaum anzeigen"
},
"shared_info": {
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}.",
@@ -1556,7 +1565,16 @@
"create-child-note": "Unternotiz anlegen",
"unhoist": "Fokus verlassen",
"toggle-sidebar": "Seitenleiste ein-/ausblenden",
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig."
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig.",
"clone-indicator-tooltip": "Diese Notiz hat {{- count}} Elterknoten: {{- parents}}",
"clone-indicator-tooltip-single": "Diese Notiz ist geklont (1 weiterer Elternknoten: {{- parent}})",
"shared-indicator-tooltip": "Diese Notiz ist öffentlich einsehbar",
"shared-indicator-tooltip-with-url": "Diese Notiz ist unter {{- url}} öffentlich einsehbar",
"subtree-hidden-tooltip_one": "{{count}} Unterknoten, der im Baum ausgeblendet ist",
"subtree-hidden-tooltip_other": "{{count}} Unterknoten, die im Baum ausgeblendet sind",
"subtree-hidden-moved-title": "Zu {{title}} hinzugefügt",
"subtree-hidden-moved-description-collection": "Diese Sammlung blendet ihre Unternotizem im Baum aus.",
"subtree-hidden-moved-description-other": "Diese Sammlung blendet ihre Unterknoten im Baum aus."
},
"title_bar_buttons": {
"window-on-top": "Dieses Fenster immer oben halten"
@@ -1567,7 +1585,9 @@
"printing_pdf": "PDF-Export läuft…",
"print_report_title": "Druckreport",
"print_report_collection_details_button": "Details anzeigen",
"print_report_collection_details_ignored_notes": "Ignorierte Notizen"
"print_report_collection_details_ignored_notes": "Ignorierte Notizen",
"print_report_collection_content_one": "{{count}} Notiz in der Sammlung konnte nicht gedruckt werden, weil sie nicht unterstützt ist oder geschützt ist.",
"print_report_collection_content_other": "{{count}} Notizen in der Sammlung konnten nicht gedruckt werden, weil sie nicht unterstützt sind oder geschützt sind."
},
"note_title": {
"placeholder": "Titel der Notiz hier eingeben…",
@@ -1720,7 +1740,8 @@
"open_note_in_new_tab": "Notiz in neuen Tab öffnen",
"open_note_in_new_split": "Notiz in neuen geteilten Tab öffnen",
"open_note_in_new_window": "Notiz in neuen Fenster öffnen",
"open_note_in_popup": "Schnellbearbeitung"
"open_note_in_popup": "Schnellbearbeitung",
"open_note_in_other_split": "Notiz in neuer Spalte öffnen"
},
"electron_integration": {
"desktop-application": "Desktop Anwendung",
@@ -1988,8 +2009,9 @@
"unknown_widget": "Unbekanntes Widget für '{{id}}'."
},
"note_language": {
"not_set": "Nicht gesetzt",
"configure-languages": "Konfiguriere Sprachen..."
"not_set": "Keine Sprache ausgewählt",
"configure-languages": "Konfiguriere Sprachen...",
"help-on-languages": "Zu Übersetzungen beitragen..."
},
"content_language": {
"title": "Inhaltssprachen",
@@ -2007,7 +2029,8 @@
"button_title": "Exportiere Diagramm als PNG"
},
"svg": {
"export_to_png": "Das Diagramm konnte als PNG nicht exportiert werden."
"export_to_png": "Das Diagramm konnte als PNG nicht exportiert werden.",
"export_to_svg": "Das Diagramm konnte nicht als SVG exportiert werden."
},
"code_theme": {
"title": "Aussehen",
@@ -2055,7 +2078,7 @@
"book_properties_config": {
"hide-weekends": "Wochenenden ausblenden",
"display-week-numbers": "Zeige Kalenderwoche",
"map-style": "Kartenstil:",
"map-style": "Kartenstil",
"max-nesting-depth": "Maximale Verschachtelungstiefe:",
"raster": "Raster",
"vector_light": "Vektor (Hell)",
@@ -2108,14 +2131,20 @@
"background_effects_title": "Hintergrundeffekte sind jetzt zuverlässig nutzbar",
"background_effects_message": "Auf Windows-Geräten sind die Hintergrundeffekte nun vollständig stabil. Die Hintergrundeffekte verleihen der Benutzeroberfläche einen Farbakzent, indem der Hintergrund dahinter weichgezeichnet wird. Diese Technik wird auch in anderen Anwendungen wie dem Windows-Explorer eingesetzt.",
"background_effects_button": "Aktiviere Hintergrundeffekte",
"dismiss": "Ablehnen"
"dismiss": "Ablehnen",
"new_layout_title": "Neues Layout",
"new_layout_message": "Wir haben ein modernisiertes Layout für Trilium eingeführt. Die Multifunktionsleiste wurde entfernt und als neue Statusanzeige und ausklappbaren Sektionen (wie hervorgehobenen Attributen), welche Schlüsselfunktionen übernehmen, nahtlos in das Hauptinterface integriert.\n\nDas neue Layout ist standardmäßig aktiviert und kann temporär in Optionen → Anzeige deaktiviert werden.",
"new_layout_button": "Mehr Informationen"
},
"settings": {
"related_settings": "Ähnliche Einstellungen"
},
"settings_appearance": {
"related_code_blocks": "Farbschema für Code-Blöcke in Textnotizen",
"related_code_notes": "Farbschema für Code-Notizen"
"related_code_notes": "Farbschema für Code-Notizen",
"ui": "Benutzeroberfläche",
"ui_old_layout": "Altes Layout",
"ui_new_layout": "Neues Layout"
},
"units": {
"percentage": "%"
@@ -2151,6 +2180,88 @@
"experimental_features": {
"title": "Experimentelle Optionen",
"disclaimer": "Diese Optionen sind experimentell und können Instabilitäten verursachen. Achtsam zu verwenden.",
"new_layout_name": "Neues Layout"
"new_layout_name": "Neues Layout",
"new_layout_description": "Probiere das neue Layout für eine modernere Darstellung und verbesserte Benutzbarkeit aus. Kann sich in Zukunft stark ändern."
},
"server": {
"unknown_http_error_title": "Bei der Kommunikation mit dem Server ist ein Fehler aufgetreten",
"unknown_http_error_content": "Statuscode: {{statusCode}}\nURL: {{method}} {{url}}\nNachricht: {{message}}",
"traefik_blocks_requests": "Der Traefik Reverse-Proxy hat ein fatales Update bekommen, welche die Kommunikation mit dem Server stört."
},
"tab_history_navigation_buttons": {
"go-back": "Zur vorherigen Notiz zurück kehren",
"go-forward": "Zur nächsten Notiz"
},
"breadcrumb": {
"hoisted_badge": "Gehoben",
"hoisted_badge_title": "Abgesenkt",
"workspace_badge": "Arbeitsfläche",
"scroll_to_top_title": "Zum Anfang der Notiz springen",
"create_new_note": "Neue Unternotiz erstellen",
"empty_hide_archived_notes": "Archivierte Notizen ausblenden"
},
"breadcrumb_badges": {
"read_only_explicit": "Nicht Änderbar",
"read_only_explicit_description": "Diese Notiz wurde händisch als nicht änderbar markiert.\nKlicke hier um sie temporär zu bearbeiten.",
"read_only_auto": "Automatisch nicht änderbar",
"read_only_auto_description": "Diese Notiz wurde automatisch aus Leistungsgründen als nicht änderbar markiert. Dieses automatische Limit kann in den Einstellungen angepasst werden.\n\nKlicke hier, um sie temporär zu bearbeiten.",
"read_only_temporarily_disabled": "Temporär bearbeitbar",
"read_only_temporarily_disabled_description": "Diese Notiz ist aktuell bearbeitbar, ist aber normalerweise nicht änderbar. Sobald du zu einer anderen Notiz navigierst, kehrt diese Notiz in ihren Normalzustand zurück.\n\nKlicke hier, um die Notiz wieder nicht änderbar zu machen.",
"shared_publicly": "Öffentlich geteilt",
"shared_locally": "Lokal geteilt",
"shared_copy_to_clipboard": "Link in die Zwischenablage kopieren",
"shared_open_in_browser": "Link öffnen",
"shared_unshare": "Teilen aufheben",
"clipped_note": "Internetschnellverweis",
"clipped_note_description": "Diese Notiz wurde von {{url}} übernommen.\n\nKlicke hier, um zum Ursprung zu gehen.",
"execute_script": "Skript ausführen",
"execute_script_description": "Diese Notiz ist eine Skriptnotiz. Klicke hier, um das Skript auszuführen.",
"execute_sql": "SQL ausführen",
"execute_sql_description": "Diese Notiz ist eine SQL-Notiz. Klicke hier, um die SQL-Abfrage auszuführen.",
"save_status_saved": "Gespeichert",
"save_status_saving": "Speichern...",
"save_status_unsaved": "Nicht gespeichert",
"save_status_error": "Speichern fehlgeschlagen",
"save_status_saving_tooltip": "Änderungen werden gespeichert.",
"save_status_unsaved_tooltip": "Es gibt ungespeicherte Änderungen, welche gleich automatisch gespeichert werden.",
"save_status_error_tooltip": "Beim speichern der Notiz ist ein Fehler aufgetreten. Wenn möglich, versuche die Notiz woandershin zu kopieren und die Applikation neu zu laden."
},
"status_bar": {
"language_title": "Inhaltssprache ändern",
"note_info_title": "Notizinfo anzeigen (z.B.: Datum, Notizgröße)",
"backlinks_one": "{{count}} Rücklink",
"backlinks_other": "{{count}} Rücklinks",
"backlinks_title_one": "Rücklink anzeigen",
"backlinks_title_other": "Rücklinks anzeigen",
"attachments_one": "{{count}} Anhang",
"attachments_other": "{{count}} Anhänge",
"attachments_title_one": "Anhang in einem neuen Tab öffnen",
"attachments_title_other": "Anhänge in einem neuen Tab öffnen",
"attributes_one": "{{count}} Eigenschaft",
"attributes_other": "{{count}} Eigenschaften",
"attributes_title": "Eigene und gererbte Eigenschaften",
"note_paths_one": "{{count}} Pfad",
"note_paths_other": "{{count}} Pfade",
"note_paths_title": "Notizpfade",
"code_note_switcher": "Sprachmodus ändern"
},
"attributes_panel": {
"title": "Notizeigenschaften"
},
"right_pane": {
"empty_message": "Für diese Notiz gibt es nichts anzuzeigen",
"empty_button": "Anzeige ausblenden",
"toggle": "Rechte Anzeige umschalten",
"custom_widget_go_to_source": "Zum Ursprungscode"
},
"pdf": {
"attachments_one": "{{count}} Anhang",
"attachments_other": "{{count}} Anhänge",
"layers_one": "{{count}} Ebene",
"layers_other": "{{count}} Ebenen",
"pages_one": "{{count}} Seite",
"pages_other": "{{count}} Seiten",
"pages_alt": "Seite {{pageNumber}}",
"pages_loading": "Laden..."
}
}

View File

@@ -69,5 +69,8 @@
"clear-color": "Clear note colour",
"set-color": "Set note colour",
"set-custom-color": "Set custom note colour"
},
"about": {
"title": "About Trilium Notes"
}
}

View File

@@ -60,5 +60,23 @@
},
"include_note": {
"label_note": "Notat"
},
"prompt": {
"title": "Ledetekst",
"ok": "OK",
"defaultTitle": "Ledetekst"
},
"info": {
"closeButton": "Lukk",
"okButton": "OK"
},
"markdown_import": {
"import_button": "Importer"
},
"protected_session_password": {
"close_label": "Lukk"
},
"recent_changes": {
"undelete_link": "gjenopprett"
}
}

View File

@@ -772,7 +772,10 @@
"filter-default": "Icons default",
"no_results": "Não foram encontrados icons.",
"search_placeholder_filtered": "Procurar {{number}} icons no {{name}}",
"icon_tooltip": "{{name}}\nPacote de icons: {{iconPack}}"
"icon_tooltip": "{{name}}\nPacote de icons: {{iconPack}}",
"search_placeholder_one": "Procurar {{number}} icon nos {{count}} pacotes",
"search_placeholder_many": "Procurar {{number}} icons em {{count}} pacotes",
"search_placeholder_other": "Procurar {{number}} icons nos {{count}} pacotes"
},
"basic_properties": {
"note_type": "Tipo da nota",
@@ -799,7 +802,8 @@
"expand_nth_level": "Expandir {{depth}} níveis",
"expand_all_levels": "Expandir todos os níveis",
"include_archived_notes": "Mostrar notas arquivadas",
"expand_tooltip": "Expande a direcção dos descendentes desta colecção (um nível). Para mais opções, carregar na seta à direita."
"expand_tooltip": "Expande a direcção dos descendentes desta colecção (um nível). Para mais opções, carregar na seta à direita.",
"hide_child_notes": "Esconder notas descendentes na árvore"
},
"edited_notes": {
"no_edited_notes_found": "Ainda não há nenhuma nota editada neste dia…",
@@ -1017,7 +1021,9 @@
"editor_crashed_title": "O editor de texto quebrou",
"editor_crashed_details_button": "Ver mais detalhes...",
"editor_crashed_details_title": "Informação técnica",
"editor_crashed_details_intro": "Se teve este erro várias vezes, considerer reportar no GitHub disponibilizando a informação abaixo."
"editor_crashed_details_intro": "Se teve este erro várias vezes, considerer reportar no GitHub disponibilizando a informação abaixo.",
"editor_crashed_content": "O seu conteudo foi recuperado com sucesso, mas alguns das alterações mais recentes podem não ter sido gravadas.",
"keeps-crashing": "Componente de edição a rebentar continuamente. Por favor tentar reiniciar Trilium. Se o problema persistir, considere abrir um bug report."
},
"empty": {
"open_note_instruction": "Abra uma nota a digitar o título da nota no campo abaixo ou escolha uma nota na árvore.",
@@ -1145,7 +1151,8 @@
"title": "Largura do Conteúdo",
"default_description": "Por padrão, o Trilium limita a largura máxima do conteúdo para melhorar a legibilidade em janelas maximizadas em ecrãs largos.",
"max_width_label": "Largura máxima do conteúdo",
"max_width_unit": "pixels"
"max_width_unit": "pixels",
"centerContent": "Manter conteúdo centrado"
},
"native_title_bar": {
"title": "Barra de Título Nativa (requer recarregar a app)",
@@ -1177,7 +1184,9 @@
"title": "Desempenho",
"enable-motion": "Ativar transições e animações",
"enable-shadows": "Ativar sombras",
"enable-backdrop-effects": "Ativar efeitos de fundo para menus, popups e painéis"
"enable-backdrop-effects": "Ativar efeitos de fundo para menus, popups e painéis",
"enable-smooth-scroll": "Activar deslocamento suave",
"app-restart-required": "(é necessário reiniciar a aplicação para aplicar as alterações)"
},
"ai_llm": {
"not_started": "Não iniciado",
@@ -1336,7 +1345,10 @@
"title": "Editor"
},
"code_mime_types": {
"title": "Tipos MIME disponíveis no dropdown"
"title": "Tipos MIME disponíveis no dropdown",
"tooltip_syntax_highlighting": "Destaque de sintaxe",
"tooltip_code_block_syntax": "Blocos de código nas notas de texto",
"tooltip_code_note_syntax": "Notas de código"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Atribuições de teclas do Vim",
@@ -1456,7 +1468,13 @@
"min-days-in-first-week": "Mínimo de dias da primeira semana",
"first-week-info": "Primeira semana que contenha a primeira Quinta-feira do ano é baseado na <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Alterar as opções de primeira semana pode causar duplicidade nas Notas Semanais existentes e estas Notas não serão atualizadas de acordo.",
"formatting-locale": "Formato de data e número"
"formatting-locale": "Formato de data e número",
"tuesday": "Terça-feira",
"wednesday": "Quarta-feira",
"thursday": "Quinta-feira",
"friday": "Sexta-feira",
"saturday": "Sábado",
"formatting-locale-auto": "Baseado na linguagem da aplicação"
},
"backup": {
"automatic_backup": "Backup automático",
@@ -1549,7 +1567,8 @@
"oauth_description_warning": "Para ativar o OAuth/OpenID, precisa definir a URL base do OAuth/OpenID, o client ID e o client secret no ficheiro config.ini e reiniciar a aplicação. Se quiser configurar via variáveis de ambiente, defina TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID e TRILIUM_OAUTH_CLIENT_SECRET.",
"oauth_user_account": "Conta do Utilizador: ",
"oauth_user_email": "E-mail do Utilizador: ",
"oauth_user_not_logged_in": "Não está logado!"
"oauth_user_not_logged_in": "Não está logado!",
"oauth_missing_vars": "Configurações em falta: {{-variables}}"
},
"shortcuts": {
"keyboard_shortcuts": "Atalhos de Teclado",
@@ -1649,7 +1668,12 @@
"apply-bulk-actions": "Aplicar ações em massa",
"converted-to-attachments": "{{count}} notas foram convertidas em anexos.",
"convert-to-attachment-confirm": "Tem certeza que deseja converter as notas selecionadas em anexos das suas notas-pai?",
"open-in-popup": "Edição rápida"
"open-in-popup": "Edição rápida",
"open-in-a-new-window": "Abrir numa nova janela",
"archive": "Arquivar",
"unarchive": "Retirar do arquivo",
"hide-subtree": "Esconder sub-árvore",
"show-subtree": "Mostrar sub-árvore"
},
"shared_info": {
"shared_publicly": "Esta nota é partilhada publicamente em {{- link}}.",
@@ -1710,7 +1734,13 @@
},
"highlights_list_2": {
"title": "Lista de Destaques",
"options": "Opções"
"options": "Opções",
"no_highlights": "Sem destaques encontrados.",
"menu_configure": "Configurar lista de destaques...",
"modal_title": "Configurar list de destaques",
"title_with_count_one": "{{count}} destaque",
"title_with_count_many": "{{count}} destaques",
"title_with_count_other": "{{count}} destaques"
},
"quick-search": {
"placeholder": "Pesquisa rápida",
@@ -1733,16 +1763,43 @@
"refresh-saved-search-results": "Atualizar resultados de pesquisa gravados",
"create-child-note": "Criar nota filha",
"unhoist": "Desafixar",
"toggle-sidebar": "Alternar barra lateral"
"toggle-sidebar": "Alternar barra lateral",
"dropping-not-allowed": "Largar notas nesta localização não é permitida",
"clone-indicator-tooltip": "Esta nota tem {{- count}} ascendentes: {{- parents}}",
"shared-indicator-tooltip": "Esta nota está partilhada publicamente",
"shared-indicator-tooltip-with-url": "Esta nota está partilhada publicamente em: {{- url}}",
"subtree-hidden-moved-title": "Adicionar ao {{title}}",
"subtree-hidden-moved-description-collection": "Esta colecção esconde as notas descendentes na árvore.",
"subtree-hidden-moved-description-other": "Notas descendentes estão escondidades na árvore para esta nota.",
"subtree-hidden-tooltip_one": "{{count}} nota descendentes escondidas da árvore",
"subtree-hidden-tooltip_many": "{{count}} notas descendentes escondidas da árvore",
"subtree-hidden-tooltip_other": "{{count}} notas descendentes escondidas da árvore",
"clone-indicator-tooltip-single": "Esta nota está clonada (1 additional parent: {{- parent}})"
},
"title_bar_buttons": {
"window-on-top": "Manter Janela no Topo"
},
"note_detail": {
"could_not_find_typewidget": "Não foi possível encontrar typeWidget para o tipo '{{type}}'"
"could_not_find_typewidget": "Não foi possível encontrar typeWidget para o tipo '{{type}}'",
"print_report_collection_details_button": "Ver detalhes",
"printing": "Impressão em progresso...",
"printing_pdf": "Exportação PDF em progresso...",
"print_report_title": "Imprimir relatório",
"print_report_collection_details_ignored_notes": "Ignorar notas",
"print_report_collection_content_one": "{{count}} nota na colecção não pode ser impressa porque não é suportado ou está protegida.",
"print_report_collection_content_many": "{{count}} notas na colecção não podem ser impressas porque não é suportado ou estão protegidas.",
"print_report_collection_content_other": "{{count}} notas na colecção não podem ser impressas porque não é suportado ou estão protegidas."
},
"note_title": {
"placeholder": "digite o título da nota aqui..."
"placeholder": "digite o título da nota aqui...",
"promoted_attributes": "Atributos destacados",
"created_on": "Criado em <Value />",
"last_modified": "Modificado em <Value />",
"note_type_switcher_label": "Alterar de {{type}} para:",
"note_type_switcher_others": "Outro tipo de nota",
"note_type_switcher_templates": "Template",
"note_type_switcher_collection": "Colecção",
"edited_notes": "Notas editadas neste dia"
},
"search_result": {
"no_notes_found": "Nenhuma nota encontrada para os parâmetros de pesquisa digitados.",
@@ -1771,7 +1828,8 @@
},
"toc": {
"table_of_contents": "Tabela de Conteúdos",
"options": "Opções"
"options": "Opções",
"no_headings": "Sem cabeçalhos."
},
"watched_file_update_status": {
"file_last_modified": "O ficheiro <code class=\"file-path\"></code> foi modificado pela última vez em <span class=\"file-last-modified\"></span>.",
@@ -1814,7 +1872,9 @@
"ws": {
"sync-check-failed": "A verificação de sincronização falhou!",
"consistency-checks-failed": "A verificação de consistência falhou! Veja os logs para pormenores.",
"encountered-error": "Encontrado o erro \"{{message}}\", verifique o console."
"encountered-error": "Encontrado o erro \"{{message}}\", verifique o console.",
"lost-websocket-connection-title": "Perdida conexão com o servidor",
"lost-websocket-connection-message": "Verifique a configuração da proxy inversa (e.g. nginx ou Apache) para assegurar conexões WebSocket estão permitidas e não bloqueadas."
},
"hoisted_note": {
"confirm_unhoisting": "A nota solicitada '{{requestedNote}}' está fora da árvore da nota fixada '{{hoistedNote}}' e precisa desafixar para aceder a nota. Quer prosseguir e desafixar?"
@@ -1870,7 +1930,8 @@
"copy-link": "Copiar ligação",
"paste": "Colar",
"paste-as-plain-text": "Colar como texto sem formatação",
"search_online": "Pesquisar por \"{{term}}\" com {{searchEngine}}"
"search_online": "Pesquisar por \"{{term}}\" com {{searchEngine}}",
"search_in_trilium": "A procurar \"{{term}}\" no Trilium"
},
"image_context_menu": {
"copy_reference_to_clipboard": "Copiar referência para a área de transferência",
@@ -1880,7 +1941,8 @@
"open_note_in_new_tab": "Abrir nota em nova guia",
"open_note_in_new_split": "Abrir nota em nova divisão",
"open_note_in_new_window": "Abrir nota em nova janela",
"open_note_in_popup": "Edição rápida"
"open_note_in_popup": "Edição rápida",
"open_note_in_other_split": "Abrir nota noutro separador"
},
"electron_integration": {
"desktop-application": "Aplicação Desktop",
@@ -1888,7 +1950,8 @@
"native-title-bar-description": "Para Windows e macOS, manter a barra de título nativa desativada faz a aplicação parecer mais compacta. No Linux, manter a barra de título nativa ativada faz a aplicação se integrar melhor com o restante do sistema.",
"background-effects": "Ativar efeitos de fundo (apenas Windows 11)",
"restart-app-button": "Reiniciar a aplicação para ver as alterações",
"zoom-factor": "Fator de Zoom"
"zoom-factor": "Fator de Zoom",
"background-effects-description": "O Mica adiciona um desfoque, fundo estiloso as janelas da aplicação, criando uma profundidade e aspecto moderno. \"Barra de titulo nativa\" deve estar inactiva."
},
"note_autocomplete": {
"search-for": "Pesquisar por \"{{term}}\"",
@@ -1948,7 +2011,8 @@
},
"note_language": {
"not_set": "Não atribuído",
"configure-languages": "Configurar idiomas..."
"configure-languages": "Configurar idiomas...",
"help-on-languages": "Ajuda nas linguagens de conteúdos..."
},
"content_language": {
"title": "Idiomas do conteúdo",
@@ -1966,7 +2030,8 @@
"button_title": "Exportar diagrama como PNG"
},
"svg": {
"export_to_png": "O diagrama não pôde ser exportado como PNG."
"export_to_png": "O diagrama não pôde ser exportado como PNG.",
"export_to_svg": "O diagrama não pode ser exportado para SVG."
},
"code_theme": {
"title": "Aparência",
@@ -1985,7 +2050,11 @@
"editorfeatures": {
"title": "Recursos",
"emoji_completion_enabled": "Ativar auto-completar de Emoji",
"note_completion_enabled": "Ativar auto-completar de notas"
"note_completion_enabled": "Ativar auto-completar de notas",
"emoji_completion_description": "Se activo, emojis podem ser facilmente inseridos em texto ao pressionar `:`, seguido do nome de um emoji.",
"note_completion_description": "Se activo, links para notas podem ser criadas ao escrever `@` seguido do titulo de uma nota.",
"slash_commands_enabled": "Activar comentários simples",
"slash_commands_description": "Se activo, editar comandos como inserir quebras de linha ou cabeçalhos podem ser activado/inactivado ao escrever `/`."
},
"table_view": {
"new-row": "Nova linha",
@@ -2027,7 +2096,16 @@
"delete-column": "Apagar coluna",
"delete-column-confirmation": "Tem certeza que deseja apagar esta coluna? O atributo correspondente também será apagado de todas as notas abaixo desta coluna.",
"new-item": "Novo elemento",
"add-column": "Adicionar Coluna"
"add-column": "Adicionar Coluna",
"delete-note": "Apagar nota...",
"remove-from-board": "Remover do quadro",
"archive-note": "Arquivar nota",
"new-item-placeholder": "Inserir titulo da nota...",
"add-column-placeholder": "Inserir nome da coluna...",
"edit-note-title": "Clicar para editar o titulo da nota",
"unarchive-note": "Remover nota do arquivo",
"edit-column-title": "Click para editar titulo da coluna",
"column-already-exists": "Esta coluna já existe no quadro."
},
"command_palette": {
"tree-action-name": "Árvore: {{name}}",
@@ -2058,16 +2136,146 @@
"background_effects_title": "Efeitos de fundo estão estáveis agora",
"background_effects_message": "Em dispositivos Windows, efeitos de fundo estão estáveis agora. Os efeitos de fundo adicionam um toque de cor à interface do utilizador borrando o plano de fundo atrás dela. Esta técnica também é usada noutras aplicações como o Windows Explorer.",
"background_effects_button": "Ativar os efeitos de fundo",
"dismiss": "Dispensar"
"dismiss": "Dispensar",
"new_layout_title": "Novo titulo do layout",
"new_layout_button": "Mais informação",
"new_layout_message": "Estamos a introduzir um layout modernizado para o Trilium. A faixa foi removida e está integrada na interface principal, com uma nota barra de estado e secções expansíveis (como as propriedades próprias) a tomar papéis principais.\n\nO novo layout está activo por defeito, e pode ser temporáriamente disabilidade em Opções → Aparência."
},
"settings": {
"related_settings": "Configurações relacionadas"
},
"settings_appearance": {
"related_code_blocks": "Esquema de cores para blocos de código em notas de texto",
"related_code_notes": "Esquema de cores para notas de código"
"related_code_notes": "Esquema de cores para notas de código",
"ui": "Interface do utilizador",
"ui_old_layout": "Layout antigo",
"ui_new_layout": "Nova aparência"
},
"units": {
"percentage": "%"
},
"experimental_features": {
"title": "Opções experimentais",
"new_layout_name": "Novo layout",
"new_layout_description": "Experimente o novo layout para um aspecto moderno e melhor estabilidade. Sujeito a grandes alterações nas próximas publicações.",
"disclaimer": "Estas opções são experimentais e podem causar instabilidade. Usar com cuidado."
},
"read-only-info": {
"read-only-note": "Actualmente a ver em modo de leitura.",
"edit-note": "Editar nota",
"auto-read-only-note": "Esta nota está a ser mostrada em modo de leitura para um carregamento mais rápido."
},
"presentation_view": {
"edit-slide": "Editar este slide",
"start-presentation": "Iniciar apresentação",
"slide-overview": "Alternar visão geral dos slides"
},
"calendar_view": {
"delete_note": "Apagar nota..."
},
"pagination": {
"page_title": "Página {{startIndex}} - {{endIndex}}",
"total_notes": "{{count}} notas"
},
"collections": {
"rendering_error": "Sem possíbilidade de mostrar conteúdos devido a um erro."
},
"note-color": {
"clear-color": "Remover cor da nota",
"set-color": "Atribuir cor da nota",
"set-custom-color": "Afectar cor personalizada da nota"
},
"popup-editor": {
"maximize": "Alterar para editor completo"
},
"server": {
"unknown_http_error_title": "Erro na comunicação com servidor",
"unknown_http_error_content": "Código de estado: {{statusCode}}\nURL: {{method}} {{url}}\nMessagem: {{message}}",
"traefik_blocks_requests": "Se está a usar o Traefik, este introduz uma alteração que afecta a comunicação com o servidor."
},
"tab_history_navigation_buttons": {
"go-back": "Ir para a nota anterior",
"go-forward": "Ir para nota seguinte"
},
"breadcrumb": {
"hoisted_badge": "Içado",
"workspace_badge": "Área de trabalho",
"scroll_to_top_title": "Saltar para o início da nota",
"create_new_note": "Criar nova nota descendente",
"empty_hide_archived_notes": "Esconder notas arquivadas",
"hoisted_badge_title": "Retirar de içado"
},
"breadcrumb_badges": {
"read_only_explicit": "Modo de leitura",
"read_only_auto": "Modo de leitura automático",
"read_only_temporarily_disabled": "Editável temporáriamente",
"read_only_auto_description": "Esta nota foi automaticamente colocada em modo de leitura por razões de performance. Este limite automatico é ajustável nas configurações.\n\nClicar para editar temporáriamente.",
"read_only_temporarily_disabled_description": "Esta nota está editável, mas normalmente está em modo de leitura. A nova vai regressar para mode de leitura assim que navegar para outra nota.\n\nClicar para reactivar o modo de leitura.",
"read_only_explicit_description": "Esta nota foi manualmente colocada em modo de leitura.\nClicar para editar temporáriamente.",
"shared_publicly": "Partilhado publicamente",
"shared_locally": "Partilhado localmente",
"shared_copy_to_clipboard": "Copiar link para a área de transferência",
"shared_open_in_browser": "Abrir link no browser",
"shared_unshare": "Remover partilha",
"clipped_note_description": "Esta nota foi retirar do {{url}}.\n\nClicar para navegar no código fonte da página.",
"clipped_note": "Web clipe",
"execute_script": "Correr script",
"execute_script_description": "Esta nota é uma nota de script. Clicar para executar o script.",
"execute_sql": "Correr SQL",
"execute_sql_description": "Esta nota é uma nota de SQL. Clicar para executar script SQL.",
"save_status_saved": "Guardar",
"save_status_saving": "A guardar...",
"save_status_unsaved": "Não gravado",
"save_status_error": "Gravar falhou",
"save_status_saving_tooltip": "Alterações estão a ser guardadas",
"save_status_unsaved_tooltip": "Existem alterações não guardadas. Serão guardadas automaticamente em breve.",
"save_status_error_tooltip": "Ocorreu um erro ao guardar a nota. Se possível, tente copiar os conteúdos da nota para outro local e reiniciar a aplicação."
},
"status_bar": {
"language_title": "Alterar lingua do conteúdo",
"note_info_title": "Ver informação da nota (e.g., datas, tamanho da nota)",
"backlinks_one": "{{count}} backlink",
"backlinks_many": "{{count}} backlinks",
"backlinks_other": "{{count}} backlinks",
"backlinks_title_one": "Ver backlink",
"backlinks_title_many": "Ver backlinks",
"backlinks_title_other": "Ver backlinks",
"attachments_one": "{{count}} anexo",
"attachments_many": "{{count}} anexos",
"attachments_other": "{{count}} anexos",
"attachments_title_one": "Ver anexo num novo separador",
"attachments_title_many": "Ver anexos num novo separador",
"attachments_title_other": "Ver anexos num novo separador",
"attributes_one": "{{count}} atributo",
"attributes_many": "{{count}} atributos",
"attributes_other": "{{count}} atributos",
"attributes_title": "Atributos próprios e herdados",
"note_paths_one": "{{count}} caminho",
"note_paths_many": "{{count}} caminhos",
"note_paths_other": "{{count}} caminhos",
"note_paths_title": "Caminhos da nota",
"code_note_switcher": "Alterar modo de linguagem"
},
"attributes_panel": {
"title": "Atributos da nota"
},
"right_pane": {
"empty_message": "Nada para mostrar nesta nota",
"empty_button": "Esconder painél",
"toggle": "Alterar painel direito",
"custom_widget_go_to_source": "Ir para código fonte"
},
"pdf": {
"attachments_one": "{{count}} anexo pdf",
"attachments_many": "{{count}} anexos pdf",
"attachments_other": "{{count}} anexos pdf",
"layers_one": "{{count}} camada",
"layers_many": "{{count}} camadas",
"layers_other": "{{count}} camadas",
"pages_one": "{{count}} página",
"pages_many": "{{count}} páginas",
"pages_other": "{{count}} páginas",
"pages_alt": "Página {{pageNumber}}",
"pages_loading": "A carregar..."
}
}

View File

@@ -5,7 +5,7 @@
"description": "Tool to compare content of Trilium databases. Useful for debugging sync problems.",
"dependencies": {
"colors": "1.4.0",
"diff": "8.0.2",
"diff": "8.0.3",
"sqlite": "5.1.1",
"sqlite3": "5.1.7"
},

View File

@@ -36,14 +36,14 @@
"@triliumnext/server": "workspace:*",
"copy-webpack-plugin": "13.0.1",
"electron": "39.2.7",
"@electron-forge/cli": "7.10.2",
"@electron-forge/maker-deb": "7.10.2",
"@electron-forge/maker-dmg": "7.10.2",
"@electron-forge/maker-flatpak": "7.10.2",
"@electron-forge/maker-rpm": "7.10.2",
"@electron-forge/maker-squirrel": "7.10.2",
"@electron-forge/maker-zip": "7.10.2",
"@electron-forge/plugin-auto-unpack-natives": "7.10.2",
"@electron-forge/cli": "7.11.1",
"@electron-forge/maker-deb": "7.11.1",
"@electron-forge/maker-dmg": "7.11.1",
"@electron-forge/maker-flatpak": "7.11.1",
"@electron-forge/maker-rpm": "7.11.1",
"@electron-forge/maker-squirrel": "7.11.1",
"@electron-forge/maker-zip": "7.11.1",
"@electron-forge/plugin-auto-unpack-natives": "7.11.1",
"prebuild-install": "7.1.3"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/edit-docs",
"version": "0.0.1",
"version": "0.101.3",
"private": true,
"description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.",
"dependencies": {
@@ -16,7 +16,9 @@
"fs-extra": "11.3.3"
},
"scripts": {
"edit-docs": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-docs.ts",
"build": "tsx scripts/build.ts",
"test-build": "vitest --config vitest.build.config.mts",
"edit-docs": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store tsx ../../scripts/electron-start.mts src/edit-docs.ts",
"edit-demo": "cross-env TRILIUM_PORT=37744 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-demo.ts"
}
}

View File

@@ -0,0 +1,40 @@
import { writeFileSync } from "fs";
import { join } from "path";
import BuildHelper from "../../../scripts/build-utils";
import originalPackageJson from "../package.json" with { type: "json" };
const build = new BuildHelper("apps/edit-docs");
async function main() {
await build.buildBackend(["src/edit-docs.ts", "src/utils.ts"]);
// Copy assets from server (needed for DB initialization)
build.copy("/apps/server/src/assets", "assets/");
build.triggerBuildAndCopyTo("packages/share-theme", "share-theme/assets/");
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
build.copy("/node_modules/ckeditor5/dist/ckeditor5-content.css", "ckeditor5-content.css");
build.buildFrontend();
// Copy node modules dependencies
build.copyNodeModules(["better-sqlite3", "bindings", "file-uri-to-path", "@electron/remote"]);
generatePackageJson();
}
function generatePackageJson() {
const { version, author, license, description, dependencies, devDependencies } = originalPackageJson;
const packageJson = {
name: "trilium-edit-docs",
main: "edit-docs.cjs",
version,
author,
license,
description,
dependencies: {"better-sqlite3": dependencies["better-sqlite3"]},
devDependencies: {electron: devDependencies.electron},
};
writeFileSync(join(build.outDir, "package.json"), JSON.stringify(packageJson, null, "\t"), "utf-8");
}
main();

View File

@@ -0,0 +1,48 @@
import { globSync } from "fs";
import { join } from "path";
import { it, describe, expect } from "vitest";
describe("Check artifacts are present", () => {
const distPath = join(__dirname, "../../dist");
it("has the necessary node modules", async () => {
const paths = [
"node_modules/better-sqlite3",
"node_modules/bindings",
"node_modules/file-uri-to-path",
"node_modules/@electron/remote"
];
ensurePathsExist(paths);
});
it("includes the client", async () => {
const paths = [
"public/assets",
"public/fonts",
"public/node_modules",
"public/src",
"public/stylesheets",
"public/translations"
];
ensurePathsExist(paths);
});
it("includes necessary assets", async () => {
const paths = [
"assets",
"share-theme",
"ckeditor5-content.css"
];
ensurePathsExist(paths);
});
function ensurePathsExist(paths: string[]) {
for (const path of paths) {
const result = globSync(join(distPath, path, "**"));
expect(result, path).not.toHaveLength(0);
}
}
});

View File

@@ -1,14 +1,17 @@
import fs from "fs/promises";
import fsExtra from "fs-extra";
import path from "path";
import type { NoteMetaFile } from "@triliumnext/server/src/services/meta/note_meta.js";
import { initializeTranslations } from "@triliumnext/server/src/services/i18n.js";
import debounce from "@triliumnext/client/src/services/debounce.js";
import { extractZip, importData, initializeDatabase, startElectron } from "./utils.js";
import cls from "@triliumnext/server/src/services/cls.js";
import type { AdvancedExportOptions, ExportFormat } from "@triliumnext/server/src/services/export/zip/abstract_provider.js";
import { initializeTranslations } from "@triliumnext/server/src/services/i18n.js";
import { parseNoteMetaFile } from "@triliumnext/server/src/services/in_app_help.js";
import type { NoteMetaFile } from "@triliumnext/server/src/services/meta/note_meta.js";
import type NoteMeta from "@triliumnext/server/src/services/meta/note_meta.js";
import fs from "fs/promises";
import fsExtra from "fs-extra";
import yaml from "js-yaml";
import path from "path";
import packageJson from "../package.json" with { type: "json" };
import { extractZip, importData, initializeDatabase, startElectron } from "./utils.js";
interface NoteMapping {
rootNoteId: string;
@@ -18,47 +21,113 @@ interface NoteMapping {
exportOnly?: boolean;
}
const { DOCS_ROOT, USER_GUIDE_ROOT } = process.env;
if (!DOCS_ROOT || !USER_GUIDE_ROOT) {
throw new Error("Missing DOCS_ROOT or USER_GUIDE_ROOT environment variable.");
interface Config {
baseUrl: string;
noteMappings: NoteMapping[];
}
const BASE_URL = "https://docs.triliumnotes.org";
// Parse command-line arguments
function parseArgs() {
const args = process.argv.slice(2);
let configPath: string | undefined;
let showHelp = false;
let showVersion = false;
const NOTE_MAPPINGS: NoteMapping[] = [
{
rootNoteId: "pOsGYCXsbNQG",
path: path.join(__dirname, DOCS_ROOT, "User Guide"),
format: "markdown"
},
{
rootNoteId: "pOsGYCXsbNQG",
path: path.join(__dirname, USER_GUIDE_ROOT),
format: "html",
ignoredFiles: ["index.html", "navigation.html", "style.css", "User Guide.html"],
exportOnly: true
},
{
rootNoteId: "jdjRLhLV3TtI",
path: path.join(__dirname, DOCS_ROOT, "Developer Guide"),
format: "markdown"
},
{
rootNoteId: "hD3V4hiu2VW4",
path: path.join(__dirname, DOCS_ROOT, "Release Notes"),
format: "markdown"
for (let i = 0; i < args.length; i++) {
if (args[i] === '--config' || args[i] === '-c') {
configPath = args[i + 1];
if (!configPath) {
console.error("Error: --config/-c requires a path argument");
process.exit(1);
}
i++; // Skip the next argument as it's the value
} else if (args[i] === '--help' || args[i] === '-h') {
showHelp = true;
} else if (args[i] === '--version' || args[i] === '-v') {
showVersion = true;
}
}
];
return { configPath, showHelp, showVersion };
}
function getVersion(): string {
return packageJson.version;
}
function printHelp() {
const version = getVersion();
console.log(`
Usage: trilium-edit-docs [options]
Options:
-c, --config <path> Path to the configuration file (default: edit-docs-config.yaml in the root)
-h, --help Display this help message
-v, --version Display version information
Version: ${version}
`);
}
function printVersion() {
const version = getVersion();
console.log(version);
}
const { configPath, showHelp, showVersion } = parseArgs();
if (showHelp) {
printHelp();
process.exit(0);
} else if (showVersion) {
printVersion();
process.exit(0);
}
// Configuration variables to be initialized
let BASE_URL: string;
let NOTE_MAPPINGS: NoteMapping[];
// Load configuration from edit-docs-config.yaml
async function loadConfig() {
let CONFIG_PATH = configPath
? path.resolve(configPath)
: path.join(process.cwd(), "edit-docs-config.yaml");
const exists = await fs.access(CONFIG_PATH).then(() => true).catch(() => false);
if (!exists && !configPath) {
// Fallback to project root if running from within a subproject
CONFIG_PATH = path.join(__dirname, "../../../edit-docs-config.yaml");
}
const configContent = await fs.readFile(CONFIG_PATH, "utf-8");
const config = yaml.load(configContent) as Config;
BASE_URL = config.baseUrl;
// Resolve all paths relative to the config file's directory (for flexibility with external configs)
const CONFIG_DIR = path.dirname(CONFIG_PATH);
NOTE_MAPPINGS = config.noteMappings.map((mapping) => ({
...mapping,
path: path.resolve(CONFIG_DIR, mapping.path)
}));
}
async function main() {
await loadConfig();
const initializedPromise = startElectron(() => {
// Wait for the import to be finished and the application to be loaded before we listen to changes.
setTimeout(() => registerHandlers(), 10_000);
setTimeout(() => {
registerHandlers();
}, 10_000);
});
await initializeTranslations();
await initializeDatabase(true);
// Wait for becca to be loaded before importing data
const beccaLoader = await import("@triliumnext/server/src/becca/becca_loader.js");
await beccaLoader.beccaLoaded;
cls.init(async () => {
for (const mapping of NOTE_MAPPINGS) {
if (!mapping.exportOnly) {
@@ -142,7 +211,7 @@ async function exportData(noteId: string, format: ExportFormat, outputPath: stri
}
}
const minifyMeta = (format === "html");
const minifyMeta = (format === "html" || format === "share");
await cleanUpMeta(outputPath, minifyMeta);
}
@@ -195,7 +264,6 @@ async function registerHandlers() {
return;
}
console.log("Got entity changed", e.entityName, e.entity.title);
debouncer();
});
}

View File

@@ -1,23 +1,27 @@
import cls from "@triliumnext/server/src/services/cls.js";
import TaskContext from "@triliumnext/server/src/services/task_context.js";
import windowService from "@triliumnext/server/src/services/window.js";
import archiver, { type Archiver } from "archiver";
import electron from "electron";
import type { WriteStream } from "fs";
import fs from "fs/promises";
import fsExtra from "fs-extra";
import path from "path";
import electron from "electron";
import windowService from "@triliumnext/server/src/services/window.js";
import archiver, { type Archiver } from "archiver";
import type { WriteStream } from "fs";
import TaskContext from "@triliumnext/server/src/services/task_context.js";
import { resolve } from "path";
import { deferred, DeferredPromise } from "../../../packages/commons/src";
export function initializeDatabase(skipDemoDb: boolean) {
return new Promise<void>(async (resolve) => {
const sqlInit = (await import("@triliumnext/server/src/services/sql_init.js")).default;
cls.init(async () => {
if (!sqlInit.isDbInitialized()) {
await sqlInit.createInitialDatabase(skipDemoDb);
}
resolve();
import { deferred, type DeferredPromise } from "../../../packages/commons/src/index.js";
export function initializeDatabase(skipDemoDb: boolean): Promise<void> {
return new Promise<void>((resolve) => {
import("@triliumnext/server/src/services/sql_init.js").then((m) => {
const sqlInit = m.default;
cls.init(async () => {
if (!sqlInit.isDbInitialized()) {
sqlInit.createInitialDatabase(skipDemoDb).then(() => resolve());
} else {
sqlInit.dbReady.resolve();
resolve();
}
});
});
});
}
@@ -32,10 +36,9 @@ export function initializeDatabase(skipDemoDb: boolean) {
*/
export function startElectron(callback: () => void): DeferredPromise<void> {
const initializedPromise = deferred<void>();
electron.app.on("ready", async () => {
await initializedPromise;
console.log("Electron is ready!");
const readyHandler = async () => {
await initializedPromise;
// Start the server.
const startTriliumServer = (await import("@triliumnext/server/src/www.js")).default;
@@ -45,7 +48,15 @@ export function startElectron(callback: () => void): DeferredPromise<void> {
await windowService.createMainWindow(electron.app);
callback();
});
};
// Handle race condition: Electron ready event may have already fired
if (electron.app.isReady()) {
readyHandler();
} else {
electron.app.on("ready", readyHandler);
}
return initializedPromise;
}
@@ -70,7 +81,6 @@ async function createImportZip(path: string) {
zlib: { level: 0 }
});
console.log("Archive path is ", resolve(path))
archive.directory(path, "/");
const outputStream = fsExtra.createWriteStream(inputFile);
@@ -85,14 +95,16 @@ async function createImportZip(path: string) {
}
function waitForEnd(archive: Archiver, stream: WriteStream) {
return new Promise<void>(async (res, rej) => {
stream.on("finish", () => res());
await archive.finalize();
return new Promise<void>((res, rej) => {
stream.on("finish", res);
stream.on("error", rej);
archive.on("error", rej);
archive.finalize().catch(rej);
});
}
export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set<string>) {
const promise = deferred<void>()
const promise = deferred<void>();
setTimeout(async () => {
// Then extract the zip.
const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js"));

View File

@@ -0,0 +1,17 @@
/// <reference types='vitest' />
import { defineConfig } from 'vite';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/apps/edit-docs',
plugins: [],
test: {
watch: false,
globals: true,
environment: "node",
include: ['spec/build-checks/**'],
reporters: [
"verbose"
]
},
}));

View File

@@ -99,7 +99,7 @@
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.6",
"i18next": "25.7.3",
"i18next": "25.7.4",
"i18next-fs-backend": "2.6.1",
"image-type": "6.0.0",
"ini": "6.0.0",

View File

@@ -13,5 +13,31 @@
},
"setup_sync-from-desktop": {
"step6-here": "her"
},
"set_password": {
"password": "Passord"
},
"setup": {
"next": "Neste",
"title": "Konfigurasjon"
},
"login": {
"title": "Logg inn",
"password": "Passord",
"button": "Logg inn"
},
"setup_sync-from-server": {
"server-host-placeholder": "https://<hostnavn>:<port>",
"proxy-server-placeholder": "https://<hostnavn>:<port>",
"note": "Obs:",
"password": "Passord",
"password-placeholder": "Passord",
"back": "Tilbake"
},
"setup_sync-in-progress": {
"outstanding-items-default": "N/A"
},
"share_page": {
"parent": "overordnet notat:"
}
}

View File

@@ -10,6 +10,7 @@ describe("data_dir.ts unit tests", async () => {
const mockFn = {
existsSyncMock: vi.fn(),
mkdirSyncMock: vi.fn(),
statSyncMock: vi.fn(),
osHomedirMock: vi.fn(),
osPlatformMock: vi.fn(),
pathJoinMock: vi.fn()
@@ -21,7 +22,8 @@ describe("data_dir.ts unit tests", async () => {
return {
default: {
existsSync: mockFn.existsSyncMock,
mkdirSync: mockFn.mkdirSyncMock
mkdirSync: mockFn.mkdirSyncMock,
statSync: mockFn.statSyncMock
}
};
});
@@ -109,34 +111,36 @@ describe("data_dir.ts unit tests", async () => {
*/
describe("case A", () => {
it("when folder exists it should return the path, without attempting to create the folder", async () => {
it("when folder exists it should return the path, handling EEXIST gracefully", async () => {
const mockTriliumDataPath = "/home/mock/trilium-data-ENV-A1";
process.env.TRILIUM_DATA_DIR = mockTriliumDataPath;
// set fs.existsSync to true, i.e. the folder does exist
mockFn.existsSyncMock.mockImplementation(() => true);
// mkdirSync throws EEXIST when folder already exists (EAFP pattern)
const eexistError = new Error("EEXIST: file already exists") as NodeJS.ErrnoException;
eexistError.code = "EEXIST";
mockFn.mkdirSyncMock.mockImplementation(() => { throw eexistError; });
// statSync confirms it's a directory
mockFn.statSyncMock.mockImplementation(() => ({ isDirectory: () => true }));
const result = getTriliumDataDir("trilium-data");
// createDirIfNotExisting should call existsync 1 time and mkdirSync 0 times -> as it does not need to create the folder
// and return value should be TRILIUM_DATA_DIR value from process.env
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(1);
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(0);
// createDirIfNotExisting tries mkdirSync first (EAFP), then statSync to verify it's a directory
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(1);
expect(mockFn.statSyncMock).toHaveBeenCalledTimes(1);
expect(result).toEqual(process.env.TRILIUM_DATA_DIR);
});
it("when folder does not exist it should attempt to create the folder and return the path", async () => {
it("when folder does not exist it should create the folder and return the path", async () => {
const mockTriliumDataPath = "/home/mock/trilium-data-ENV-A2";
process.env.TRILIUM_DATA_DIR = mockTriliumDataPath;
// set fs.existsSync mock to return false, i.e. the folder does not exist
mockFn.existsSyncMock.mockImplementation(() => false);
// mkdirSync succeeds when folder doesn't exist
mockFn.mkdirSyncMock.mockImplementation(() => undefined);
const result = getTriliumDataDir("trilium-data");
// createDirIfNotExisting should call existsync 1 time and mkdirSync 1 times -> as it has to create the folder
// and return value should be TRILIUM_DATA_DIR value from process.env
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(1);
// createDirIfNotExisting calls mkdirSync which succeeds
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(1);
expect(result).toEqual(process.env.TRILIUM_DATA_DIR);
});
@@ -171,19 +175,19 @@ describe("data_dir.ts unit tests", async () => {
// use Generator to precisely control order of fs.existSync return values
const existsSyncMockGen = (function* () {
// 1) fs.existSync -> case B
// 1) fs.existSync -> case B -> checking if folder exists in home dir
yield false;
// 2) fs.existSync -> case C -> checking if default OS PlatformAppDataDir exists
yield true;
// 3) fs.existSync -> case C -> checking if Trilium Data folder exists
yield false;
})();
mockFn.existsSyncMock.mockImplementation(() => existsSyncMockGen.next().value);
// mkdirSync succeeds (folder doesn't exist)
mockFn.mkdirSyncMock.mockImplementation(() => undefined);
const result = getTriliumDataDir(dataDirName);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(3);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(2);
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(1);
expect(result).toEqual(mockPlatformDataPath);
});
@@ -198,21 +202,26 @@ describe("data_dir.ts unit tests", async () => {
// use Generator to precisely control order of fs.existSync return values
const existsSyncMockGen = (function* () {
// 1) fs.existSync -> case B
// 1) fs.existSync -> case B -> checking if folder exists in home dir
yield false;
// 2) fs.existSync -> case C -> checking if default OS PlatformAppDataDir exists
yield true;
// 3) fs.existSync -> case C -> checking if Trilium Data folder exists
yield true;
})();
mockFn.existsSyncMock.mockImplementation(() => existsSyncMockGen.next().value);
// mkdirSync throws EEXIST (folder already exists), statSync confirms it's a directory
const eexistError = new Error("EEXIST: file already exists") as NodeJS.ErrnoException;
eexistError.code = "EEXIST";
mockFn.mkdirSyncMock.mockImplementation(() => { throw eexistError; });
mockFn.statSyncMock.mockImplementation(() => ({ isDirectory: () => true }));
const result = getTriliumDataDir(dataDirName);
expect(result).toEqual(mockPlatformDataPath);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(3);
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(0);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(2);
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(1);
expect(mockFn.statSyncMock).toHaveBeenCalledTimes(1);
});
it("w/ Platform 'win32' and set process.env.APPDATA behaviour", async () => {
@@ -227,20 +236,20 @@ describe("data_dir.ts unit tests", async () => {
// use Generator to precisely control order of fs.existSync return values
const existsSyncMockGen = (function* () {
// 1) fs.existSync -> case B
// 1) fs.existSync -> case B -> checking if folder exists in home dir
yield false;
// 2) fs.existSync -> case C -> checking if default OS PlatformAppDataDir exists
yield true;
// 3) fs.existSync -> case C -> checking if Trilium Data folder exists
yield false;
})();
mockFn.existsSyncMock.mockImplementation(() => existsSyncMockGen.next().value);
// mkdirSync succeeds (folder doesn't exist)
mockFn.mkdirSyncMock.mockImplementation(() => undefined);
const result = getTriliumDataDir(dataDirName);
expect(result).toEqual(mockPlatformDataPath);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(3);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(2);
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(1);
});
});
@@ -253,19 +262,15 @@ describe("data_dir.ts unit tests", async () => {
setMockPlatform("aix", homedir, mockPlatformDataPath);
const existsSyncMockGen = (function* () {
// first fs.existSync -> case B -> checking if folder exists in home folder
yield false;
// second fs.existSync -> case D -> triggered by createDirIfNotExisting
yield false;
})();
mockFn.existsSyncMock.mockImplementation(() => existsSyncMockGen.next().value);
// fs.existSync -> case B -> checking if folder exists in home folder
mockFn.existsSyncMock.mockImplementation(() => false);
// mkdirSync succeeds (folder doesn't exist)
mockFn.mkdirSyncMock.mockImplementation(() => undefined);
const result = getTriliumDataDir(dataDirName);
expect(result).toEqual(mockPlatformDataPath);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(2);
expect(mockFn.existsSyncMock).toHaveBeenCalledTimes(1);
expect(mockFn.mkdirSyncMock).toHaveBeenCalledTimes(1);
});
});

View File

@@ -75,9 +75,56 @@ export function getPlatformAppDataDir(platform: ReturnType<typeof os.platform>,
}
}
function outputPermissionDiagnostics(targetPath: fs.PathLike) {
const pathStr = targetPath.toString();
const parentDir = pathJoin(pathStr, "..");
console.error("\n========== PERMISSION ERROR DIAGNOSTICS ==========");
console.error(`Failed to create directory: ${pathStr}`);
// Output current process UID:GID (Unix only)
if (typeof process.getuid === "function" && typeof process.getgid === "function") {
console.error(`Process running as UID:GID = ${process.getuid()}:${process.getgid()}`);
}
// Try to get parent directory stats
try {
const stats = fs.statSync(parentDir);
console.error(`Parent directory: ${parentDir}`);
console.error(` Owner UID:GID = ${stats.uid}:${stats.gid}`);
console.error(` Permissions = ${(stats.mode & 0o777).toString(8)} (octal)`);
} catch {
console.error(`Parent directory ${parentDir} is not accessible`);
}
console.error("\nTo fix this issue:");
console.error(" - Ensure the data directory is owned by the user running Trilium");
console.error(" - Or set USER_UID and USER_GID environment variables to match the directory owner");
console.error(" - Example: docker run -e USER_UID=$(id -u) -e USER_GID=$(id -g) ...");
console.error("====================================================\n");
}
function createDirIfNotExisting(path: fs.PathLike, permissionMode: fs.Mode = FOLDER_PERMISSIONS) {
if (!fs.existsSync(path)) {
try {
fs.mkdirSync(path, permissionMode);
} catch (err: unknown) {
if (err && typeof err === "object" && "code" in err) {
const code = (err as { code: string }).code;
if (code === "EACCES") {
outputPermissionDiagnostics(path);
} else if (code === "EEXIST") {
// Directory already exists - verify it's actually a directory
try {
if (fs.statSync(path).isDirectory()) {
return;
}
} catch {
// If we can't stat it, fall through to re-throw original error
}
}
}
throw err;
}
}

View File

@@ -9,12 +9,12 @@
"preview": "pnpm build && vite preview"
},
"dependencies": {
"i18next": "25.7.3",
"i18next": "25.7.4",
"i18next-http-backend": "3.0.2",
"preact": "10.28.2",
"preact-iso": "2.11.1",
"preact-render-to-string": "6.6.5",
"react-i18next": "16.5.1"
"react-i18next": "16.5.2"
},
"devDependencies": {
"@preact/preset-vite": "2.10.2",
@@ -23,7 +23,7 @@
"typescript": "5.9.3",
"user-agent-data-types": "0.4.2",
"vite": "7.3.1",
"vitest": "4.0.16"
"vitest": "4.0.17"
},
"eslintConfig": {
"extends": "preact"

View File

@@ -21,7 +21,7 @@
"note_structure_description": "Notizen lassen sich hierarchisch anordnen. Ordner sind nicht nötig, da jede Notiz Unternotizen enthalten kann. Eine einzelne Notiz kann an mehreren Stellen in der Hierarchie hinzugefügt werden.",
"hoisting_description": "Trennen Sie Ihre persönlichen und beruflichen Notizen ganz einfach, indem Sie sie in einem Arbeitsbereich gruppieren. Dadurch wird Ihre Notizstruktur so fokussiert, dass nur ein bestimmter Satz von Notizen angezeigt wird.",
"hoisting_title": "Arbeitsbereiche und Fokusansicht",
"attributes_description": "Verwenden Sie Beziehungen zwischen Notizen oder fügen Sie Beschriftungen hinzu, um die Kategorisierung zu vereinfachen. Verwenden Sie hervorgehobene Attribute, um strukturierte Informationen einzugeben, die in Tabellen und Boards verwendet werden können."
"attributes_description": "Für leichtes kategorsieren, nutze Verbindungen zwischen Notizen oder füge Label hinzu. Verwende hervorgehobene Attribute, um sie als strukturierte Informationen in Tabellen oder Anschlagbretter zu verwenden."
},
"productivity_benefits": {
"revisions_title": "Notizrevisionen",
@@ -30,7 +30,7 @@
"protected_notes_title": "Geschützte Notizen",
"jump_to_title": "Schnellsuche und Kommandos",
"search_title": "Leistungsstarke Suche",
"web_clipper_title": "Web clipper",
"web_clipper_title": "Webschnipsel",
"revisions_content": "Notizen werden regelmäßig im Hintergrund gespeichert und Revisionen können zur Überprüfung oder zum Rückgängigmachen versehentlicher Änderungen verwendet werden. Revisionen können auch bei Bedarf erstellt werden.",
"sync_content": "Verwenden Sie eine selbst gehostete oder Cloud-Instanz, um Ihre Notizen ganz einfach auf mehreren Geräten zu synchronisieren und über eine WebApp von Ihrem mobilen Gerät aus darauf zuzugreifen.",
"protected_notes_content": "Halten Sie vertrauliche Informationen sicher, indem Sie Notizen verschlüsseln und mit einem Passwort schützen.",
@@ -41,7 +41,7 @@
"note_types": {
"text_title": "Text Notizen",
"code_title": "Code Notizen",
"canvas_title": "Canvas",
"canvas_title": "Leinwand",
"mermaid_title": "Mermaid Diagramm",
"mindmap_title": "Mind Map",
"text_description": "Die Notizen werden mit einem visuellen Editor (WYSIWYG) bearbeitet, der Tabellen, Bilder, mathematische Ausdrücke und Code-Blöcke mit Syntaxhervorhebung unterstützt. Formatieren Sie den Text schnell mit einer Markdown-ähnlichen Syntax oder mit Slash-Befehlen.",
@@ -162,7 +162,7 @@
},
"social_buttons": {
"github": "GitHub",
"github_discussions": "GitHub Discussions",
"github_discussions": "GitHub Diskussionen",
"matrix": "Matrix",
"reddit": "Reddit"
},
@@ -184,7 +184,7 @@
"way_market": "Weitersagen: Teilen Sie Trilium Notes mit Freunden, in Blogs und sozialen Medien."
},
"404": {
"title": "404: Not Found",
"title": "404: Nicht gefunden",
"description": "Die gesuchte Seite konnte nicht gefunden werden. Möglicherweise wurde sie gelöscht oder die URL ist falsch."
},
"download_helper_desktop_windows": {
@@ -193,7 +193,7 @@
"description_x64": "Kompatibel mit Intel- oder AMD-Geräten unter Windows 10 und 11.",
"description_arm64": "Kompatibel mit ARM-Geräten (z. B. mit Qualcomm Snapdragon).",
"quick_start": "Installation über Winget:",
"download_exe": "Download Installer (.exe)",
"download_exe": "Installationsdatei herunterladen (.exe)",
"download_zip": "Portable (.zip)",
"download_scoop": "Scoop"
}

4
docs/README-de.md vendored
View File

@@ -132,8 +132,8 @@ Unsere Dokumentation ist verfügbar in mehreren Formaten:
einfachen Speichern von Webinhalten
* Anpassbare Benutzeroberfläche (Seitenleisten-Schaltflächen, benutzerdefinierte
Widgets, ...)
* [Metriken](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics)
zusammen mit einem Grafana-Dashboard.
* [Metrics](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics),
zusätzlich mit dem Grafana Dashboard.
✨ Weitere Informationen zu TriliumNext findet man in den folgenden
Ressourcen/Communities von Drittanbietern:

View File

@@ -91,8 +91,8 @@ Vår dokumentasjon er tilgjengelig i flere format:
* Direct [OpenID and TOTP
integration](https://docs.triliumnotes.org/user-guide/setup/server/mfa) for
more secure login
* [Synchronization](https://docs.triliumnotes.org/user-guide/setup/synchronization)
with self-hosted sync server
* [Synkronisering](https://docs.triliumnotes.org/user-guide/setup/synchronization)
med selv-hostet sync server
* there are [3rd party services for hosting synchronisation
server](https://docs.triliumnotes.org/user-guide/setup/server/cloud-hosting)
* [Sharing](https://docs.triliumnotes.org/user-guide/advanced-usage/sharing)

24
edit-docs-config.yaml Normal file
View File

@@ -0,0 +1,24 @@
baseUrl: "https://docs.triliumnotes.org"
noteMappings:
- rootNoteId: "pOsGYCXsbNQG"
path: "docs/User Guide"
format: "markdown"
- rootNoteId: "pOsGYCXsbNQG"
path: "apps/server/src/assets/doc_notes/en/User Guide"
format: "html"
ignoredFiles:
- "index.html"
- "navigation.html"
- "style.css"
- "User Guide.html"
exportOnly: true
- rootNoteId: "jdjRLhLV3TtI"
path: "docs/Developer Guide"
format: "markdown"
- rootNoteId: "hD3V4hiu2VW4"
path: "docs/Release Notes"
format: "markdown"

View File

@@ -112,7 +112,7 @@
nodejs.python
removeReferencesTo
]
++ lib.optionals (app == "desktop") [
++ lib.optionals (app == "desktop" || app == "edit-docs") [
copyDesktopItems
# required for NIXOS_OZONE_WL expansion
# https://github.com/NixOS/nixpkgs/issues/172583
@@ -252,10 +252,33 @@
--add-flags $out/opt/trilium-server/main.cjs
'';
};
edit-docs = makeApp {
app = "edit-docs";
preBuildCommands = ''
export npm_config_nodedir=${electron.headers}
pnpm postinstall
'';
buildTask = "edit-docs:build";
mainProgram = "trilium-edit-docs";
installCommands = ''
#remove-references-to -t ${electron.headers} apps/edit-docs/dist/node_modules/better-sqlite3/build/config.gypi
#remove-references-to -t ${nodejs.python} apps/edit-docs/dist/node_modules/better-sqlite3/build/config.gypi
mkdir -p $out/{bin,opt/trilium-edit-docs}
cp --archive apps/edit-docs/dist/* $out/opt/trilium-edit-docs
makeShellWrapper ${lib.getExe electron} $out/bin/trilium-edit-docs \
--set-default ELECTRON_IS_DEV 0 \
--set TRILIUM_RESOURCE_DIR $out/opt/trilium-edit-docs \
--add-flags $out/opt/trilium-edit-docs/edit-docs.cjs
'';
};
in
{
packages.desktop = desktop;
packages.server = server;
packages.edit-docs = edit-docs;
packages.default = desktop;

View File

@@ -17,6 +17,8 @@
"desktop:start": "pnpm run --filter desktop dev",
"desktop:build": "pnpm run --filter desktop build",
"desktop:start-prod": "pnpm run --filter desktop start-prod",
"edit-docs:edit-docs": "pnpm run --filter edit-docs edit-docs",
"edit-docs:build": "pnpm run --filter edit-docs build",
"website:start": "pnpm run --filter website dev",
"website:build": "pnpm run --filter website build",
"electron:build": "pnpm desktop:build",
@@ -28,7 +30,6 @@
"chore:update-version": "tsx ./scripts/update-version.ts",
"docs:build": "pnpm run --filter build-docs start",
"docs:preview": "pnpm http-server site -p 9000",
"edit-docs:edit-docs": "pnpm run --filter edit-docs edit-docs",
"edit-docs:edit-demo": "pnpm run --filter edit-docs edit-demo",
"test:all": "pnpm test:parallel && pnpm test:sequential",
"test:parallel": "pnpm --filter=!server --filter=!ckeditor5-mermaid --filter=!ckeditor5-math --parallel test",
@@ -48,10 +49,11 @@
"@playwright/test": "1.57.0",
"@triliumnext/server": "workspace:*",
"@types/express": "5.0.6",
"@types/node": "24.10.7",
"@vitest/browser-webdriverio": "4.0.16",
"@vitest/coverage-v8": "4.0.16",
"@vitest/ui": "4.0.16",
"@types/js-yaml": "4.0.9",
"@types/node": "24.10.8",
"@vitest/browser-webdriverio": "4.0.17",
"@vitest/coverage-v8": "4.0.17",
"@vitest/ui": "4.0.17",
"chalk": "5.6.2",
"cross-env": "10.1.0",
"dpdm": "3.14.0",
@@ -59,22 +61,23 @@
"eslint": "9.39.2",
"eslint-config-preact": "2.0.0",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-playwright": "2.4.1",
"eslint-plugin-playwright": "2.5.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"happy-dom": "~20.0.0",
"happy-dom": "20.1.0",
"http-server": "14.1.1",
"jiti": "2.6.1",
"js-yaml": "4.1.1",
"jsonc-eslint-parser": "2.4.2",
"react-refresh": "0.18.0",
"rollup-plugin-webpack-stats": "2.1.9",
"tslib": "2.8.1",
"tsx": "4.21.0",
"typescript": "~5.9.0",
"typescript-eslint": "8.52.0",
"typescript": "5.9.3",
"typescript-eslint": "8.53.0",
"upath": "2.0.1",
"vite": "7.3.1",
"vite-plugin-dts": "~4.5.0",
"vitest": "4.0.16"
"vite-plugin-dts": "4.5.4",
"vitest": "4.0.17"
},
"license": "AGPL-3.0-only",
"author": {

View File

@@ -24,10 +24,10 @@
"@ckeditor/ckeditor5-dev-build-tools": "54.2.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "~8.52.0",
"@typescript-eslint/parser": "8.52.0",
"@vitest/browser": "4.0.16",
"@vitest/coverage-istanbul": "4.0.16",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"@vitest/browser": "4.0.17",
"@vitest/coverage-istanbul": "4.0.17",
"ckeditor5": "47.3.0",
"eslint": "9.39.2",
"eslint-config-ckeditor5": ">=9.1.0",
@@ -37,8 +37,8 @@
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "~2.0.0",
"vitest": "4.0.16",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.17",
"webdriverio": "9.23.0"
},
"peerDependencies": {

View File

@@ -25,10 +25,10 @@
"@ckeditor/ckeditor5-dev-build-tools": "54.2.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "~8.52.0",
"@typescript-eslint/parser": "8.52.0",
"@vitest/browser": "4.0.16",
"@vitest/coverage-istanbul": "4.0.16",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"@vitest/browser": "4.0.17",
"@vitest/coverage-istanbul": "4.0.17",
"ckeditor5": "47.3.0",
"eslint": "9.39.2",
"eslint-config-ckeditor5": ">=9.1.0",
@@ -38,8 +38,8 @@
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "~2.0.0",
"vitest": "4.0.16",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.17",
"webdriverio": "9.23.0"
},
"peerDependencies": {

View File

@@ -27,10 +27,10 @@
"@ckeditor/ckeditor5-dev-build-tools": "54.2.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "~8.52.0",
"@typescript-eslint/parser": "8.52.0",
"@vitest/browser": "4.0.16",
"@vitest/coverage-istanbul": "4.0.16",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"@vitest/browser": "4.0.17",
"@vitest/coverage-istanbul": "4.0.17",
"ckeditor5": "47.3.0",
"eslint": "9.39.2",
"eslint-config-ckeditor5": ">=9.1.0",
@@ -40,8 +40,8 @@
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "~2.0.0",
"vitest": "4.0.16",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.17",
"webdriverio": "9.23.0"
},
"peerDependencies": {

View File

@@ -27,10 +27,10 @@
"@ckeditor/ckeditor5-dev-build-tools": "54.2.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "~8.52.0",
"@typescript-eslint/parser": "8.52.0",
"@vitest/browser": "4.0.16",
"@vitest/coverage-istanbul": "4.0.16",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"@vitest/browser": "4.0.17",
"@vitest/coverage-istanbul": "4.0.17",
"ckeditor5": "47.3.0",
"eslint": "9.39.2",
"eslint-config-ckeditor5": ">=9.1.0",
@@ -40,8 +40,8 @@
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "~2.0.0",
"vitest": "4.0.16",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.17",
"webdriverio": "9.23.0"
},
"peerDependencies": {

View File

@@ -27,10 +27,10 @@
"@ckeditor/ckeditor5-dev-build-tools": "54.2.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "~8.52.0",
"@typescript-eslint/parser": "8.52.0",
"@vitest/browser": "4.0.16",
"@vitest/coverage-istanbul": "4.0.16",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"@vitest/browser": "4.0.17",
"@vitest/coverage-istanbul": "4.0.17",
"ckeditor5": "47.3.0",
"eslint": "9.39.2",
"eslint-config-ckeditor5": ">=9.1.0",
@@ -40,8 +40,8 @@
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "~2.0.0",
"vitest": "4.0.16",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.17",
"webdriverio": "9.23.0"
},
"peerDependencies": {

View File

@@ -16,7 +16,7 @@
"ckeditor5-premium-features": "47.3.0"
},
"devDependencies": {
"@smithy/middleware-retry": "4.4.19",
"@smithy/middleware-retry": "4.4.20",
"@types/jquery": "3.5.33"
}
}

View File

@@ -31,8 +31,8 @@
"devDependencies": {
"@digitak/esrun": "3.2.26",
"@triliumnext/ckeditor5": "workspace:*",
"@typescript-eslint/eslint-plugin": "8.52.0",
"@typescript-eslint/parser": "8.52.0",
"@typescript-eslint/eslint-plugin": "8.53.0",
"@typescript-eslint/parser": "8.53.0",
"dotenv": "17.2.3",
"esbuild": "0.27.2",
"eslint": "9.39.2",

1363
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,8 @@ import { getElectronPath, isNixOS } from "./utils.mjs";
const LD_LIBRARY_PATH = isNixOS() && execSync("nix eval --raw nixpkgs#gcc.cc.lib").toString("utf-8") + "/lib";
execSync(`${getElectronPath()} ${process.argv[2]} --no-sandbox`, {
const args = process.argv.slice(2);
execSync(`${getElectronPath()} ${args.join(" ")} --no-sandbox`, {
stdio: "inherit",
env: {
...process.env,

View File

@@ -26,7 +26,7 @@ function getVersion(packageJsonPath: string) {
function main() {
const version = getVersion(join(__dirname, "..", "package.json"));
for (const appName of ["server", "client", "desktop"]) {
for (const appName of ["server", "client", "desktop", "edit-docs"]) {
patchPackageJson(join(__dirname, "..", "apps", appName, "package.json"), version);
}