Merge branch 'develop' into siriusxt_patch

This commit is contained in:
SiriusXT 2024-11-11 18:26:07 +08:00
commit ce40c74e83
24 changed files with 1751 additions and 18 deletions

View File

@ -18,6 +18,8 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q
There are no special migration steps to migrate from a zadam/Trilium instance to a TriliumNext/Notes instance. Just upgrade your Trilium instance to the latest version and [install TriliumNext/Notes as usual](#-installation) There are no special migration steps to migrate from a zadam/Trilium instance to a TriliumNext/Notes instance. Just upgrade your Trilium instance to the latest version and [install TriliumNext/Notes as usual](#-installation)
Versions up to and including [v0.90.4](https://github.com/TriliumNext/Notes/releases/tag/v0.90.4) are compatible with the latest zadam/trilium version of [v0.63.7](https://github.com/zadam/trilium/releases/tag/v0.63.7). Any later versions of TriliumNext have their sync versions incremented.
## 💬 Discuss with us ## 💬 Discuss with us
Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have! Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have!

49
libraries/ckeditor/ckeditor.d.ts vendored Normal file
View File

@ -0,0 +1,49 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
import { DecoupledEditor as DecoupledEditorBase } from '@ckeditor/ckeditor5-editor-decoupled';
import { Essentials } from '@ckeditor/ckeditor5-essentials';
import { Alignment } from '@ckeditor/ckeditor5-alignment';
import { FontSize, FontFamily, FontColor, FontBackgroundColor } from '@ckeditor/ckeditor5-font';
import { CKFinderUploadAdapter } from '@ckeditor/ckeditor5-adapter-ckfinder';
import { Autoformat } from '@ckeditor/ckeditor5-autoformat';
import { Bold, Italic, Strikethrough, Underline } from '@ckeditor/ckeditor5-basic-styles';
import { BlockQuote } from '@ckeditor/ckeditor5-block-quote';
import { CKBox } from '@ckeditor/ckeditor5-ckbox';
import { CKFinder } from '@ckeditor/ckeditor5-ckfinder';
import { EasyImage } from '@ckeditor/ckeditor5-easy-image';
import { Heading } from '@ckeditor/ckeditor5-heading';
import { Image, ImageCaption, ImageResize, ImageStyle, ImageToolbar, ImageUpload, PictureEditing } from '@ckeditor/ckeditor5-image';
import { Indent, IndentBlock } from '@ckeditor/ckeditor5-indent';
import { Link } from '@ckeditor/ckeditor5-link';
import { List, ListProperties } from '@ckeditor/ckeditor5-list';
import { MediaEmbed } from '@ckeditor/ckeditor5-media-embed';
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';
import { PasteFromOffice } from '@ckeditor/ckeditor5-paste-from-office';
import { Table, TableToolbar } from '@ckeditor/ckeditor5-table';
import { TextTransformation } from '@ckeditor/ckeditor5-typing';
import { CloudServices } from '@ckeditor/ckeditor5-cloud-services';
export default class DecoupledEditor extends DecoupledEditorBase {
static builtinPlugins: (typeof TextTransformation | typeof Essentials | typeof Alignment | typeof FontBackgroundColor | typeof FontColor | typeof FontFamily | typeof FontSize | typeof CKFinderUploadAdapter | typeof Paragraph | typeof Heading | typeof Autoformat | typeof Bold | typeof Italic | typeof Strikethrough | typeof Underline | typeof BlockQuote | typeof Image | typeof ImageCaption | typeof ImageResize | typeof ImageStyle | typeof ImageToolbar | typeof ImageUpload | typeof CloudServices | typeof CKBox | typeof CKFinder | typeof EasyImage | typeof List | typeof ListProperties | typeof Indent | typeof IndentBlock | typeof Link | typeof MediaEmbed | typeof PasteFromOffice | typeof Table | typeof TableToolbar | typeof PictureEditing)[];
static defaultConfig: {
toolbar: {
items: string[];
};
image: {
resizeUnit: "px";
toolbar: string[];
};
table: {
contentToolbar: string[];
};
list: {
properties: {
styles: boolean;
startIndex: boolean;
reversed: boolean;
};
};
language: string;
};
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -82,6 +82,7 @@ import MovePaneButton from "../widgets/buttons/move_pane_button.js";
import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js"; import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_reference_button.js"; import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_reference_button.js";
import ScrollPaddingWidget from "../widgets/scroll_padding.js"; import ScrollPaddingWidget from "../widgets/scroll_padding.js";
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
export default class DesktopLayout { export default class DesktopLayout {
constructor(customWidgets) { constructor(customWidgets) {
@ -140,6 +141,7 @@ export default class DesktopLayout {
// the order of the widgets matter. Some of these want to "activate" themselves // the order of the widgets matter. Some of these want to "activate" themselves
// when visible. When this happens to multiple of them, the first one "wins". // when visible. When this happens to multiple of them, the first one "wins".
// promoted attributes should always win. // promoted attributes should always win.
.ribbon(new ClassicEditorToolbar())
.ribbon(new PromotedAttributesWidget()) .ribbon(new PromotedAttributesWidget())
.ribbon(new ScriptExecutorWidget()) .ribbon(new ScriptExecutorWidget())
.ribbon(new SearchDefinitionWidget()) .ribbon(new SearchDefinitionWidget())

View File

@ -23,6 +23,7 @@ import LauncherContainer from "../widgets/containers/launcher_container.js";
import RootContainer from "../widgets/containers/root_container.js"; import RootContainer from "../widgets/containers/root_container.js";
import SharedInfoWidget from "../widgets/shared_info.js"; import SharedInfoWidget from "../widgets/shared_info.js";
import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js"; import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
const MOBILE_CSS = ` const MOBILE_CSS = `
<style> <style>
@ -167,6 +168,7 @@ export default class MobileLayout {
.child(new NoteListWidget()) .child(new NoteListWidget())
.child(new FilePropertiesWidget().css('font-size','smaller')) .child(new FilePropertiesWidget().css('font-size','smaller'))
) )
.child(new ClassicEditorToolbar())
) )
.child(new ProtectedSessionPasswordDialog()) .child(new ProtectedSessionPasswordDialog())
.child(new ConfirmDialog()) .child(new ConfirmDialog())

View File

@ -527,6 +527,58 @@ function downloadSvg(nameWithoutExtension, svgContent) {
document.body.removeChild(element); document.body.removeChild(element);
} }
/**
* Compares two semantic version strings.
* Returns:
* 1 if v1 is greater than v2
* 0 if v1 is equal to v2
* -1 if v1 is less than v2
*
* @param {string} v1 First version string
* @param {string} v2 Second version string
* @returns {number}
*/
function compareVersions(v1, v2) {
// Remove 'v' prefix and everything after dash if present
v1 = v1.replace(/^v/, '').split('-')[0];
v2 = v2.replace(/^v/, '').split('-')[0];
const v1parts = v1.split('.').map(Number);
const v2parts = v2.split('.').map(Number);
// Pad shorter version with zeros
while (v1parts.length < 3) v1parts.push(0);
while (v2parts.length < 3) v2parts.push(0);
// Compare major version
if (v1parts[0] !== v2parts[0]) {
return v1parts[0] > v2parts[0] ? 1 : -1;
}
// Compare minor version
if (v1parts[1] !== v2parts[1]) {
return v1parts[1] > v2parts[1] ? 1 : -1;
}
// Compare patch version
if (v1parts[2] !== v2parts[2]) {
return v1parts[2] > v2parts[2] ? 1 : -1;
}
return 0;
}
/**
* Compares two semantic version strings and returns `true` if the latest version is greater than the current version.
* @param {string} latestVersion
* @param {string} currentVersion
* @returns {boolean}
*/
function isUpdateAvailable(latestVersion, currentVersion) {
return compareVersions(latestVersion, currentVersion) > 0;
}
export default { export default {
reloadFrontendApp, reloadFrontendApp,
parseDate, parseDate,
@ -567,5 +619,7 @@ export default {
areObjectsEqual, areObjectsEqual,
copyHtmlToClipboard, copyHtmlToClipboard,
createImageSrcUrl, createImageSrcUrl,
downloadSvg downloadSvg,
compareVersions,
isUpdateAvailable
}; };

View File

@ -347,8 +347,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget {
this.$editor.on("click", e => this.handleEditorClick(e)); this.$editor.on("click", e => this.handleEditorClick(e));
/** @property {BalloonEditor} */ this.textEditor = await CKEditor.BalloonEditor.create(this.$editor[0], editorConfig);
this.textEditor = await BalloonEditor.create(this.$editor[0], editorConfig);
this.textEditor.model.document.on('change:data', () => this.dataChanged()); this.textEditor.model.document.on('change:data', () => this.dataChanged());
this.textEditor.editing.view.document.on('enter', (event, data) => { this.textEditor.editing.view.document.on('enter', (event, data) => {
// disable entering new line - see https://github.com/ckeditor/ckeditor5/issues/9422 // disable entering new line - see https://github.com/ckeditor/ckeditor5/issues/9422
@ -358,9 +357,6 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget {
// disable spellcheck for attribute editor // disable spellcheck for attribute editor
this.textEditor.editing.view.change(writer => writer.setAttribute('spellcheck', 'false', this.textEditor.editing.view.document.getRoot())); this.textEditor.editing.view.change(writer => writer.setAttribute('spellcheck', 'false', this.textEditor.editing.view.document.getRoot()));
//await import(/* webpackIgnore: true */'../../libraries/ckeditor/inspector');
//CKEditorInspector.attach(this.textEditor);
} }
dataChanged() { dataChanged() {

View File

@ -333,7 +333,8 @@ export default class GlobalMenuWidget extends BasicWidget {
const latestVersion = await this.fetchLatestVersion(); const latestVersion = await this.fetchLatestVersion();
this.updateAvailableWidget.updateVersionStatus(latestVersion); this.updateAvailableWidget.updateVersionStatus(latestVersion);
this.$updateToLatestVersionButton.toggle(latestVersion > glob.triliumVersion); // Show "click to download" button in options menu if there's a new version available
this.$updateToLatestVersionButton.toggle(utils.isUpdateAvailable(latestVersion, glob.triliumVersion));
this.$updateToLatestVersionButton.find(".version-text").text(`Version ${latestVersion} is available, click to download.`); this.$updateToLatestVersionButton.find(".version-text").text(`Version ${latestVersion} is available, click to download.`);
} }

View File

@ -1,5 +1,6 @@
import { t } from "../../services/i18n.js"; import { t } from "../../services/i18n.js";
import BasicWidget from "../basic_widget.js"; import BasicWidget from "../basic_widget.js";
import utils from "../../services/utils.js";
const TPL = ` const TPL = `
<div style="display: none;"> <div style="display: none;">
@ -34,6 +35,6 @@ export default class UpdateAvailableWidget extends BasicWidget {
} }
updateVersionStatus(latestVersion) { updateVersionStatus(latestVersion) {
this.$widget.toggle(latestVersion > glob.triliumVersion); this.$widget.toggle(utils.isUpdateAvailable(latestVersion, glob.triliumVersion));
} }
} }

View File

@ -216,7 +216,7 @@ export default class RibbonContainer extends NoteContextAwareWidget {
this.$tabContainer.empty(); this.$tabContainer.empty();
for (const ribbonWidget of this.ribbonWidgets) { for (const ribbonWidget of this.ribbonWidgets) {
const ret = ribbonWidget.getTitle(note); const ret = await ribbonWidget.getTitle(note);
if (!ret.show) { if (!ret.show) {
continue; continue;
@ -351,6 +351,16 @@ export default class RibbonContainer extends NoteContextAwareWidget {
} }
} }
/**
* Executed as soon as the user presses the "Edit" floating button in a read-only text note.
*
* <p>
* We need to refresh the ribbon for cases such as the classic editor which relies on the read-only state.
*/
readOnlyTemporarilyDisabledEvent() {
this.refresh();
}
getActiveRibbonWidget() { getActiveRibbonWidget() {
return this.ribbonWidgets.find(ch => ch.componentId === this.lastActiveComponentId) return this.ribbonWidgets.find(ch => ch.componentId === this.lastActiveComponentId)
} }

View File

@ -0,0 +1,83 @@
import { t } from "../../services/i18n.js";
import options from "../../services/options.js";
import NoteContextAwareWidget from "../note_context_aware_widget.js";
const TPL = `\
<div class="classic-toolbar-widget"></div>
<style>
.classic-toolbar-widget {
--ck-color-toolbar-background: transparent;
--ck-color-button-default-background: transparent;
--ck-color-button-default-disabled-background: transparent;
min-height: 39px;
}
.classic-toolbar-widget .ck.ck-toolbar {
border: none;
}
.classic-toolbar-widget .ck.ck-button.ck-disabled {
opacity: 0.3;
}
body.mobile .classic-toolbar-widget {
position: relative;
overflow-x: auto;
}
body.mobile .classic-toolbar-widget .ck.ck-toolbar {
position: absolute;
}
</style>
`;
/**
* Handles the editing toolbar when the CKEditor is in decoupled mode.
*
* <p>
* This toolbar is only enabled if the user has selected the classic CKEditor.
*
* <p>
* The ribbon item is active by default for text notes, as long as they are not in read-only mode.
*/
export default class ClassicEditorToolbar extends NoteContextAwareWidget {
get name() {
return "classicEditor";
}
get toggleCommand() {
return "toggleRibbonTabClassicEditor";
}
doRender() {
this.$widget = $(TPL);
this.contentSized();
}
async getTitle() {
return {
show: await this.#shouldDisplay(),
activate: true,
title: t("classic_editor_toolbar.title"),
icon: "bx bx-edit-alt"
};
}
async #shouldDisplay() {
if (options.get("textNoteEditorType") !== "ckeditor-classic") {
return false;
}
if (this.note.type !== "text") {
return false;
}
if (await this.noteContext.isReadOnly()) {
return false;
}
return true;
}
}

View File

@ -35,6 +35,7 @@ import AttachmentErasureTimeoutOptions from "./options/other/attachment_erasure_
import RibbonOptions from "./options/appearance/ribbon.js"; import RibbonOptions from "./options/appearance/ribbon.js";
import LocalizationOptions from "./options/appearance/i18n.js"; import LocalizationOptions from "./options/appearance/i18n.js";
import CodeBlockOptions from "./options/appearance/code_block.js"; import CodeBlockOptions from "./options/appearance/code_block.js";
import EditorOptions from "./options/text_notes/editor.js";
const TPL = `<div class="note-detail-content-widget note-detail-printable"> const TPL = `<div class="note-detail-content-widget note-detail-printable">
<style> <style>
@ -68,6 +69,7 @@ const CONTENT_WIDGETS = {
], ],
_optionsShortcuts: [ KeyboardShortcutsOptions ], _optionsShortcuts: [ KeyboardShortcutsOptions ],
_optionsTextNotes: [ _optionsTextNotes: [
EditorOptions,
HeadingStyleOptions, HeadingStyleOptions,
TableOfContentsOptions, TableOfContentsOptions,
HighlightsListOptions, HighlightsListOptions,

View File

@ -12,7 +12,6 @@ import appContext from "../../components/app_context.js";
import dialogService from "../../services/dialog.js"; import dialogService from "../../services/dialog.js";
import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js"; import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js";
import options from "../../services/options.js"; import options from "../../services/options.js";
import { isSyntaxHighlightEnabled } from "../../services/syntax_highlight.js";
const ENABLE_INSPECTOR = false; const ENABLE_INSPECTOR = false;
@ -107,6 +106,12 @@ function buildListOfLanguages() {
]; ];
} }
/**
* The editor can operate into two distinct modes:
*
* - Ballon block mode, in which there is a floating toolbar for the selected text, but another floating button for the entire block (i.e. paragraph).
* - Decoupled mode, in which the editing toolbar is actually added on the client side (in {@link ClassicEditorToolbar}), see https://ckeditor.com/docs/ckeditor5/latest/examples/framework/bottom-toolbar-editor.html for an example on how the decoupled editor works.
*/
export default class EditableTextTypeWidget extends AbstractTextTypeWidget { export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
static getType() { return "editableText"; } static getType() { return "editableText"; }
@ -125,6 +130,8 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
async initEditor() { async initEditor() {
await libraryLoader.requireLibrary(libraryLoader.CKEDITOR); await libraryLoader.requireLibrary(libraryLoader.CKEDITOR);
const isClassicEditor = (options.get("textNoteEditorType") === "ckeditor-classic")
const editorClass = (isClassicEditor ? CKEditor.DecoupledEditor : CKEditor.BalloonEditor);
const codeBlockLanguages = buildListOfLanguages(); const codeBlockLanguages = buildListOfLanguages();
@ -133,7 +140,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
// display of $widget in both branches. // display of $widget in both branches.
this.$widget.show(); this.$widget.show();
this.watchdog = new EditorWatchdog(BalloonEditor, { this.watchdog = new CKEditor.EditorWatchdog(editorClass, {
// An average number of milliseconds between the last editor errors (defaults to 5000). // An average number of milliseconds between the last editor errors (defaults to 5000).
// When the period of time between errors is lower than that and the crashNumberLimit // When the period of time between errors is lower than that and the crashNumberLimit
// is also reached, the watchdog changes its state to crashedPermanently, and it stops // is also reached, the watchdog changes its state to crashedPermanently, and it stops
@ -169,10 +176,23 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
}); });
this.watchdog.setCreator(async (elementOrData, editorConfig) => { this.watchdog.setCreator(async (elementOrData, editorConfig) => {
const editor = await BalloonEditor.create(elementOrData, editorConfig); const editor = await editorClass.create(elementOrData, editorConfig);
await initSyntaxHighlighting(editor); await initSyntaxHighlighting(editor);
if (isClassicEditor) {
let $classicToolbarWidget;
if (!utils.isMobile()) {
const $parentSplit = this.$widget.parents(".note-split.type-text");
$classicToolbarWidget = $parentSplit.find("> .ribbon-container .classic-toolbar-widget");
} else {
$classicToolbarWidget = $("body").find(".classic-toolbar-widget");
}
$classicToolbarWidget.empty();
$classicToolbarWidget[0].appendChild(editor.ui.view.toolbar.element);
}
editor.model.document.on('change:data', () => this.spacedUpdate.scheduleUpdate()); editor.model.document.on('change:data', () => this.spacedUpdate.scheduleUpdate());
if (glob.isDev && ENABLE_INSPECTOR) { if (glob.isDev && ENABLE_INSPECTOR) {

View File

@ -0,0 +1,30 @@
import { t } from "../../../../services/i18n.js";
import utils from "../../../../services/utils.js";
import OptionsWidget from "../options_widget.js";
const TPL = `
<div class="options-section">
<h4>${t("editing.editor_type.label")}</h4>
<select class="editor-type-select form-select">
<option value="ckeditor-balloon">${t("editing.editor_type.floating")}</option>
<option value="ckeditor-classic">${t("editing.editor_type.fixed")}</option>
</select>
</div>`;
export default class EditorOptions extends OptionsWidget {
doRender() {
this.$widget = $(TPL);
this.$body = $("body");
this.$editorType = this.$widget.find(".editor-type-select");
this.$editorType.on('change', async () => {
const newEditorType = this.$editorType.val();
await this.updateOption('textNoteEditorType', newEditorType);
utils.reloadFrontendApp("editor type change");
});
}
async optionsLoaded(options) {
this.$editorType.val(options.textNoteEditorType);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1512,5 +1512,18 @@
}, },
"code_block": { "code_block": {
"word_wrapping": "Word wrapping" "word_wrapping": "Word wrapping"
},
"classic_editor_toolbar": {
"title": "Formatting"
},
"editor": {
"title": "Editor"
},
"editing": {
"editor_type": {
"label": "Formatting toolbar",
"floating": "Floating (editing tools appear near the cursor)",
"fixed": "Fixed (editing tools appear in the \"Formatting\" ribbon tab)"
}
} }
} }

View File

@ -1508,5 +1508,18 @@
}, },
"code_block": { "code_block": {
"word_wrapping": "Încadrare text" "word_wrapping": "Încadrare text"
},
"classic_editor_toolbar": {
"title": "Formatare"
},
"editing": {
"editor_type": {
"fixed": "Editor cu bară fixă (uneltele de editare vor apărea în tab-ul „Formatare” din panglică)",
"floating": "Editor cu bară flotantă (uneltele de editare vor apărea lângă cursor)",
"label": "Bară de formatare"
}
},
"editor": {
"title": "Editor"
} }
} }

View File

@ -65,7 +65,8 @@ const ALLOWED_OPTIONS = new Set([
'promotedAttributesOpenInRibbon', 'promotedAttributesOpenInRibbon',
'editedNotesOpenInRibbon', 'editedNotesOpenInRibbon',
'locale', 'locale',
'firstDayOfWeek' 'firstDayOfWeek',
'textNoteEditorType'
]); ]);
function getOptions() { function getOptions() {
@ -152,6 +153,10 @@ function getSupportedLocales() {
"id": "en", "id": "en",
"name": "English" "name": "English"
}, },
{
"id": "de",
"name": "Deutsch"
},
{ {
"id": "es", "id": "es",
"name": "Español" "name": "Español"

View File

@ -420,6 +420,12 @@ function getDefaultKeyboardActions() {
separator: t("keyboard_actions.ribbon-tabs") separator: t("keyboard_actions.ribbon-tabs")
}, },
{
actionName: "toggleRibbonTabClassicEditor",
defaultShortcuts: [],
description: t("keyboard_actions.toggle-classic-editor-toolbar"),
scope: "window"
},
{ {
actionName: "toggleRibbonTabBasicProperties", actionName: "toggleRibbonTabBasicProperties",
defaultShortcuts: [], defaultShortcuts: [],

View File

@ -131,7 +131,10 @@ const defaultOptions: DefaultOption[] = [
return "default:stackoverflow-dark"; return "default:stackoverflow-dark";
} }
}, isSynced: false }, }, isSynced: false },
{ name: "codeBlockWordWrap", value: "false", isSynced: true } { name: "codeBlockWordWrap", value: "false", isSynced: true },
// Text note configuration
{ name: "textNoteEditorType", value: "ckeditor-balloon", isSynced: true }
]; ];
/** /**

196
translations/de/server.json Normal file
View File

@ -0,0 +1,196 @@
{
"keyboard_actions": {
"open-jump-to-note-dialog": "Öffne das Dialogfeld \"Zu Notiz springen\"",
"search-in-subtree": "Suche nach Notizen im Unterbaum der aktuellen Notiz",
"expand-subtree": "Erweitere den Unterbaum der aktuellen Notiz",
"collapse-tree": "Kollabiere den gesamten Notizbaum",
"collapse-subtree": "Kollabiere den Unterbaum der aktuellen Notiz",
"sort-child-notes": "Sortiere untergeordnete Notizen",
"creating-and-moving-notes": "Erstellen und Verschieben von Notizen",
"create-note-into-inbox": "Erstelle eine Notiz im Posteingang (falls definiert) oder in der Tagesnotiz",
"delete-note": "Notiz löschen",
"move-note-up": "Notiz nach oben verschieben",
"move-note-down": "Notiz nach unten verschieben",
"move-note-up-in-hierarchy": "Notiz in der Hierarchie nach oben verschieben",
"move-note-down-in-hierarchy": "Notiz in der Hierarchie nach unten verschieben",
"edit-note-title": "Springe vom Baum zur Notiz-Detailansicht und bearbeite den Titel",
"edit-branch-prefix": "Zeige Dialog zum Bearbeiten des Zweigpräfixes",
"note-clipboard": "Notiz-Zwischenablage",
"copy-notes-to-clipboard": "Kopiere ausgewählte Notizen in die Zwischenablage",
"paste-notes-from-clipboard": "Füge Notizen aus der Zwischenablage in die aktive Notiz ein",
"cut-notes-to-clipboard": "Schneide ausgewählte Notizen in die Zwischenablage",
"select-all-notes-in-parent": "Wähle alle Notizen der aktuellen Notizenebene",
"add-note-above-to-the-selection": "Füge eine Notiz oberhalb zur Auswahl hinzu",
"add-note-below-to-selection": "Füge eine Notiz unterhalb zur Auswahl hinzu",
"duplicate-subtree": "Dupliziere den Unterbaum",
"tabs-and-windows": "Tabs & Fenster",
"open-new-tab": "Öffne einen neuen Tab",
"close-active-tab": "Schließe den aktiven Tab",
"reopen-last-tab": "Öffne den zuletzt geschlossenen Tab",
"activate-next-tab": "Aktiviere den Tab rechts",
"activate-previous-tab": "Aktiviere den Tab links",
"open-new-window": "Öffne ein neues leeres Fenster",
"toggle-tray": "Zeige/verstecke die Anwendung im Systemtray",
"first-tab": "Aktiviere den ersten Tab in der Liste",
"second-tab": "Aktiviere den zweiten Tab in der Liste",
"third-tab": "Aktiviere den dritten Tab in der Liste",
"fourth-tab": "Aktiviere den vierten Tab in der Liste",
"fifth-tab": "Aktiviere den fünften Tab in der Liste",
"sixth-tab": "Aktiviere den sechsten Tab in der Liste",
"seventh-tab": "Aktiviere den siebten Tab in der Liste",
"eight-tab": "Aktiviere den achten Tab in der Liste",
"ninth-tab": "Aktiviere den neunten Tab in der Liste",
"last-tab": "Aktiviere den letzten Tab in der Liste",
"dialogs": "Dialoge",
"show-note-source": "Zeige das Dialogfeld der Notizquelle",
"show-options": "Zeige das Dialogfeld der Optionen",
"show-revisions": "Zeige das Dialogfeld der Notizrevisionen",
"show-recent-changes": "Zeige das Dialogfeld der letzten Änderungen",
"show-sql-console": "Zeige das Dialogfeld der SQL-Konsole",
"show-backend-log": "Zeige das Dialogfeld des Backend-Logs",
"text-note-operations": "Textnotizoperationen",
"add-link-to-text": "Öffne das Dialogfeld zum Hinzufügen eines Links zum Text",
"follow-link-under-cursor": "Folge dem Link, unter dem sich der Cursor befindet",
"insert-date-and-time-to-text": "Füge das aktuelle Datum und die Uhrzeit in den Text ein",
"paste-markdown-into-text": "Füge Markdown aus der Zwischenablage in die Textnotiz ein",
"cut-into-note": "Schneide die Auswahl aus der aktuellen Notiz und erstelle eine Unternotiz mit dem ausgewählten Text",
"add-include-note-to-text": "Öffne das Dialogfeld zum Einfügen einer Notiz",
"edit-readonly-note": "Bearbeite eine schreibgeschützte Notiz",
"attributes-labels-and-relations": "Attribute (Labels & Beziehungen)",
"add-new-label": "Erstelle ein neues Label",
"create-new-relation": "Erstelle eine neue Beziehung",
"ribbon-tabs": "Ribbon-Tabs",
"toggle-basic-properties": "Schalte die Grundattribute um",
"toggle-file-properties": "Schalte die Dateiattribute um",
"toggle-image-properties": "Schalte die Bildattribute um",
"toggle-owned-attributes": "Schalte eigene Attribute um",
"toggle-inherited-attributes": "Schalte vererbte Attribute um",
"toggle-promoted-attributes": "Schalte beworbene Attribute um",
"toggle-link-map": "Schalte die Link-Karte um",
"toggle-note-info": "Schalte Notizinformationen um",
"toggle-note-paths": "Schalte Notizpfade um",
"toggle-similar-notes": "Schalte ähnliche Notizen um",
"other": "Andere",
"toggle-right-pane": "Schalte die Anzeige des rechten Fensters um, das Inhaltsverzeichnis und Markierungen enthält",
"print-active-note": "Drucke die aktive Notiz",
"open-note-externally": "Öffne die Notiz als Datei mit der Standardanwendung",
"render-active-note": "Render (erneut rendern) der aktiven Notiz",
"run-active-note": "Führe den aktiven JavaScript (Frontend/Backend) Notizcode aus",
"toggle-note-hoisting": "Schaltet das Hoisting der aktiven Notiz um",
"unhoist": "Von überall ent-hoisten",
"reload-frontend-app": "Lade die Frontend-App neu",
"open-dev-tools": "Öffne die Entwicklertools",
"toggle-left-note-tree-panel": "Schalte das linke Notizbaum-Panel um",
"toggle-full-screen": "Schalte den Vollbildmodus um",
"zoom-out": "Zoome heraus",
"zoom-in": "Zoome hinein",
"note-navigation": "Notiznavigation",
"reset-zoom-level": "Setze den Zoomlevel zurück",
"copy-without-formatting": "Kopiere den ausgewählten Text ohne Formatierung",
"force-save-revision": "Erzwinge das Erstellen / Speichern einer neuen Notizrevision der aktiven Notiz",
"show-help": "Zeige die eingebaute Hilfe / Cheat-Sheet",
"toggle-book-properties": "Schalte die Buch-Eigenschaften um"
},
"login": {
"title": "Anmeldung",
"heading": "Trilium Anmeldung",
"incorrect-password": "Das Passwort ist falsch. Bitte versuche es erneut.",
"password": "Passwort",
"remember-me": "Erinnere dich an mich",
"button": "Anmelden"
},
"set_password": {
"heading": "Passwort festlegen",
"description": "Bevor du Trilium im Web verwenden kannst, musst du zuerst ein Passwort festlegen. Du wirst dieses Passwort dann zur Anmeldung verwenden.",
"password": "Passwort",
"password-confirmation": "Passwortbestätigung",
"button": "Passwort festlegen"
},
"javascript-required": "Trilium erfordert, dass JavaScript aktiviert ist.",
"setup": {
"heading": "TriliumNext Notizen Setup",
"new-document": "Ich bin ein neuer Benutzer und möchte ein neues Trilium-Dokument für meine Notizen erstellen",
"sync-from-desktop": "Ich habe bereits eine Desktop-Instanz und möchte die Synchronisierung damit einrichten",
"sync-from-server": "Ich habe bereits eine Server-Instanz und möchte die Synchronisierung damit einrichten",
"next": "Weiter",
"init-in-progress": "Dokumenteninitialisierung läuft",
"redirecting": "Du wirst in Kürze zur Anwendung weitergeleitet.",
"title": "Setup"
},
"setup_sync-from-desktop": {
"heading": "Synchronisation vom Desktop",
"description": "Dieses Setup muss von der Desktop-Instanz aus initiiert werden:",
"step1": "Öffne deine TriliumNext Notes Desktop-Instanz.",
"step2": "Klicke im Trilium-Menü auf Optionen.",
"step3": "Klicke auf die Kategorie Synchronisation.",
"step4": "Ändere die Server-Instanzadresse auf: {{- host}} und klicke auf Speichern.",
"step5": "Klicke auf den Button \"Test-Synchronisation\", um zu überprüfen, ob die Verbindung erfolgreich ist.",
"step6": "Sobald du diese Schritte abgeschlossen hast, klicke auf {{- link}}.",
"step6-here": "hier"
},
"setup_sync-from-server": {
"heading": "Synchronisation vom Server",
"instructions": "Bitte gib unten die Trilium-Server-Adresse und die Zugangsdaten ein. Dies wird das gesamte Trilium-Dokument vom Server herunterladen und die Synchronisation einrichten. Je nach Dokumentgröße und Verbindungsgeschwindigkeit kann dies eine Weile dauern.",
"server-host": "Trilium Server-Adresse",
"server-host-placeholder": "https://<hostname>:<port>",
"proxy-server": "Proxy-Server (optional)",
"proxy-server-placeholder": "https://<hostname>:<port>",
"note": "Hinweis:",
"proxy-instruction": "Wenn du die Proxy-Einstellung leer lässt, wird der System-Proxy verwendet (nur für die Desktop-Anwendung)",
"password": "Passwort",
"password-placeholder": "Passwort",
"back": "Zurück",
"finish-setup": "Setup abschließen"
},
"setup_sync-in-progress": {
"heading": "Synchronisation läuft",
"successful": "Die Synchronisation wurde erfolgreich eingerichtet. Es wird eine Weile dauern, bis die erste Synchronisation abgeschlossen ist. Sobald dies erledigt ist, wirst du zur Anmeldeseite weitergeleitet.",
"outstanding-items": "Ausstehende Synchronisationselemente:",
"outstanding-items-default": "N/A"
},
"share_404": {
"title": "Nicht gefunden",
"heading": "Nicht gefunden"
},
"share_page": {
"parent": "Eltern:",
"clipped-from": "Diese Notiz wurde ursprünglich von {{- url}} ausgeschnitten",
"child-notes": "Untergeordnete Notizen:",
"no-content": "Diese Notiz hat keinen Inhalt."
},
"weekdays": {
"monday": "Montag",
"tuesday": "Dienstag",
"wednesday": "Mittwoch",
"thursday": "Donnerstag",
"friday": "Freitag",
"saturday": "Samstag",
"sunday": "Sonntag"
},
"months": {
"january": "Januar",
"february": "Februar",
"march": "März",
"april": "April",
"may": "Mai",
"june": "Juni",
"july": "Juli",
"august": "August",
"september": "September",
"october": "Oktober",
"november": "November",
"december": "Dezember"
},
"special_notes": {
"search_prefix": "Suche:"
},
"code_block": {
"theme_none": "Keine Syntax-Hervorhebung",
"theme_group_light": "Helle Themen",
"theme_group_dark": "Dunkle Themen"
},
"test_sync": {
"not-configured": "Der Synchronisations-Server-Host ist nicht konfiguriert. Bitte konfiguriere zuerst die Synchronisation.",
"successful": "Die Server-Verbindung wurde erfolgreich hergestellt, die Synchronisation wurde gestartet."
}
}

View File

@ -89,7 +89,8 @@
"copy-without-formatting": "Copy selected text without formatting", "copy-without-formatting": "Copy selected text without formatting",
"force-save-revision": "Force creating / saving new note revision of the active note", "force-save-revision": "Force creating / saving new note revision of the active note",
"show-help": "Shows built-in Help / cheatsheet", "show-help": "Shows built-in Help / cheatsheet",
"toggle-book-properties": "Toggle Book Properties" "toggle-book-properties": "Toggle Book Properties",
"toggle-classic-editor-toolbar": "Toggle the Formatting tab for the editor with fixed toolbar"
}, },
"login": { "login": {
"title": "Login", "title": "Login",

View File

@ -89,7 +89,8 @@
"toggle-tray": "Afișează/ascunde aplicația din tray-ul de sistem", "toggle-tray": "Afișează/ascunde aplicația din tray-ul de sistem",
"unhoist": "Defocalizează complet", "unhoist": "Defocalizează complet",
"zoom-in": "Mărește zoom-ul", "zoom-in": "Mărește zoom-ul",
"zoom-out": "Micșorează zoom-ul" "zoom-out": "Micșorează zoom-ul",
"toggle-classic-editor-toolbar": "Comută tab-ul „Formatare” pentru editorul cu bară fixă"
}, },
"login": { "login": {
"button": "Autentifică", "button": "Autentifică",