Merge branch 'main' into mhw-nightly

This commit is contained in:
matt wilkie
2025-08-11 21:11:17 -07:00
committed by GitHub
528 changed files with 111918 additions and 16030 deletions

40
.github/instructions/nx.instructions.md vendored Normal file
View File

@@ -0,0 +1,40 @@
---
applyTo: '**'
---
// This file is automatically generated by Nx Console
You are in an nx workspace using Nx 21.3.9 and pnpm as the package manager.
You have access to the Nx MCP server and the tools it provides. Use them. Follow these guidelines in order to best help the user:
# General Guidelines
- When answering questions, use the nx_workspace tool first to gain an understanding of the workspace architecture
- For questions around nx configuration, best practices or if you're unsure, use the nx_docs tool to get relevant, up-to-date docs!! Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the 'nx_workspace' tool to get any errors
- To help answer questions about the workspace structure or simply help with demonstrating how tasks depend on each other, use the 'nx_visualize_graph' tool
# Generation Guidelines
If the user wants to generate something, use the following flow:
- learn about the nx workspace and any specifics the user needs by using the 'nx_workspace' tool and the 'nx_project_details' tool if applicable
- get the available generators using the 'nx_generators' tool
- decide which generator to use. If no generators seem relevant, check the 'nx_available_plugins' tool to see if the user could install a plugin to help them
- get generator details using the 'nx_generator_schema' tool
- you may use the 'nx_docs' tool to learn more about a specific generator or technology if you're unsure
- decide which options to provide in order to best complete the user's request. Don't make any assumptions and keep the options minimalistic
- open the generator UI using the 'nx_open_generate_ui' tool
- wait for the user to finish the generator
- read the generator log file using the 'nx_read_generator_log' tool
- use the information provided in the log file to answer the user's question or continue with what they were doing
# Running Tasks Guidelines
If the user wants help with tasks or commands (which include keywords like "test", "build", "lint", or other similar actions), use the following flow:
- Use the 'nx_current_running_tasks_details' tool to get the list of tasks (this can include tasks that were completed, stopped or failed).
- If there are any tasks, ask the user if they would like help with a specific task then use the 'nx_current_running_task_output' tool to get the terminal output for that task/command
- Use the terminal output from 'nx_current_running_task_output' to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary
- If the user would like to rerun the task or command, always use `nx run <taskId>` to rerun in the terminal. This will ensure that the task will run in the nx context and will be run the same way it originally executed
- If the task was marked as "continuous" do not offer to rerun the task. This task is already running and the user can see the output in the terminal. You can use 'nx_current_running_task_output' to get the output of the task to verify the output.

View File

@@ -223,7 +223,7 @@ jobs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v4
uses: actions/download-artifact@v5
with:
path: /tmp/digests
pattern: digests-*

View File

@@ -107,7 +107,7 @@ jobs:
docs/Release Notes
- name: Download all artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v5
with:
merge-multiple: true
pattern: release-*

11
.github/workflows/unblock_signing.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
name: Unblock signing
on:
workflow_dispatch:
jobs:
unblock-win-signing:
runs-on: win-signing
steps:
- run: |
cat ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
rm ${{ vars.WINDOWS_SIGN_ERROR_LOG }}

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@ node_modules
# IDEs and editors
/.idea
.idea
.project
.classpath
.c9/

6
.idea/.gitignore generated vendored
View File

@@ -1,6 +0,0 @@
# Default ignored files
/workspace.xml
# Datasource local storage ignored files
/dataSources.local.xml
/dataSources/

View File

@@ -1,15 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

12
.idea/dataSources.xml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="document.db" uuid="2a4ac1e6-b828-4a2a-8e4a-3f59f10aff26">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/data/document.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

4
.idea/encodings.xml generated
View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

View File

@@ -1,11 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="Node.js Core" />
</component>
</project>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JSLintConfiguration">
<option devel="true" />
<option es6="true" />
<option maxerr="50" />
<option node="true" />
</component>
</project>

8
.idea/misc.xml generated
View File

@@ -1,8 +0,0 @@
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/trilium.iml" filepath="$PROJECT_DIR$/trilium.iml" />
</modules>
</component>
</project>

7
.idea/sqldialects.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$" dialect="SQLite" />
<file url="PROJECT" dialect="SQLite" />
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

2
.nvmrc
View File

@@ -1 +1 @@
22.17.1
22.18.0

View File

@@ -3,6 +3,7 @@
languageIds:
- javascript
- typescript
- typescriptreact
- html
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
@@ -25,9 +26,10 @@ scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
# The "$1" will be replaced by the keypath specified.
refactorTemplates:
- t("$1")
- {t("$1")}
- ${t("$1")}
- <%= t("$1") %>
# If set to true, only enables this custom framework (will disable all built-in frameworks)
monopoly: true
monopoly: true

8
.vscode/mcp.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"servers": {
"nx-mcp": {
"type": "http",
"url": "http://localhost:9461/mcp"
}
}
}

View File

@@ -35,5 +35,6 @@
"docs/**/*.png": true,
"apps/server/src/assets/doc_notes/**": true,
"apps/edit-docs/demo/**": true
}
},
"nxConsole.generateAiAgentRules": true
}

161
CLAUDE.md Normal file
View File

@@ -0,0 +1,161 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. It's built as a TypeScript monorepo using NX, with multiple applications and shared packages.
## Development Commands
### Setup
- `pnpm install` - Install all dependencies
- `corepack enable` - Enable pnpm if not available
### Running Applications
- `pnpm run server:start` - Start development server (http://localhost:8080)
- `pnpm nx run server:serve` - Alternative server start command
- `pnpm nx run desktop:serve` - Run desktop Electron app
- `pnpm run server:start-prod` - Run server in production mode
### Building
- `pnpm nx build <project>` - Build specific project (server, client, desktop, etc.)
- `pnpm run client:build` - Build client application
- `pnpm run server:build` - Build server application
- `pnpm run electron:build` - Build desktop application
### Testing
- `pnpm test:all` - Run all tests (parallel + sequential)
- `pnpm test:parallel` - Run tests that can run in parallel
- `pnpm test:sequential` - Run tests that must run sequentially (server, ckeditor5-mermaid, ckeditor5-math)
- `pnpm nx test <project>` - Run tests for specific project
- `pnpm coverage` - Generate coverage reports
### Linting & Type Checking
- `pnpm nx run <project>:lint` - Lint specific project
- `pnpm nx run <project>:typecheck` - Type check specific project
## Architecture Overview
### Monorepo Structure
- **apps/**: Runnable applications
- `client/` - Frontend application (shared by server and desktop)
- `server/` - Node.js server with web interface
- `desktop/` - Electron desktop application
- `web-clipper/` - Browser extension for saving web content
- Additional tools: `db-compare`, `dump-db`, `edit-docs`
- **packages/**: Shared libraries
- `commons/` - Shared interfaces and utilities
- `ckeditor5/` - Custom rich text editor with Trilium-specific plugins
- `codemirror/` - Code editor customizations
- `highlightjs/` - Syntax highlighting
- Custom CKEditor plugins: `ckeditor5-admonition`, `ckeditor5-footnotes`, `ckeditor5-math`, `ckeditor5-mermaid`
### Core Architecture Patterns
#### Three-Layer Cache System
- **Becca** (Backend Cache): Server-side entity cache (`apps/server/src/becca/`)
- **Froca** (Frontend Cache): Client-side mirror of backend data (`apps/client/src/services/froca.ts`)
- **Shaca** (Share Cache): Optimized cache for shared/published notes (`apps/server/src/share/`)
#### Entity System
Core entities are defined in `apps/server/src/becca/entities/`:
- `BNote` - Notes with content and metadata
- `BBranch` - Hierarchical relationships between notes (allows multiple parents)
- `BAttribute` - Key-value metadata attached to notes
- `BRevision` - Note version history
- `BOption` - Application configuration
#### Widget-Based UI
Frontend uses a widget system (`apps/client/src/widgets/`):
- `BasicWidget` - Base class for all UI components
- `NoteContextAwareWidget` - Widgets that respond to note changes
- `RightPanelWidget` - Widgets displayed in the right panel
- Type-specific widgets in `type_widgets/` directory
#### API Architecture
- **Internal API**: REST endpoints in `apps/server/src/routes/api/`
- **ETAPI**: External API for third-party integrations (`apps/server/src/etapi/`)
- **WebSocket**: Real-time synchronization (`apps/server/src/services/ws.ts`)
### Key Files for Understanding Architecture
1. **Application Entry Points**:
- `apps/server/src/main.ts` - Server startup
- `apps/client/src/desktop.ts` - Client initialization
2. **Core Services**:
- `apps/server/src/becca/becca.ts` - Backend data management
- `apps/client/src/services/froca.ts` - Frontend data synchronization
- `apps/server/src/services/backend_script_api.ts` - Scripting API
3. **Database Schema**:
- `apps/server/src/assets/db/schema.sql` - Core database structure
4. **Configuration**:
- `nx.json` - NX workspace configuration
- `package.json` - Project dependencies and scripts
## Note Types and Features
Trilium supports multiple note types, each with specialized widgets:
- **Text**: Rich text with CKEditor5 (markdown import/export)
- **Code**: Syntax-highlighted code editing with CodeMirror
- **File**: Binary file attachments
- **Image**: Image display with editing capabilities
- **Canvas**: Drawing/diagramming with Excalidraw
- **Mermaid**: Diagram generation
- **Relation Map**: Visual note relationship mapping
- **Web View**: Embedded web pages
- **Doc/Book**: Hierarchical documentation structure
## Development Guidelines
### Testing Strategy
- Server tests run sequentially due to shared database
- Client tests can run in parallel
- E2E tests use Playwright for both server and desktop apps
- Build validation tests check artifact integrity
### Scripting System
Trilium provides powerful user scripting capabilities:
- Frontend scripts run in browser context
- Backend scripts run in Node.js context with full API access
- Script API documentation available in `docs/Script API/`
### Internationalization
- Translation files in `apps/client/src/translations/`
- Supported languages: English, German, Spanish, French, Romanian, Chinese
### Security Considerations
- Per-note encryption with granular protected sessions
- CSRF protection for API endpoints
- OpenID and TOTP authentication support
- Sanitization of user-generated content
## Common Development Tasks
### Adding New Note Types
1. Create widget in `apps/client/src/widgets/type_widgets/`
2. Register in `apps/client/src/services/note_types.ts`
3. Add backend handling in `apps/server/src/services/notes.ts`
### Extending Search
- Search expressions handled in `apps/server/src/services/search/`
- Add new search operators in search context files
### Custom CKEditor Plugins
- Create new package in `packages/` following existing plugin structure
- Register in `packages/ckeditor5/src/plugins.ts`
### Database Migrations
- Add migration scripts in `apps/server/src/migrations/`
- Update schema in `apps/server/src/assets/db/schema.sql`
## Build System Notes
- Uses NX for monorepo management with build caching
- Vite for fast development builds
- ESBuild for production optimization
- pnpm workspaces for dependency management
- Docker support with multi-stage builds

View File

@@ -1,10 +1,9 @@
# Trilium Notes
Donate: ![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran?style=flat-square) ![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran?style=flat-square)
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/notes?style=flat-square)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/notes/total?style=flat-square)
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop&style=flat-square)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp)
![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran) ![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/notes)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/notes/total)
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [![Translation status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
[English](./README.md) | [Chinese](./docs/README-ZH_CN.md) | [Russian](./docs/README.ru.md) | [Japanese](./docs/README.ja.md) | [Italian](./docs/README.it.md) | [Spanish](./docs/README.es.md)
@@ -83,7 +82,7 @@ Feel free to join our official conversations. We would love to hear what feature
### Windows / MacOS
Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable.
Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package and run the `trilium` executable.
### Linux
@@ -91,7 +90,7 @@ If your distribution is listed in the table below, use your distribution's packa
[![Packaging status](https://repology.org/badge/vertical-allrepos/triliumnext.svg)](https://repology.org/project/triliumnext/versions)
You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable.
You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package and run the `trilium` executable.
TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
@@ -116,6 +115,14 @@ To install TriliumNext on your own server (including via Docker from [Dockerhub]
## 💻 Contribute
### Translations
If you are a native speaker, help us translate Trilium by heading over to our [Weblate page](https://hosted.weblate.org/engage/trilium/).
Here's the language coverage we have so far:
[![Translation status](https://hosted.weblate.org/widget/trilium/multi-auto.svg)](https://hosted.weblate.org/engage/trilium/)
### Code
Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):

View File

@@ -35,13 +35,13 @@
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"devDependencies": {
"@playwright/test": "1.54.1",
"@stylistic/eslint-plugin": "5.2.0",
"@playwright/test": "1.54.2",
"@stylistic/eslint-plugin": "5.2.3",
"@types/express": "5.0.3",
"@types/node": "22.16.5",
"@types/node": "22.17.1",
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.2.4",
"eslint": "9.31.0",
"eslint": "9.33.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.4",
@@ -49,7 +49,7 @@
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"tslib": "2.8.1",
"typedoc": "0.28.7",
"typedoc": "0.28.10",
"typedoc-plugin-missing-exports": "4.0.0"
},
"optionalDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.97.0",
"version": "0.97.2",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@@ -10,14 +10,15 @@
"url": "https://github.com/TriliumNext/Notes"
},
"dependencies": {
"@eslint/js": "9.31.0",
"@eslint/js": "9.33.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.18",
"@fullcalendar/daygrid": "6.1.18",
"@fullcalendar/interaction": "6.1.18",
"@fullcalendar/list": "6.1.18",
"@fullcalendar/multimonth": "6.1.18",
"@fullcalendar/timegrid": "6.1.18",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
"@fullcalendar/interaction": "6.1.19",
"@fullcalendar/list": "6.1.19",
"@fullcalendar/multimonth": "6.1.19",
"@fullcalendar/timegrid": "6.1.19",
"@maplibre/maplibre-gl-leaflet": "0.1.3",
"@mermaid-js/layout-elk": "0.1.8",
"@mind-elixir/node-menu": "5.0.0",
"@popperjs/core": "2.11.8",
@@ -35,10 +36,9 @@
"draggabilly": "3.0.0",
"force-graph": "1.50.1",
"globals": "16.3.0",
"i18next": "25.3.2",
"i18next": "25.3.4",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery-hotkeys": "0.2.2",
"jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6",
"katex": "0.16.22",
@@ -46,12 +46,12 @@
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "16.1.1",
"marked": "16.1.2",
"mermaid": "11.9.0",
"mind-elixir": "5.0.2",
"mind-elixir": "5.0.5",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.26.9",
"preact": "10.27.0",
"split.js": "1.6.5",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
@@ -59,12 +59,13 @@
},
"devDependencies": {
"@ckeditor/ckeditor5-inspector": "5.0.0",
"@preact/preset-vite": "2.10.2",
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.32",
"@types/leaflet": "1.9.20",
"@types/leaflet-gpx": "1.3.7",
"@types/mark.js": "8.11.12",
"@types/tabulator-tables": "6.2.7",
"@types/tabulator-tables": "6.2.9",
"copy-webpack-plugin": "13.0.0",
"happy-dom": "18.0.1",
"script-loader": "0.7.2",

View File

@@ -30,6 +30,7 @@ import type CodeMirror from "@triliumnext/codemirror";
import { StartupChecks } from "./startup_checks.js";
import type { CreateNoteOpts } from "../services/note_create.js";
import { ColumnComponent } from "tabulator-tables";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
interface Layout {
getRootWidget: (appContext: AppContext) => RootWidget;
@@ -92,7 +93,9 @@ export type CommandMappings = {
closeTocCommand: CommandData;
closeHlt: CommandData;
showLaunchBarSubtree: CommandData;
showRevisions: CommandData;
showRevisions: CommandData & {
noteId?: string | null;
};
showLlmChat: CommandData;
createAiChat: CommandData;
showOptions: CommandData & {
@@ -133,6 +136,8 @@ export type CommandMappings = {
hideLeftPane: CommandData;
showCpuArchWarning: CommandData;
showLeftPane: CommandData;
showAttachments: CommandData;
showSearchHistory: CommandData;
hoistNote: CommandData & { noteId: string };
leaveProtectedSession: CommandData;
enterProtectedSession: CommandData;
@@ -173,7 +178,7 @@ export type CommandMappings = {
deleteNotes: ContextMenuCommandData;
importIntoNote: ContextMenuCommandData;
exportNote: ContextMenuCommandData;
searchInSubtree: ContextMenuCommandData;
searchInSubtree: CommandData & { notePath: string; };
moveNoteUp: ContextMenuCommandData;
moveNoteDown: ContextMenuCommandData;
moveNoteUpInHierarchy: ContextMenuCommandData;
@@ -262,6 +267,73 @@ export type CommandMappings = {
closeThisNoteSplit: CommandData;
moveThisNoteSplit: CommandData & { isMovingLeft: boolean };
jumpToNote: CommandData;
commandPalette: CommandData;
// Keyboard shortcuts
backInNoteHistory: CommandData;
forwardInNoteHistory: CommandData;
forceSaveRevision: CommandData;
scrollToActiveNote: CommandData;
quickSearch: CommandData;
collapseTree: CommandData;
createNoteAfter: CommandData;
createNoteInto: CommandData;
addNoteAboveToSelection: CommandData;
addNoteBelowToSelection: CommandData;
openNewTab: CommandData;
activateNextTab: CommandData;
activatePreviousTab: CommandData;
openNewWindow: CommandData;
toggleTray: CommandData;
firstTab: CommandData;
secondTab: CommandData;
thirdTab: CommandData;
fourthTab: CommandData;
fifthTab: CommandData;
sixthTab: CommandData;
seventhTab: CommandData;
eigthTab: CommandData;
ninthTab: CommandData;
lastTab: CommandData;
showNoteSource: CommandData;
showSQLConsole: CommandData;
showBackendLog: CommandData;
showCheatsheet: CommandData;
showHelp: CommandData;
addLinkToText: CommandData;
followLinkUnderCursor: CommandData;
insertDateTimeToText: CommandData;
pasteMarkdownIntoText: CommandData;
cutIntoNote: CommandData;
addIncludeNoteToText: CommandData;
editReadOnlyNote: CommandData;
toggleRibbonTabClassicEditor: CommandData;
toggleRibbonTabBasicProperties: CommandData;
toggleRibbonTabBookProperties: CommandData;
toggleRibbonTabFileProperties: CommandData;
toggleRibbonTabImageProperties: CommandData;
toggleRibbonTabOwnedAttributes: CommandData;
toggleRibbonTabInheritedAttributes: CommandData;
toggleRibbonTabPromotedAttributes: CommandData;
toggleRibbonTabNoteMap: CommandData;
toggleRibbonTabNoteInfo: CommandData;
toggleRibbonTabNotePaths: CommandData;
toggleRibbonTabSimilarNotes: CommandData;
toggleRightPane: CommandData;
printActiveNote: CommandData;
exportAsPdf: CommandData;
openNoteExternally: CommandData;
renderActiveNote: CommandData;
unhoist: CommandData;
reloadFrontendApp: CommandData;
openDevTools: CommandData;
findInText: CommandData;
toggleLeftPane: CommandData;
toggleFullscreen: CommandData;
zoomOut: CommandData;
zoomIn: CommandData;
zoomReset: CommandData;
copyWithoutFormatting: CommandData;
// Geomap
deleteFromMap: { noteId: string };
@@ -299,6 +371,9 @@ export type CommandMappings = {
};
refreshTouchBar: CommandData;
reloadTextEditor: CommandData;
chooseNoteType: CommandData & {
callback: ChooseNoteTypeCallback
}
};
type EventMappings = {

View File

@@ -30,13 +30,6 @@ interface CreateChildrenResponse {
export default class Entrypoints extends Component {
constructor() {
super();
if (jQuery.hotkeys) {
// hot keys are active also inside inputs and content editables
jQuery.hotkeys.options.filterInputAcceptingElements = false;
jQuery.hotkeys.options.filterContentEditable = false;
jQuery.hotkeys.options.filterTextInputs = false;
}
}
openDevToolsCommand() {
@@ -113,7 +106,9 @@ export default class Entrypoints extends Component {
if (win.isFullScreenable()) {
win.setFullScreen(!win.isFullScreen());
}
} // outside of electron this is handled by the browser
} else {
document.documentElement.requestFullscreen();
}
}
reloadFrontendAppCommand() {

View File

@@ -325,8 +325,9 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
return false;
}
// Some book types must always display a note list, even if no children.
if (["calendar", "table", "geoMap"].includes(note.getLabelValue("viewType") ?? "")) {
// Collections must always display a note list, even if no children.
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
}

View File

@@ -13,7 +13,6 @@ import type ElectronRemote from "@electron/remote";
import type Electron from "electron";
import "./stylesheets/bootstrap.scss";
import "boxicons/css/boxicons.min.css";
import "jquery-hotkeys";
import "autocomplete.js/index_jquery.js";
await appContext.earlyInit();

View File

@@ -26,6 +26,7 @@ import TabRowWidget from "../widgets/tab_row.js";
import RefreshButton from "../widgets/floating_buttons/refresh_button.js";
import MobileEditorToolbar from "../widgets/ribbon_widgets/mobile_editor_toolbar.js";
import { applyModals } from "./layout_commons.js";
import CloseZenButton from "../widgets/close_zen_button.js";
const MOBILE_CSS = `
<style>
@@ -174,7 +175,8 @@ export default class MobileLayout {
.id("mobile-bottom-bar")
.child(new TabRowWidget().css("height", "40px"))
.child(new FlexContainer("row").class("horizontal").css("height", "53px").child(new LauncherContainer(true)).child(new GlobalMenuWidget(true)).id("launcher-pane"))
);
)
.child(new CloseZenButton());
applyModals(rootContainer);
return rootContainer;
}

View File

@@ -23,7 +23,7 @@ let lastTargetNode: HTMLElement | null = null;
// This will include all commands that implement ContextMenuCommandData, but it will not work if it additional options are added via the `|` operator,
// so they need to be added manually.
export type TreeCommandNames = FilteredCommandNames<ContextMenuCommandData> | "openBulkActionsDialog";
export type TreeCommandNames = FilteredCommandNames<ContextMenuCommandData> | "openBulkActionsDialog" | "searchInSubtree";
export default class TreeContextMenu implements SelectMenuItemEventListener<TreeCommandNames> {
private treeWidget: NoteTreeWidget;
@@ -129,7 +129,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
enabled: isNotRoot && parentNotSearch && noSelectedNotes && notOptionsOrHelp
},
{ title: t("tree-context-menu.convert-to-attachment"), command: "convertNoteToAttachment", uiIcon: "bx bx-paperclip", enabled: isNotRoot && !isHoisted && notOptionsOrHelp },
{ title: "----" },
{ title: `${t("tree-context-menu.expand-subtree")} <kbd data-command="expandSubtree"></kbd>`, command: "expandSubtree", uiIcon: "bx bx-expand", enabled: noSelectedNotes },

View File

@@ -79,7 +79,19 @@ async function renderAttributes(attributes: FAttribute[], renderIsInheritable: b
return $container;
}
const HIDDEN_ATTRIBUTES = ["originalFileName", "fileSize", "template", "inherit", "cssClass", "iconClass", "pageSize", "viewType", "geolocation", "docName"];
const HIDDEN_ATTRIBUTES = [
"originalFileName",
"fileSize",
"template",
"inherit",
"cssClass",
"iconClass",
"pageSize",
"viewType",
"geolocation",
"docName",
"webViewSrc"
];
async function renderNormalAttributes(note: FNote) {
const promotedDefinitionAttributes = note.getPromotedDefinitionAttributes();

View File

@@ -91,10 +91,10 @@ function parseActions(note: FNote) {
.filter((action) => !!action);
}
export async function executeBulkActions(parentNoteId: string, actions: BulkAction[]) {
export async function executeBulkActions(targetNoteIds: string[], actions: BulkAction[], includeDescendants = false) {
await server.post("bulk-action/execute", {
noteIds: [ parentNoteId ],
includeDescendants: true,
noteIds: targetNoteIds,
includeDescendants,
actions
});

View File

@@ -0,0 +1,295 @@
import { ActionKeyboardShortcut } from "@triliumnext/commons";
import appContext, { type CommandNames } from "../components/app_context.js";
import type NoteTreeWidget from "../widgets/note_tree.js";
import { t, translationsInitializedPromise } from "./i18n.js";
import keyboardActions from "./keyboard_actions.js";
import utils from "./utils.js";
export interface CommandDefinition {
id: string;
name: string;
description?: string;
icon?: string;
shortcut?: string;
commandName?: CommandNames;
handler?: () => Promise<unknown> | null | undefined | void;
aliases?: string[];
source?: "manual" | "keyboard-action";
/** Reference to the original keyboard action for scope checking. */
keyboardAction?: ActionKeyboardShortcut;
}
class CommandRegistry {
private commands: Map<string, CommandDefinition> = new Map();
private aliases: Map<string, string> = new Map();
constructor() {
this.loadCommands();
}
private async loadCommands() {
await translationsInitializedPromise;
this.registerDefaultCommands();
await this.loadKeyboardActionsAsync();
}
private registerDefaultCommands() {
this.register({
id: "export-note",
name: t("command_palette.export_note_title"),
description: t("command_palette.export_note_description"),
icon: "bx bx-export",
handler: () => {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (notePath) {
appContext.triggerCommand("showExportDialog", {
notePath,
defaultType: "single"
});
}
}
});
this.register({
id: "show-attachments",
name: t("command_palette.show_attachments_title"),
description: t("command_palette.show_attachments_description"),
icon: "bx bx-paperclip",
handler: () => appContext.triggerCommand("showAttachments")
});
// Special search commands with custom logic
this.register({
id: "search-notes",
name: t("command_palette.search_notes_title"),
description: t("command_palette.search_notes_description"),
icon: "bx bx-search",
handler: () => appContext.triggerCommand("searchNotes", {})
});
this.register({
id: "search-in-subtree",
name: t("command_palette.search_subtree_title"),
description: t("command_palette.search_subtree_description"),
icon: "bx bx-search-alt",
handler: () => {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (notePath) {
appContext.triggerCommand("searchInSubtree", { notePath });
}
}
});
this.register({
id: "show-search-history",
name: t("command_palette.search_history_title"),
description: t("command_palette.search_history_description"),
icon: "bx bx-history",
handler: () => appContext.triggerCommand("showSearchHistory")
});
this.register({
id: "show-launch-bar",
name: t("command_palette.configure_launch_bar_title"),
description: t("command_palette.configure_launch_bar_description"),
icon: "bx bx-sidebar",
handler: () => appContext.triggerCommand("showLaunchBarSubtree")
});
}
private async loadKeyboardActionsAsync() {
try {
const actions = await keyboardActions.getActions();
this.registerKeyboardActions(actions);
} catch (error) {
console.error("Failed to load keyboard actions:", error);
}
}
private registerKeyboardActions(actions: ActionKeyboardShortcut[]) {
for (const action of actions) {
// Skip actions that we've already manually registered
if (this.commands.has(action.actionName)) {
continue;
}
// Skip actions that don't have a description (likely separators)
if (!action.description) {
continue;
}
// Skip Electron-only actions if not in Electron environment
if (action.isElectronOnly && !utils.isElectron()) {
continue;
}
// Skip actions that should not appear in the command palette
if (action.ignoreFromCommandPalette) {
continue;
}
// Get the primary shortcut (first one in the list)
const primaryShortcut = action.effectiveShortcuts?.[0];
let name = action.friendlyName;
if (action.scope === "note-tree") {
name = t("command_palette.tree-action-name", { name: action.friendlyName });
}
// Create a command definition from the keyboard action
const commandDef: CommandDefinition = {
id: action.actionName,
name,
description: action.description,
icon: action.iconClass,
shortcut: primaryShortcut ? this.formatShortcut(primaryShortcut) : undefined,
commandName: action.actionName as CommandNames,
source: "keyboard-action",
keyboardAction: action
};
this.register(commandDef);
}
}
private formatShortcut(shortcut: string): string {
// Convert electron accelerator format to display format
return shortcut
.replace(/CommandOrControl/g, 'Ctrl')
.replace(/\+/g, ' + ');
}
register(command: CommandDefinition) {
this.commands.set(command.id, command);
// Register aliases
if (command.aliases) {
for (const alias of command.aliases) {
this.aliases.set(alias.toLowerCase(), command.id);
}
}
}
getCommand(id: string): CommandDefinition | undefined {
return this.commands.get(id);
}
getAllCommands(): CommandDefinition[] {
const commands = Array.from(this.commands.values());
// Sort commands by name
commands.sort((a, b) => a.name.localeCompare(b.name));
return commands;
}
searchCommands(query: string): CommandDefinition[] {
const normalizedQuery = query.toLowerCase();
const results: { command: CommandDefinition; score: number }[] = [];
for (const command of this.commands.values()) {
let score = 0;
// Exact match on name
if (command.name.toLowerCase() === normalizedQuery) {
score = 100;
}
// Name starts with query
else if (command.name.toLowerCase().startsWith(normalizedQuery)) {
score = 80;
}
// Name contains query
else if (command.name.toLowerCase().includes(normalizedQuery)) {
score = 60;
}
// Description contains query
else if (command.description?.toLowerCase().includes(normalizedQuery)) {
score = 40;
}
// Check aliases
else if (command.aliases?.some(alias => alias.toLowerCase().includes(normalizedQuery))) {
score = 50;
}
if (score > 0) {
results.push({ command, score });
}
}
// Sort by score (highest first) and then by name
results.sort((a, b) => {
if (a.score !== b.score) {
return b.score - a.score;
}
return a.command.name.localeCompare(b.command.name);
});
return results.map(r => r.command);
}
async executeCommand(commandId: string) {
const command = this.getCommand(commandId);
if (!command) {
console.error(`Command not found: ${commandId}`);
return;
}
// Execute custom handler if provided
if (command.handler) {
await command.handler();
return;
}
// Handle keyboard action with scope-aware execution
if (command.keyboardAction && command.commandName) {
if (command.keyboardAction.scope === "note-tree") {
this.executeWithNoteTreeFocus(command.commandName);
} else if (command.keyboardAction.scope === "text-detail") {
this.executeWithTextDetail(command.commandName);
} else {
appContext.triggerCommand(command.commandName, {
ntxId: appContext.tabManager.activeNtxId
});
}
return;
}
// Fallback for commands without keyboard action reference
if (command.commandName) {
appContext.triggerCommand(command.commandName, {
ntxId: appContext.tabManager.activeNtxId
});
return;
}
console.error(`Command ${commandId} has no handler or commandName`);
}
private executeWithNoteTreeFocus(actionName: CommandNames) {
const tree = document.querySelector(".tree-wrapper") as HTMLElement;
if (!tree) {
return;
}
const treeComponent = appContext.getComponentByEl(tree) as NoteTreeWidget;
const activeNode = treeComponent.getActiveNode();
treeComponent.triggerCommand(actionName, {
ntxId: appContext.tabManager.activeNtxId,
node: activeNode
});
}
private async executeWithTextDetail(actionName: CommandNames) {
const typeWidget = await appContext.tabManager.getActiveContext()?.getTypeWidget();
if (!typeWidget) {
return;
}
typeWidget.triggerCommand(actionName, {
ntxId: appContext.tabManager.activeNtxId
});
}
}
const commandRegistry = new CommandRegistry();
export default commandRegistry;

View File

@@ -65,6 +65,9 @@ async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FA
$renderedContent.append($("<div>").append("<div>This note is protected and to access it you need to enter password.</div>").append("<br/>").append($button));
} else if (entity instanceof FNote) {
$renderedContent
.css("display", "flex")
.css("flex-direction", "column");
$renderedContent.append(
$("<div>")
.css("display", "flex")
@@ -72,8 +75,33 @@ async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FA
.css("align-items", "center")
.css("height", "100%")
.css("font-size", "500%")
.css("flex-grow", "1")
.append($("<span>").addClass(entity.getIcon()))
);
if (entity.type === "webView" && entity.hasLabel("webViewSrc")) {
const $footer = $("<footer>")
.addClass("webview-footer");
const $openButton = $(`
<button class="file-open btn btn-primary" type="button">
<span class="bx bx-link-external"></span>
${t("content_renderer.open_externally")}
</button>
`)
.appendTo($footer)
.on("click", () => {
const webViewSrc = entity.getLabelValue("webViewSrc");
if (webViewSrc) {
if (utils.isElectron()) {
const electron = utils.dynamicRequire("electron");
electron.shell.openExternal(webViewSrc);
} else {
window.open(webViewSrc, '_blank', 'noopener,noreferrer');
}
}
});
$footer.appendTo($renderedContent);
}
}
if (entity instanceof FNote) {

View File

@@ -6,6 +6,11 @@ import type { Locale } from "@triliumnext/commons";
let locales: Locale[] | null;
/**
* A deferred promise that resolves when translations are initialized.
*/
export let translationsInitializedPromise = $.Deferred();
export async function initLocale() {
const locale = (options.get("locale") as string) || "en";
@@ -19,6 +24,8 @@ export async function initLocale() {
},
returnEmptyString: false
});
translationsInitializedPromise.resolve();
}
export function getAvailableLocales() {

View File

@@ -2,21 +2,15 @@ import server from "./server.js";
import appContext, { type CommandNames } from "../components/app_context.js";
import shortcutService from "./shortcuts.js";
import type Component from "../components/component.js";
import type { ActionKeyboardShortcut } from "@triliumnext/commons";
const keyboardActionRepo: Record<string, Action> = {};
const keyboardActionRepo: Record<string, ActionKeyboardShortcut> = {};
// TODO: Deduplicate with server.
export interface Action {
actionName: CommandNames;
effectiveShortcuts: string[];
scope: string;
}
const keyboardActionsLoaded = server.get<Action[]>("keyboard-actions").then((actions) => {
const keyboardActionsLoaded = server.get<ActionKeyboardShortcut[]>("keyboard-actions").then((actions) => {
actions = actions.filter((a) => !!a.actionName); // filter out separators
for (const action of actions) {
action.effectiveShortcuts = action.effectiveShortcuts.filter((shortcut) => !shortcut.startsWith("global:"));
action.effectiveShortcuts = (action.effectiveShortcuts ?? []).filter((shortcut) => !shortcut.startsWith("global:"));
keyboardActionRepo[action.actionName] = action;
}
@@ -38,7 +32,7 @@ async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, c
const actions = await getActionsForScope(scope);
for (const action of actions) {
for (const shortcut of action.effectiveShortcuts) {
for (const shortcut of action.effectiveShortcuts ?? []) {
shortcutService.bindElShortcut($el, shortcut, () => component.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId }));
}
}
@@ -46,7 +40,7 @@ async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, c
getActionsForScope("window").then((actions) => {
for (const action of actions) {
for (const shortcut of action.effectiveShortcuts) {
for (const shortcut of action.effectiveShortcuts ?? []) {
shortcutService.bindGlobalShortcut(shortcut, () => appContext.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId }));
}
}
@@ -80,7 +74,7 @@ function updateDisplayedShortcuts($container: JQuery<HTMLElement>) {
const action = await getAction(actionName, true);
if (action) {
const keyboardActions = action.effectiveShortcuts.join(", ");
const keyboardActions = (action.effectiveShortcuts ?? []).join(", ");
if (keyboardActions || $(el).text() !== "not set") {
$(el).text(keyboardActions);
@@ -99,7 +93,7 @@ function updateDisplayedShortcuts($container: JQuery<HTMLElement>) {
if (action) {
const title = $(el).attr("title");
const shortcuts = action.effectiveShortcuts.join(", ");
const shortcuts = (action.effectiveShortcuts ?? []).join(", ");
if (title?.includes(shortcuts)) {
return;

View File

@@ -3,6 +3,7 @@ import appContext from "../components/app_context.js";
import noteCreateService from "./note_create.js";
import froca from "./froca.js";
import { t } from "./i18n.js";
import commandRegistry from "./command_registry.js";
import type { MentionFeedObjectItem } from "@triliumnext/ckeditor5";
// this key needs to have this value, so it's hit by the tooltip
@@ -29,13 +30,16 @@ export interface Suggestion {
notePathTitle?: string;
notePath?: string;
highlightedNotePathTitle?: string;
action?: string | "create-note" | "search-notes" | "external-link";
action?: string | "create-note" | "search-notes" | "external-link" | "command";
parentNoteId?: string;
icon?: string;
commandId?: string;
commandDescription?: string;
commandShortcut?: string;
}
interface Options {
container?: HTMLElement;
export interface Options {
container?: HTMLElement | null;
fastSearch?: boolean;
allowCreatingNotes?: boolean;
allowJumpToSearchNotes?: boolean;
@@ -44,6 +48,8 @@ interface Options {
hideGoToSelectedNoteButton?: boolean;
/** If set, hides all right-side buttons in the autocomplete dropdown */
hideAllButtons?: boolean;
/** If set, enables command palette mode */
isCommandPalette?: boolean;
}
async function autocompleteSourceForCKEditor(queryText: string) {
@@ -73,6 +79,31 @@ async function autocompleteSourceForCKEditor(queryText: string) {
}
async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void, options: Options = {}) {
// Check if we're in command mode
if (options.isCommandPalette && term.startsWith(">")) {
const commandQuery = term.substring(1).trim();
// Get commands (all if no query, filtered if query provided)
const commands = commandQuery.length === 0
? commandRegistry.getAllCommands()
: commandRegistry.searchCommands(commandQuery);
// Convert commands to suggestions
const commandSuggestions: Suggestion[] = commands.map(cmd => ({
action: "command",
commandId: cmd.id,
noteTitle: cmd.name,
notePathTitle: `>${cmd.name}`,
highlightedNotePathTitle: cmd.name,
commandDescription: cmd.description,
commandShortcut: cmd.shortcut,
icon: cmd.icon
}));
cb(commandSuggestions);
return;
}
const fastSearch = options.fastSearch === false ? false : true;
if (fastSearch === false) {
if (term.trim().length === 0) {
@@ -146,6 +177,12 @@ function showRecentNotes($el: JQuery<HTMLElement>) {
$el.trigger("focus");
}
function showAllCommands($el: JQuery<HTMLElement>) {
searchDelay = 0;
$el.setSelectedNotePath("");
$el.autocomplete("val", ">").autocomplete("open");
}
function fullTextSearch($el: JQuery<HTMLElement>, options: Options) {
const searchString = $el.autocomplete("val") as unknown as string;
if (options.fastSearch === false || searchString?.trim().length === 0) {
@@ -270,7 +307,24 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
},
displayKey: "notePathTitle",
templates: {
suggestion: (suggestion) => `<span class="${suggestion.icon ?? "bx bx-note"}"></span> ${suggestion.highlightedNotePathTitle}`
suggestion: (suggestion) => {
if (suggestion.action === "command") {
let html = `<div class="command-suggestion">`;
html += `<span class="command-icon ${suggestion.icon || "bx bx-terminal"}"></span>`;
html += `<div class="command-content">`;
html += `<div class="command-name">${suggestion.highlightedNotePathTitle}</div>`;
if (suggestion.commandDescription) {
html += `<div class="command-description">${suggestion.commandDescription}</div>`;
}
html += `</div>`;
if (suggestion.commandShortcut) {
html += `<kbd class="command-shortcut">${suggestion.commandShortcut}</kbd>`;
}
html += '</div>';
return html;
}
return `<span class="${suggestion.icon ?? "bx bx-note"}"></span> ${suggestion.highlightedNotePathTitle}`;
}
},
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
cache: false
@@ -280,6 +334,12 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
// TODO: Types fail due to "autocomplete:selected" not being registered in type definitions.
($el as any).on("autocomplete:selected", async (event: Event, suggestion: Suggestion) => {
if (suggestion.action === "command") {
$el.autocomplete("close");
$el.trigger("autocomplete:commandselected", [suggestion]);
return;
}
if (suggestion.action === "external-link") {
$el.setSelectedNotePath(null);
$el.setSelectedExternalLink(suggestion.externalLink);
@@ -392,10 +452,26 @@ function init() {
};
}
/**
* Convenience function which triggers the display of recent notes in the autocomplete input and focuses it.
*
* @param inputElement - The input element to trigger recent notes on.
*/
export function triggerRecentNotes(inputElement: HTMLInputElement | null | undefined) {
if (!inputElement) {
return;
}
const $el = $(inputElement);
showRecentNotes($el);
$el.trigger("focus").trigger("select");
}
export default {
autocompleteSourceForCKEditor,
initNoteAutocomplete,
showRecentNotes,
showAllCommands,
setText,
init
};

View File

@@ -109,8 +109,6 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
async function chooseNoteType() {
return new Promise<ChooseNoteTypeResponse>((res) => {
// TODO: Remove ignore after callback for chooseNoteType is defined in app_context.ts
//@ts-ignore
appContext.triggerCommand("chooseNoteType", { callback: res });
});
}

View File

@@ -1,4 +1,5 @@
import type FNote from "../entities/fnote.js";
import BoardView from "../widgets/view_widgets/board_view/index.js";
import CalendarView from "../widgets/view_widgets/calendar_view.js";
import GeoView from "../widgets/view_widgets/geo_view/index.js";
import ListOrGridView from "../widgets/view_widgets/list_or_grid_view.js";
@@ -6,8 +7,9 @@ import TableView from "../widgets/view_widgets/table_view/index.js";
import type { ViewModeArgs } from "../widgets/view_widgets/view_mode.js";
import type ViewMode from "../widgets/view_widgets/view_mode.js";
const allViewTypes = ["list", "grid", "calendar", "table", "geoMap", "board"] as const;
export type ArgsWithoutNoteId = Omit<ViewModeArgs, "noteIds">;
export type ViewTypeOptions = "list" | "grid" | "calendar" | "table" | "geoMap";
export type ViewTypeOptions = typeof allViewTypes[number];
export default class NoteListRenderer {
@@ -23,7 +25,7 @@ export default class NoteListRenderer {
#getViewType(parentNote: FNote): ViewTypeOptions {
const viewType = parentNote.getLabelValue("viewType");
if (!["list", "grid", "calendar", "table", "geoMap"].includes(viewType || "")) {
if (!(allViewTypes as readonly string[]).includes(viewType || "")) {
// when not explicitly set, decide based on the note type
return parentNote.type === "search" ? "list" : "grid";
} else {
@@ -57,6 +59,8 @@ export default class NoteListRenderer {
return new TableView(args);
case "geoMap":
return new GeoView(args);
case "board":
return new BoardView(args);
case "list":
case "grid":
default:

View File

@@ -13,8 +13,8 @@ let openTooltipElements: JQuery<HTMLElement>[] = [];
let dismissTimer: ReturnType<typeof setTimeout>;
function setupGlobalTooltip() {
$(document).on("mouseenter", "a", mouseEnterHandler);
$(document).on("mouseenter", "[data-href]", mouseEnterHandler);
$(document).on("mouseenter", "a:not(.no-tooltip-preview)", mouseEnterHandler);
$(document).on("mouseenter", "[data-href]:not(.no-tooltip-preview)", mouseEnterHandler);
// close any note tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
$(document).on("click", (e) => {

View File

@@ -1,4 +1,4 @@
export type LabelType = "text" | "number" | "boolean" | "date" | "datetime" | "time" | "url";
export type LabelType = "text" | "number" | "boolean" | "date" | "datetime" | "time" | "url" | "color";
type Multiplicity = "single" | "multi";
export interface DefinitionObject {
@@ -17,7 +17,7 @@ function parse(value: string) {
for (const token of tokens) {
if (token === "promoted") {
defObj.isPromoted = true;
} else if (["text", "number", "boolean", "date", "datetime", "time", "url"].includes(token)) {
} else if (["text", "number", "boolean", "date", "datetime", "time", "url", "color"].includes(token)) {
defObj.labelType = token as LabelType;
} else if (["single", "multi"].includes(token)) {
defObj.multiplicity = token as Multiplicity;

View File

@@ -0,0 +1,323 @@
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import shortcuts, { keyMatches, matchesShortcut } from "./shortcuts.js";
// Mock utils module
vi.mock("./utils.js", () => ({
default: {
isDesktop: () => true
}
}));
// Mock jQuery globally since it's used in the shortcuts module
const mockElement = {
addEventListener: vi.fn(),
removeEventListener: vi.fn()
};
const mockJQuery = vi.fn(() => [mockElement]);
(mockJQuery as any).length = 1;
mockJQuery[0] = mockElement;
(global as any).$ = mockJQuery as any;
global.document = mockElement as any;
describe("shortcuts", () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
// Clean up any active bindings after each test
shortcuts.removeGlobalShortcut("test-namespace");
});
describe("normalizeShortcut", () => {
it("should normalize shortcut to lowercase and remove whitespace", () => {
expect(shortcuts.normalizeShortcut("Ctrl + A")).toBe("ctrl+a");
expect(shortcuts.normalizeShortcut(" SHIFT + F1 ")).toBe("shift+f1");
expect(shortcuts.normalizeShortcut("Alt+Space")).toBe("alt+space");
});
it("should handle empty or null shortcuts", () => {
expect(shortcuts.normalizeShortcut("")).toBe("");
expect(shortcuts.normalizeShortcut(null as any)).toBe(null);
expect(shortcuts.normalizeShortcut(undefined as any)).toBe(undefined);
});
it("should handle shortcuts with multiple spaces", () => {
expect(shortcuts.normalizeShortcut("Ctrl + Shift + A")).toBe("ctrl+shift+a");
});
it("should warn about malformed shortcuts", () => {
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
shortcuts.normalizeShortcut("ctrl+");
shortcuts.normalizeShortcut("+a");
shortcuts.normalizeShortcut("ctrl++a");
expect(consoleSpy).toHaveBeenCalledTimes(3);
consoleSpy.mockRestore();
});
});
describe("keyMatches", () => {
const createKeyboardEvent = (key: string, code?: string) => ({
key,
code: code || `Key${key.toUpperCase()}`
} as KeyboardEvent);
it("should match regular letter keys using key code", () => {
const event = createKeyboardEvent("a", "KeyA");
expect(keyMatches(event, "a")).toBe(true);
expect(keyMatches(event, "A")).toBe(true);
});
it("should match number keys using digit codes", () => {
const event = createKeyboardEvent("1", "Digit1");
expect(keyMatches(event, "1")).toBe(true);
});
it("should match special keys using key mapping", () => {
expect(keyMatches({ key: "Enter" } as KeyboardEvent, "return")).toBe(true);
expect(keyMatches({ key: "Enter" } as KeyboardEvent, "enter")).toBe(true);
expect(keyMatches({ key: "Delete" } as KeyboardEvent, "del")).toBe(true);
expect(keyMatches({ key: "Escape" } as KeyboardEvent, "esc")).toBe(true);
expect(keyMatches({ key: " " } as KeyboardEvent, "space")).toBe(true);
expect(keyMatches({ key: "ArrowUp" } as KeyboardEvent, "up")).toBe(true);
});
it("should match function keys", () => {
expect(keyMatches({ key: "F1" } as KeyboardEvent, "f1")).toBe(true);
expect(keyMatches({ key: "F12" } as KeyboardEvent, "f12")).toBe(true);
});
it("should handle undefined or null keys", () => {
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
expect(keyMatches({} as KeyboardEvent, null as any)).toBe(false);
expect(keyMatches({} as KeyboardEvent, undefined as any)).toBe(false);
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
describe("matchesShortcut", () => {
const createKeyboardEvent = (options: {
key: string;
code?: string;
ctrlKey?: boolean;
altKey?: boolean;
shiftKey?: boolean;
metaKey?: boolean;
}) => ({
key: options.key,
code: options.code || `Key${options.key.toUpperCase()}`,
ctrlKey: options.ctrlKey || false,
altKey: options.altKey || false,
shiftKey: options.shiftKey || false,
metaKey: options.metaKey || false
} as KeyboardEvent);
it("should match simple key shortcuts", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA" });
expect(matchesShortcut(event, "a")).toBe(true);
});
it("should match shortcuts with modifiers", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true });
expect(matchesShortcut(event, "ctrl+a")).toBe(true);
const shiftEvent = createKeyboardEvent({ key: "a", code: "KeyA", shiftKey: true });
expect(matchesShortcut(shiftEvent, "shift+a")).toBe(true);
});
it("should match complex modifier combinations", () => {
const event = createKeyboardEvent({
key: "a",
code: "KeyA",
ctrlKey: true,
shiftKey: true
});
expect(matchesShortcut(event, "ctrl+shift+a")).toBe(true);
});
it("should not match when modifiers don't match", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true });
expect(matchesShortcut(event, "alt+a")).toBe(false);
expect(matchesShortcut(event, "a")).toBe(false);
});
it("should handle alternative modifier names", () => {
const ctrlEvent = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true });
expect(matchesShortcut(ctrlEvent, "control+a")).toBe(true);
const metaEvent = createKeyboardEvent({ key: "a", code: "KeyA", metaKey: true });
expect(matchesShortcut(metaEvent, "cmd+a")).toBe(true);
expect(matchesShortcut(metaEvent, "command+a")).toBe(true);
});
it("should handle empty or invalid shortcuts", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA" });
expect(matchesShortcut(event, "")).toBe(false);
expect(matchesShortcut(event, null as any)).toBe(false);
});
it("should handle invalid events", () => {
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
expect(matchesShortcut(null as any, "a")).toBe(false);
expect(matchesShortcut({} as KeyboardEvent, "a")).toBe(false);
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
it("should warn about invalid shortcut formats", () => {
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
const event = createKeyboardEvent({ key: "a", code: "KeyA" });
matchesShortcut(event, "ctrl+");
matchesShortcut(event, "+");
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
describe("bindGlobalShortcut", () => {
it("should bind a global shortcut", () => {
const handler = vi.fn();
shortcuts.bindGlobalShortcut("ctrl+a", handler, "test-namespace");
expect(mockElement.addEventListener).toHaveBeenCalledWith("keydown", expect.any(Function));
});
it("should not bind shortcuts when handler is null", () => {
shortcuts.bindGlobalShortcut("ctrl+a", null, "test-namespace");
expect(mockElement.addEventListener).not.toHaveBeenCalled();
});
it("should remove previous bindings when namespace is reused", () => {
const handler1 = vi.fn();
const handler2 = vi.fn();
shortcuts.bindGlobalShortcut("ctrl+a", handler1, "test-namespace");
expect(mockElement.addEventListener).toHaveBeenCalledTimes(1);
shortcuts.bindGlobalShortcut("ctrl+b", handler2, "test-namespace");
expect(mockElement.removeEventListener).toHaveBeenCalledTimes(1);
expect(mockElement.addEventListener).toHaveBeenCalledTimes(2);
});
});
describe("bindElShortcut", () => {
it("should bind shortcut to specific element", () => {
const mockEl = { addEventListener: vi.fn(), removeEventListener: vi.fn() };
const mockJQueryEl = [mockEl] as any;
mockJQueryEl.length = 1;
const handler = vi.fn();
shortcuts.bindElShortcut(mockJQueryEl, "ctrl+a", handler, "test-namespace");
expect(mockEl.addEventListener).toHaveBeenCalledWith("keydown", expect.any(Function));
});
it("should fall back to document when element is empty", () => {
const emptyJQuery = [] as any;
emptyJQuery.length = 0;
const handler = vi.fn();
shortcuts.bindElShortcut(emptyJQuery, "ctrl+a", handler, "test-namespace");
expect(mockElement.addEventListener).toHaveBeenCalledWith("keydown", expect.any(Function));
});
});
describe("removeGlobalShortcut", () => {
it("should remove shortcuts for a specific namespace", () => {
const handler = vi.fn();
shortcuts.bindGlobalShortcut("ctrl+a", handler, "test-namespace");
shortcuts.removeGlobalShortcut("test-namespace");
expect(mockElement.removeEventListener).toHaveBeenCalledWith("keydown", expect.any(Function));
});
});
describe("event handling", () => {
it.skip("should call handler when shortcut matches", () => {
const handler = vi.fn();
shortcuts.bindGlobalShortcut("ctrl+a", handler, "test-namespace");
// Get the listener that was registered
expect(mockElement.addEventListener.mock.calls).toHaveLength(1);
const [, listener] = mockElement.addEventListener.mock.calls[0];
// First verify that matchesShortcut works directly
const testEvent = {
type: "keydown",
key: "a",
code: "KeyA",
ctrlKey: true,
altKey: false,
shiftKey: false,
metaKey: false,
preventDefault: vi.fn(),
stopPropagation: vi.fn()
} as any;
// Test matchesShortcut directly first
expect(matchesShortcut(testEvent, "ctrl+a")).toBe(true);
// Now test the actual listener
listener(testEvent);
expect(handler).toHaveBeenCalled();
expect(testEvent.preventDefault).toHaveBeenCalled();
expect(testEvent.stopPropagation).toHaveBeenCalled();
});
it("should not call handler for non-keyboard events", () => {
const handler = vi.fn();
shortcuts.bindGlobalShortcut("ctrl+a", handler, "test-namespace");
const [, listener] = mockElement.addEventListener.mock.calls[0];
// Simulate a non-keyboard event
const event = {
type: "click"
} as any;
listener(event);
expect(handler).not.toHaveBeenCalled();
});
it("should not call handler when shortcut doesn't match", () => {
const handler = vi.fn();
shortcuts.bindGlobalShortcut("ctrl+a", handler, "test-namespace");
const [, listener] = mockElement.addEventListener.mock.calls[0];
// Simulate a non-matching keydown event
const event = {
type: "keydown",
key: "b",
code: "KeyB",
ctrlKey: true,
altKey: false,
shiftKey: false,
metaKey: false,
preventDefault: vi.fn(),
stopPropagation: vi.fn()
} as any;
listener(event);
expect(handler).not.toHaveBeenCalled();
expect(event.preventDefault).not.toHaveBeenCalled();
});
});
});

View File

@@ -1,7 +1,18 @@
import utils from "./utils.js";
type ElementType = HTMLElement | Document;
type Handler = (e: JQuery.TriggeredEvent<ElementType | Element, string, ElementType | Element, ElementType | Element>) => void;
type Handler = (e: KeyboardEvent) => void;
interface ShortcutBinding {
element: HTMLElement | Document;
shortcut: string;
handler: Handler;
namespace: string | null;
listener: (evt: Event) => void;
}
// Store all active shortcut bindings for management
const activeBindings: Map<string, ShortcutBinding[]> = new Map();
function removeGlobalShortcut(namespace: string) {
bindGlobalShortcut("", null, namespace);
@@ -15,38 +26,167 @@ function bindElShortcut($el: JQuery<ElementType | Element>, keyboardShortcut: st
if (utils.isDesktop()) {
keyboardShortcut = normalizeShortcut(keyboardShortcut);
let eventName = "keydown";
// If namespace is provided, remove all previous bindings for this namespace
if (namespace) {
eventName += `.${namespace}`;
// if there's a namespace, then we replace the existing event handler with the new one
$el.off(eventName);
removeNamespaceBindings(namespace);
}
// method can be called to remove the shortcut (e.g. when keyboardShortcut label is deleted)
if (keyboardShortcut) {
$el.bind(eventName, keyboardShortcut, (e) => {
if (handler) {
handler(e);
// Method can be called to remove the shortcut (e.g. when keyboardShortcut label is deleted)
if (keyboardShortcut && handler) {
const element = $el.length > 0 ? $el[0] as (HTMLElement | Document) : document;
const listener = (evt: Event) => {
// Only handle keyboard events
if (evt.type !== 'keydown' || !(evt instanceof KeyboardEvent)) {
return;
}
e.preventDefault();
e.stopPropagation();
});
const e = evt as KeyboardEvent;
if (matchesShortcut(e, keyboardShortcut)) {
e.preventDefault();
e.stopPropagation();
handler(e);
}
};
// Add the event listener
element.addEventListener('keydown', listener);
// Store the binding for later cleanup
const binding: ShortcutBinding = {
element,
shortcut: keyboardShortcut,
handler,
namespace,
listener
};
const key = namespace || 'global';
if (!activeBindings.has(key)) {
activeBindings.set(key, []);
}
activeBindings.get(key)!.push(binding);
}
}
}
function removeNamespaceBindings(namespace: string) {
const bindings = activeBindings.get(namespace);
if (bindings) {
// Remove all event listeners for this namespace
bindings.forEach(binding => {
binding.element.removeEventListener('keydown', binding.listener);
});
activeBindings.delete(namespace);
}
}
export function matchesShortcut(e: KeyboardEvent, shortcut: string): boolean {
if (!shortcut) return false;
// Ensure we have a proper KeyboardEvent with key property
if (!e || typeof e.key !== 'string') {
console.warn('matchesShortcut called with invalid event:', e);
return false;
}
const parts = shortcut.toLowerCase().split('+');
const key = parts[parts.length - 1]; // Last part is the actual key
const modifiers = parts.slice(0, -1); // Everything before is modifiers
// Defensive check - ensure we have a valid key
if (!key || key.trim() === '') {
console.warn('Invalid shortcut format:', shortcut);
return false;
}
// Check if the main key matches
if (!keyMatches(e, key)) {
return false;
}
// Check modifiers
const expectedCtrl = modifiers.includes('ctrl') || modifiers.includes('control');
const expectedAlt = modifiers.includes('alt');
const expectedShift = modifiers.includes('shift');
const expectedMeta = modifiers.includes('meta') || modifiers.includes('cmd') || modifiers.includes('command');
return e.ctrlKey === expectedCtrl &&
e.altKey === expectedAlt &&
e.shiftKey === expectedShift &&
e.metaKey === expectedMeta;
}
export function keyMatches(e: KeyboardEvent, key: string): boolean {
// Defensive check for undefined/null key
if (!key) {
console.warn('keyMatches called with undefined/null key');
return false;
}
// Handle special key mappings and aliases
const keyMap: { [key: string]: string[] } = {
'return': ['Enter'],
'enter': ['Enter'], // alias for return
'del': ['Delete'],
'delete': ['Delete'], // alias for del
'esc': ['Escape'],
'escape': ['Escape'], // alias for esc
'space': [' ', 'Space'],
'tab': ['Tab'],
'backspace': ['Backspace'],
'home': ['Home'],
'end': ['End'],
'pageup': ['PageUp'],
'pagedown': ['PageDown'],
'up': ['ArrowUp'],
'down': ['ArrowDown'],
'left': ['ArrowLeft'],
'right': ['ArrowRight']
};
// Function keys
for (let i = 1; i <= 19; i++) {
keyMap[`f${i}`] = [`F${i}`];
}
const mappedKeys = keyMap[key.toLowerCase()];
if (mappedKeys) {
return mappedKeys.includes(e.key) || mappedKeys.includes(e.code);
}
// For number keys, use the physical key code regardless of modifiers
// This works across all keyboard layouts
if (key >= '0' && key <= '9') {
return e.code === `Digit${key}`;
}
// For letter keys, use the physical key code for consistency
if (key.length === 1 && key >= 'a' && key <= 'z') {
return e.code === `Key${key.toUpperCase()}`;
}
// For regular keys, check both key and code as fallback
return e.key.toLowerCase() === key.toLowerCase() ||
e.code.toLowerCase() === key.toLowerCase();
}
/**
* Normalize to the form expected by the jquery.hotkeys.js
* Simple normalization - just lowercase and trim whitespace
*/
function normalizeShortcut(shortcut: string): string {
if (!shortcut) {
return shortcut;
}
return shortcut.toLowerCase().replace("enter", "return").replace("delete", "del").replace("ctrl+alt", "alt+ctrl").replace("meta+alt", "alt+meta"); // alt needs to be first;
const normalized = shortcut.toLowerCase().trim().replace(/\s+/g, '');
// Warn about potentially problematic shortcuts
if (normalized.endsWith('+') || normalized.startsWith('+') || normalized.includes('++')) {
console.warn('Potentially malformed shortcut:', shortcut, '-> normalized to:', normalized);
}
return normalized;
}
export default {

View File

@@ -51,6 +51,14 @@ export default class SpacedUpdate {
this.lastUpdated = Date.now();
}
/**
* Sets the update interval for the spaced update.
* @param interval The update interval in milliseconds.
*/
setUpdateInterval(interval: number) {
this.updateInterval = interval;
}
triggerUpdate() {
if (!this.changed) {
return;

View File

@@ -36,7 +36,9 @@ export function applyCopyToClipboardButton($codeBlock: JQuery<HTMLElement>) {
const $copyButton = $("<button>")
.addClass("bx component icon-action tn-tool-button bx-copy copy-button")
.attr("title", t("code_block.copy_title"))
.on("click", () => {
.on("click", (e) => {
e.stopPropagation();
if (!isShare) {
copyTextWithToast($codeBlock.text());
} else {

View File

@@ -1,5 +1,4 @@
import "jquery";
import "jquery-hotkeys";
import utils from "./services/utils.js";
import ko from "knockout";
import "./stylesheets/bootstrap.scss";

View File

@@ -29,6 +29,14 @@ async function formatCodeBlocks() {
await formatCodeBlocks($("#content"));
}
async function setupTextNote() {
formatCodeBlocks();
applyMath();
const setupMermaid = (await import("./share/mermaid.js")).default;
setupMermaid();
}
/**
* Fetch note with given ID from backend
*
@@ -47,8 +55,11 @@ async function fetchNote(noteId: string | null = null) {
document.addEventListener(
"DOMContentLoaded",
() => {
formatCodeBlocks();
applyMath();
const noteType = determineNoteType();
if (noteType === "text") {
setupTextNote();
}
const toggleMenuButton = document.getElementById("toggleMenuButton");
const layout = document.getElementById("layout");
@@ -60,6 +71,12 @@ document.addEventListener(
false
);
function determineNoteType() {
const bodyClass = document.body.className;
const match = bodyClass.match(/type-([^\s]+)/);
return match ? match[1] : null;
}
// workaround to prevent webpack from removing "fetchNote" as dead code:
// add fetchNote as property to the window object
Object.defineProperty(window, "fetchNote", {

View File

@@ -0,0 +1,17 @@
import mermaid from "mermaid";
export default function setupMermaid() {
for (const codeBlock of document.querySelectorAll("#content pre code.language-mermaid")) {
const parentPre = codeBlock.parentElement;
if (!parentPre) {
continue;
}
const mermaidDiv = document.createElement("div");
mermaidDiv.classList.add("mermaid");
mermaidDiv.innerHTML = codeBlock.innerHTML;
parentPre.replaceWith(mermaidDiv);
}
mermaid.init();
}

View File

@@ -320,3 +320,8 @@ h6 {
page-break-after: avoid;
break-after: avoid;
}
figure.table {
/* Workaround for https://github.com/ckeditor/ckeditor5/issues/18903. Remove once official fix is released */
display: table !important;
}

View File

@@ -139,12 +139,6 @@ textarea,
color: var(--muted-text-color);
}
/* Restore default apperance */
input[type="number"],
input[type="checkbox"] {
appearance: auto !important;
}
/* Add a gap between consecutive radios / check boxes */
label.tn-radio + label.tn-radio,
label.tn-checkbox + label.tn-checkbox {
@@ -648,6 +642,10 @@ table.promoted-attributes-in-tooltip th {
z-index: calc(var(--ck-z-panel) - 1) !important;
}
.tooltip.tooltip-top {
z-index: 32767 !important;
}
.tooltip-trigger {
background: transparent;
pointer-events: none;
@@ -1786,6 +1784,54 @@ textarea {
padding: 1rem;
}
/* Command palette styling */
.jump-to-note-dialog .command-suggestion {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.9em;
}
.jump-to-note-dialog .aa-suggestion .command-suggestion,
.jump-to-note-dialog .aa-suggestion .command-suggestion div {
padding: 0;
}
.jump-to-note-dialog .aa-cursor .command-suggestion,
.jump-to-note-dialog .aa-suggestion:hover .command-suggestion {
border-left-color: var(--link-color);
background-color: var(--hover-background-color);
}
.jump-to-note-dialog .command-icon {
color: var(--muted-text-color);
font-size: 1.125rem;
flex-shrink: 0;
margin-top: 0.125rem;
}
.jump-to-note-dialog .command-content {
flex-grow: 1;
min-width: 0;
}
.jump-to-note-dialog .command-name {
font-weight: bold;
}
.jump-to-note-dialog .command-description {
font-size: 0.8em;
line-height: 1.3;
opacity: 0.75;
}
.jump-to-note-dialog kbd.command-shortcut {
background-color: transparent;
color: inherit;
opacity: 0.75;
font-family: inherit !important;
}
.empty-table-placeholder {
text-align: center;
color: var(--muted-text-color);
@@ -1844,6 +1890,7 @@ body.zen #launcher-container,
body.zen #launcher-pane,
body.zen #left-pane,
body.zen #right-pane,
body.zen #mobile-sidebar-wrapper,
body.zen .tab-row-container,
body.zen .tab-row-widget,
body.zen .ribbon-container:not(:has(.classic-toolbar-widget.visible)),
@@ -1851,7 +1898,8 @@ body.zen .ribbon-container:has(.classic-toolbar-widget.visible) .ribbon-top-row,
body.zen .ribbon-container .ribbon-body:not(:has(.classic-toolbar-widget.visible)),
body.zen .note-icon-widget,
body.zen .title-row .button-widget,
body.zen .floating-buttons-children > *:not(.bx-edit-alt) {
body.zen .floating-buttons-children > *:not(.bx-edit-alt),
body.zen .action-button {
display: none !important;
}
@@ -1893,14 +1941,20 @@ body.zen .note-title-widget input {
background: transparent !important;
}
body.zen #detail-container {
width: 100%;
}
/* Content renderer */
footer.file-footer {
footer.file-footer,
footer.webview-footer {
display: flex;
justify-content: center;
}
footer.file-footer button {
footer.file-footer button,
footer.webview-footer button {
margin: 5px;
}

View File

@@ -458,6 +458,11 @@ body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
padding: 1rem;
}
.note-list-wrapper .note-book-card .note-book-content.type-image .rendered-content,
.note-list-wrapper .note-book-card .note-book-content.type-pdf .rendered-content {
padding: 0;
}
.note-list-wrapper .note-book-card .note-book-content .rendered-content.text-with-ellipsis {
padding: 1rem !important;
}

View File

@@ -128,10 +128,15 @@ div.tn-tool-dialog {
.jump-to-note-dialog .modal-header {
padding: unset !important;
padding-bottom: 26px !important;
}
.jump-to-note-dialog .modal-body {
padding: 26px 0 !important;
padding: 0 !important;
}
.jump-to-note-dialog .modal-footer {
padding-top: 26px;
}
/* Search box wrapper */
@@ -228,16 +233,16 @@ div.tn-tool-dialog {
/* Item title link */
.recent-changes-content ul li .note-title a {
.recent-changes-content ul li a {
color: currentColor;
}
.recent-changes-content ul li .note-title a:hover {
.recent-changes-content ul li a:hover {
text-decoration: underline;
}
/* Item title for deleted notes */
.recent-changes-content ul li.deleted-note .note-title > .note-title {
.recent-changes-content ul li.deleted-note .note-title {
text-decoration: line-through;
}

View File

@@ -1678,4 +1678,42 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
#right-pane .highlights-list li:active {
background: transparent;
transition: none;
}
/** Canvas **/
.excalidraw {
--border-radius-lg: 6px;
}
.excalidraw .Island {
backdrop-filter: var(--dropdown-backdrop-filter);
}
.excalidraw .Island.App-toolbar {
--island-bg-color: var(--floating-button-background-color);
--shadow-island: 1px 1px 1px var(--floating-button-shadow-color);
}
.excalidraw .dropdown-menu {
border: unset !important;
box-shadow: unset !important;
background-color: transparent !important;
--island-bg-color: var(--menu-background-color);
--shadow-island: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
--default-border-color: var(--bs-dropdown-divider-bg);
--button-hover-bg: var(--hover-item-background-color);
}
.excalidraw .dropdown-menu .dropdown-menu-container {
border-radius: var(--dropdown-border-radius);
}
.excalidraw .dropdown-menu .dropdown-menu-container > div:not([class]):not(:last-child) {
margin-left: calc(var(--padding) * var(--space-factor) * -1) !important;
margin-right: calc(var(--padding) * var(--space-factor) * -1) !important;
}
.excalidraw .dropdown-menu:before {
content: unset !important;
}

View File

@@ -0,0 +1,214 @@
{
"about": {
"title": "Sobre Trilium Notes",
"close": "Tanca",
"homepage": "Pàgina principal:"
},
"add_link": {
"note": "Nota",
"close": "Tanca"
},
"branch_prefix": {
"close": "Tanca",
"prefix": "Prefix: ",
"save": "Desa"
},
"bulk_actions": {
"close": "Tanca",
"labels": "Etiquetes",
"relations": "Relacions",
"notes": "Notes",
"other": "Altres"
},
"clone_to": {
"close": "Tanca"
},
"confirm": {
"confirmation": "Confirmació",
"close": "Tanca",
"cancel": "Cancel·la",
"ok": "OK"
},
"delete_notes": {
"close": "Tanca",
"cancel": "Cancel·la",
"ok": "OK"
},
"export": {
"close": "Tanca",
"export": "Exporta"
},
"help": {
"close": "Tanca",
"troubleshooting": "Solució de problemes",
"other": "Altres"
},
"import": {
"close": "Tanca",
"options": "Opcions",
"import": "Importa"
},
"include_note": {
"close": "Tanca",
"label_note": "Nota"
},
"info": {
"closeButton": "Tanca",
"okButton": "OK"
},
"jump_to_note": {
"close": "Tanca"
},
"markdown_import": {
"close": "Tanca"
},
"move_to": {
"close": "Tanca"
},
"note_type_chooser": {
"close": "Tanca",
"templates": "Plantilles:"
},
"password_not_set": {
"close": "Tanca"
},
"prompt": {
"title": "Sol·licitud",
"close": "Tanca",
"defaultTitle": "Sol·licitud"
},
"protected_session_password": {
"close_label": "Tanca"
},
"recent_changes": {
"close": "Tanca",
"undelete_link": "recuperar"
},
"revisions": {
"close": "Tanca",
"restore_button": "Restaura",
"delete_button": "Suprimeix",
"download_button": "Descarrega",
"mime": "MIME: ",
"preview": "Vista prèvia:"
},
"sort_child_notes": {
"close": "Tanca",
"title": "títol",
"ascending": "ascendent",
"descending": "descendent",
"folders": "Carpetes"
},
"upload_attachments": {
"close": "Tanca",
"options": "Opcions",
"upload": "Puja"
},
"attribute_detail": {
"name": "Nom",
"value": "Valor",
"promoted": "Destacat",
"promoted_alias": "Àlies",
"multiplicity": "Multiplicitat",
"label_type": "Tipus",
"text": "Text",
"number": "Número",
"boolean": "Booleà",
"date": "Data",
"time": "Hora",
"url": "URL",
"precision": "Precisió",
"digits": "dígits",
"inheritable": "Heretable",
"delete": "Suprimeix",
"color_type": "Color"
},
"rename_label": {
"to": "Per"
},
"move_note": {
"to": "a"
},
"add_relation": {
"to": "a"
},
"rename_relation": {
"to": "Per"
},
"update_relation_target": {
"to": "a"
},
"attachments_actions": {
"download": "Descarrega"
},
"calendar": {
"mon": "Dl",
"tue": "Dt",
"wed": "dc",
"thu": "Dj",
"fri": "Dv",
"sat": "Ds",
"sun": "Dg",
"january": "Gener",
"febuary": "Febrer",
"march": "Març",
"april": "Abril",
"may": "Maig",
"june": "Juny",
"july": "Juliol",
"august": "Agost",
"september": "Setembre",
"october": "Octubre",
"november": "Novembre",
"december": "Desembre"
},
"global_menu": {
"menu": "Menú",
"options": "Opcions",
"zoom": "Zoom",
"advanced": "Avançat",
"logout": "Tanca la sessió"
},
"zpetne_odkazy": {
"relation": "relació"
},
"note_icon": {
"category": "Categoria:",
"search": "Cerca:"
},
"basic_properties": {
"editable": "Editable",
"language": "Llengua"
},
"book_properties": {
"grid": "Graella",
"list": "Llista",
"collapse": "Replega",
"expand": "Desplega",
"calendar": "Calendari",
"table": "Taula",
"board": "Tauler"
},
"edited_notes": {
"deleted": "(suprimit)"
},
"file_properties": {
"download": "Descarrega",
"open": "Obre",
"title": "Fitxer"
},
"image_properties": {
"download": "Descarrega",
"open": "Obre",
"title": "Imatge"
},
"note_info_widget": {
"created": "Creat",
"modified": "Modificat",
"type": "Tipus",
"calculate": "calcula"
},
"note_paths": {
"archived": "Arxivat"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
{
"about": {
"title": "Πληροφορίες για το Trilium Notes",
"close": "Κλείσιμο",
"homepage": "Αρχική Σελίδα:",
"app_version": "Έκδοση εφαρμογής:",
"db_version": "Έκδοση βάσης δεδομένων:",
"sync_version": "Έκδοση πρωτοκόλου συγχρονισμού:",
"build_date": "Ημερομηνία χτισίματος εφαρμογής:",
"build_revision": "Αριθμός αναθεώρησης χτισίματος:",
"data_directory": "Φάκελος δεδομένων:"
},
"toast": {
"critical-error": {
"title": "Κρίσιμο σφάλμα",
"message": "Συνέβη κάποιο κρίσιμο σφάλμα, το οποίο δεν επιτρέπει στην εφαρμογή χρήστη να ξεκινήσει:\n\n{{message}}\n\nΤο πιθανότερο είναι να προκλήθηκε από κάποιο script που απέτυχε απρόοπτα. Δοκιμάστε να ξεκινήσετε την εφαρμογή σε ασφαλή λειτουργία για να λύσετε το πρόβλημα."
}
}
}

View File

@@ -1,7 +1,6 @@
{
"about": {
"title": "About Trilium Notes",
"close": "Close",
"homepage": "Homepage:",
"app_version": "App version:",
"db_version": "DB version:",
@@ -28,25 +27,22 @@
"add_link": {
"add_link": "Add link",
"help_on_links": "Help on links",
"close": "Close",
"note": "Note",
"search_note": "search for note by its name",
"link_title_mirrors": "link title mirrors the note's current title",
"link_title_arbitrary": "link title can be changed arbitrarily",
"link_title": "Link title",
"button_add_link": "Add link <kbd>enter</kbd>"
"button_add_link": "Add link"
},
"branch_prefix": {
"edit_branch_prefix": "Edit branch prefix",
"help_on_tree_prefix": "Help on Tree prefix",
"close": "Close",
"prefix": "Prefix: ",
"save": "Save",
"branch_prefix_saved": "Branch prefix has been saved."
},
"bulk_actions": {
"bulk_actions": "Bulk actions",
"close": "Close",
"affected_notes": "Affected notes",
"include_descendants": "Include descendants of the selected notes",
"available_actions": "Available actions",
@@ -61,20 +57,18 @@
},
"clone_to": {
"clone_notes_to": "Clone notes to...",
"close": "Close",
"help_on_links": "Help on links",
"notes_to_clone": "Notes to clone",
"target_parent_note": "Target parent note",
"search_for_note_by_its_name": "search for note by its name",
"cloned_note_prefix_title": "Cloned note will be shown in note tree with given prefix",
"prefix_optional": "Prefix (optional)",
"clone_to_selected_note": "Clone to selected note <kbd>enter</kbd>",
"clone_to_selected_note": "Clone to selected note",
"no_path_to_clone_to": "No path to clone to.",
"note_cloned": "Note \"{{clonedTitle}}\" has been cloned into \"{{targetTitle}}\""
},
"confirm": {
"confirmation": "Confirmation",
"close": "Close",
"cancel": "Cancel",
"ok": "OK",
"are_you_sure_remove_note": "Are you sure you want to remove the note \"{{title}}\" from relation map? ",
@@ -87,9 +81,9 @@
"delete_all_clones_description": "Delete also all clones (can be undone in recent changes)",
"erase_notes_description": "Normal (soft) deletion only marks the notes as deleted and they can be undeleted (in recent changes dialog) within a period of time. Checking this option will erase the notes immediately and it won't be possible to undelete the notes.",
"erase_notes_warning": "Erase notes permanently (can't be undone), including all clones. This will force application reload.",
"notes_to_be_deleted": "Following notes will be deleted ({{- noteCount}})",
"notes_to_be_deleted": "Following notes will be deleted ({{notesCount}})",
"no_note_to_delete": "No note will be deleted (only clones).",
"broken_relations_to_be_deleted": "Following relations will be broken and deleted ({{- relationCount}})",
"broken_relations_to_be_deleted": "Following relations will be broken and deleted ({{ relationCount}})",
"cancel": "Cancel",
"ok": "OK",
"deleted_relation_text": "Note {{- note}} (to be deleted) is referenced by relation {{- relation}} originating from {{- source}}."
@@ -113,21 +107,20 @@
"format_pdf": "PDF - for printing or sharing purposes."
},
"help": {
"fullDocumentation": "Help (full documentation is available <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
"close": "Close",
"title": "Cheatsheet",
"noteNavigation": "Note navigation",
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - go up/down in the list of notes",
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - collapse/expand node",
"goUpDown": "go up/down in the list of notes",
"collapseExpand": "collapse/expand node",
"notSet": "not set",
"goBackForwards": "go back / forwards in the history",
"showJumpToNoteDialog": "show <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Jump to\" dialog</a>",
"scrollToActiveNote": "scroll to active note",
"jumpToParentNote": "<kbd>Backspace</kbd> - jump to parent note",
"jumpToParentNote": "jump to parent note",
"collapseWholeTree": "collapse whole note tree",
"collapseSubTree": "collapse sub-tree",
"tabShortcuts": "Tab shortcuts",
"newTabNoteLink": "<kbd>Ctrl+click</kbd> - (or <kbd>middle mouse click</kbd>) on note link opens note in a new tab",
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+click</kbd> - (or <kbd>Shift+middle mouse click</kbd>) on note link opens and activates the note in a new tab",
"newTabNoteLink": "on note link opens note in a new tab",
"newTabWithActivationNoteLink": "on note link opens and activates the note in a new tab",
"onlyInDesktop": "Only in desktop (Electron build)",
"openEmptyTab": "open empty tab",
"closeActiveTab": "close active tab",
@@ -142,14 +135,14 @@
"moveNoteUpHierarchy": "move note up in the hierarchy",
"multiSelectNote": "multi-select note above/below",
"selectAllNotes": "select all notes in the current level",
"selectNote": "<kbd>Shift+click</kbd> - select note",
"selectNote": "select note",
"copyNotes": "copy active note (or current selection) into clipboard (used for <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">cloning</a>)",
"cutNotes": "cut current note (or current selection) into clipboard (used for moving notes)",
"pasteNotes": "paste note(s) as sub-note into active note (which is either move or clone depending on whether it was copied or cut into clipboard)",
"deleteNotes": "delete note / sub-tree",
"editingNotes": "Editing notes",
"editNoteTitle": "in tree pane will switch from tree pane into note title. Enter from note title will switch focus to text editor. <kbd>Ctrl+.</kbd> will switch back from editor to tree pane.",
"createEditLink": "<kbd>Ctrl+K</kbd> - create / edit external link",
"createEditLink": "create / edit external link",
"createInternalLink": "create internal link",
"followLink": "follow link under cursor",
"insertDateTime": "insert current date and time at caret position",
@@ -169,7 +162,6 @@
},
"import": {
"importIntoNote": "Import into note",
"close": "Close",
"chooseImportFile": "Choose import file",
"importDescription": "Content of the selected file(s) will be imported as child note(s) into",
"options": "Options",
@@ -196,14 +188,13 @@
},
"include_note": {
"dialog_title": "Include note",
"close": "Close",
"label_note": "Note",
"placeholder_search": "search for note by its name",
"box_size_prompt": "Box size of the included note:",
"box_size_small": "small (~ 10 lines)",
"box_size_medium": "medium (~ 30 lines)",
"box_size_full": "full (box shows complete text)",
"button_include": "Include note <kbd>enter</kbd>"
"button_include": "Include note"
},
"info": {
"modalTitle": "Info message",
@@ -211,24 +202,21 @@
"okButton": "OK"
},
"jump_to_note": {
"search_placeholder": "search for note by its name",
"close": "Close",
"search_button": "Search in full text <kbd>Ctrl+Enter</kbd>"
"search_placeholder": "Search for note by its name or type > for commands...",
"search_button": "Search in full text"
},
"markdown_import": {
"dialog_title": "Markdown import",
"close": "Close",
"modal_body_text": "Because of browser sandbox it's not possible to directly read clipboard from JavaScript. Please paste the Markdown to import to textarea below and click on Import button",
"import_button": "Import Ctrl+Enter",
"import_button": "Import",
"import_success": "Markdown content has been imported into the document."
},
"move_to": {
"dialog_title": "Move notes to ...",
"close": "Close",
"notes_to_move": "Notes to move",
"target_parent_note": "Target parent note",
"search_placeholder": "search for note by its name",
"move_button": "Move to selected note <kbd>enter</kbd>",
"move_button": "Move to selected note",
"error_no_path": "No path to move to.",
"move_success_message": "Selected notes have been moved into "
},
@@ -236,20 +224,19 @@
"change_path_prompt": "Change where to create the new note:",
"search_placeholder": "search path by name (default if empty)",
"modal_title": "Choose note type",
"close": "Close",
"modal_body": "Choose note type / template of the new note:",
"templates": "Templates:"
"templates": "Templates",
"builtin_templates": "Built-in Templates"
},
"password_not_set": {
"title": "Password is not set",
"close": "Close",
"body1": "Protected notes are encrypted using a user password, but password has not been set yet.",
"body2": "To be able to protect notes, click <a class=\"open-password-options-button\" href=\"javascript:\">here</a> to open the Options dialog and set your password."
"body2": "To be able to protect notes, click the button below to open the Options dialog and set your password.",
"go_to_password_options": "Go to Password options"
},
"prompt": {
"title": "Prompt",
"close": "Close",
"ok": "OK <kbd>enter</kbd>",
"ok": "OK",
"defaultTitle": "Prompt"
},
"protected_session_password": {
@@ -257,12 +244,11 @@
"help_title": "Help on Protected notes",
"close_label": "Close",
"form_label": "To proceed with requested action you need to start protected session by entering password:",
"start_button": "Start protected session <kbd>enter</kbd>"
"start_button": "Start protected session"
},
"recent_changes": {
"title": "Recent changes",
"erase_notes_button": "Erase deleted notes now",
"close": "Close",
"deleted_notes_message": "Deleted notes have been erased.",
"no_changes_message": "No changes yet...",
"undelete_link": "undelete",
@@ -273,7 +259,6 @@
"delete_all_revisions": "Delete all revisions of this note",
"delete_all_button": "Delete all revisions",
"help_title": "Help on Note Revisions",
"close": "Close",
"revision_last_edited": "This revision was last edited on {{date}}",
"confirm_delete_all": "Do you want to delete all revisions of this note?",
"no_revisions": "No revisions for this note yet...",
@@ -295,7 +280,6 @@
},
"sort_child_notes": {
"sort_children_by": "Sort children by...",
"close": "Close",
"sorting_criteria": "Sorting criteria",
"title": "title",
"date_created": "date created",
@@ -309,13 +293,12 @@
"sort_with_respect_to_different_character_sorting": "sort with respect to different character sorting and collation rules in different languages or regions.",
"natural_sort_language": "Natural sort language",
"the_language_code_for_natural_sort": "The language code for natural sort, e.g. \"zh-CN\" for Chinese.",
"sort": "Sort <kbd>enter</kbd>"
"sort": "Sort"
},
"upload_attachments": {
"upload_attachments_to_note": "Upload attachments to note",
"close": "Close",
"choose_files": "Choose files",
"files_will_be_uploaded": "Files will be uploaded as attachments into",
"files_will_be_uploaded": "Files will be uploaded as attachments into {{noteTitle}}",
"options": "Options",
"shrink_images": "Shrink images",
"upload": "Upload",
@@ -443,7 +426,8 @@
"other_notes_with_name": "Other notes with {{attributeType}} name \"{{attributeName}}\"",
"and_more": "... and {{count}} more.",
"print_landscape": "When exporting to PDF, changes the orientation of the page to landscape instead of portrait.",
"print_page_size": "When exporting to PDF, changes the size of the page. Supported values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>."
"print_page_size": "When exporting to PDF, changes the size of the page. Supported values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
"color_type": "Color"
},
"attribute_editor": {
"help_text_body1": "To add label, just type e.g. <code>#rock</code> or if you want to add also value then e.g. <code>#year = 2020</code>",
@@ -762,7 +746,8 @@
"invalid_view_type": "Invalid view type '{{type}}'",
"calendar": "Calendar",
"table": "Table",
"geo-map": "Geo Map"
"geo-map": "Geo Map",
"board": "Board"
},
"edited_notes": {
"no_edited_notes_found": "No edited notes on this day yet...",
@@ -839,7 +824,8 @@
"unknown_label_type": "Unknown label type '{{type}}'",
"unknown_attribute_type": "Unknown attribute type '{{type}}'",
"add_new_attribute": "Add new attribute",
"remove_this_attribute": "Remove this attribute"
"remove_this_attribute": "Remove this attribute",
"remove_color": "Remove the color label"
},
"script_executor": {
"query": "Query",
@@ -1615,7 +1601,7 @@
"relation-map": "Relation Map",
"note-map": "Note Map",
"render-note": "Render Note",
"book": "Book",
"book": "Collection",
"mermaid-diagram": "Mermaid Diagram",
"canvas": "Canvas",
"web-view": "Web View",
@@ -1964,9 +1950,47 @@
},
"book_properties_config": {
"hide-weekends": "Hide weekends",
"display-week-numbers": "Display week numbers"
"display-week-numbers": "Display week numbers",
"map-style": "Map style:",
"max-nesting-depth": "Max nesting depth:",
"raster": "Raster",
"vector_light": "Vector (Light)",
"vector_dark": "Vector (Dark)",
"show-scale": "Show scale"
},
"table_context_menu": {
"delete_row": "Delete row"
},
"board_view": {
"delete-note": "Delete Note",
"move-to": "Move to",
"insert-above": "Insert above",
"insert-below": "Insert below",
"delete-column": "Delete column",
"delete-column-confirmation": "Are you sure you want to delete this column? The corresponding attribute will be deleted in the notes under this column as well.",
"new-item": "New item",
"add-column": "Add Column"
},
"command_palette": {
"tree-action-name": "Tree: {{name}}",
"export_note_title": "Export Note",
"export_note_description": "Export current note",
"show_attachments_title": "Show Attachments",
"show_attachments_description": "View note attachments",
"search_notes_title": "Search Notes",
"search_notes_description": "Open advanced search",
"search_subtree_title": "Search in Subtree",
"search_subtree_description": "Search within current subtree",
"search_history_title": "Show Search History",
"search_history_description": "View previous searches",
"configure_launch_bar_title": "Configure Launch Bar",
"configure_launch_bar_description": "Open the launch bar configuration, to add or remove items."
},
"content_renderer": {
"open_externally": "Open externally"
},
"modal": {
"close": "Close",
"help_title": "Display more information about this screen"
}
}

View File

@@ -34,7 +34,7 @@
"link_title_mirrors": "el título del enlace replica el título actual de la nota",
"link_title_arbitrary": "el título del enlace se puede cambiar arbitrariamente",
"link_title": "Título del enlace",
"button_add_link": "Agregar enlace <kbd>Enter</kbd>"
"button_add_link": "Agregar enlace"
},
"branch_prefix": {
"edit_branch_prefix": "Editar prefijo de rama",
@@ -68,7 +68,7 @@
"search_for_note_by_its_name": "buscar nota por su nombre",
"cloned_note_prefix_title": "La nota clonada se mostrará en el árbol de notas con el prefijo dado",
"prefix_optional": "Prefijo (opcional)",
"clone_to_selected_note": "Clonar a nota seleccionada <kbd>enter</kbd>",
"clone_to_selected_note": "Clonar a nota seleccionada",
"no_path_to_clone_to": "No hay ruta para clonar.",
"note_cloned": "La nota \"{{clonedTitle}}\" a sido clonada en \"{{targetTitle}}\""
},
@@ -87,9 +87,9 @@
"delete_all_clones_description": "Eliminar también todos los clones (se puede deshacer en cambios recientes)",
"erase_notes_description": "La eliminación normal (suave) solo marca las notas como eliminadas y se pueden recuperar (en el cuadro de diálogo de cambios recientes) dentro de un periodo de tiempo. Al marcar esta opción se borrarán las notas inmediatamente y no será posible recuperarlas.",
"erase_notes_warning": "Eliminar notas permanentemente (no se puede deshacer), incluidos todos los clones. Esto forzará la recarga de la aplicación.",
"notes_to_be_deleted": "Las siguientes notas serán eliminadas ({{- noteCount}})",
"notes_to_be_deleted": "Las siguientes notas serán eliminadas ({{notesCount}})",
"no_note_to_delete": "No se eliminará ninguna nota (solo clones).",
"broken_relations_to_be_deleted": "Las siguientes relaciones se romperán y serán eliminadas ({{- relationCount}})",
"broken_relations_to_be_deleted": "Las siguientes relaciones se romperán y serán eliminadas ({{ relationCount}})",
"cancel": "Cancelar",
"ok": "Aceptar",
"deleted_relation_text": "Nota {{- note}} (para ser eliminada) está referenciado por la relación {{- relation}} que se origina en {{- source}}."
@@ -113,21 +113,20 @@
"format_pdf": "PDF - para propósitos de impresión o compartición."
},
"help": {
"fullDocumentation": "Ayuda (la documentación completa está disponible <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
"close": "Cerrar",
"noteNavigation": "Navegación de notas",
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - subir/bajar en la lista de notas",
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - colapsar/expandir nodo",
"goUpDown": "subir/bajar en la lista de notas",
"collapseExpand": "colapsar/expandir nodo",
"notSet": "no establecido",
"goBackForwards": "retroceder / avanzar en la historia",
"showJumpToNoteDialog": "mostrar <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Saltar a\" diálogo</a>",
"scrollToActiveNote": "desplazarse hasta la nota activa",
"jumpToParentNote": "<kbd>Backspace</kbd> - saltar a la nota padre",
"jumpToParentNote": "saltar a la nota padre",
"collapseWholeTree": "colapsar todo el árbol de notas",
"collapseSubTree": "colapsar subárbol",
"tabShortcuts": "Atajos de pestañas",
"newTabNoteLink": "<kbd>CTRL+clic</kbd> - (o clic central del mouse) en el enlace de la nota abre la nota en una nueva pestaña",
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+clic</kbd> - (o <kbd>Shift+clic de rueda de ratón</kbd>) en el enlace de la nota abre y activa la nota en una nueva pestaña",
"newTabNoteLink": "en el enlace de la nota abre la nota en una nueva pestaña",
"newTabWithActivationNoteLink": "en el enlace de la nota abre y activa la nota en una nueva pestaña",
"onlyInDesktop": "Solo en escritorio (compilación con Electron)",
"openEmptyTab": "abrir pestaña vacía",
"closeActiveTab": "cerrar pestaña activa",
@@ -142,14 +141,14 @@
"moveNoteUpHierarchy": "mover nota hacia arriba en la jerarquía",
"multiSelectNote": "selección múltiple de nota hacia arriba/abajo",
"selectAllNotes": "seleccionar todas las notas en el nivel actual",
"selectNote": "<kbd>Shift+click</kbd> - seleccionar nota",
"selectNote": "seleccionar nota",
"copyNotes": "copiar nota activa (o selección actual) al portapapeles (usado para <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonar</a>)",
"cutNotes": "cortar la nota actual (o la selección actual) en el portapapeles (usado para mover notas)",
"pasteNotes": "pegar notas como subnotas en la nota activa (que se puede mover o clonar dependiendo de si se copió o cortó en el portapapeles)",
"deleteNotes": "eliminar nota/subárbol",
"editingNotes": "Editando notas",
"editNoteTitle": "en el panel de árbol cambiará del panel de árbol al título de la nota. Ingresar desde el título de la nota cambiará el foco al editor de texto. <kbd>Ctrl+.</kbd> cambiará de nuevo del editor al panel de árbol.",
"createEditLink": "<kbd>Ctrl+K</kbd> - crear/editar enlace externo",
"createEditLink": "crear/editar enlace externo",
"createInternalLink": "crear enlace interno",
"followLink": "siga el enlace debajo del cursor",
"insertDateTime": "insertar la fecha y hora actuales en la posición del cursor",
@@ -203,7 +202,7 @@
"box_size_small": "pequeño (~ 10 líneas)",
"box_size_medium": "medio (~ 30 líneas)",
"box_size_full": "completo (el cuadro muestra el texto completo)",
"button_include": "Incluir nota <kbd>Enter</kbd>"
"button_include": "Incluir nota"
},
"info": {
"modalTitle": "Mensaje informativo",
@@ -211,15 +210,15 @@
"okButton": "Aceptar"
},
"jump_to_note": {
"search_placeholder": "buscar nota por su nombre",
"close": "Cerrar",
"search_button": "Buscar en texto completo <kbd>Ctrl+Enter</kbd>"
"search_button": "Buscar en texto completo",
"search_placeholder": "Busque nota por su nombre o escriba > para comandos..."
},
"markdown_import": {
"dialog_title": "Importación de Markdown",
"close": "Cerrar",
"modal_body_text": "Debido al entorno limitado del navegador, no es posible leer directamente el portapapeles desde JavaScript. Por favor, pegue el código Markdown para importar en el área de texto a continuación y haga clic en el botón Importar",
"import_button": "Importar Ctrl+Enter",
"import_button": "Importar",
"import_success": "El contenido de Markdown se ha importado al documento."
},
"move_to": {
@@ -228,7 +227,7 @@
"notes_to_move": "Notas a mover",
"target_parent_note": "Nota padre de destino",
"search_placeholder": "buscar nota por su nombre",
"move_button": "Mover a la nota seleccionada <kbd>enter</kbd>",
"move_button": "Mover a la nota seleccionada",
"error_no_path": "No hay ruta a donde mover.",
"move_success_message": "Las notas seleccionadas se han movido a "
},
@@ -238,18 +237,17 @@
"modal_title": "Elija el tipo de nota",
"close": "Cerrar",
"modal_body": "Elija el tipo de nota/plantilla de la nueva nota:",
"templates": "Plantillas:"
"templates": "Plantillas"
},
"password_not_set": {
"title": "La contraseña no está establecida",
"close": "Cerrar",
"body1": "Las notas protegidas se cifran mediante una contraseña de usuario, pero la contraseña aún no se ha establecido.",
"body2": "Para poder proteger notas, dé clic <a class=\"open-password-options-button\" href=\"javascript:\">aquí</a> para abrir el diálogo de Opciones y establecer tu contraseña."
"body1": "Las notas protegidas se cifran mediante una contraseña de usuario, pero la contraseña aún no se ha establecido."
},
"prompt": {
"title": "Aviso",
"close": "Cerrar",
"ok": "Aceptar <kbd>enter</kbd>",
"ok": "Aceptar",
"defaultTitle": "Aviso"
},
"protected_session_password": {
@@ -257,7 +255,7 @@
"help_title": "Ayuda sobre notas protegidas",
"close_label": "Cerrar",
"form_label": "Para continuar con la acción solicitada, debe iniciar en la sesión protegida ingresando la contraseña:",
"start_button": "Iniciar sesión protegida <kbd>entrar</kbd>"
"start_button": "Iniciar sesión protegida"
},
"recent_changes": {
"title": "Cambios recientes",
@@ -309,13 +307,13 @@
"sort_with_respect_to_different_character_sorting": "ordenar con respecto a diferentes reglas de ordenamiento y clasificación de caracteres en diferentes idiomas o regiones.",
"natural_sort_language": "Idioma de clasificación natural",
"the_language_code_for_natural_sort": "El código del idioma para el ordenamiento natural, ej. \"zh-CN\" para Chino.",
"sort": "Ordenar <kbd>Enter</kbd>"
"sort": "Ordenar"
},
"upload_attachments": {
"upload_attachments_to_note": "Cargar archivos adjuntos a nota",
"close": "Cerrar",
"choose_files": "Elija los archivos",
"files_will_be_uploaded": "Los archivos se cargarán como archivos adjuntos en",
"files_will_be_uploaded": "Los archivos se cargarán como archivos adjuntos en {{noteTitle}}",
"options": "Opciones",
"shrink_images": "Reducir imágenes",
"upload": "Subir",
@@ -443,7 +441,8 @@
"other_notes_with_name": "Otras notas con nombre de {{attributeType}} \"{{attributeName}}\"",
"and_more": "... y {{count}} más.",
"print_landscape": "Al exportar a PDF, cambia la orientación de la página a paisaje en lugar de retrato.",
"print_page_size": "Al exportar a PDF, cambia el tamaño de la página. Valores soportados: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>."
"print_page_size": "Al exportar a PDF, cambia el tamaño de la página. Valores soportados: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
"color_type": "Color"
},
"attribute_editor": {
"help_text_body1": "Para agregar una etiqueta, simplemente escriba, por ejemplo. <code>#rock</code> o si desea agregar también valor, p.e. <code>#año = 2020</code>",
@@ -758,9 +757,12 @@
"expand_all_children": "Ampliar todas las subnotas",
"collapse": "Colapsar",
"expand": "Expandir",
"book_properties": "",
"invalid_view_type": "Tipo de vista inválida '{{type}}'",
"calendar": "Calendario"
"calendar": "Calendario",
"book_properties": "Propiedades de colección",
"table": "Tabla",
"geo-map": "Mapa Geo",
"board": "Tablero"
},
"edited_notes": {
"no_edited_notes_found": "Aún no hay notas editadas en este día...",
@@ -837,7 +839,8 @@
"unknown_label_type": "Tipo de etiqueta desconocido '{{type}}'",
"unknown_attribute_type": "Tipo de atributo desconocido '{{type}}'",
"add_new_attribute": "Agregar nuevo atributo",
"remove_this_attribute": "Eliminar este atributo"
"remove_this_attribute": "Eliminar este atributo",
"remove_color": "Eliminar la etiqueta del color"
},
"script_executor": {
"query": "Consulta",
@@ -1598,7 +1601,8 @@
"import-into-note": "Importar a nota",
"apply-bulk-actions": "Aplicar acciones en lote",
"converted-to-attachments": "{{count}} notas han sido convertidas en archivos adjuntos.",
"convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres?"
"convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres?",
"open-in-popup": "Edición rápida"
},
"shared_info": {
"shared_publicly": "Esta nota está compartida públicamente en",
@@ -1612,7 +1616,6 @@
"relation-map": "Mapa de Relaciones",
"note-map": "Mapa de Notas",
"render-note": "Nota de Renderizado",
"book": "Libro",
"mermaid-diagram": "Diagrama Mermaid",
"canvas": "Lienzo",
"web-view": "Vista Web",
@@ -1626,7 +1629,10 @@
"geo-map": "Mapa Geo",
"beta-feature": "Beta",
"ai-chat": "Chat de IA",
"task-list": "Lista de tareas"
"task-list": "Lista de tareas",
"book": "Colección",
"new-feature": "Nuevo",
"collections": "Colecciones"
},
"protect_note": {
"toggle-on": "Proteger la nota",
@@ -1828,7 +1834,8 @@
"link_context_menu": {
"open_note_in_new_tab": "Abrir nota en una pestaña nueva",
"open_note_in_new_split": "Abrir nota en una nueva división",
"open_note_in_new_window": "Abrir nota en una nueva ventana"
"open_note_in_new_window": "Abrir nota en una nueva ventana",
"open_note_in_popup": "Edición rápida"
},
"electron_integration": {
"desktop-application": "Aplicación de escritorio",
@@ -1848,7 +1855,8 @@
"full-text-search": "Búsqueda de texto completo"
},
"note_tooltip": {
"note-has-been-deleted": "La nota ha sido eliminada."
"note-has-been-deleted": "La nota ha sido eliminada.",
"quick-edit": "Edición rápida"
},
"geo-map": {
"create-child-note-title": "Crear una nueva subnota y agregarla al mapa",
@@ -1857,7 +1865,8 @@
},
"geo-map-context": {
"open-location": "Abrir ubicación",
"remove-from-map": "Eliminar del mapa"
"remove-from-map": "Eliminar del mapa",
"add-note": "Agregar un marcador en esta ubicación"
},
"help-button": {
"title": "Abrir la página de ayuda relevante"
@@ -1928,5 +1937,74 @@
"download_link": "Descargar versión nativa",
"continue_anyway": "Continuar de todas maneras",
"dont_show_again": "No mostrar esta advertencia otra vez"
},
"book_properties_config": {
"hide-weekends": "Ocultar fines de semana",
"show-scale": "Mostrar escala",
"display-week-numbers": "Mostrar números de semana",
"map-style": "Estilo de mapa:",
"max-nesting-depth": "Máxima profundidad de anidamiento:",
"vector_light": "Vector (claro)",
"vector_dark": "Vector (oscuro)",
"raster": "Trama"
},
"table_context_menu": {
"delete_row": "Eliminar fila"
},
"board_view": {
"delete-note": "Eliminar nota",
"move-to": "Mover a",
"insert-above": "Insertar arriba",
"insert-below": "Insertar abajo",
"delete-column": "Eliminar columna",
"delete-column-confirmation": "¿Seguro que desea eliminar esta columna? El atributo correspondiente también se eliminará de las notas de esta columna.",
"add-column": "Añadir columna",
"new-item": "Nuevo elemento"
},
"content_renderer": {
"open_externally": "Abrir externamente"
},
"table_view": {
"new-column": "Nueva columna",
"new-row": "Nueva fila",
"show-hide-columns": "Mostrar/ocultar columnas",
"row-insert-above": "Insertar fila arriba",
"row-insert-below": "Insertar fila debajo",
"sort-column-by": "Ordenar por \"{{title}}\"",
"sort-column-ascending": "Ascendiente",
"sort-column-descending": "Descendiente",
"sort-column-clear": "Quitar ordenación",
"hide-column": "Ocultar columna \"{{title}}\"",
"add-column-to-the-left": "Añadir columna a la izquierda",
"add-column-to-the-right": "Añadir columna a la derecha",
"edit-column": "Editar columna",
"delete_column_confirmation": "¿Seguro que desea eliminar esta columna? Se eliminará el atributo asociado de todas las notas.",
"new-column-label": "Etiqueta",
"new-column-relation": "Relación",
"delete-column": "Eliminar columna",
"row-insert-child": "Insertar subnota"
},
"editorfeatures": {
"note_completion_enabled": "Activar autocompletado de notas",
"emoji_completion_enabled": "Activar autocompletado de emojis",
"title": "Funciones"
},
"command_palette": {
"tree-action-name": "Árbol:{{name}}",
"export_note_title": "Exportar nota",
"export_note_description": "Exportar nota actual",
"show_attachments_title": "Mostrar adjuntos",
"show_attachments_description": "Ver adjuntos de la nota",
"search_notes_title": "Buscar notas",
"search_notes_description": "Abrir búsqueda avanzada",
"search_subtree_title": "Buscar en subárbol",
"search_subtree_description": "Buscar dentro del subárbol actual",
"search_history_title": "Mostrar historial de búsqueda",
"search_history_description": "Ver búsquedas previas",
"configure_launch_bar_title": "Configurar barra de inicio",
"configure_launch_bar_description": "Abrir la configuración de la barra de inicio, para agregar o quitar elementos."
},
"modal": {
"close": "Cerrar"
}
}

View File

@@ -34,7 +34,7 @@
"link_title_mirrors": "le titre du lien reflète le titre actuel de la note",
"link_title_arbitrary": "le titre du lien peut être modifié arbitrairement",
"link_title": "Titre du lien",
"button_add_link": "Ajouter un lien <kbd>Entrée</kbd>"
"button_add_link": "Ajouter un lien"
},
"branch_prefix": {
"edit_branch_prefix": "Modifier le préfixe de branche",
@@ -68,7 +68,7 @@
"search_for_note_by_its_name": "rechercher une note par son nom",
"cloned_note_prefix_title": "La note clonée sera affichée dans l'arbre des notes avec le préfixe donné",
"prefix_optional": "Préfixe (facultatif)",
"clone_to_selected_note": "Cloner vers la note sélectionnée <kbd>entrer</kbd>",
"clone_to_selected_note": "Cloner vers la note sélectionnée",
"no_path_to_clone_to": "Aucun chemin vers lequel cloner.",
"note_cloned": "La note \"{{clonedTitle}}\" a été clonée dans \"{{targetTitle}}\""
},
@@ -87,9 +87,9 @@
"delete_all_clones_description": "Supprimer aussi les clones (peut être annulé dans des modifications récentes)",
"erase_notes_description": "La suppression normale (douce) marque uniquement les notes comme supprimées et elles peuvent être restaurées (dans la boîte de dialogue des Modifications récentes) dans un délai donné. Cocher cette option effacera les notes immédiatement et il ne sera pas possible de les restaurer.",
"erase_notes_warning": "Efface les notes de manière permanente (ne peut pas être annulée), y compris les clones. L'application va être rechargée.",
"notes_to_be_deleted": "Les notes suivantes seront supprimées ({{- noteCount}})",
"notes_to_be_deleted": "Les notes suivantes seront supprimées ({{notesCount}})",
"no_note_to_delete": "Aucune note ne sera supprimée (uniquement les clones).",
"broken_relations_to_be_deleted": "Les relations suivantes seront rompues et supprimées ({{- relationCount}})",
"broken_relations_to_be_deleted": "Les relations suivantes seront rompues et supprimées ({{ relationCount}})",
"cancel": "Annuler",
"ok": "OK",
"deleted_relation_text": "Note {{- note}} (à supprimer) est référencée dans la relation {{- relation}} provenant de {{- source}}."
@@ -113,20 +113,19 @@
"format_pdf": "PDF - pour l'impression ou le partage de documents."
},
"help": {
"fullDocumentation": "Aide (la documentation complète est disponible <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">en ligne</a>)",
"close": "Fermer",
"noteNavigation": "Navigation dans les notes",
"goUpDown": "<kbd>HAUT</kbd>, <kbd>BAS</kbd> - aller vers le haut/bas dans la liste des notes",
"collapseExpand": "<kbd>GAUCHE</kbd>, <kbd>DROITE</kbd> - réduire/développer le nœud",
"goUpDown": "aller vers le haut/bas dans la liste des notes",
"collapseExpand": "réduire/développer le nœud",
"notSet": "non défini",
"goBackForwards": "reculer/avancer dans l'historique",
"showJumpToNoteDialog": "afficher la <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">boîte de dialogue \"Aller à la note\"</a>",
"scrollToActiveNote": "faire défiler jusqu'à la note active",
"jumpToParentNote": "<kbd>Retour arrière</kbd> - aller à la note parent",
"jumpToParentNote": "aller à la note parent",
"collapseWholeTree": "réduire tout l'arbre des notes",
"collapseSubTree": "réduire le sous-arbre",
"tabShortcuts": "Raccourcis des onglets",
"newTabNoteLink": "<kbd>CTRL+clic</kbd> - (ou clic central de la souris) sur le lien de la note ouvre la note dans un nouvel onglet",
"newTabNoteLink": "sur le lien de la note ouvre la note dans un nouvel onglet",
"onlyInDesktop": "Uniquement sur ordinateur (version Electron)",
"openEmptyTab": "ouvrir un onglet vide",
"closeActiveTab": "fermer l'onglet actif",
@@ -141,14 +140,14 @@
"moveNoteUpHierarchy": "déplacer la note vers le haut dans la hiérarchie",
"multiSelectNote": "sélectionner plusieurs notes au-dessus/au-dessous",
"selectAllNotes": "sélectionner toutes les notes du niveau actuel",
"selectNote": "<kbd>Shift+clic</kbd> - sélectionner une note",
"selectNote": "sélectionner une note",
"copyNotes": "copier la note active (ou la sélection actuelle) dans le presse-papiers (utilisé pour le <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonage</a>)",
"cutNotes": "couper la note actuelle (ou la sélection actuelle) dans le presse-papiers (utilisé pour déplacer les notes)",
"pasteNotes": "coller la ou les notes en tant que sous-note dans la note active (qui est soit déplacée, soit clonée selon qu'elle a été copiée ou coupée dans le presse-papiers)",
"deleteNotes": "supprimer une note / un sous-arbre",
"editingNotes": "Édition des notes",
"editNoteTitle": "dans le volet de l'arborescence, basculera du volet au titre de la note. Presser Entrer à partir du titre de la note basculera vers léditeur de texte. <kbd>Ctrl+.</kbd> bascule de l'éditeur au volet arborescent.",
"createEditLink": "<kbd>Ctrl+K</kbd> - créer/éditer un lien externe",
"createEditLink": "créer/éditer un lien externe",
"createInternalLink": "créer un lien interne",
"followLink": "suivre le lien sous le curseur",
"insertDateTime": "insérer la date et l'heure courante à la position du curseur",
@@ -202,7 +201,7 @@
"box_size_small": "petit (~ 10 lignes)",
"box_size_medium": "moyen (~ 30 lignes)",
"box_size_full": "complet (la boîte affiche le texte complet)",
"button_include": "Inclure une note <kbd>Entrée</kbd>"
"button_include": "Inclure une note"
},
"info": {
"modalTitle": "Message d'information",
@@ -210,15 +209,14 @@
"okButton": "OK"
},
"jump_to_note": {
"search_placeholder": "rechercher une note par son nom",
"close": "Fermer",
"search_button": "Rechercher dans le texte intégral <kbd>Ctrl+Entrée</kbd>"
"search_button": "Rechercher dans le texte intégral"
},
"markdown_import": {
"dialog_title": "Importation Markdown",
"close": "Fermer",
"modal_body_text": "En raison du bac à sable du navigateur, il n'est pas possible de lire directement le presse-papiers à partir de JavaScript. Veuillez coller le Markdown à importer dans la zone de texte ci-dessous et cliquez sur le bouton Importer",
"import_button": "Importer Ctrl+Entrée",
"import_button": "Importer",
"import_success": "Le contenu Markdown a été importé dans le document."
},
"move_to": {
@@ -227,7 +225,7 @@
"notes_to_move": "Notes à déplacer",
"target_parent_note": "Note parent cible",
"search_placeholder": "rechercher une note par son nom",
"move_button": "Déplacer vers la note sélectionnée <kbd>entrer</kbd>",
"move_button": "Déplacer vers la note sélectionnée",
"error_no_path": "Aucun chemin vers lequel déplacer.",
"move_success_message": "Les notes sélectionnées ont été déplacées dans "
},
@@ -235,18 +233,17 @@
"modal_title": "Choisissez le type de note",
"close": "Fermer",
"modal_body": "Choisissez le type de note/le modèle de la nouvelle note :",
"templates": "Modèles :"
"templates": "Modèles"
},
"password_not_set": {
"title": "Le mot de passe n'est pas défini",
"close": "Fermer",
"body1": "Les notes protégées sont cryptées à l'aide d'un mot de passe utilisateur, mais le mot de passe n'a pas encore été défini.",
"body2": "Pour pouvoir protéger les notes, cliquez <a class=\"open-password-options-button\" href=\"javascript:\">ici</a> pour ouvrir les Options et définir votre mot de passe."
"body1": "Les notes protégées sont cryptées à l'aide d'un mot de passe utilisateur, mais le mot de passe n'a pas encore été défini."
},
"prompt": {
"title": "Prompt",
"close": "Fermer",
"ok": "OK <kbd>entrer</kbd>",
"ok": "OK",
"defaultTitle": "Prompt"
},
"protected_session_password": {
@@ -254,7 +251,7 @@
"help_title": "Aide sur les notes protégées",
"close_label": "Fermer",
"form_label": "Pour procéder à l'action demandée, vous devez démarrer une session protégée en saisissant le mot de passe :",
"start_button": "Démarrer une session protégée <kbd>entrer</kbd>"
"start_button": "Démarrer une session protégée"
},
"recent_changes": {
"title": "Modifications récentes",
@@ -274,9 +271,7 @@
"revision_last_edited": "Cette version a été modifiée pour la dernière fois le {{date}}",
"confirm_delete_all": "Voulez-vous supprimer toutes les versions de cette note ?",
"no_revisions": "Aucune version pour cette note pour l'instant...",
"restore_button": "",
"confirm_restore": "Voulez-vous restaurer cette version ? Le titre et le contenu actuels de la note seront écrasés par cette version.",
"delete_button": "",
"confirm_delete": "Voulez-vous supprimer cette version ?",
"revisions_deleted": "Les versions de notes ont été supprimées.",
"revision_restored": "La version de la note a été restaurée.",
@@ -306,13 +301,13 @@
"sort_with_respect_to_different_character_sorting": "trier en fonction de différentes règles de tri et de classement des caractères dans différentes langues ou régions.",
"natural_sort_language": "Langage de tri naturel",
"the_language_code_for_natural_sort": "Le code de langue pour le tri naturel, par ex. \"zh-CN\" pour le chinois.",
"sort": "Trier <kbd>Entrée</kbd>"
"sort": "Trier"
},
"upload_attachments": {
"upload_attachments_to_note": "Téléverser des pièces jointes à la note",
"close": "Fermer",
"choose_files": "Choisir des fichiers",
"files_will_be_uploaded": "Les fichiers seront téléversés sous forme de pièces jointes dans",
"files_will_be_uploaded": "Les fichiers seront téléversés sous forme de pièces jointes dans {{noteTitle}}",
"options": "Options",
"shrink_images": "Réduire les images",
"upload": "Téléverser",
@@ -753,7 +748,6 @@
"expand_all_children": "Développer tous les enfants",
"collapse": "Réduire",
"expand": "Développer",
"book_properties": "",
"invalid_view_type": "Type de vue non valide '{{type}}'",
"calendar": "Calendrier"
},
@@ -1251,10 +1245,8 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI est une API REST utilisée pour accéder à l'instance Trilium par programme, sans interface utilisateur.",
"see_more": "",
"wiki": "wiki",
"openapi_spec": "Spec ETAPI OpenAPI",
"swagger_ui": "",
"create_token": "Créer un nouveau jeton ETAPI",
"existing_tokens": "Jetons existants",
"no_tokens_yet": "Il n'y a pas encore de jetons. Cliquez sur le bouton ci-dessus pour en créer un.",
@@ -1408,7 +1400,6 @@
"relation-map": "Carte des relations",
"note-map": "Carte de notes",
"render-note": "Rendu Html",
"book": "Livre",
"mermaid-diagram": "Diagramme Mermaid",
"canvas": "Canevas",
"web-view": "Affichage Web",
@@ -1574,7 +1565,6 @@
"auto-detect-language": "Détecté automatiquement"
},
"highlighting": {
"title": "",
"description": "Contrôle la coloration syntaxique des blocs de code à l'intérieur des notes texte, les notes de code ne seront pas affectées.",
"color-scheme": "Jeu de couleurs"
},
@@ -1674,5 +1664,11 @@
"time_selector": {
"invalid_input": "La valeur de l'heure saisie n'est pas un nombre valide.",
"minimum_input": "La valeur de temps saisie doit être d'au moins {{minimumSeconds}} secondes."
},
"multi_factor_authentication": {
"oauth_user_email": "Courriel de l'utilisateur : "
},
"modal": {
"close": "Fermer"
}
}

View File

@@ -0,0 +1,383 @@
{
"about": {
"close": "Chiudi",
"app_version": "Versione dell'app:",
"db_version": "Versione DB:",
"sync_version": "Versione Sync:",
"data_directory": "Cartella dati:",
"title": "Informazioni su Trilium Notes",
"build_date": "Data della build:",
"build_revision": "Revisione della build:",
"homepage": "Homepage:"
},
"toast": {
"critical-error": {
"title": "Errore critico",
"message": "Si è verificato un errore critico che impedisce l'avvio dell'applicazione client:\n\n{{message}}\n\nQuesto è probabilmente causato da un errore di script inaspettato. Prova a avviare l'applicazione in modo sicuro e controlla il problema."
},
"bundle-error": {
"title": "Non si è riusciti a caricare uno script personalizzato",
"message": "Lo script della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}"
},
"widget-error": {
"title": "Impossibile inizializzare un widget",
"message-custom": "Il widget personalizzato della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}",
"message-unknown": "Un widget sconosciuto non è stato inizializzato a causa di:\n\n{{message}}"
}
},
"add_link": {
"add_link": "Aggiungi un collegamento",
"close": "Chiudi",
"note": "Nota",
"search_note": "cerca una nota per nome",
"link_title_mirrors": "il titolo del collegamento rispecchia il titolo della nota corrente",
"link_title_arbitrary": "il titolo del collegamento può essere modificato arbitrariamente",
"link_title": "Titolo del collegamento",
"button_add_link": "Aggiungi il collegamento <kbd>invio</kbd>",
"help_on_links": "Aiuto sui collegamenti"
},
"branch_prefix": {
"edit_branch_prefix": "Modifica il prefisso del ramo",
"help_on_tree_prefix": "Aiuto sui prefissi dell'Albero",
"close": "Chiudi",
"prefix": "Prefisso: ",
"save": "Salva",
"branch_prefix_saved": "Il prefisso del ramo è stato salvato."
},
"bulk_actions": {
"bulk_actions": "Azioni massive",
"close": "Chiudi",
"affected_notes": "Note influenzate",
"include_descendants": "Includi i discendenti della nota selezionata",
"available_actions": "Azioni disponibili",
"chosen_actions": "Azioni scelte",
"execute_bulk_actions": "Esegui le azioni massive",
"bulk_actions_executed": "Le azioni massive sono state eseguite con successo.",
"none_yet": "Ancora nessuna... aggiungi una azione cliccando su una di quelle disponibili sopra.",
"labels": "Etichette",
"relations": "Relazioni",
"notes": "Note",
"other": "Altro"
},
"clone_to": {
"clone_notes_to": "Clona note in...",
"close": "Chiudi",
"help_on_links": "Aiuto sui collegamenti",
"notes_to_clone": "Note da clonare",
"target_parent_note": "Nodo padre obiettivo",
"search_for_note_by_its_name": "cerca una nota per nome",
"cloned_note_prefix_title": "Le note clonate saranno mostrate nell'albero delle note con il dato prefisso",
"prefix_optional": "Prefisso (opzionale)",
"clone_to_selected_note": "Clona sotto la nota selezionata <kbd>invio</kbd>",
"no_path_to_clone_to": "Nessun percorso per clonare dentro.",
"note_cloned": "La nota \"{{clonedTitle}}\" è stata clonata in \"{{targetTitle}}\""
},
"confirm": {
"close": "Chiudi",
"cancel": "Annulla",
"ok": "OK",
"confirmation": "Conferma",
"are_you_sure_remove_note": "Sei sicuro di voler rimuovere la nota \"{{title}}\" dalla mappa delle relazioni? ",
"if_you_dont_check": "Se non lo selezioni, la nota sarà rimossa solamente dalla mappa delle relazioni.",
"also_delete_note": "Rimuove anche la nota"
},
"delete_notes": {
"ok": "OK",
"close": "Chiudi",
"delete_notes_preview": "Anteprima di eliminazione delle note",
"delete_all_clones_description": "Elimina anche tutti i cloni (può essere disfatto tramite i cambiamenti recenti)",
"erase_notes_description": "L'eliminazione normale (soft) marca le note come eliminate e potranno essere recuperate entro un certo lasso di tempo (dalla finestra dei cambiamenti recenti). Selezionando questa opzione le note si elimineranno immediatamente e non sarà possibile recuperarle.",
"erase_notes_warning": "Elimina le note in modo permanente (non potrà essere disfatto), compresi tutti i cloni. Ciò forzerà un nuovo caricamento dell'applicazione.",
"cancel": "Annulla",
"notes_to_be_deleted": "Le seguenti note saranno eliminate ({{- noteCount}})",
"no_note_to_delete": "Nessuna nota sarà eliminata (solo i cloni).",
"broken_relations_to_be_deleted": "Le seguenti relazioni saranno interrotte ed eliminate ({{- relationCount}})",
"deleted_relation_text": "La nota {{- note}} (da eliminare) è referenziata dalla relazione {{- relation}} originata da {{- source}}."
},
"info": {
"okButton": "OK",
"closeButton": "Chiudi"
},
"export": {
"close": "Chiudi",
"export_note_title": "Esporta la nota",
"export_status": "Stato dell'esportazione",
"export": "Esporta",
"choose_export_type": "Scegli prima il tipo di esportazione, per favore",
"export_in_progress": "Esportazione in corso: {{progressCount}}",
"export_finished_successfully": "Esportazione terminata con successo.",
"format_pdf": "PDF- allo scopo di stampa o esportazione.",
"export_type_subtree": "Questa nota e tutti i suoi discendenti",
"format_html": "HTML - raccomandato in quanto mantiene tutti i formati",
"format_html_zip": "HTML in archivio ZIP - questo è raccomandato in quanto conserva tutta la formattazione.",
"format_markdown": "MArkdown - questo conserva la maggior parte della formattazione."
},
"help": {
"close": "Chiudi",
"fullDocumentation": "Aiuto (la documentazione completa è disponibile <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)"
},
"import": {
"close": "Chiudi"
},
"include_note": {
"close": "Chiudi"
},
"jump_to_note": {
"close": "Chiudi"
},
"markdown_import": {
"close": "Chiudi"
},
"move_to": {
"close": "Chiudi"
},
"note_type_chooser": {
"close": "Chiudi"
},
"password_not_set": {
"close": "Chiudi",
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
"body2": "Per proteggere le note, fare clic su <a class=\"open-password-options-button\" href=\"javascript:\">qui</a> per aprire la finestra di dialogo Opzioni e impostare la password."
},
"protected_session_password": {
"close_label": "Chiudi"
},
"prompt": {
"close": "Chiudi"
},
"recent_changes": {
"close": "Chiudi"
},
"revisions": {
"close": "Chiudi"
},
"abstract_bulk_action": {
"remove_this_search_action": "Rimuovi questa azione di ricerca"
},
"etapi": {
"new_token_title": "Nuovo token ETAPI",
"new_token_message": "Inserire il nuovo nome del token"
},
"electron_integration": {
"zoom-factor": "Fattore di ingrandimento",
"desktop-application": "Applicazione Desktop"
},
"note_autocomplete": {
"search-for": "Cerca \"{{term}}\"",
"create-note": "Crea e collega la nota figlia \"{{term}}\"",
"insert-external-link": "Inserisci il collegamento esterno a \"{{term}}\"",
"clear-text-field": "Pulisci il campo di testo",
"show-recent-notes": "Mostra le note recenti",
"full-text-search": "Ricerca full text"
},
"note_tooltip": {
"note-has-been-deleted": "La nota è stata eliminata.",
"quick-edit": "Modifica veloce"
},
"geo-map": {
"create-child-note-title": "Crea una nota figlia e aggiungila alla mappa",
"create-child-note-instruction": "Clicca sulla mappa per creare una nuova nota qui o premi Escape per uscire.",
"unable-to-load-map": "Impossibile caricare la mappa."
},
"geo-map-context": {
"open-location": "Apri la posizione",
"remove-from-map": "Rimuovi dalla mappa",
"add-note": "Aggiungi un marcatore in questa posizione"
},
"debug": {
"debug": "Debug"
},
"database_anonymization": {
"light_anonymization": "Anonimizzazione parziale",
"title": "Anonimizzazione del Database",
"full_anonymization": "Anonimizzazione completa",
"full_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà (rimuove tutti i contenuti delle note, lasciando solo la struttura e qualche metadato non sensibile) per condividerlo online allo scopo di debugging, senza paura di far trapelare i tuoi dati personali.",
"save_fully_anonymized_database": "Salva il database completamente anonimizzato",
"light_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà in parzialmente — in particolare, solo il contenuto delle note sarà rimosso, ma i titoli e gli attributi rimarranno. Inoltre, note con script personalizzati JS di frontend/backend e widget personalizzati lasciando rimarranno. Ciò mette a disposizione più contesto per il debug dei problemi.",
"choose_anonymization": "Puoi decidere da solo se fornire un database completamente o parzialmente anonimizzato. Anche un database completamente anonimizzato è molto utile, sebbene in alcuni casi i database parzialmente anonimizzati possono accelerare il processo di identificazione dei bug e la loro correzione.",
"no_anonymized_database_yet": "Nessun database ancora anonimizzato.",
"save_lightly_anonymized_database": "Salva il database parzialmente anonimizzato",
"successfully_created_fully_anonymized_database": "Database completamente anonimizzato creato in {{anonymizedFilePath}}",
"successfully_created_lightly_anonymized_database": "Database parzialmente anonimizzato creato in {{anonymizedFilePath}}"
},
"cpu_arch_warning": {
"title": "Per favore scarica la versione ARM64",
"continue_anyway": "Continua Comunque",
"dont_show_again": "Non mostrare più questo avviso",
"download_link": "Scarica la Versione Nativa"
},
"editorfeatures": {
"title": "Caratteristiche",
"emoji_completion_enabled": "Abilita il completamento automatico delle Emoji",
"note_completion_enabled": "Abilita il completamento automatico delle note"
},
"table_view": {
"new-row": "Nuova riga",
"new-column": "Nuova colonna",
"sort-column-by": "Ordina per \"{{title}}\"",
"sort-column-ascending": "Ascendente",
"sort-column-descending": "Discendente",
"sort-column-clear": "Cancella l'ordinamento",
"hide-column": "Nascondi la colonna \"{{title}}\"",
"show-hide-columns": "Mostra/nascondi le colonne",
"row-insert-above": "Inserisci una riga sopra",
"row-insert-below": "Inserisci una riga sotto"
},
"abstract_search_option": {
"remove_this_search_option": "Rimuovi questa opzione di ricerca",
"failed_rendering": "Opzione di ricerca di rendering non riuscita: {{dto}} con errore: {{error}} {{stack}}"
},
"ancestor": {
"label": "Antenato"
},
"add_label": {
"add_label": "Aggiungi etichetta",
"label_name_placeholder": "nome dell'etichetta",
"new_value_placeholder": "nuovo valore",
"to_value": "al valore"
},
"update_label_value": {
"to_value": "al valore",
"label_name_placeholder": "nome dell'etichetta"
},
"delete_label": {
"delete_label": "Elimina etichetta",
"label_name_placeholder": "nome dell'etichetta",
"label_name_title": "Sono ammessi i caratteri alfanumerici, il carattere di sottolineato e i due punti."
},
"tree-context-menu": {
"move-to": "Muovi in...",
"cut": "Taglia"
},
"electron_context_menu": {
"cut": "Taglia",
"copy": "Copia",
"paste": "Incolla",
"copy-link": "Copia collegamento",
"paste-as-plain-text": "Incolla come testo semplice"
},
"editing": {
"editor_type": {
"multiline-toolbar": "Mostra la barra degli strumenti su più linee se non entra."
}
},
"edit_button": {
"edit_this_note": "Modifica questa nota"
},
"shortcuts": {
"shortcuts": "Scorciatoie"
},
"shared_switch": {
"toggle-on-title": "Condividi la nota",
"toggle-off-title": "Non condividere la nota"
},
"search_string": {
"search_prefix": "Cerca:"
},
"attachment_detail": {
"open_help_page": "Apri la pagina di aiuto sugli allegati"
},
"search_definition": {
"ancestor": "antenato",
"debug": "debug",
"action": "azione",
"add_search_option": "Aggiungi un opzione di ricerca:",
"search_string": "cerca la stringa",
"limit": "limite"
},
"modal": {
"close": "Chiudi"
},
"board_view": {
"insert-below": "Inserisci sotto",
"delete-column": "Elimina la colonna",
"delete-column-confirmation": "Sei sicuro di vole eliminare questa colonna? Il corrispondente attributo sarà eliminato anche nelle note sotto questa colonna."
},
"backup": {
"enable_weekly_backup": "Abilita le archiviazioni settimanali",
"enable_monthly_backup": "Abilita le archiviazioni mensili",
"backup_recommendation": "Si raccomanda di mantenere attive le archiviazioni, sebbene ciò possa rendere l'avvio dell'applicazione lento con database grandi e/o dispositivi di archiviazione lenti.",
"backup_now": "Archivia adesso",
"backup_database_now": "Archivia il database adesso",
"existing_backups": "Backup esistenti",
"date-and-time": "Data e ora",
"path": "Percorso",
"database_backed_up_to": "Il database è stato archiviato in {{backupFilePath}}",
"enable_daily_backup": "Abilita le archiviazioni giornaliere",
"no_backup_yet": "Ancora nessuna archiviazione"
},
"backend_log": {
"refresh": "Aggiorna"
},
"consistency_checks": {
"find_and_fix_button": "Trova e correggi i problemi di coerenza",
"finding_and_fixing_message": "In cerca e correzione dei problemi di coerenza...",
"issues_fixed_message": "Qualsiasi problema di coerenza che possa essere stato trovato ora è corretto."
},
"database_integrity_check": {
"check_button": "Controllo dell'integrità del database",
"checking_integrity": "Controllo dell'integrità del database in corso...",
"title": "Controllo di Integrità del database",
"description": "Controllerà che il database non sia corrotto a livello SQLite. Può durare un po' di tempo, a seconda della grandezza del DB.",
"integrity_check_failed": "Controllo di integrità fallito: {{results}}"
},
"sync": {
"title": "Sincronizza",
"force_full_sync_button": "Forza una sincronizzazione completa",
"failed": "Sincronizzazione fallita: {{message}}"
},
"sync_2": {
"config_title": "Configurazione per la Sincronizzazione",
"proxy_label": "Server Proxy per la sincronizzazione (opzionale)",
"test_title": "Test di sincronizzazione",
"timeout": "Timeout per la sincronizzazione",
"timeout_unit": "millisecondi",
"save": "Salva",
"help": "Aiuto"
},
"search_engine": {
"save_button": "Salva"
},
"sql_table_schemas": {
"tables": "Tabelle"
},
"tab_row": {
"close_tab": "Chiudi la scheda",
"add_new_tab": "Aggiungi una nuova scheda",
"close": "Chiudi",
"close_other_tabs": "Chiudi le altre schede",
"close_right_tabs": "Chiudi le schede a destra",
"close_all_tabs": "Chiudi tutte le schede",
"reopen_last_tab": "Riapri l'ultima scheda chiusa",
"move_tab_to_new_window": "Sposta questa scheda in una nuova finestra",
"copy_tab_to_new_window": "Copia questa scheda in una nuova finestra",
"new_tab": "Nuova scheda"
},
"toc": {
"table_of_contents": "Sommario"
},
"table_of_contents": {
"title": "Sommario"
},
"tray": {
"title": "Vassoio di Sistema",
"enable_tray": "Abilita il vassoio (Trilium necessita di essere riavviato affinché la modifica abbia effetto)"
},
"heading_style": {
"title": "Stile dell'Intestazione",
"plain": "Normale",
"underline": "Sottolineato",
"markdown": "Stile Markdown"
},
"highlights_list": {
"title": "Punti salienti"
},
"highlights_list_2": {
"title": "Punti salienti",
"options": "Opzioni"
},
"quick-search": {
"placeholder": "Ricerca rapida",
"searching": "Ricerca in corso..."
}
}

View File

@@ -0,0 +1,23 @@
{
"about": {
"title": "Trilium Notesについて",
"close": "閉じる",
"homepage": "ホームページ:",
"app_version": "アプリのヴァージョン:",
"db_version": "データベースのヴァージョン:",
"sync_version": "同期のヴァージョン:",
"build_date": "Build の日時:",
"build_revision": "Build のヴァージョン:",
"data_directory": "データの場所:"
},
"toast": {
"critical-error": {
"title": "致命的なエラー",
"message": "致命的なエラーのせいでアプリをスタートできません:\n\n{{message}}\n\nおそらくスクリプトが予期しないバグを含んでいると思われます。アプリをセーフモードでスタートしてみて下さい。"
},
"widget-error": {
"title": "ウィジェットを初期化できませんでした",
"message-custom": "ートID”{{id}}”, ノートタイトル “{{title}}” のカスタムウィジェットを初期化できませんでした:\n\n{{message}}"
}
}
}

View File

@@ -1,10 +1,431 @@
{
"revisions": {
"delete_button": ""
},
"code_block": {
"theme_none": "Sem destaque de sintaxe",
"theme_group_light": "Temas claros",
"theme_group_dark": "Temas escuros"
}
"code_block": {
"theme_none": "Sem destaque de sintaxe",
"theme_group_light": "Temas claros",
"theme_group_dark": "Temas escuros"
},
"about": {
"title": "Sobre o Trilium Notes",
"close": "Fechar",
"homepage": "Página inicial:",
"app_version": "Versão do App:",
"db_version": "Versão do db:",
"sync_version": "Versão de sincronização:",
"build_date": "Data de compilação:",
"build_revision": "Revisão da compilação:",
"data_directory": "Diretório de dados:"
},
"toast": {
"critical-error": {
"title": "Erro crítico",
"message": "Ocorreu um erro crítico que impede a inicialização do aplicativo cliente:\n\n{{message}}\n\nIsso provavelmente foi causado por um script que falhou de maneira inesperada. Tente iniciar o aplicativo no modo seguro e resolva o problema."
},
"widget-error": {
"title": "Falha ao inicializar um widget",
"message-custom": "O widget personalizado da nota com ID \"{{id}}\", intitulada \"{{title}}\", não pôde ser inicializado devido a:\n\n{{message}}",
"message-unknown": "Widget desconhecido não pôde ser inicializado devido a:\n\n{{message}}"
},
"bundle-error": {
"title": "Falha para carregar o script customizado",
"message": "O script da nota com ID \"{{id}}\", intitulada \"{{title}}\", não pôde ser executado devido a:\n\n{{message}}"
}
},
"add_link": {
"add_link": "Adicionar link",
"help_on_links": "Ajuda sobre links",
"close": "Fechar",
"note": "Nota",
"search_note": "pesquisar nota pelo nome",
"link_title_mirrors": "o título do link reflete o título atual da nota",
"link_title_arbitrary": "o título do link pode ser alterado livremente",
"link_title": "Titulo do link",
"button_add_link": "Adicionar link <kbd>enter</kbd>"
},
"branch_prefix": {
"close": "Fechar",
"prefix": "Prefixo: ",
"save": "Salvar",
"edit_branch_prefix": "Editar Prefixo do Branch",
"help_on_tree_prefix": "Ajuda sobre o prefixo da árvore de notas",
"branch_prefix_saved": "O prefixo de ramificação foi salvo."
},
"bulk_actions": {
"bulk_actions": "Ações em massa",
"close": "Fechar",
"affected_notes": "Notas Afetadas",
"include_descendants": "Incluir notas filhas das notas selecionadas",
"available_actions": "Ações disponíveis",
"chosen_actions": "Ações selecionadas",
"execute_bulk_actions": "Executar ações em massa",
"bulk_actions_executed": "As ações em massa foram concluídas com sucesso.",
"none_yet": "Nenhuma até agora... adicione uma ação clicando em uma das disponíveis acima.",
"labels": "Etiquetas",
"relations": "Relações",
"notes": "Notas",
"other": "Outros"
},
"clone_to": {
"clone_notes_to": "Clonar notas para...",
"close": "Fechar",
"help_on_links": "Ajuda sobre links",
"notes_to_clone": "Notas para clonar",
"search_for_note_by_its_name": "pesquisar nota pelo nome",
"cloned_note_prefix_title": "A nota clonada aparecerá na árvore de notas com o prefixo fornecido",
"prefix_optional": "Prefixo (opcional)",
"no_path_to_clone_to": "Nenhum caminho para clonar.",
"target_parent_note": "Nota pai-alvo",
"clone_to_selected_note": "Clonar para a nota selecionada <kbd>enter</kbd>",
"note_cloned": "A nota \"{{clonedTitle}}\" foi clonada para \"{{targetTitle}}\""
},
"ai_llm": {
"n_notes_queued_0": "{{ count }} nota enfileirada para indexação",
"n_notes_queued_1": "{{ count }} notas enfileiradas para indexação",
"n_notes_queued_2": "{{ count }} notas enfileiradas para indexação",
"notes_indexed_0": "{{ count }} nota indexada",
"notes_indexed_1": "{{ count }} notas indexadas",
"notes_indexed_2": "{{ count }} notas indexadas"
},
"confirm": {
"confirmation": "Confirmação",
"close": "Fechar",
"cancel": "Cancelar",
"ok": "OK",
"are_you_sure_remove_note": "Tem certeza de que deseja remover a nota '{{title}}' do mapa de relações? ",
"if_you_dont_check": "Se você não marcar isso, a nota será removida apenas do mapa de relações.",
"also_delete_note": "Também excluir a nota"
},
"delete_notes": {
"delete_notes_preview": "Excluir pré-visualização de notas",
"close": "Fechar",
"delete_all_clones_description": "Excluir também todos os clones (pode ser desfeito em alterações recentes)",
"erase_notes_description": "A exclusão normal (suave) apenas marca as notas como excluídas, permitindo que sejam recuperadas (no diálogo de alterações recentes) dentro de um período de tempo. Se esta opção for marcada, as notas serão apagadas imediatamente e não será possível restaurá-las.",
"erase_notes_warning": "Apagar notas permanentemente (não pode ser desfeito), incluindo todos os clones. Isso forçará o recarregamento do aplicativo.",
"notes_to_be_deleted": "As seguintes notas serão excluídas ({{- noteCount}})",
"no_note_to_delete": "Nenhuma nota será excluída (apenas os clones).",
"broken_relations_to_be_deleted": "As seguintes relações serão quebradas e excluídas ({{- relationCount}})",
"cancel": "Cancelar",
"ok": "OK",
"deleted_relation_text": "A nota {{- note}} (a ser excluída) está referenciada pela relação {{- relation}} originada de {{- source}}."
},
"export": {
"export_note_title": "Exportar nota",
"close": "Fechar",
"export_type_subtree": "Esta nota e todos os seus descendentes",
"format_html": "HTML recomendado, pois mantém toda a formatação",
"format_html_zip": "HTML em arquivo ZIP recomendado, pois isso preserva toda a formatação.",
"format_markdown": "Markdown isso preserva a maior parte da formatação.",
"format_opml": "OPML - formato de intercâmbio de outliners apenas para texto. Formatação, imagens e arquivos não estão incluídos.",
"opml_version_1": "OPML v1.0 apenas texto simples",
"opml_version_2": "OPML v2.0 permite também HTML",
"export_type_single": "Apenas esta nota, sem seus descendentes",
"export": "Exportar",
"choose_export_type": "Por favor, escolha primeiro o tipo de exportação",
"export_status": "Status da exportação",
"export_in_progress": "Exportação em andamento: {{progressCount}}",
"export_finished_successfully": "Exportação concluída com sucesso.",
"format_pdf": "PDF para impressão ou compartilhamento."
},
"help": {
"fullDocumentation": "Ajuda (a documentação completa está disponível <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
"close": "Fechar",
"noteNavigation": "Navegação de notas",
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> subir/descer na lista de notas",
"collapseExpand": "<kbd>ESQUERDA</kbd>, <kbd>DIREITA</kbd> recolher/expandir nó",
"notSet": "não definido",
"goBackForwards": "voltar / avançar no histórico",
"showJumpToNoteDialog": "mostrar diálogo <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Ir para\"</a>",
"scrollToActiveNote": "rolar até a nota atual",
"jumpToParentNote": "<kbd>Backspace</kbd> ir para a nota pai",
"collapseWholeTree": "recolher toda a árvore de notas",
"collapseSubTree": "recolher subárvore",
"tabShortcuts": "Atalhos de abas",
"newTabNoteLink": "<kbd>Ctrl+clique</kbd> (ou <kbd>clique com o botão do meio do mouse</kbd>) em um link de nota abre a nota em uma nova aba",
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+clique</kbd> (ou <kbd>Shift+clique com o botão do meio do mouse</kbd>) em um link de nota abre e ativa a nota em uma nova aba",
"onlyInDesktop": "Apenas na versão para desktop (compilação Electron)",
"openEmptyTab": "abrir aba vazia",
"closeActiveTab": "fechar aba ativa",
"activateNextTab": "ativar próxima aba",
"activatePreviousTab": "ativar aba anterior",
"creatingNotes": "Criando notas",
"createNoteAfter": "criar nova nota após a nota atual",
"createNoteInto": "criar nova subnota dentro da nota atual",
"editBranchPrefix": "editar <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefixo</a> do clone da nota ativa",
"movingCloningNotes": "Movendo / clonando notas",
"moveNoteUpDown": "mover nota para cima/baixo na lista de notas",
"moveNoteUpHierarchy": "mover nota para cima na hierarquia",
"multiSelectNote": "selecionar múltiplas notas acima/abaixo",
"selectAllNotes": "selecionar todas as notas no nível atual",
"selectNote": "<kbd>Shift+clique</kbd> - selecionar nota",
"copyNotes": "copiar nota ativa (ou seleção atual) para a área de transferência (usado para <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonar</a>)",
"cutNotes": "recortar nota atual (ou seleção atual) para a área de transferência (usado para mover notas)",
"pasteNotes": "colar nota(s) como subnota dentro da nota ativa (o que pode ser mover ou clonar dependendo se foi copiado ou recortado para a área de transferência)",
"deleteNotes": "excluir nota / subárvore",
"editingNotes": "Edição de notas",
"editNoteTitle": "no painel de árvore, a navegação mudará do painel de árvore para o título da nota. Pressionar Enter no título da nota mudará o foco para o editor de texto. <kbd>Ctrl+.</kbd> mudará o foco de volta do editor para o painel de árvore.",
"createEditLink": "<kbd>Ctrl+K</kbd> - criar / editar link externo",
"createInternalLink": "criar link interno",
"followLink": "seguir link sob o cursor",
"insertDateTime": "inserir data e hora atual na posição do cursor",
"jumpToTreePane": "ir para a árvore de notas e rolar até a nota ativa",
"markdownAutoformat": "Autoformatação estilo Markdown",
"headings": "<code>##</code>, <code>###</code>, <code>####</code> etc. seguidos de espaço para títulos",
"bulletList": "<code>*</code> ou <code>-</code> seguidos de espaço para lista com marcadores",
"numberedList": "<code>1.</code> ou <code>1)</code> seguidos de espaço para lista numerada",
"blockQuote": "comece uma linha com <code>></code> seguido de espaço para citação em bloco",
"troubleshooting": "Solução de problemas",
"reloadFrontend": "recarregar o frontend do Trilium",
"showDevTools": "mostrar ferramentas de desenvolvedor",
"showSQLConsole": "mostrar console SQL",
"other": "Outros",
"quickSearch": "focar no campo de pesquisa rápida",
"inPageSearch": "pesquisa na página"
},
"import": {
"importIntoNote": "Importar para a nota",
"close": "Fechar",
"chooseImportFile": "Escolher arquivo para importar",
"importDescription": "O conteúdo do(s) arquivo(s) selecionado(s) será importado como nota(s) filha(s) em",
"options": "Opções",
"safeImportTooltip": "Arquivos de exportação Trilium<code> .zip</code> podem conter scripts executáveis que podem apresentar comportamentos prejudiciais. A importação segura desativará a execução automática de todos os scripts importados. Desmarque “Importação segura” apenas se o arquivo de importação contiver scripts executáveis e você confiar totalmente no conteúdo do arquivo importado.",
"safeImport": "Importação segura",
"explodeArchivesTooltip": "Se esta opção estiver marcada, o Trilium irá ler arquivos <code>.zip</code>, <code>.enex</code> e <code>.opml</code> e criar notas a partir dos arquivos contidos nesses arquivos compactados. Se estiver desmarcada, o Trilium irá anexar os próprios arquivos compactados à nota.",
"explodeArchives": "Ler conteúdos de arquivos <code>.zip</code>, <code>.enex</code> e <code>.opml</code>.",
"shrinkImagesTooltip": "<p>Se você marcar esta opção, o Trilium tentará reduzir o tamanho das imagens importadas por meio de escala e otimização, o que pode afetar a qualidade visual das imagens. Se desmarcada, as imagens serão importadas sem alterações.</p><p>Isso não se aplica a importações de arquivos <code>.zip</code> com metadados, pois presume-se que esses arquivos já estejam otimizados.</p>",
"shrinkImages": "Reduzir imagens",
"textImportedAsText": "Importar arquivos HTML, Markdown e TXT como notas de texto caso não esteja claro pelos metadados",
"codeImportedAsCode": "Importar arquivos de código reconhecidos (por exemplo, <code>.json</code>) como notas de código caso não esteja claro pelos metadados",
"replaceUnderscoresWithSpaces": "Substituir sublinhados por espaços nos nomes das notas importadas",
"import": "Importar",
"failed": "Falha na importação: {{message}}.",
"html_import_tags": {
"title": "Tags de importação HTML",
"description": "Configurar quais tags HTML devem ser preservadas ao importar notas. As tags que não estiverem nesta lista serão removidas durante a importação. Algumas tags (como 'script') são sempre removidas por motivos de segurança.",
"placeholder": "Digite as tags HTML, uma por linha",
"reset_button": "Redefinir para lista padrão"
},
"import-status": "Status da importação",
"in-progress": "Importação em andamento: {{progress}}",
"successful": "Importação concluída com sucesso."
},
"include_note": {
"dialog_title": "Incluir nota",
"close": "Fechar",
"label_note": "Nota",
"placeholder_search": "pesquisar nota pelo nome",
"box_size_prompt": "Dimensão da caixa da nota incluída:",
"box_size_small": "pequeno (~ 10 linhas)",
"box_size_medium": "médio (~ 30 linhas)",
"box_size_full": "completo (a caixa exibe o texto completo)",
"button_include": "Incluir nota <kbd>enter</kbd>"
},
"info": {
"modalTitle": "Mensagem informativa",
"closeButton": "Fechar",
"okButton": "OK"
},
"jump_to_note": {
"search_placeholder": "Pesquise uma nota pelo nome ou digite > para comandos...",
"close": "Fechar",
"search_button": "Pesquisar em texto completo <kbd>Ctrl+Enter</kbd>"
},
"markdown_import": {
"dialog_title": "Importar Markdown",
"close": "Fechar",
"modal_body_text": "Por motivos de segurança (sandbox do navegador), o JavaScript não pode acessar diretamente a área de transferência. Por favor, cole o conteúdo Markdown na área de texto abaixo e clique em Importar",
"import_button": "Importar Ctrl+Enter",
"import_success": "O conteúdo Markdown foi importado para o documento."
},
"move_to": {
"dialog_title": "Mover notas para...",
"close": "Fechar",
"notes_to_move": "Notas para mover",
"target_parent_note": "Nota pai-alvo",
"search_placeholder": "pesquisar nota pelo nome",
"move_button": "Mover para a nota selecionada <kbd>enter</kbd>",
"error_no_path": "Nenhum caminho para mover.",
"move_success_message": "As notas selecionadas foram movidas para "
},
"note_type_chooser": {
"change_path_prompt": "Alterar onde criar a nova nota:",
"search_placeholder": "buscar caminho pelo nome (valor padrão se não for preenchido)",
"modal_title": "Escolher tipo de nota",
"close": "Fechar",
"modal_body": "Escolha o tipo/modelo da nova nota:",
"templates": "Modelos:"
},
"password_not_set": {
"title": "A senha não está definida",
"close": "Fechar",
"body1": "Notas protegidas são criptografadas usando uma senha do usuário, mas a senha ainda não foi definida.",
"body2": "Para poder proteger notas, clique <a class=\"open-password-options-button\" href=\"javascript:\">aqui</a> para abrir a caixa de diálogo de Opções e definir sua senha."
},
"prompt": {
"title": "Prompt",
"close": "Fechar",
"ok": "OK <kbd>enter</kbd>",
"defaultTitle": "Prompt"
},
"protected_session_password": {
"modal_title": "Sessão Protegida",
"help_title": "Ajuda sobre notas protegidas",
"close_label": "Fechar",
"form_label": "Para prosseguir com a ação solicitada, você precisa iniciar uma sessão protegida digitando a senha:",
"start_button": "Iniciar sessão protegida <kbd>enter</kbd>"
},
"recent_changes": {
"title": "Alterações recentes",
"erase_notes_button": "Remover permanentemente as notas excluídas agora",
"close": "Fechar",
"deleted_notes_message": "As notas excluídas foram removidas permanentemente.",
"no_changes_message": "Nenhuma alteração ainda...",
"undelete_link": "Restaurar",
"confirm_undelete": "Você deseja restaurar esta nota e suas subnotas?"
},
"revisions": {
"note_revisions": "Versões da nota",
"delete_all_revisions": "Excluir todas as versões desta nota",
"delete_all_button": "Excluir todas as versões",
"help_title": "Ajuda sobre as versões da nota",
"close": "Fechar",
"revision_last_edited": "Esta versão foi editada pela última vez em {{date}}",
"confirm_delete_all": "Você quer excluir todas as versões desta nota?",
"no_revisions": "Ainda não há versões para esta nota...",
"restore_button": "Recuperar",
"confirm_restore": "Deseja restaurar esta versão? Isso irá substituir o título e o conteúdo atuais da nota por esta versão.",
"delete_button": "Excluir",
"confirm_delete": "Deseja excluir esta versão?",
"revisions_deleted": "As versões da nota foram removidas.",
"revision_restored": "A versão da nota foi restaurada.",
"revision_deleted": "A versão da nota foi excluída.",
"snapshot_interval": "Intervalo de captura das versões da nota: {{seconds}}s.",
"maximum_revisions": "Limite de capturas das versões da nota: {{number}}.",
"settings": "Configurações de versões da nota",
"download_button": "Download",
"mime": "MIME: ",
"file_size": "Tamanho do arquivo:",
"preview": "Visualizar:",
"preview_not_available": "A visualização não está disponível para este tipo de nota."
},
"sort_child_notes": {
"sort_children_by": "Ordenar notas filhas por...",
"close": "Fechar",
"sorting_criteria": "Critérios de ordenação",
"title": "título",
"date_created": "data de criação",
"date_modified": "data de modificação",
"sorting_direction": "Direção de ordenação",
"ascending": "crescente",
"descending": "decrescente",
"folders": "Pastas",
"sort_folders_at_top": "colocar pastas no topo",
"natural_sort": "Ordenação Natural",
"sort_with_respect_to_different_character_sorting": "classificar de acordo com diferentes regras de ordenação de caracteres e colação em diferentes idiomas ou regiões.",
"natural_sort_language": "Linguagem da ordenação natural",
"the_language_code_for_natural_sort": "O código do idioma para ordenação natural, por exemplo, \"zh-CN\" para chinês.",
"sort": "Ordenar <kbd>enter</kbd>"
},
"upload_attachments": {
"upload_attachments_to_note": "Enviar anexos para a nota",
"close": "Fechar",
"choose_files": "Escolher arquivos",
"files_will_be_uploaded": "Os arquivos serão enviados como anexos para",
"options": "Opções",
"shrink_images": "Reduzir imagens",
"upload": "Enviar",
"tooltip": "Se você marcar esta opção, o Trilium tentará reduzir as imagens enviadas redimensionando e otimizando, o que pode afetar a qualidade visual percebida. Se desmarcada, as imagens serão enviadas sem alterações."
},
"attribute_detail": {
"attr_detail_title": "Título Detalhado do Atributo",
"close_button_title": "Cancelar alterações e fechar",
"attr_is_owned_by": "O atributo pertence a",
"attr_name_title": "O nome do atributo pode ser composto apenas por caracteres alfanuméricos, dois-pontos e sublinhado",
"name": "Nome",
"value": "Valor",
"target_note_title": "Relação é uma conexão nomeada entre a nota de origem e a nota de destino.",
"target_note": "Nota de destino",
"promoted_title": "O atributo promovido é exibido de forma destacada na nota.",
"promoted": "Promovido",
"promoted_alias_title": "O nome a ser exibido na interface de atributos promovidos.",
"promoted_alias": "Alias",
"multiplicity_title": "Multiplicidade define quantos atributos com o mesmo nome podem ser criados — no máximo 1 ou mais de 1.",
"multiplicity": "Multiplicidade",
"single_value": "Valor único",
"multi_value": "Valor múltiplo",
"label_type_title": "O tipo do rótulo ajudará o Trilium a escolher a interface adequada para inserir o valor do rótulo.",
"label_type": "Tipo",
"text": "Texto",
"number": "Número",
"boolean": "Booleano",
"date": "Data",
"date_time": "Data e Hora",
"time": "Hora",
"url": "URL",
"precision_title": "Qual número de dígitos após o ponto decimal deve estar disponível na interface de configuração de valor.",
"precision": "Precisão",
"digits": "dígitos",
"inverse_relation_title": "Configuração opcional para definir a qual relação esta é oposta. Exemplo: Pai - Filho são relações inversas entre si.",
"inverse_relation": "Relação inversa",
"inheritable_title": "O atributo herdável será transmitido para todos os descendentes deste ramo.",
"inheritable": "Herdável",
"save_and_close": "Salvar e fechar <kbd>Ctrl+Enter</kbd>",
"delete": "Excluir",
"related_notes_title": "Outras notas com este rótulo",
"more_notes": "Mais notas",
"label": "Detalhe do rótulo",
"label_definition": "Detalhe da definição do rótulo",
"relation": "Detalhe da relação",
"relation_definition": "Detalhe da definição da relação",
"disable_versioning": "desativa a versão automática. Útil, por exemplo, para notas grandes, mas sem importância como grandes bibliotecas JS usadas para scripts",
"calendar_root": "marca a nota que deve ser usada como raiz para notas diárias. Apenas uma deve ser marcada assim.",
"archived": "notas com este rótulo não serão exibidas por padrão nos resultados de busca (também nos diálogos Ir para, Adicionar link, etc).",
"exclude_from_export": "notas (junto com sua subárvore) não serão incluídas em nenhuma exportação de notas",
"run": "define em quais eventos o script deve ser executado. Os valores possíveis são:\n<ul>\n<li>frontendStartup - quando o frontend do Trilium inicia (ou é atualizado), mas não no celular.</li>\n<li>mobileStartup - quando o frontend do Trilium inicia (ou é atualizado), no celular.</li>\n<li>backendStartup - quando o backend do Trilium inicia</li>\n<li>hourly - executa uma vez por hora. Você pode usar o rótulo adicional <code>runAtHour</code> para especificar em qual hora.</li>\n<li>daily - executa uma vez por dia</li>\n</ul>",
"run_on_instance": "Define em qual instância do Trilium isso deve ser executado. Por padrão, todas as instâncias.",
"run_at_hour": "Em qual hora isso deve ser executado. Deve ser usado junto com <code>#run=hourly</code>. Pode ser definido várias vezes para executar mais de uma vez ao dia.",
"disable_inclusion": "scripts com este rótulo não serão incluídos na execução do script pai.",
"sorted": "mantém as notas filhas ordenadas alfabeticamente pelo título",
"sort_direction": "ASC (padrão) ou DESC",
"sort_folders_first": "Pastas (notas com filhos) devem ser ordenadas no topo",
"top": "mantenha a nota fornecida no topo em seu pai (aplica-se apenas a pais ordenados)",
"hide_promoted_attributes": "Ocultar atributos promovidos nesta nota",
"read_only": "o editor está em modo somente leitura. Funciona apenas para notas de texto e código.",
"auto_read_only_disabled": "notas de texto/código podem ser automaticamente configuradas para modo de leitura quando são muito grandes. Você pode desabilitar esse comportamento por nota adicionando este rótulo à nota",
"app_css": "marca notas CSS que são carregadas no aplicativo Trilium e, portanto, podem ser usadas para modificar a aparência do Trilium.",
"app_theme": "marca notas CSS que são temas completos do Trilium e, portanto, estão disponíveis nas opções do Trilium.",
"app_theme_base": "defina como \"next\", \"next-light\" ou \"next-dark\" para usar o tema TriliumNext correspondente (auto, claro ou escuro) como base para um tema personalizado, em vez do tema legado.",
"css_class": "o valor deste rótulo é então adicionado como classe CSS ao nó que representa a nota específica na árvore. Isso pode ser útil para temas avançados. Pode ser usado em notas de modelo.",
"icon_class": "o valor deste rótulo é adicionado como uma classe CSS ao ícone na árvore, o que pode ajudar a distinguir visualmente as notas na árvore. Um exemplo pode ser bx bx-home os ícones são retirados do boxicons. Pode ser usado em notas de modelo.",
"page_size": "número de itens por página na listagem de notas",
"custom_request_handler": "veja <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Manipulador de requisição personalizada</a>",
"custom_resource_provider": "veja <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Manipulador de requisição personalizada</a>",
"widget": "marca esta nota como um widget personalizado que será adicionado à árvore de componentes do Trilium",
"workspace": "marca esta nota como um espaço de trabalho, o que permite fácil hoisting",
"workspace_icon_class": "define a classe CSS do ícone box que será usada na aba quando esta nota for hoisted",
"workspace_tab_background_color": "cor CSS usada na aba da nota quando esta nota é hoisted",
"workspace_calendar_root": "Define a raiz do calendário por espaço de trabalho",
"workspace_template": "Esta nota aparecerá na seleção de modelos disponíveis ao criar uma nova nota, mas apenas quando estiver destacada em um espaço de trabalho que contenha este modelo",
"search_home": "novas notas de pesquisa serão criadas como filhas desta nota",
"workspace_search_home": "novas notas de pesquisa serão criadas como filhas desta nota quando ela for destacada para algum ancestral desta nota de área de trabalho",
"inbox": "localização padrão da caixa de entrada para novas notas quando você cria uma nota usando o botão \"nova nota\" na barra lateral, as notas serão criadas como notas filhas na nota marcada com o rótulo <code>#inbox</code>.",
"workspace_inbox": "local padrão da caixa de entrada para novas notas quando esta nota for destacada para algum ancestral desta nota de área de trabalho",
"sql_console_home": "localização padrão das notas do console SQL",
"bookmark_folder": "nota com este rótulo aparecerá nos favoritos como uma pasta (permitindo acesso aos seus filhos)",
"share_hidden_from_tree": "esta nota está oculta na árvore de navegação à esquerda, mas ainda pode ser acessada via sua URL",
"share_external_link": "a nota funcionará como um link para um site externo na árvore de compartilhamento",
"share_alias": "defina um alias por meio do qual a nota ficará disponível em https://your_trilium_host/share/[your_alias]",
"share_omit_default_css": "o CSS padrão da página de compartilhamento será omitido. Use quando você fizer alterações extensas de estilo.",
"share_root": "marca a nota que é servida na raiz de /share.",
"share_description": "defina o texto a ser adicionado à meta tag HTML \"description\"",
"share_raw": "a nota será servida em seu formato bruto, sem o wrapper HTML",
"share_disallow_robot_indexing": "impedirá que robôs indexem esta nota por meio do cabeçalho <code>X-Robots-Tag: noindex</code>",
"share_credentials": "exigir credenciais para acessar esta nota compartilhada. O valor deve estar no formato 'usuário:senha'. Não se esqueça de tornar esta configuração herdável para que seja aplicada às notas-filhas/imagens.",
"share_index": "notas com este rótulo irão listar todas as raízes das notas compartilhadas",
"display_relations": "nomes das relações separados por vírgula que devem ser exibidos. Todas as outras serão ocultadas.",
"hide_relations": "nomes das relações separados por vírgula que devem ser ocultados. Todas as outras serão exibidas.",
"title_template": "Título padrão das notas criadas como filhas desta nota. O valor é avaliado como uma string JavaScript e pode ser enriquecido com conteúdo dinâmico usando as variáveis injetadas <code>now</code> e <code>parentNote</code>. Exemplos:\n\n<ul>\n <li><code>${parentNote.getLabelValue('authorName')}'s literary works</code></li>\n <li><code>Log for ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n</ul>\n\nVeja a <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki com detalhes</a>, a documentação da API para <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> e para <a href=\"https://day.js.org/docs/en/display/format\">now</a> para mais informações.",
"template": "Esta nota aparecerá na seleção de modelos disponíveis ao criar uma nova nota",
"toc": "<code>#toc</code> ou <code>#toc=show</code> irá forçar a exibição do Sumário, <code>#toc=hide</code> irá forçar que ele fique oculto. Se o rótulo não existir, será considerado o ajuste global",
"color": "define a cor da nota na árvore de notas, links etc. Use qualquer valor de cor CSS válido, como 'red' ou #a13d5f",
"keyboard_shortcut": "Define um atalho de teclado que irá pular imediatamente para esta nota. Exemplo: 'ctrl+alt+e'. É necessário recarregar o frontend para que a alteração tenha efeito."
}
}

View File

@@ -37,7 +37,7 @@
"link_title_mirrors": "titlul legăturii corespunde titlul curent al notiței",
"note": "Notiță",
"search_note": "căutați notița după nume",
"button_add_link": "Adaugă legătură <kbd>Enter</kbd>"
"button_add_link": "Adaugă legătură"
},
"add_relation": {
"add_relation": "Adaugă relație",
@@ -232,7 +232,8 @@
"workspace_template": "Această notița va apărea în lista de șabloane când se crează o nouă notiță, dar doar când spațiul de lucru în care se află notița este focalizat",
"app_theme_base": "setați valoarea la „next” pentru a folosi drept temă de bază „TriliumNext” în loc de cea clasică.",
"print_landscape": "Schimbă orientarea paginii din portret în vedere atunci când se exportă în PDF.",
"print_page_size": "Schimbă dimensiunea paginii când se exportă în PDF. Valori suportate: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>."
"print_page_size": "Schimbă dimensiunea paginii când se exportă în PDF. Valori suportate: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
"color_type": "Culoare"
},
"attribute_editor": {
"add_a_new_attribute": "Adaugă un nou attribut",
@@ -274,7 +275,6 @@
"no_children_help": "Această notiță de tip Carte nu are nicio subnotiță așadar nu este nimic de afișat. Vedeți <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> pentru detalii."
},
"book_properties": {
"book_properties": "",
"collapse": "Minimizează",
"collapse_all_notes": "Minimizează toate notițele",
"expand": "Expandează",
@@ -283,7 +283,11 @@
"invalid_view_type": "Mod de afișare incorect „{{type}}”",
"list": "Listă",
"view_type": "Mod de afișare",
"calendar": "Calendar"
"calendar": "Calendar",
"book_properties": "Proprietăți colecție",
"table": "Tabel",
"geo-map": "Hartă geografică",
"board": "Tablă Kanban"
},
"bookmark_switch": {
"bookmark": "Semn de carte",
@@ -333,11 +337,12 @@
"sun": "Dum",
"thu": "Joi",
"tue": "Mar",
"wed": "Mie"
"wed": "Mie",
"cannot_find_week_note": "Nu s-a putut găsi notița săptămânală"
},
"clone_to": {
"clone_notes_to": "Clonează notițele către...",
"clone_to_selected_note": "Clonează notița selectată <kbd>enter</kbd>",
"clone_to_selected_note": "Clonează notița selectată",
"cloned_note_prefix_title": "Notița clonată va fi afișată în ierarhia notiței utilizând prefixul dat",
"help_on_links": "Informații despre legături",
"no_path_to_clone_to": "Nicio cale de clonat.",
@@ -431,14 +436,14 @@
"undelete_notes_instruction": "După ștergere, se pot recupera din ecranul Schimbări recente."
},
"delete_notes": {
"broken_relations_to_be_deleted": "Următoarele relații vor fi întrerupte și șterse ({{- relationCount}})",
"broken_relations_to_be_deleted": "Următoarele relații vor fi întrerupte și șterse ({{ relationCount}})",
"cancel": "Anulează",
"delete_all_clones_description": "Șterge și toate clonele (se pot recupera în ecranul Schimbări recente)",
"delete_notes_preview": "Previzualizare ștergerea notițelor",
"erase_notes_description": "Ștergerea obișnuită doar marchează notițele ca fiind șterse și pot fi recuperate (în ecranul Schimbări recente) pentru o perioadă de timp. Dacă se bifează această opțiune, notițele vor fi șterse imediat fără posibilitatea de a le recupera.",
"erase_notes_warning": "Șterge notițele permanent (nu se mai pot recupera), incluzând toate clonele. Va forța reîncărcarea aplicației.",
"no_note_to_delete": "Nicio notiță nu va fi ștearsă (doar clonele).",
"notes_to_be_deleted": "Următoarele notițe vor fi șterse ({{- noteCount}})",
"notes_to_be_deleted": "Următoarele notițe vor fi șterse ({{notesCount}})",
"ok": "OK",
"deleted_relation_text": "Notița {{- note}} ce va fi ștearsă este referențiată de relația {{- relation}}, originând din {{- source}}.",
"close": "Închide"
@@ -612,11 +617,11 @@
"bulletList": "<code>*</code> sau <code>-</code> urmat de spațiu pentru o listă punctată",
"close": "Închide",
"closeActiveTab": "închide tabul activ",
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - minimizează/expandează nodul",
"collapseExpand": "minimizează/expandează nodul",
"collapseSubTree": "minimizează subarborele",
"collapseWholeTree": "minimizează întregul arbore de notițe",
"copyNotes": "copiază notița activă (sau selecția curentă) în clipboard (utilizat pentru <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonare</a>)",
"createEditLink": "<kbd>Ctrl+K</kbd> - crează/editează legătură externă",
"createEditLink": "crează/editează legătură externă",
"createInternalLink": "crează legătură internă",
"createNoteAfter": "crează o nouă notiță după notița activă",
"createNoteInto": "crează o subnotiță în notița activă",
@@ -627,20 +632,19 @@
"editNoteTitle": "va sări de la arborele de notițe către titlul notiței. Enter de la titlul notiței va sări către editorul de text. <kbd>Ctrl+.</kbd> va sări înapoi de la editor către arborele de notițe.",
"editingNotes": "Editarea notițelor",
"followLink": "urmărește link-ul sub cursor",
"fullDocumentation": "Instrucțiuni (documentația completă se regăsește <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
"goBackForwards": "mergi înapoi/înainte în istoric",
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - mergi sus/jos în lista de notițe",
"goUpDown": "mergi sus/jos în lista de notițe",
"headings": "<code>##</code>, <code>###</code>, <code>####</code> etc. urmat de spațiu pentru titluri",
"inPageSearch": "caută în interiorul paginii",
"insertDateTime": "inserează data și timpul curente la poziția cursorului",
"jumpToParentNote": "<kbd>Backspace</kbd> - sari la pagina părinte",
"jumpToParentNote": "sari la pagina părinte",
"jumpToTreePane": "sari către arborele de notițe și scrolează către notița activă",
"markdownAutoformat": "Formatare în stil Markdown",
"moveNoteUpDown": "mută notița sus/jos în lista de notițe",
"moveNoteUpHierarchy": "mută notița mai sus în ierarhie",
"movingCloningNotes": "Mutarea/clonarea notițelor",
"multiSelectNote": "selectează multiplu notița de sus/jos",
"newTabNoteLink": "<kbd>CTRL+clic</kbd> - (sau clic mijlociu) pe o legătură către o notiță va deschide notița într-un tab nou",
"newTabNoteLink": "pe o legătură către o notiță va deschide notița într-un tab nou",
"notSet": "nesetat",
"noteNavigation": "Navigarea printre notițe",
"numberedList": "<kbd>1.</code> sau <code>1)</code> urmat de spațiu pentru o listă numerotată",
@@ -652,12 +656,13 @@
"reloadFrontend": "reîncarcă interfața Trilium",
"scrollToActiveNote": "scrolează la notița activă",
"selectAllNotes": "selectează toate notițele din nivelul curent",
"selectNote": "<kbd>Shift+Click</kbd> - selectează notița",
"selectNote": "selectează notița",
"showDevTools": "afișează instrumentele de dezvoltatori",
"showJumpToNoteDialog": "afișează <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">ecranul „Sari la”</a>",
"showSQLConsole": "afișează consola SQL",
"tabShortcuts": "Scurtături pentru tab-uri",
"troubleshooting": "Unelte pentru depanare"
"troubleshooting": "Unelte pentru depanare",
"newTabWithActivationNoteLink": "pe o legătură către o notiță deschide și activează notița într-un tab nou"
},
"hide_floating_buttons_button": {
"button_title": "Ascunde butoanele"
@@ -680,7 +685,14 @@
"monday": "Luni",
"sunday": "Duminică",
"title": "Localizare",
"formatting-locale": "Format dată și numere"
"formatting-locale": "Format dată și numere",
"first-week-of-the-year": "Prima săptămână din an",
"first-week-contains-first-day": "Prima săptămână conține prima zi din an",
"first-week-contains-first-thursday": "Prima săptămână conține prima zi de joi din an",
"first-week-has-minimum-days": "Prima săptămână are numărul minim de zile",
"min-days-in-first-week": "Numărul minim de zile pentru prima săptămână",
"first-week-info": "Opțiunea de prima săptămână conține prima zi de joi din an este bazată pe standardul <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Schimbarea opțiunii primei săptămâni poate cauza duplicate cu notițele săptămânale existente deoarece acestea nu vor fi actualizate retroactiv."
},
"image_properties": {
"copy_reference_to_clipboard": "Copiază referință în clipboard",
@@ -738,7 +750,7 @@
"box_size_medium": "mediu (~ 30 de rânduri)",
"box_size_prompt": "Dimensiunea căsuței notiței incluse:",
"box_size_small": "mică (~ 10 rânduri)",
"button_include": "Include notița <kbd>Enter</kbd>",
"button_include": "Include notița",
"dialog_title": "Includere notița",
"label_note": "Notiță",
"placeholder_search": "căutați notița după denumirea ei",
@@ -754,9 +766,9 @@
"title": "Atribute moștenite"
},
"jump_to_note": {
"search_button": "Caută în întregul conținut <kbd>Ctrl+Enter</kbd>",
"search_placeholder": "căutați o notiță după denumirea ei",
"close": "Închide"
"search_button": "Caută în întregul conținut",
"close": "Închide",
"search_placeholder": "Căutați notițe după nume sau tastați > pentru comenzi..."
},
"left_pane_toggle": {
"hide_panel": "Ascunde panoul",
@@ -768,7 +780,7 @@
},
"markdown_import": {
"dialog_title": "Importă Markdown",
"import_button": "Importă Ctrl+Enter",
"import_button": "Importă",
"import_success": "Conținutul Markdown a fost importat în document.",
"modal_body_text": "Din cauza limitărilor la nivel de navigator, nu este posibilă citirea clipboard-ului din JavaScript. Inserați Markdown-ul pentru a-l importa în caseta de mai jos și dați clic pe butonul Import",
"close": "Închide"
@@ -804,7 +816,7 @@
"move_to": {
"dialog_title": "Mută notițele în...",
"error_no_path": "Nicio cale la care să poată fi mutate.",
"move_button": "Mută la notița selectată <kbd>enter</kbd>",
"move_button": "Mută la notița selectată",
"move_success_message": "Notițele selectate au fost mutate în",
"notes_to_move": "Notițe de mutat",
"search_placeholder": "căutați notița după denumirea ei",
@@ -884,8 +896,10 @@
"note_type_chooser": {
"modal_body": "Selectați tipul notiței/șablonul pentru noua notiță:",
"modal_title": "Selectați tipul notiței",
"templates": "Șabloane:",
"close": "Închide"
"templates": "Șabloane",
"close": "Închide",
"change_path_prompt": "Selectați locul unde să se creeze noua notiță:",
"search_placeholder": "căutare cale notiță după nume (cea implicită dacă este necompletat)"
},
"onclick_button": {
"no_click_handler": "Butonul „{{componentId}}” nu are nicio acțiune la clic definită"
@@ -939,7 +953,6 @@
},
"password_not_set": {
"body1": "Notițele protejate sunt criptate utilizând parola de utilizator, dar nu a fost setată nicio parolă.",
"body2": "Pentru a putea să protejați notițe, clic <a class=\"open-password-options-button\" href=\"javascript:\">aici</a> pentru a deschide ecranul de opțiuni și pentru a seta parola.",
"title": "Parola nu este setată",
"close": "Închide"
},
@@ -951,11 +964,12 @@
"unknown_attribute_type": "Tip de atribut necunoscut „{{type}}”",
"unknown_label_type": "Tip de etichetă necunoscut „{{type}}”",
"url_placeholder": "http://siteweb...",
"unset-field-placeholder": "nesetat"
"unset-field-placeholder": "nesetat",
"remove_color": "Înlătura culoarea"
},
"prompt": {
"defaultTitle": "Aviz",
"ok": "OK <kbd>enter</kbd>",
"ok": "OK",
"title": "Aviz",
"close": "Închide"
},
@@ -976,7 +990,7 @@
"form_label": "Pentru a putea continua cu acțiunea cerută este nevoie să fie pornită sesiunea protejată prin introducerea parolei:",
"help_title": "Informații despre notițe protejate",
"modal_title": "Sesiune protejată",
"start_button": "Pornește sesiunea protejată <kbd>enter</kbd>"
"start_button": "Pornește sesiunea protejată"
},
"protected_session_status": {
"active": "Sesiunea protejată este activă. Clic pentru a închide sesiunea protejată.",
@@ -1177,7 +1191,7 @@
"folders": "Dosare",
"natural_sort": "Ordonare naturală",
"natural_sort_language": "Limba pentru ordonare naturală",
"sort": "Ordonare <kbd>Enter</kbd>",
"sort": "Ordonare",
"sort_children_by": "Ordonează subnotițele după...",
"sort_folders_at_top": "ordonează dosarele primele",
"sort_with_respect_to_different_character_sorting": "ordonează respectând regulile de sortare și clasificare diferite în funcție de limbă și regiune.",
@@ -1295,7 +1309,7 @@
},
"upload_attachments": {
"choose_files": "Selectați fișierele",
"files_will_be_uploaded": "Fișierele vor fi încărcate ca atașamente în",
"files_will_be_uploaded": "Fișierele vor fi încărcate ca atașamente în {{noteTitle}}",
"options": "Opțuni",
"shrink_images": "Micșorează imaginile",
"tooltip": "Dacă această opțiune este bifată, Trilium va încerca micșorarea imaginilor încărcate prin scalarea și optimizarea lor, aspect ce va putea afecta calitatea imaginilor. Dacă nu este bifată, imaginile vor fi încărcate fără nicio schimbare.",
@@ -1369,7 +1383,8 @@
"hoist-note": "Focalizează notița",
"unhoist-note": "Defocalizează notița",
"converted-to-attachments": "{{count}} notițe au fost convertite în atașamente.",
"convert-to-attachment-confirm": "Doriți convertirea notițelor selectate în atașamente ale notiței părinte?"
"convert-to-attachment-confirm": "Doriți convertirea notițelor selectate în atașamente ale notiței părinte?",
"open-in-popup": "Editare rapidă"
},
"shared_info": {
"help_link": "Pentru informații vizitați <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki-ul</a>.",
@@ -1377,7 +1392,7 @@
"shared_publicly": "Această notiță este partajată public la"
},
"note_types": {
"book": "Carte",
"book": "Colecție",
"canvas": "Schiță",
"code": "Cod sursă",
"mermaid-diagram": "Diagramă Mermaid",
@@ -1396,7 +1411,10 @@
"confirm-change": "Nu se recomandă schimbarea tipului notiței atunci când ea are un conținut. Procedați oricum?",
"geo-map": "Hartă geografică",
"beta-feature": "Beta",
"task-list": "Listă de sarcini"
"task-list": "Listă de sarcini",
"ai-chat": "Discuție cu AI-ul",
"new-feature": "Nou",
"collections": "Colecții"
},
"protect_note": {
"toggle-off": "Deprotejează notița",
@@ -1530,7 +1548,9 @@
},
"clipboard": {
"copied": "Notițele au fost copiate în clipboard.",
"cut": "Notițele au fost decupate în clipboard."
"cut": "Notițele au fost decupate în clipboard.",
"copy_failed": "Nu se poate copia în clipboard din cauza unor probleme de permisiuni.",
"copy_success": "S-a copiat în clipboard."
},
"entrypoints": {
"note-executed": "Notița a fost executată.",
@@ -1581,14 +1601,15 @@
},
"highlighting": {
"color-scheme": "Temă de culori",
"title": "",
"description": "Controlează evidențierea de sintaxă pentru blocurile de cod în interiorul notițelor text, notițele de tip cod nu vor fi afectate de aceste setări."
"description": "Controlează evidențierea de sintaxă pentru blocurile de cod în interiorul notițelor text, notițele de tip cod nu vor fi afectate de aceste setări.",
"title": "Blocuri de cod"
},
"code_block": {
"word_wrapping": "Încadrare text",
"theme_none": "Fără evidențiere de sintaxă",
"theme_group_dark": "Teme întunecate",
"theme_group_light": "Teme luminoase"
"theme_group_light": "Teme luminoase",
"copy_title": "Copiază în clipboard"
},
"classic_editor_toolbar": {
"title": "Formatare"
@@ -1626,7 +1647,8 @@
"link_context_menu": {
"open_note_in_new_split": "Deschide notița într-un panou nou",
"open_note_in_new_tab": "Deschide notița într-un tab nou",
"open_note_in_new_window": "Deschide notița într-o fereastră nouă"
"open_note_in_new_window": "Deschide notița într-o fereastră nouă",
"open_note_in_popup": "Editare rapidă"
},
"note_autocomplete": {
"clear-text-field": "Șterge conținutul casetei",
@@ -1646,7 +1668,8 @@
"zoom-factor": "Factor de zoom"
},
"note_tooltip": {
"note-has-been-deleted": "Notița a fost ștearsă."
"note-has-been-deleted": "Notița a fost ștearsă.",
"quick-edit": "Editare rapidă"
},
"notes": {
"duplicate-note-suffix": "(dupl.)",
@@ -1654,11 +1677,13 @@
},
"geo-map-context": {
"open-location": "Deschide locația",
"remove-from-map": "Înlătură de pe hartă"
"remove-from-map": "Înlătură de pe hartă",
"add-note": "Adaugă un marcaj la această poziție"
},
"geo-map": {
"create-child-note-title": "Crează o notiță nouă și adaug-o pe hartă",
"unable-to-load-map": "Nu s-a putut încărca harta."
"unable-to-load-map": "Nu s-a putut încărca harta.",
"create-child-note-instruction": "Click pe hartă pentru a crea o nouă notiță la acea poziție sau apăsați Escape pentru a anula."
},
"duration": {
"days": "zile",
@@ -1721,5 +1746,274 @@
"toggle_read_only_button": {
"lock-editing": "Blochează editarea",
"unlock-editing": "Deblochează editarea"
},
"ai_llm": {
"not_started": "Nu s-a pornit",
"title": "Setări AI",
"processed_notes": "Notițe procesate",
"total_notes": "Totalul de notițe",
"progress": "Progres",
"queued_notes": "Notițe în curs de procesare",
"failed_notes": "Notițe ce au eșuat",
"last_processed": "Ultima procesare",
"refresh_stats": "Reîmprospătare statistici",
"enable_ai_features": "Activează funcțiile AI/LLM",
"enable_ai_description": "Activează funcțiile AI precum sumarizarea notițelor, generarea de conținut și alte capabilități ale LLM-ului",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Activează funcții AI/LLM",
"enable_ai_desc": "Activează funcțiile AI precum sumarizarea notițelor, generarea de conținut și alte capabilități ale LLM-ului",
"provider_configuration": "Setările furnizorului de AI",
"provider_precedence": "Ordinea de precedență a furnizorilor",
"provider_precedence_description": "Lista de furnizori în ordinea de precedență, separate de virgulă (ex. „openai,anthropic,ollama”)",
"temperature": "Temperatură",
"temperature_description": "Controlează aleatoritatea din răspunsuri (0 = deterministic, 2 = maxim aleator)",
"system_prompt": "Prompt-ul de sistem",
"system_prompt_description": "Prompt-ul de sistem folosit pentru toate interacțiunile cu AI-ul",
"openai_configuration": "Configurația OpenAI",
"openai_settings": "Setările OpenAI",
"api_key": "Cheie API",
"url": "URL de bază",
"model": "Model",
"openai_api_key_description": "Cheia de API din OpenAI pentru a putea accesa serviciile de AI",
"anthropic_api_key_description": "Cheia de API din Anthropic pentru a accesa modelele Claude",
"default_model": "Modelul implicit",
"openai_model_description": "Exemple: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL de bază",
"openai_url_description": "Implicit: https://api.openai.com/v1",
"anthropic_settings": "Setări Anthropic",
"anthropic_url_description": "URL de bază pentru API-ul Anthropic (implicit: https://api.anthropic.com)",
"anthropic_model_description": "Modele Anthropic Claude pentru auto-completare",
"voyage_settings": "Setări Voyage AI",
"ollama_settings": "Setări Ollama",
"ollama_url_description": "URL pentru API-ul Ollama (implicit: http://localhost:11434)",
"ollama_model_description": "Modelul Ollama pentru auto-completare",
"anthropic_configuration": "Configurația Anthropic",
"voyage_configuration": "Configurația Voyage AI",
"voyage_url_description": "Implicit: https://api.voyageai.com/v1",
"ollama_configuration": "Configurația Ollama",
"enable_ollama": "Activează Ollama",
"enable_ollama_description": "Activează Ollama pentru a putea utiliza modele AI locale",
"ollama_url": "URL Ollama",
"ollama_model": "Model Ollama",
"refresh_models": "Reîmprospătează modelele",
"refreshing_models": "Reîmprospătare...",
"enable_automatic_indexing": "Activează indexarea automată",
"rebuild_index": "Reconstruire index",
"rebuild_index_error": "Eroare la reconstruirea indexului. Verificați logurile pentru mai multe detalii.",
"note_title": "Titlul notiței",
"error": "Eroare",
"last_attempt": "Ultima încercare",
"actions": "Acțiuni",
"retry": "Reîncercare",
"partial": "{{ percentage }}% finalizat",
"retry_queued": "Notiță pusă în coadă pentru reîncercare",
"retry_failed": "Nu s-a putut pune notița în coada pentru reîncercare",
"max_notes_per_llm_query": "Număr maximum de notițe per interogare",
"max_notes_per_llm_query_description": "Numărul maxim de notițe similare incluse în contextul pentru AI",
"active_providers": "Furnizori activi",
"disabled_providers": "Furnizori dezactivați",
"remove_provider": "Șterge furnizorul din căutare",
"restore_provider": "Restaurează furnizorul pentru căutare",
"similarity_threshold": "Prag de similaritate",
"similarity_threshold_description": "Scorul minim de similaritate (0-1) pentru a include notițele în contextul interogărilor LLM",
"reprocess_index": "Reconstruiește indexul de căutare",
"reprocessing_index": "Reconstruire...",
"reprocess_index_started": "S-a pornit în fundal optimizarea indexului de căutare",
"reprocess_index_error": "Eroare la reconstruirea indexului de căutare",
"index_rebuild_progress": "Reconstruire index în curs",
"index_rebuilding": "Optimizare index ({{percentage}}%)",
"index_rebuild_complete": "Optimizarea indexului a avut loc cu succes",
"index_rebuild_status_error": "Eroare la verificarea stării reconstruirii indexului",
"never": "Niciodată",
"processing": "Procesare ({{percentage}}%)",
"incomplete": "Incomplet ({{percentage}}%)",
"complete": "Complet (100%)",
"refreshing": "Reîmprospătare...",
"auto_refresh_notice": "Reîmprospătare automată la fiecare {{seconds}} secunde",
"note_queued_for_retry": "Notiță pusă în coadă pentru reîncercare",
"failed_to_retry_note": "Eroare la reîncercarea notiței",
"all_notes_queued_for_retry": "Toate notițele eșuate au fost puse în coada de reîncercare",
"failed_to_retry_all": "Eroare la reîncercarea notițelor",
"ai_settings": "Setări AI",
"api_key_tooltip": "Cheia API pentru accesarea serviciului",
"empty_key_warning": {
"anthropic": "Cheia API pentru Anthropic lipsește. Introduceți o cheie API validă.",
"openai": "Cheia API pentru OpenAI lipsește. Introduceți o cheie API validă.",
"voyage": "Cheia API pentru Voyage lipsește. Introduceți o cheie API validă.",
"ollama": "Cheia API pentru Ollama lipsește. Introduceți o cheie API validă."
},
"agent": {
"processing": "Procesare...",
"thinking": "Raționalizare...",
"loading": "Încărcare...",
"generating": "Generare..."
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "Folosește context îmbogățit",
"enhanced_context_description": "Oferă AI-ului mai multe informații de context din notiță și notițele similare pentru răspunsuri mai bune",
"show_thinking": "Afișează procesul de raționalizare",
"show_thinking_description": "Afișează lanțul de acțiuni din procesul de gândire al AI-ului",
"enter_message": "Introduceți mesajul...",
"error_contacting_provider": "Eroare la contactarea furnizorului de AI. Verificați setările și conexiunea la internet.",
"error_generating_response": "Eroare la generarea răspunsului AI",
"index_all_notes": "Indexează toate notițele",
"index_status": "Starea indexării",
"indexed_notes": "Notițe indexate",
"indexing_stopped": "Indexarea s-a oprit",
"indexing_in_progress": "Indexare în curs...",
"last_indexed": "Ultima indexare",
"n_notes_queued_0": "O notiță adăugată în coada de indexare",
"n_notes_queued_1": "{{ count }} notițe adăugate în coada de indexare",
"n_notes_queued_2": "{{ count }} de notițe adăugate în coada de indexare",
"note_chat": "Discuție pe baza notițelor",
"notes_indexed_0": "O notiță indexată",
"notes_indexed_1": "{{ count }} notițe indexate",
"notes_indexed_2": "{{ count }} de notițe indexate",
"sources": "Surse",
"start_indexing": "Indexează",
"use_advanced_context": "Folosește context îmbogățit",
"ollama_no_url": "Ollama nu este configurat. Introduceți un URL corect.",
"chat": {
"root_note_title": "Discuții cu AI-ul",
"root_note_content": "Această notiță stochează conversația cu AI-ul.",
"new_chat_title": "Discuție nouă",
"create_new_ai_chat": "Crează o nouă discuție cu AI-ul"
},
"create_new_ai_chat": "Crează o nouă discuție cu AI-ul",
"configuration_warnings": "Sunt câteva probleme la configurația AI-ului. Verificați setările.",
"experimental_warning": "Funcția LLM este experimentală!",
"selected_provider": "Furnizor selectat",
"selected_provider_description": "Selectați furnizorul de AI pentru funcțiile de discuție și completare",
"select_model": "Selectați modelul...",
"select_provider": "Selectați furnizorul..."
},
"custom_date_time_format": {
"title": "Format dată/timp personalizat",
"description": "Personalizați formatul de dată și timp inserat prin <kbd></kbd> sau din bara de unelte. Vedeți <a href=\"https://day.js.org/docs/en/display/format\" target=\"_blank\" rel=\"noopener noreferrer\">Documentația Day.js</a> pentru câmpurile de formatare disponibile.",
"format_string": "Șir de formatare:",
"formatted_time": "Data și ora formatate:"
},
"multi_factor_authentication": {
"title": "Autentificare multi-factor",
"description": "Autentificarea multifactor (MFA) adaugă un strat de securitate adițional. Pe lângă introducerea parolei pentru atentificare, este necesară o dovadă adițională pentru a verifica identitatea. În acest fel, chiar dacă cineva este în posesia parolei dvs., nu vor putea accesa contul fără dovada adițională.<br><br>Urmați instrucțiunile de mai jos pentru a activa MFA. Dacă configurația nu este corectă, autentificarea va face doar cu parolă.",
"mfa_enabled": "Activare autentificare multi-factor",
"mfa_method": "Metodă MFA",
"electron_disabled": "Autentificarea multi-factor este suportată doar în aplicația desktop momentan.",
"totp_title": "Parolă unică bazată pe timp (TOTP)",
"totp_description": "TOTP (Time-Based One-Time Password) este o funcție de securitate care crează un cod unic, temporar care se schimbă la fiecare 30 de secunde. Acest cod se poate folosi pe lângă parolă pentru a face accesul neautorizat mult mai dificil.",
"totp_secret_title": "Generează secret TOTP",
"totp_secret_generate": "Generează secret TOTP",
"totp_secret_regenerate": "Regenerează secretul TOTP",
"no_totp_secret_warning": "Pentru a activa TOTP trebuie mai întâi generat un secret TOTP.",
"totp_secret_description_warning": "După generarea unui nou secret TOTP, va trebui să vă autentificați din nou cu folosirea codului TOTP.",
"totp_secret_generated": "Secret TOTP generat",
"totp_secret_warning": "Stocați secretul generat într-un loc securizat. Acesta nu va mai fi afișat din nou.",
"totp_secret_regenerate_confirm": "Doriți regenerarea secretului TOTP? Acest lucru va invalida secretul TOTP anterior și toate codurile de recuperere preexistente.",
"recovery_keys_title": "Chei unice de recuperare",
"recovery_keys_description": "Fiecare cheie unică poate fi folosită o singură dată pentru autentificare chiar dacă nu mai aveți acces la codurile generate.",
"recovery_keys_description_warning": "Cheile de recuperare nu vor mai fi afișate după părăsirea acestei pagini; păstrați-le într-un loc sigur.<br>Odată ce o cheie de recuperare este folosită, ea nu mai poate fi refolosită.",
"recovery_keys_error": "Eroare la generarea codurilor de recuperare",
"recovery_keys_no_key_set": "Niciun cod de recuperare nu a fost setat",
"recovery_keys_generate": "Generează codurile de recuperare",
"recovery_keys_regenerate": "Regenerează codurile de recuperare",
"recovery_keys_used": "Folosit la: {{date}}",
"recovery_keys_unused": "Codul de recuperere {{index}} este nefolosit",
"oauth_title": "OAuth/OpenID",
"oauth_description": "OpenID este o cale standardizată ce permite autentificarea într-un site folosind un cont dintr-un alt serviciu, precum Google, pentru a verifica identitatea. În mod implicit furnizorul este Google, dar se poate schimba cu orice furnizor OpenID. Pentru mai multe informații, consultați <a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">ghidul</a>. Urmați <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">aceste instrucțiuni</a> pentru a putea configura OpenID prin Google.",
"oauth_description_warning": "Pentru a activa OAuth sau OpenID, trebuie să configurați URL-ul de bază, ID-ul de client și secretul de client în fișierul config.ini și să reporniți aplicația. Dacă doriți să utilizați variabile de environment, puteți seta TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID și TRILIUM_OAUTH_CLIENT_SECRET.",
"oauth_missing_vars": "Setări lipsă: {{variables}}",
"oauth_user_account": "Cont: ",
"oauth_user_email": "Email: ",
"oauth_user_not_logged_in": "Neautentificat!"
},
"svg": {
"export_to_png": "Diagrama nu a putut fi exportată în PNG."
},
"code_theme": {
"title": "Afișare",
"word_wrapping": "Încadrare text",
"color-scheme": "Temă de culori"
},
"cpu_arch_warning": {
"title": "Descărcați versiunea de ARM64",
"message_macos": "Aplicația rulează momentan sub stratul de translație Rosetta 2, ceea ce înseamnă că folosiți versiunea de Intel (x64) pe un Mac cu Apple Silicon. Acest lucru impactează semnificativ performanța aplicației și durata de viață a bateriei.",
"message_windows": "Aplicația rulează în mod de emulare, ceea ce înseamnă că folosiți versiunea de Intel (x64) pe un dispozitiv Windows pe ARM. Acest lucru impactează semnificativ performanția aplicației și durata de viață a bateriei.",
"recommendation": "Pentru cea mai bună experiență, descărcați versiunea nativă de ARM64 a aplicației de pe pagina de release-uri.",
"download_link": "Descarcă versiunea nativă",
"continue_anyway": "Continuă oricum",
"dont_show_again": "Nu mai afișa acest mesaj"
},
"editorfeatures": {
"title": "Funcții",
"emoji_completion_enabled": "Activează auto-completarea pentru emoji-uri",
"note_completion_enabled": "Activează auto-completarea pentru notițe"
},
"table_view": {
"new-row": "Rând nou",
"new-column": "Coloană nouă",
"sort-column-by": "Ordonează după „{{title}}”",
"sort-column-ascending": "Ascendent",
"sort-column-descending": "Descendent",
"sort-column-clear": "Dezactivează ordonarea",
"hide-column": "Ascunde coloana „{{title}}”",
"show-hide-columns": "Afișează/ascunde coloane",
"row-insert-above": "Inserează rând deasupra",
"row-insert-below": "Inserează rând dedesubt",
"row-insert-child": "Inserează subnotiță",
"add-column-to-the-left": "Adaugă coloană la stânga",
"add-column-to-the-right": "Adaugă coloană la dreapta",
"edit-column": "Editează coloana",
"delete_column_confirmation": "Doriți ștergerea acestei coloane? Atributul corespunzător va fi șters din toate notițele din ierarhie.",
"delete-column": "Șterge coloana",
"new-column-label": "Etichetă",
"new-column-relation": "Relație"
},
"book_properties_config": {
"hide-weekends": "Ascunde weekend-urile",
"display-week-numbers": "Afișează numărul săptămânii",
"map-style": "Stil hartă:",
"max-nesting-depth": "Nivel maxim de imbricare:",
"raster": "Raster",
"vector_light": "Vectorial (culoare deschisă)",
"vector_dark": "Vectorial (culoare închisă)",
"show-scale": "Afișează scara hărții"
},
"table_context_menu": {
"delete_row": "Șterge rândul"
},
"board_view": {
"delete-note": "Șterge notița",
"move-to": "Mută la",
"insert-above": "Inserează deasupra",
"insert-below": "Inserează dedesubt",
"delete-column": "Șterge coloana",
"delete-column-confirmation": "Doriți ștergerea acestei coloane? Atributul corespunzător va fi șters din notițele din acest tabel.",
"new-item": "Intrare nouă",
"add-column": "Adaugă coloană"
},
"command_palette": {
"tree-action-name": "Listă de notițe: {{name}}",
"export_note_title": "Exportă notița",
"export_note_description": "Exportă notița curentă",
"show_attachments_title": "Afișează atașamentele",
"show_attachments_description": "Vedeți lista de atașamente corespunzătoare notiței",
"search_notes_title": "Căutare notițe",
"search_notes_description": "Deschide căutare avansată",
"search_subtree_title": "Caută în ierarhie",
"search_subtree_description": "Caută în notițele din ierarhia curentă",
"search_history_title": "Afișează istoricul de căutare",
"search_history_description": "Afișează căutarile anterioare",
"configure_launch_bar_title": "Configurează bara de lansare",
"configure_launch_bar_description": "Deschide configurația barei de lansare, pentru a putea adăuga sau ștergere intrări."
},
"content_renderer": {
"open_externally": "Deschide în afara programului"
},
"modal": {
"close": "Închide"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,517 @@
{
"about": {
"title": "O Trilium Belеškama",
"close": "Zatvori",
"homepage": "Početna stranica:",
"app_version": "Verzija aplikacije:",
"db_version": "Verzija baze podataka:",
"sync_version": "Verzija sinhronizacije:",
"build_date": "Datum izgradnje:",
"build_revision": "Revizija izgradnje:",
"data_directory": "Direktorijum sa podacima:"
},
"toast": {
"critical-error": {
"title": "Kritična greška",
"message": "Došlo je do kritične greške koja sprečava pokretanje klijentske aplikacije.\n\n{{message}}\n\nOva greška je najverovatnije izazvana neočekivanim problemom prilikom izvršavanja skripte. Pokušajte da pokrenete aplikaciju u bezbednom režimu i da pronađete šta izaziva grešku."
},
"widget-error": {
"title": "Pokretanje vidžeta nije uspelo",
"message-custom": "Prilagođeni viđet sa beleške sa ID-jem \"{{id}}\", nazivom \"{{title}}\" nije uspeo da se pokrene zbog:\n\n{{message}}",
"message-unknown": "Nepoznati vidžet nije mogao da se pokrene zbog:\n\n{{message}}"
},
"bundle-error": {
"title": "Pokretanje prilagođene skripte neuspešno",
"message": "Skripta iz beleške sa ID-jem \"{{id}}\", naslovom \"{{title}}\" nije mogla da se izvrši zbog:\n\n{{message}}"
}
},
"add_link": {
"add_link": "Dodaj link",
"help_on_links": "Pomoć na linkovima",
"close": "Zatvori",
"note": "Beleška",
"search_note": "potražite belešku po njenom imenu",
"link_title_mirrors": "naziv linka preslikava trenutan naziv beleške",
"link_title_arbitrary": "naziv linka se može proizvoljno menjati",
"link_title": "Naziv linka",
"button_add_link": "Dodaj link <kbd>enter</kbd>"
},
"branch_prefix": {
"edit_branch_prefix": "Izmeni prefiks grane",
"help_on_tree_prefix": "Pomoć na prefiksu Drveta",
"close": "Zatvori",
"prefix": "Prefiks: ",
"save": "Sačuvaj",
"branch_prefix_saved": "Prefiks grane je sačuvan."
},
"bulk_actions": {
"bulk_actions": "Grupne akcije",
"close": "Zatvori",
"affected_notes": "Pogođene beleške",
"include_descendants": "Obuhvati potomke izabranih beleški",
"available_actions": "Dostupne akcije",
"chosen_actions": "Izabrane akcije",
"execute_bulk_actions": "Izvrši grupne akcije",
"bulk_actions_executed": "Grupne akcije su uspešno izvršene.",
"none_yet": "Nijedna za sad... dodajte akciju tako što ćete pritisnuti na neku od dostupnih akcija iznad.",
"labels": "Oznake",
"relations": "Odnosi",
"notes": "Beleške",
"other": "Ostalo"
},
"clone_to": {
"clone_notes_to": "Klonirajte beleške u...",
"close": "Zatvori",
"help_on_links": "Pomoć na linkovima",
"notes_to_clone": "Beleške za kloniranje",
"target_parent_note": "Ciljna nadređena beleška",
"search_for_note_by_its_name": "potražite belešku po njenom imenu",
"cloned_note_prefix_title": "Klonirana beleška će biti prikazana u drvetu beleški sa datim prefiksom",
"prefix_optional": "Prefiks (opciono)",
"clone_to_selected_note": "Kloniranje u izabranu belešku <kbd>enter</kbd>",
"no_path_to_clone_to": "Nema putanje za kloniranje.",
"note_cloned": "Beleška \"{{clonedTitle}}\" je klonirana u \"{{targetTitle}}\""
},
"confirm": {
"confirmation": "Potvrda",
"close": "Zatvori",
"cancel": "Otkaži",
"ok": "U redu",
"are_you_sure_remove_note": "Da li ste sigurni da želite da uklonite belešku \"{{title}}\" iz mape odnosa? ",
"if_you_dont_check": "Ako ne izaberete ovo, beleška će biti uklonjena samo sa mape odnosa.",
"also_delete_note": "Takođe obriši belešku"
},
"delete_notes": {
"delete_notes_preview": "Obriši pregled beleške",
"close": "Zatvori",
"delete_all_clones_description": "Obriši i sve klonove (može biti poništeno u skorašnjim izmenama)",
"erase_notes_description": "Normalno (blago) brisanje samo označava beleške kao obrisane i one mogu biti vraćene (u dijalogu skorašnjih izmena) u određenom vremenskom periodu. Biranje ove opcije će momentalno obrisati beleške i ove beleške neće biti moguće vratiti.",
"erase_notes_warning": "Trajno obriši beleške (ne može se opozvati), uključujući sve klonove. Ovo će prisiliti aplikaciju da se ponovo pokrene.",
"notes_to_be_deleted": "Sledeće beleške će biti obrisane ({{- noteCount}})",
"no_note_to_delete": "Nijedna beleška neće biti obrisana (samo klonovi).",
"broken_relations_to_be_deleted": "Sledeći odnosi će biti prekinuti i obrisani ({{- relationCount}})",
"cancel": "Otkaži",
"ok": "U redu",
"deleted_relation_text": "Beleška {{- note}} (za brisanje) je referencirana sa odnosom {{- relation}} koji potiče iz {{- source}}."
},
"export": {
"export_note_title": "Izvezi belešku",
"close": "Zatvori",
"export_type_subtree": "Ova beleška i svi njeni potomci",
"format_html": "HTML - preporučuje se jer čuva formatiranje",
"format_html_zip": "HTML u ZIP arhivi - ovo se preporučuje jer se na taj način čuva celokupno formatiranje.",
"format_markdown": "Markdown - ovo čuva većinu formatiranja.",
"format_opml": "OPML - format za razmenu okvira samo za tekst. Formatiranje, slike i datoteke nisu uključeni.",
"opml_version_1": "OPML v1.0 - samo običan tekst",
"opml_version_2": "OPML v2.0 - dozvoljava i HTML",
"export_type_single": "Samo ovu belešku bez njenih potomaka",
"export": "Izvoz",
"choose_export_type": "Molimo vas da prvo izaberete tip izvoza",
"export_status": "Status izvoza",
"export_in_progress": "Izvoz u toku: {{progressCount}}",
"export_finished_successfully": "Izvoz je uspešno završen.",
"format_pdf": "PDF - za namene štampanja ili deljenja."
},
"help": {
"fullDocumentation": "Pomoć (puna dokumentacija je dostupna <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
"close": "Zatvori",
"noteNavigation": "Navigacija beleški",
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - kretanje gore/dole u listi sa beleškama",
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - sakupi/proširi čvor",
"notSet": "nije podešeno",
"goBackForwards": "idi u nazad/napred kroz istoriju",
"showJumpToNoteDialog": "prikaži <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Idi na\" dijalog</a>",
"scrollToActiveNote": "skroluj do aktivne beleške",
"jumpToParentNote": "idi do nadređene beleške",
"collapseWholeTree": "sakupi celo drvo beleški",
"collapseSubTree": "sakupi pod-drvo",
"tabShortcuts": "Prečice na karticama",
"newTabNoteLink": "na link beleške otvara belešku u novoj kartici",
"newTabWithActivationNoteLink": "na link beleške otvara i aktivira belešku u novoj kartici",
"onlyInDesktop": "Samo na dektop-u (Electron verzija)",
"openEmptyTab": "otvori praznu karticu",
"closeActiveTab": "zatvori aktivnu karticu",
"activateNextTab": "aktiviraj narednu karticu",
"activatePreviousTab": "aktiviraj prethodnu karticu",
"creatingNotes": "Pravljenje beleški",
"createNoteAfter": "napravi novu belešku nakon aktivne beleške",
"createNoteInto": "napravi novu pod-belešku u aktivnoj belešci",
"editBranchPrefix": "izmeni <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefiks</a> klona aktivne beleške",
"movingCloningNotes": "Premeštanje / kloniranje beleški",
"moveNoteUpDown": "pomeri belešku gore/dole u listi beleški",
"moveNoteUpHierarchy": "pomeri belešku na gore u hijerarhiji",
"multiSelectNote": "višestruki izbor beleški iznad/ispod",
"selectAllNotes": "izaberi sve beleške u trenutnom nivou",
"selectNote": "izaberi belešku",
"copyNotes": "kopiraj aktivnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">kloniranje</a>)",
"cutNotes": "iseci trenutnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za premeštanje beleški)",
"pasteNotes": "nalepi belešku/e kao podbelešku u aktivnoj belešci (koja se ili premešta ili klonira u zavisnosti od toga da li je beleška kopirana ili isečena u privremenu memoriju)",
"deleteNotes": "obriši belešku / podstablo",
"editingNotes": "Izmena beleški",
"editNoteTitle": "u ravni drveta će se prebaciti sa ravni drveta na naslov beleške. Ulaz sa naslova beleške će prebaciti fokus na uređivač teksta. <kbd>Ctrl+.</kbd> će se vratiti sa uređivača na ravan drveta.",
"createEditLink": "napravi / izmeni spoljašnji link",
"createInternalLink": "napravi unutrašnji link",
"followLink": "prati link ispod kursora",
"insertDateTime": "ubaci trenutan datum i vreme na poziciju kursora",
"jumpToTreePane": "idi na ravan stabla i pomeri se do aktivne beleške",
"markdownAutoformat": "Autoformatiranje kao u Markdown-u",
"headings": "<code>##</code>, <code>###</code>, <code>####</code> itd. praćeno razmakom za naslove",
"bulletList": "<code>*</code> ili <code>-</code> praćeno razmakom za listu sa tačkama",
"numberedList": "<code>1.</code> ili <code>1)</code> praćeno razmakom za numerisanu listu",
"blockQuote": "započnite liniju sa <code>></code> praćeno sa razmakom za blok citat",
"troubleshooting": "Rešavanje problema",
"reloadFrontend": "ponovo učitaj Trilium frontend",
"showDevTools": "prikaži alate za programere",
"showSQLConsole": "prikaži SQL konzolu",
"other": "Ostalo",
"quickSearch": "fokus na unos za brzu pretragu",
"inPageSearch": "pretraga unutar stranice"
},
"import": {
"importIntoNote": "Uvezi u belešku",
"close": "Zatvori",
"chooseImportFile": "Izaberi datoteku za uvoz",
"importDescription": "Sadržaj izabranih datoteka će biti uvezen kao podbeleške u",
"options": "Opcije",
"safeImportTooltip": "Trilium <code>.zip</code> izvozne datoteke mogu da sadrže izvršne skripte koje mogu imati štetno ponašanje. Bezbedan uvoz će deaktivirati automatsko izvršavanje svih uvezenih skripti. Isključite \"Bezbedan uvoz\" samo ako uvezena arhiva treba da sadrži izvršne skripte i ako potpuno verujete sadržaju uvezene datoteke.",
"safeImport": "Bezbedan uvoz",
"explodeArchivesTooltip": "Ako je ovo označeno onda će Trilium pročitati <code>.zip</code>, <code>.enex</code> i <code>.opml</code> datoteke i napraviti beleške od datoteka unutar tih arhiva. Ako nije označeno, Trilium će same arhive priložiti belešci.",
"explodeArchives": "Pročitaj sadržaj <code>.zip</code>, <code>.enex</code> i <code>.opml</code> arhiva.",
"shrinkImagesTooltip": "<p>Ako označite ovu opciju, Trilium će pokušati da smanji uvezene slike skaliranjem i optimizacijom što će možda uticati na kvalitet slike. Ako nije označeno, slike će biti uvezene bez promena.</p><p>Ovo se ne primenjuje na <code>.zip</code> uvoze sa metapodacima jer se tada podrazumeva da su te datoteke već optimizovane.</p>",
"shrinkImages": "Smanji slike",
"textImportedAsText": "Uvezi HTML, Markdown i TXT kao tekstualne beleške ako je nejasno iz metapodataka",
"codeImportedAsCode": "Uvezi prepoznate datoteke sa kodom (poput <code>.json</code>) ako beleške sa kodom ako nije jasno iz metapodataka",
"replaceUnderscoresWithSpaces": "Zameni podvlake sa razmacima u nazivima uvezenih beleški",
"import": "Uvezi",
"failed": "Uvoz nije uspeo: {{message}}.",
"html_import_tags": {
"title": "HTML oznake za uvoz",
"description": "Podesite koje HTML oznake trebaju biti sačuvane kada se uvoze beleške. Oznake koje se ne nalaze na listi će biti uklonjene tokom uvoza. Pojedine oznake (poput 'script') se uvek uklanjaju zbog bezbednosti.",
"placeholder": "Unesite HTML oznake, po jednu u svaki red",
"reset_button": "Vrati na podrazumevanu listu"
},
"import-status": "Status uvoza",
"in-progress": "Uvoz u toku: {{progress}}",
"successful": "Uvoz je uspešno završen."
},
"include_note": {
"dialog_title": "Uključi belešku",
"close": "Zatvori",
"label_note": "Beleška",
"placeholder_search": "pretraži belešku po njenom imenu",
"box_size_prompt": "Veličina kutije priložene beleške:",
"box_size_small": "mala (~ 10 redova)",
"box_size_medium": "srednja (~ 30 redova)",
"box_size_full": "puna (kutija prikazuje ceo tekst)",
"button_include": "Uključi belešku"
},
"info": {
"modalTitle": "Informativna poruka",
"closeButton": "Zatvori",
"okButton": "U redu"
},
"jump_to_note": {
"search_placeholder": "Pretraži belešku po njenom imenu ili unesi > za komande...",
"close": "Zatvori",
"search_button": "Pretraga u punom tekstu <kbd>Ctrl+Enter</kbd>"
},
"markdown_import": {
"dialog_title": "Uvoz za Markdown",
"close": "Zatvori",
"modal_body_text": "Zbog Sandbox-a pretraživača nije moguće direktno učitati privremenu memoriju iz JavaScript-a. Molimo vas da nalepite Markdown za uvoz u tekstualno polje ispod i kliknete na dugme za uvoz",
"import_button": "Uvoz",
"import_success": "Markdown sadržaj je učitan u dokument."
},
"move_to": {
"dialog_title": "Premesti beleške u ...",
"close": "Zatvori",
"notes_to_move": "Beleške za premeštanje",
"target_parent_note": "Ciljana nadbeleška",
"search_placeholder": "potraži belešku po njenom imenu",
"move_button": "Pređi na izabranu belešku",
"error_no_path": "Nema putanje za premeštanje.",
"move_success_message": "Izabrane beleške su premeštene u "
},
"note_type_chooser": {
"change_path_prompt": "Promenite gde će se napraviti nova beleška:",
"search_placeholder": "pretraži putanju po njenom imenu (podrazumevano ako je prazno)",
"modal_title": "Izaberite tip beleške",
"close": "Zatvori",
"modal_body": "Izaberite tip beleške / šablon za novu belešku:",
"templates": "Šabloni"
},
"password_not_set": {
"title": "Lozinka nije podešena",
"close": "Zatvori",
"body1": "Zaštićene beleške su enkriptovane sa korisničkom lozinkom, ali lozinka još uvek nije podešena.",
"body2": "Za biste mogli da sačuvate beleške, kliknite <a class=\"open-password-options-button\" href=\"javascript:\">ovde</a> da otvorite dijalog sa Opcijama i podesite svoju lozinku."
},
"prompt": {
"title": "Upit",
"close": "Zatvori",
"ok": "U redu <kbd>enter</kbd>",
"defaultTitle": "Upit"
},
"protected_session_password": {
"modal_title": "Zaštićena sesija",
"help_title": "Pomoć za Zaštićene beleške",
"close_label": "Zatvori",
"form_label": "Da biste nastavili sa traženom akcijom moraćete započeti zaštićenu sesiju tako što ćete uneti lozinku:",
"start_button": "Započni zaštićenu sesiju"
},
"recent_changes": {
"title": "Nedavne promene",
"erase_notes_button": "Obriši izabrane beleške odmah",
"close": "Zatvori",
"deleted_notes_message": "Obrisane beleške su uklonjene.",
"no_changes_message": "Još uvek nema izmena...",
"undelete_link": "poništi brisanje",
"confirm_undelete": "Da li želite da poništite brisanje ove beleške i njenih podbeleški?"
},
"revisions": {
"note_revisions": "Revizije beleški",
"delete_all_revisions": "Obriši sve revizije ove beleške",
"delete_all_button": "Obriši sve revizije",
"help_title": "Pomoć za Revizije beleški",
"close": "Zatvori",
"revision_last_edited": "Ova revizija je poslednji put izmenjena {{date}}",
"confirm_delete_all": "Da li želite da obrišete sve revizije ove beleške?",
"no_revisions": "Još uvek nema revizija za ovu belešku...",
"restore_button": "Vrati",
"confirm_restore": "Da li želite da vratite ovu reviziju? Ovo će prepisati trenutan naslov i sadržaj beleške sa ovom revizijom.",
"delete_button": "Obriši",
"confirm_delete": "Da li želite da obrišete ovu reviziju?",
"revisions_deleted": "Revizije beleške su obrisane.",
"revision_restored": "Revizija beleške je vraćena.",
"revision_deleted": "Revizija beleške je obrisana.",
"snapshot_interval": "Interval snimanja revizije beleške: {{seconds}}s.",
"maximum_revisions": "Ograničenje broja slika revizije beleške: {{number}}.",
"settings": "Podešavanja revizija beleški",
"download_button": "Preuzmi",
"mime": "MIME: ",
"file_size": "Veličina datoteke:",
"preview": "Pregled:",
"preview_not_available": "Pregled nije dostupan za ovaj tip beleške."
},
"sort_child_notes": {
"sort_children_by": "Sortiranje podbeleški po...",
"close": "Zatvori",
"sorting_criteria": "Kriterijum za sortiranje",
"title": "naslov",
"date_created": "datum kreiranja",
"date_modified": "datum izmene",
"sorting_direction": "Smer sortiranja",
"ascending": "uzlazni",
"descending": "silazni",
"folders": "Fascikle",
"sort_folders_at_top": "sortiraj fascikle na vrh",
"natural_sort": "Prirodno sortiranje",
"sort_with_respect_to_different_character_sorting": "sortiranje sa poštovanjem različitih pravila sortiranja karaktera i kolacija u različitim jezicima ili regionima.",
"natural_sort_language": "Jezik za prirodno sortiranje",
"the_language_code_for_natural_sort": "Kod jezika za prirodno sortiranje, npr. \"zh-CN\" za Kineski.",
"sort": "Sortiraj"
},
"upload_attachments": {
"upload_attachments_to_note": "Otpremite priloge uz belešku",
"close": "Zatvori",
"choose_files": "Izaberite datoteke",
"files_will_be_uploaded": "Datoteke će biti otpremljene kao prilozi u {{noteTitle}}",
"options": "Opcije",
"shrink_images": "Smanji slike",
"upload": "Otpremi",
"tooltip": "Ako je označeno, Trilium će pokušati da smanji otpremljene slike skaliranjem i optimizacijom što može uticati na kvalitet slike. Ako nije označeno, slike će biti otpremljene bez izmena."
},
"attribute_detail": {
"attr_detail_title": "Naslov detalja atributa",
"close_button_title": "Otkaži izmene i zatvori",
"attr_is_owned_by": "Atribut je u vlasništvu",
"attr_name_title": "Naziv atributa može biti sastavljen samo od alfanumeričkih znakova, dvotačke i donje crte",
"name": "Naziv",
"value": "Vrednost",
"target_note_title": "Relacija je imenovana veza između izvorne beleške i ciljne beleške.",
"target_note": "Ciljna beleška",
"promoted_title": "Promovisani atribut je istaknut na belešci.",
"promoted": "Promovisan",
"promoted_alias_title": "Naziv koji će biti prikazan u korisničkom interfejsu promovisanih atributa.",
"promoted_alias": "Pseudonim",
"multiplicity_title": "Multiplicitet definiše koliko atributa sa istim nazivom se može napraviti - najviše 1 ili više od 1.",
"multiplicity": "Multiplicitet",
"single_value": "Jednostruka vrednost",
"multi_value": "Višestruka vrednost",
"label_type_title": "Tip oznake će pomoći Triliumu da izabere odgovarajući interfejs za unos vrednosti oznake.",
"label_type": "Tip",
"text": "Tekst",
"number": "Broj",
"boolean": "Boolean",
"date": "Datum",
"date_time": "Datum i vreme",
"time": "Vreme",
"url": "URL",
"precision_title": "Broj cifara posle zareza treba biti dostupan u interfejsu za postavljanje vrednosti.",
"precision": "Preciznost",
"digits": "cifre",
"inverse_relation_title": "Opciono podešavanje za definisanje kojoj relaciji je ova suprotna. Primer: Otac - Sin su inverzne relacije jedna drugoj.",
"inverse_relation": "Inverzna relacija",
"inheritable_title": "Atributi koji mogu da se nasleđuju će biti nasleđeni od strane svih potomaka unutar ovog stabla.",
"inheritable": "Nasledno",
"save_and_close": "Sačuvaj i zatvori <kbd>Ctrl+Enter</kbd>",
"delete": "Obriši",
"related_notes_title": "Druge beleške sa ovom oznakom",
"more_notes": "Još beleški",
"label": "Detalji oznake",
"label_definition": "Detalji definicije oznake",
"relation": "Detalji relacije",
"relation_definition": "Detalji definicije relacije",
"disable_versioning": "onemogućava auto-verzionisanje. Korisno za npr. velike, ali nebitne beleške - poput velikih JS biblioteka koje se koriste za skripte",
"calendar_root": "obeležava belešku koju treba koristiti kao osnova za dnevne beleške. Samo jedna beleška treba da bude označena kao takva.",
"archived": "beleške sa ovom oznakom neće biti podrazumevano vidljive u rezultatima pretrage (kao ni u dijalozima za Idi na, Dodaj link, itd.).",
"exclude_from_export": "beleške (sa svojim podstablom) neće biti uključene u bilo koji izvoz beleški",
"run": "definiše u kojim događajima se skripta pokreće. Moguće vrednosti su:\n<ul>\n<li>frontendStartup - kada se pokrene Trilium frontend (ili se osveži), ali ne na mobilnom uređaju.</li>\n<li>mobileStartup - kada se pokrene Trilium frontend (ili se osveži), na mobilnom uređaju..</li>\n<li>backendStartup - kada se Trilium backend pokrene</li>\n<li>hourly - pokreće se svaki sat. Može se koristiti dodatna oznaka <code>runAtHour</code> da se označi u kom satu.</li>\n<li>daily - pokreće se jednom dnevno</li>\n</ul>",
"run_on_instance": "Definiše u kojoj instanci Trilium-a ovo treba da se pokreće. Podrazumevano podešavanje je na svim instancama.",
"run_at_hour": "U kom satu ovo treba da se pokreće. Treba se koristiti zajedno sa <code>#run=hourly</code>. Može biti definisano više puta za više pokretanja u toku dana.",
"disable_inclusion": "skripte sa ovom oznakom neće biti uključene u izvršavanju nadskripte.",
"sorted": "čuva podbeleške sortirane alfabetski po naslovu",
"sort_direction": "Uzlazno (podrazumevano) ili silazno",
"sort_folders_first": "Fascikle (beleške sa podbeleškama) treba da budu sortirane na vrhu",
"top": "zadrži datu belešku na vrhu njene nadbeleške (primenjuje se samo na sortiranim nadbeleškama)",
"hide_promoted_attributes": "Sakrij promovisane atribute na ovoj belešci",
"read_only": "uređivač je u režimu samo za čitanje. Radi samo za tekst i beleške sa kodom.",
"auto_read_only_disabled": "beleške sa tekstom/kodom se mogu automatski podesiti u režim za čitanje kada su prevelike. Ovo ponašanje možete onemogućiti pojedinačno za belešku dodavanjem ove oznake na belešku",
"app_css": "označava CSS beleške koje nisu učitane u Trilium aplikaciju i zbog toga se mogu koristiti za menjanje izgleda Triliuma.",
"app_theme": "označava CSS beleške koje su pune Trilium teme i stoga su dostupne u Trilium podešavanjima.",
"app_theme_base": "podesite na „sledeće“, „sledeće-svetlo“ ili „sledeće-tamno“ da biste koristili odgovarajuću TriliumNext temu (automatsku, svetlu ili tamnu) kao osnovu za prilagođenu temu, umesto podrazumevane teme.",
"css_class": "vrednost ove oznake se zatim dodaje kao CSS klasa čvoru koji predstavlja datu belešku u stablu. Ovo može biti korisno za napredno temiranje. Može se koristiti u šablonima beleški.",
"workspace": "označava ovu belešku kao radni prostor što omogućava lako podizanje",
"workspace_icon_class": "definiše CSS klasu ikone okvira koja će se koristiti u kartici kada se podigne na ovoj belešci",
"workspace_tab_background_color": "CSS boja korišćena u kartici beleške kada se prebaci na ovu belešku",
"workspace_calendar_root": "Definiše koren kalendara za svaki radni prostor",
"workspace_template": "Ova beleška će se pojaviti u izboru dostupnih šablona prilikom kreiranja nove beleške, ali samo kada se podigne u radni prostor koji sadrži ovaj šablon",
"search_home": "nove beleške o pretrazi biće kreirane kao podređeni delovi ove beleške",
"workspace_search_home": "nove beleške o pretrazi biće kreirane kao podređeni delovi ove beleške kada se podignu na nekog pretka ove beleške iz radnog prostora",
"inbox": "podrazumevana lokacija u prijemnom sandučetu za nove beleške - kada kreirate belešku pomoću dugmeta „nova beleška“ u bočnoj traci, beleške će biti kreirane kao podbeleške u belešci označenoj sa oznakom <code>#inbox</code>.",
"workspace_inbox": "podrazumevana lokacija prijemnog sandučeta za nove beleške kada se prebace na nekog pretka ove beleške iz radnog prostora",
"sql_console_home": "podrazmevana lokacija beleški SQL konzole",
"bookmark_folder": "beleška sa ovom oznakom će se pojaviti u obeleživačima kao fascikla (omogućavajući pristup njenim podređenim fasciklama)",
"share_hidden_from_tree": "ova beleška je skrivena u levom navigacionom stablu, ali je i dalje dostupna preko svoje URL adrese",
"share_external_link": "beleška će služiti kao veza ka eksternoj veb stranici u stablu deljenja",
"share_alias": "definišite alias pomoću kog će beleška biti dostupna na https://your_trilium_host/share/[your_alias]",
"share_omit_default_css": "CSS kod podrazumevane stranice za deljenje će biti izostavljen. Koristite ga kada pravite opsežne promene stila.",
"share_root": "obeležava belešku koja se prikazuje na /share korenu.",
"share_description": "definišite tekst koji će se dodati HTML meta oznaci za opis",
"share_raw": "beleška će biti prikazana u svom sirovom (raw) formatu, bez HTML omotača",
"share_disallow_robot_indexing": "zabraniće robotsko indeksiranje ove beleške putem zaglavlja <code>X-Robots-Tag: noindex</code>",
"share_credentials": "potrebni su kredencijali za pristup ovoj deljenoj belešci. Očekuje se da vrednost bude u formatu „korisničko ime:lozinka“. Ne zaboravite da ovo označite kao nasledno da bi se primenilo na podbeleške/slike.",
"share_index": "beleška sa ovom oznakom će izlistati sve korene deljenih beleški",
"display_relations": "imena relacija razdvojenih zarezima koja treba da budu prikazana. Sva ostala će biti skrivena.",
"hide_relations": "imena relacija razdvojenih zarezima koja treba da budu skrivena. Sva ostala će biti prikazana.",
"title_template": "podrazumevani naslov beleški kreiranih kao deca ove beleške. Vrednost se procenjuje kao JavaScript string \n i stoga se može obogatiti dinamičkim sadržajem putem ubrizganih promenljivih <code>now</code> and <code>parentNote</code>. Primeri:\n \n <ul>\n <li><code>${parentNote.getLabelValue('authorName')}'s literary works</code></li>\n <li><code>Log for ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n Pogledati <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki sa detaljima</a>, API dokumentacija za <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> i <a href=\"https://day.js.org/docs/en/display/format\">now</a> za detalje.",
"template": "Ova beleška će biti prikazana u izboru dostupnih šablona prilikom pravljenja nove beleške",
"toc": "<code>#toc</code> ili <code>#toc=show</code> će pristiliti Sadržaj (Table of Contents) da bude prikazan, <code>#toc=hide</code> prisiliti njegovo sakrivanje. Ako oznaka ne postoji, ponašanje će biti usklađeno sa globalnim podešavanjem",
"color": "definiše boju beleške u stablu beleški, linkovima itd. Koristite bilo koju važeću CSS vrednost boje kao što je „crvena“ ili #a13d5f",
"keyboard_shortcut": "Definiše prečicu na tastaturi koja će odmah preći na ovu belešku. Primer: „ctrl+alt+e“. Potrebno je ponovno učitavanje frontenda da bi promena stupila na snagu.",
"keep_current_hoisting": "Otvaranje ove veze neće promeniti podizanje čak i ako beleška nije prikazana u trenutno podignutom podstablu.",
"execute_button": "Naslov dugmeta koje će izvršiti trenutnu belešku sa kodom",
"execute_description": "Duži opis trenutne beleške sa kodom prikazan je zajedno sa dugmetom za izvršavanje",
"exclude_from_note_map": "Beleške sa ovom oznakom biće skrivene sa mape beleški",
"new_notes_on_top": "Nove beleške će biti napravljene na vrhu matične beleške, a ne na dnu.",
"hide_highlight_widget": "Sakrij vidžet sa listom istaknutih",
"run_on_note_creation": "izvršava se kada se beleška napravi na serverskoj strani. Koristite ovu relaciju ako želite da pokrenete skriptu za sve beleške napravljene u okviru određenog podstabla. U tom slučaju, kreirajte je na korenu beleške podstabla i učinite je naslednom. Nova beleška napravljena unutar podstabla (bilo koje dubine) pokrenuće skriptu.",
"run_on_child_note_creation": "izvršava se kada se napravi nova beleška ispod beleške gde je ova relacija definisana",
"run_on_note_title_change": "izvršava se kada se promeni naslov beleške (uključuje i pravljenje beleške)",
"run_on_note_content_change": "izvršava se kada se promeni sadržaj beleške (uključuje i pravljenje beleške).",
"run_on_note_change": "izvršava se kada se promeni beleška (uključuje i pravljenje beleške). Ne uključuje promene sadržaja",
"icon_class": "vrednost ove oznake se dodaje kao CSS klasa ikoni na stablu što može pomoći u vizuelnom razlikovanju beleški u stablu. Primer može biti bx bx-home - ikone su preuzete iz boxicons. Može se koristiti u šablonima beleški.",
"page_size": "broj stavki po stranici u listi beleški",
"custom_request_handler": "pogledajte <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Prilagođeni obrađivač zahteva</a>",
"custom_resource_provider": "pogledajte <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Prilagođeni obrađivač zahteva</a>",
"widget": "označava ovu belešku kao prilagođeni vidžet koji će biti dodat u stablo komponenti Trilijuma",
"run_on_note_deletion": "izvršava se kada se beleška briše",
"run_on_branch_creation": "izvršava se kada se pravi grana. Grana je veza između matične i podređene beleške i pravi se npr. prilikom kloniranja ili premeštanja beleške.",
"run_on_branch_change": "izvršava se kada se grana ažurira.",
"run_on_branch_deletion": "izvršava se kada se grana briše. Grana je veza između nadređene beleške i podređene beleške i briše se npr. prilikom premeštanja beleške (stara grana/veza se briše).",
"run_on_attribute_creation": "izvršava se kada se pravi novi atribut za belešku koji definiše ovu relaciju",
"run_on_attribute_change": " izvršava se kada se promeni atribut beleške koja definiše ovu relaciju. Ovo se pokreće i kada se atribut obriše",
"relation_template": "atributi beleške će biti nasleđeni čak i bez odnosa roditelj-dete, sadržaj i podstablo beleške će biti dodati instanci beleške ako je prazna. Pogledajte dokumentaciju za detalje.",
"inherit": "Atributi beleške će biti nasleđeni čak i bez odnosa roditelj-dete. Pogledajte relaciju šablona za sličan koncept. Pogledajte nasleđivanje atributa u dokumentaciji.",
"render_note": "Beleške tipa „render HTML note“ će biti prikazane korišćenjem beleške za kod (HTML ili skripte) i potrebno je pomoću ove relacije ukazati na to koja beleška treba da se prikaže",
"widget_relation": "meta ove relacije će biti izvršena i prikazana kao vidžet u bočnoj traci",
"share_css": "CSS napomena koja će biti ubrizgana na stranicu za deljenje. CSS napomena mora biti i u deljenom podstablu. Razmotrite i korišćenje „share_hidden_from_tree“ i „share_omit_default_css“.",
"share_js": "JavaScript beleška koja će biti ubrizgana na stranicu za deljenje. JS beleška takođe mora biti u deljenom podstablu. Razmislite o korišćenju „share_hidden_from_tree“.",
"share_template": "Ugrađena JavaScript beleška koja će se koristiti kao šablon za prikazivanje deljene beleške. U slučaju neuspeha vraća se na podrazumevani šablon. Razmislite o korišćenju „share_hidden_from_tree“.",
"share_favicon": "Favicon beleška koju treba postaviti na deljenu stranicu. Obično je potrebno da je podesite da deli koren i učinite je naslednom. Favicon beleška takođe mora biti u deljenom podstablu. Razmislite o korišćenju „share_hidden_from_tree“.",
"is_owned_by_note": "je u vlasništvu beleške",
"other_notes_with_name": "Ostale beleške sa {{attributeType}} nazivom „{{attributeName}}“",
"and_more": "... i još {{count}}.",
"print_landscape": "Prilikom izvoza u PDF, menja orijentaciju stranice u pejzažnu umesto uspravne.",
"print_page_size": "Prilikom izvoza u PDF, menja veličinu stranice. Podržane vrednosti: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
"color_type": "Boja"
},
"ai_llm": {
"n_notes_queued_0": "{{ count }} beleška stavljena u red za indeksiranje",
"n_notes_queued_1": "{{ count }} beleški stavljeno u red za indeksiranje",
"n_notes_queued_2": "{{ count }} beleški stavljeno u red za indeksiranje",
"notes_indexed_0": "{{ count }} beleška je indeksirana",
"notes_indexed_1": "{{ count }} beleški je indeksirano",
"notes_indexed_2": "{{ count }} beleški je indeksirano"
},
"attribute_editor": {
"help_text_body1": "Da biste dodali oznaku, samo unesite npr. <code>#rock</code> ili ako želite da dodate i vrednost, onda npr. <code>#year = 2020</code>",
"help_text_body2": "Za relaciju, unesite <code>~author = @</code> što bi trebalo da otvori automatsko dovršavanje gde možete potražiti željenu belešku.",
"help_text_body3": "Alternativno, možete dodati oznaku i relaciju pomoću dugmeta <code>+</code> sa desne strane.",
"save_attributes": "Sačuvaj atribute <enter>",
"add_a_new_attribute": "Dodajte novi atribut",
"add_new_label": "Dodajte novu oznaku <kbd data-command=\"addNewLabel\"></kbd>",
"add_new_relation": "Dodajte novu relaciju <kbd data-command=\"addNewRelation\"></kbd>",
"add_new_label_definition": "Dodajte novu definiciju oznake",
"add_new_relation_definition": "Dodajte novu definiciju relacije",
"placeholder": "Ovde unesite oznake i relacije"
},
"abstract_bulk_action": {
"remove_this_search_action": "Ukloni ovu radnju pretrage"
},
"execute_script": {
"execute_script": "Izvrši skriptu",
"help_text": "Možete izvršiti jednostavne skripte na podudarnim beleškama.",
"example_1": "Na primer, da biste dodali string u naslov beleške, koristite ovu malu skriptu:",
"example_2": "Složeniji primer bi bio brisanje svih atributa podudarnih beleški:"
},
"add_label": {
"add_label": "Dodaj oznaku",
"label_name_placeholder": "ime oznake",
"label_name_title": "Alfanumerički znakovi, donja crta i dvotačka su dozvoljeni znakovi.",
"to_value": "za vrednost",
"new_value_placeholder": "nova vrednost",
"help_text": "Na svim podudarnim beleškama:",
"help_text_item1": "dodajte datu oznaku ako beleška još uvek nema jednu",
"help_text_item2": "ili izmenite vrednost postojeće oznake",
"help_text_note": "Takođe možete pozvati ovu metodu bez vrednosti, u tom slučaju će oznaka biti dodeljena belešci bez vrednosti."
},
"delete_label": {
"delete_label": "Obriši oznaku",
"label_name_placeholder": "ime oznake",
"label_name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi."
},
"rename_label": {
"rename_label": "Preimenuj oznaku",
"rename_label_from": "Preimenuj oznaku iz",
"old_name_placeholder": "stari naziv",
"to": "U",
"new_name_placeholder": "novi naziv",
"name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi."
},
"update_label_value": {
"update_label_value": "Ažuriraj vrednost oznake",
"label_name_placeholder": "ime oznake",
"label_name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi.",
"to_value": "u vrednost",
"new_value_placeholder": "nova vrednost",
"help_text": "Na svim podudarnim beleškama, promenite vrednost postojeće oznake.",
"help_text_note": "Takođe možete pozvati ovu metodu bez vrednosti, u tom slučaju će oznaka biti dodeljena belešci bez vrednosti."
},
"delete_note": {
"delete_note": "Obriši belešku",
"delete_matched_notes": "Obriši podudarne beleške",
"delete_matched_notes_description": "Ovo će obrisati podudarne beleške.",
"undelete_notes_instruction": "Nakon brisanja, moguće ga je poništiti iz dijaloga Nedavne izmene."
}
}

View File

@@ -0,0 +1,71 @@
{
"about": {
"close": "Kapat",
"homepage": "Giriş sayfası:",
"app_version": "Uygulama versiyonu:",
"db_version": "Veritabanı versiyonu:"
},
"add_link": {
"close": "Kapat"
},
"branch_prefix": {
"close": "Kapat",
"save": "Kaydet"
},
"bulk_actions": {
"close": "Kapat"
},
"clone_to": {
"close": "Kapat"
},
"confirm": {
"close": "Kapat"
},
"recent_changes": {
"close": "Kapat"
},
"delete_notes": {
"close": "Kapat"
},
"export": {
"close": "Kapat"
},
"help": {
"close": "Kapat"
},
"include_note": {
"close": "Kapat"
},
"import": {
"close": "Kapat",
"chooseImportFile": "İçe aktarım dosyası",
"importDescription": "Seçilen dosya(lar) alt not olarak içe aktarılacaktır"
},
"info": {
"closeButton": "Kapat"
},
"jump_to_note": {
"close": "Kapat"
},
"markdown_import": {
"close": "Kapat"
},
"move_to": {
"close": "Kapat"
},
"note_type_chooser": {
"close": "Kapat"
},
"password_not_set": {
"close": "Kapat"
},
"prompt": {
"close": "Kapat"
},
"protected_session_password": {
"close_label": "Kapat"
},
"revisions": {
"close": "Kapat"
}
}

View File

@@ -33,7 +33,7 @@
"link_title_mirrors": "鏈接標題跟隨筆記標題變化",
"link_title_arbitrary": "鏈接標題可隨意修改",
"link_title": "鏈接標題",
"button_add_link": "添加鏈接 <kbd>Enter</kbd>"
"button_add_link": "添加鏈接"
},
"branch_prefix": {
"edit_branch_prefix": "編輯分支前綴",
@@ -66,7 +66,7 @@
"search_for_note_by_its_name": "按名稱搜尋筆記",
"cloned_note_prefix_title": "複製的筆記將在筆記樹中顯示給定的前綴",
"prefix_optional": "前綴(可選)",
"clone_to_selected_note": "複製到選定的筆記 <kbd>Enter</kbd>",
"clone_to_selected_note": "複製到選定的筆記",
"no_path_to_clone_to": "沒有複製路徑。",
"note_cloned": "筆記 \"{{clonedTitle}}\" 已複製到 \"{{targetTitle}}\""
},
@@ -83,9 +83,9 @@
"delete_all_clones_description": "同時刪除所有複製(可以在最近修改中撤消)",
"erase_notes_description": "通常(軟)刪除僅標記筆記為已刪除,可以在一段時間內通過最近修改對話框撤消。選中此選項將立即擦除筆記,無法撤銷。",
"erase_notes_warning": "永久擦除筆記(無法撤銷),包括所有複製。這將強制應用程式重新加載。",
"notes_to_be_deleted": "將刪除以下筆記 ({{- noteCount}})",
"notes_to_be_deleted": "將刪除以下筆記 ({{notesCount}})",
"no_note_to_delete": "沒有筆記將被刪除(僅複製)。",
"broken_relations_to_be_deleted": "將刪除以下關係並斷開連接 ({{- relationCount}})",
"broken_relations_to_be_deleted": "將刪除以下關係並斷開連接 ({{ relationCount}})",
"cancel": "取消",
"ok": "確定",
"deleted_relation_text": "筆記 {{- note}} (將被刪除的筆記) 被以下關係 {{- relation}} 引用, 來自 {{- source}}。"
@@ -107,20 +107,18 @@
"export_finished_successfully": "匯出成功完成。"
},
"help": {
"fullDocumentation": "幫助(完整<a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">在線文檔</a>)",
"close": "關閉",
"noteNavigation": "筆記導航",
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - 在筆記列表中向上/向下移動",
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - 折疊/展開節點",
"goUpDown": "在筆記列表中向上/向下移動",
"collapseExpand": "折疊/展開節點",
"notSet": "未設定",
"goBackForwards": "在歷史記錄中前後移動",
"showJumpToNoteDialog": "顯示<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"跳轉到\" 對話框</a>",
"scrollToActiveNote": "滾動到活動筆記",
"jumpToParentNote": "<kbd>Backspace</kbd> - 跳轉到上級筆記",
"jumpToParentNote": "跳轉到上級筆記",
"collapseWholeTree": "折疊整個筆記樹",
"collapseSubTree": "折疊子樹",
"tabShortcuts": "標籤快捷鍵",
"newTabNoteLink": "<kbd>CTRL+click</kbd> - 在筆記鏈接上使用CTRL+點擊(或中鍵點擊)在新標籤中打開筆記",
"onlyInDesktop": "僅在桌面版(電子構建)中",
"openEmptyTab": "打開空白標籤頁",
"closeActiveTab": "關閉活動標籤頁",
@@ -135,14 +133,14 @@
"moveNoteUpHierarchy": "在層級結構中向上移動筆記",
"multiSelectNote": "多選上/下筆記",
"selectAllNotes": "選擇當前級別的所有筆記",
"selectNote": "<kbd>Shift+Click</kbd> - 選擇筆記",
"selectNote": "選擇筆記",
"copyNotes": "將活動筆記(或當前選擇)複製到剪貼簿(用於<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">複製</a>",
"cutNotes": "將當前筆記(或當前選擇)剪下到剪貼簿(用於移動筆記)",
"pasteNotes": "將筆記貼上為活動筆記的子筆記(根據是複製還是剪下到剪貼簿來決定是移動還是複製)",
"deleteNotes": "刪除筆記/子樹",
"editingNotes": "編輯筆記",
"editNoteTitle": "在樹形筆記樹中,焦點會從筆記樹切換到筆記標題。按下 Enter 鍵會將焦點從筆記標題切換到文字編輯器。按下 <kbd>Ctrl+.</kbd> 會將焦點從編輯器切換回筆記樹。",
"createEditLink": "<kbd>Ctrl+K</kbd> - 新增/編輯外部鏈接",
"createEditLink": "新增/編輯外部鏈接",
"createInternalLink": "新增內部鏈接",
"followLink": "跟隨遊標下的鏈接",
"insertDateTime": "在插入點插入當前日期和時間",
@@ -186,7 +184,7 @@
"box_size_small": "小型 (顯示大約10行)",
"box_size_medium": "中型 (顯示大約30行)",
"box_size_full": "完整顯示(完整文字框)",
"button_include": "包含筆記 <kbd>Enter</kbd>"
"button_include": "包含筆記"
},
"info": {
"modalTitle": "資訊消息",
@@ -194,13 +192,12 @@
"okButton": "確定"
},
"jump_to_note": {
"search_placeholder": "按筆記名稱搜尋",
"search_button": "全文搜尋 <kbd>Ctrl+Enter</kbd>"
"search_button": "全文搜尋"
},
"markdown_import": {
"dialog_title": "Markdown 匯入",
"modal_body_text": "由於瀏覽器沙盒的限制,無法直接從 JavaScript 讀取剪貼簿內容。請將要匯入的 Markdown 文字貼上到下面的文字框中,然後點擊匯入按鈕",
"import_button": "匯入 Ctrl+Enter",
"import_button": "匯入",
"import_success": "已成功匯入 Markdown 內容文檔。"
},
"move_to": {
@@ -208,23 +205,22 @@
"notes_to_move": "需要移動的筆記",
"target_parent_note": "目標上級筆記",
"search_placeholder": "通過名稱搜尋筆記",
"move_button": "移動到選定的筆記 <kbd>Enter</kbd>",
"move_button": "移動到選定的筆記",
"error_no_path": "沒有可以移動到的路徑。",
"move_success_message": "已移動所選筆記到 "
},
"note_type_chooser": {
"modal_title": "選擇筆記類型",
"modal_body": "選擇新筆記的類型或模板:",
"templates": "模板"
"templates": "模板"
},
"password_not_set": {
"title": "密碼未設定",
"body1": "受保護的筆記使用用戶密碼加密,但密碼尚未設定。",
"body2": "點擊<a class=\"open-password-options-button\" href=\"javascript:\">這裡</a>打開選項對話框並設定您的密碼。"
"body1": "受保護的筆記使用用戶密碼加密,但密碼尚未設定。"
},
"prompt": {
"title": "提示",
"ok": "確定 <kbd>Enter</kbd>",
"ok": "確定",
"defaultTitle": "提示"
},
"protected_session_password": {
@@ -232,7 +228,7 @@
"help_title": "關於保護筆記的幫助",
"close_label": "關閉",
"form_label": "輸入密碼進入保護會話以繼續:",
"start_button": "開始保護會話 <kbd>Enter</kbd>"
"start_button": "開始保護會話"
},
"recent_changes": {
"title": "最近修改",
@@ -250,9 +246,7 @@
"revision_last_edited": "此歷史版本上次編輯於 {{date}}",
"confirm_delete_all": "您是否要刪除此筆記的所有歷史版本?",
"no_revisions": "此筆記暫無歷史版本...",
"restore_button": "",
"confirm_restore": "您是否要恢復此歷史版本?這將使用此歷史版本覆蓋筆記的當前標題和內容。",
"delete_button": "",
"confirm_delete": "您是否要刪除此歷史版本?",
"revisions_deleted": "已刪除筆記歷史版本。",
"revision_restored": "已恢復筆記歷史版本。",
@@ -281,12 +275,12 @@
"sort_with_respect_to_different_character_sorting": "根據不同語言或地區的字符排序和排序規則排序。",
"natural_sort_language": "自然排序語言",
"the_language_code_for_natural_sort": "自然排序的語言程式碼,例如繁體中文的 \"zh-TW\"。",
"sort": "排序 <kbd>Enter</kbd>"
"sort": "排序"
},
"upload_attachments": {
"upload_attachments_to_note": "上傳附件到筆記",
"choose_files": "選擇文件",
"files_will_be_uploaded": "文件將作為附件上傳到",
"files_will_be_uploaded": "文件將作為附件上傳到 {{noteTitle}}",
"options": "選項",
"shrink_images": "縮小圖片",
"upload": "上傳",
@@ -718,7 +712,6 @@
"expand_all_children": "展開所有子項",
"collapse": "折疊",
"expand": "展開",
"book_properties": "",
"invalid_view_type": "無效的查看類型 '{{type}}'"
},
"edited_notes": {
@@ -1097,7 +1090,6 @@
"attachment_erasure_timeout": {
"attachment_erasure_timeout": "附件清理超時",
"attachment_auto_deletion_description": "如果附件在一段時間後不再被筆記引用,它們將自動被刪除(並被清理)。",
"erase_attachments_after": "",
"manual_erasing_description": "您還可以手動觸發清理(而不考慮上述定義的超時時間):",
"erase_unused_attachments_now": "立即清理未使用的附件筆記",
"unused_attachments_erased": "未使用的附件已被刪除。"
@@ -1109,16 +1101,10 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "筆記清理超時",
"note_erasure_description": "被刪除的筆記(以及屬性、歷史版本等)最初僅被標記為「刪除」,可以從「最近修改」對話框中恢復它們。經過一段時間後,已刪除的筆記會被「清理」,這意味著它們的內容將無法恢復。此設定允許您設定從刪除到清除筆記之間的時間長度。",
"erase_notes_after": "",
"manual_erasing_description": "您還可以手動觸發清理(不考慮上述定義的超時):",
"erase_deleted_notes_now": "立即清理已刪除的筆記",
"deleted_notes_erased": "已刪除的筆記已被清理。"
},
"revisions_snapshot_interval": {
"note_revisions_snapshot_interval_title": "",
"note_revisions_snapshot_description": "",
"snapshot_time_interval_label": ""
},
"revisions_snapshot_limit": {
"note_revisions_snapshot_limit_title": "筆記歷史快照限制",
"note_revisions_snapshot_limit_description": "筆記歷史快照數限制指的是每個筆記可以保存的最大歷史記錄數量。其中 -1 表示沒有限制0 表示刪除所有歷史記錄。你可以通過 #versioningLimit 標籤設定單個筆記的最大歷史記錄數量。",
@@ -1198,10 +1184,8 @@
"etapi": {
"title": "ETAPI",
"description": "ETAPI 是一個 REST API用於以編程方式訪問 Trilium 實例,而無需 UI。",
"see_more": "",
"wiki": "維基",
"openapi_spec": "ETAPI OpenAPI 規範",
"swagger_ui": "",
"create_token": "新增新的 ETAPI 令牌",
"existing_tokens": "現有令牌",
"no_tokens_yet": "目前還沒有令牌。點擊上面的按鈕新增一個。",
@@ -1236,7 +1220,6 @@
"protected_session_timeout_description": "保護會話超時是一個時間段,超時後保護會話會從瀏覽器內存中清除。這是從最後一次與保護筆記的交互開始計時的。更多資訊請見",
"wiki": "維基",
"for_more_info": "更多資訊。",
"protected_session_timeout_label": "",
"reset_confirmation": "重置密碼將永久喪失對所有現受保護筆記的訪問。您真的要重置密碼嗎?",
"reset_success_message": "密碼已重置。請設定新密碼",
"change_password_heading": "更改密碼",
@@ -1354,7 +1337,6 @@
"relation-map": "關係圖",
"note-map": "筆記地圖",
"render-note": "渲染筆記",
"book": "書",
"mermaid-diagram": "美人魚圖Mermaid",
"canvas": "畫布",
"web-view": "網頁視圖",
@@ -1513,7 +1495,6 @@
"auto-detect-language": "自動檢測"
},
"highlighting": {
"title": "",
"description": "控制文字筆記中程式碼塊的語法高亮,程式碼筆記不會受到影響。",
"color-scheme": "顏色方案"
},

View File

@@ -0,0 +1,43 @@
{
"about": {
"close": "Đóng",
"homepage": "Trang chủ:",
"title": "Về Trilium Notes"
},
"add_link": {
"close": "Đóng"
},
"bulk_actions": {
"close": "Đóng"
},
"branch_prefix": {
"close": "Đóng",
"save": "Lưu"
},
"clone_to": {
"close": "Đóng"
},
"confirm": {
"close": "Đóng",
"ok": "OK"
},
"delete_notes": {
"close": "Đóng",
"ok": "OK"
},
"export": {
"close": "Đóng"
},
"help": {
"close": "Đóng"
},
"toast": {
"critical-error": {
"title": "Lỗi nghiêm trọng"
}
},
"import": {
"close": "Đóng",
"options": "Tuỳ chọn"
}
}

View File

@@ -3,6 +3,11 @@ declare module "*.png" {
export default path;
}
declare module "*.json" {
var content: any;
export default content;
}
declare module "*?url" {
var path: string;
export default path;

View File

@@ -97,16 +97,6 @@ declare global {
setNote(noteId: string);
}
interface JQueryStatic {
hotkeys: {
options: {
filterInputAcceptingElements: boolean;
filterContentEditable: boolean;
filterTextInputs: boolean;
}
}
}
var logError: (message: string, e?: Error | string) => void;
var logInfo: (message: string) => void;
var glob: CustomGlobals;

View File

@@ -142,6 +142,7 @@ const TPL = /*html*/`
<option value="datetime">${t("attribute_detail.date_time")}</option>
<option value="time">${t("attribute_detail.time")}</option>
<option value="url">${t("attribute_detail.url")}</option>
<option value="color">${t("attribute_detail.color_type")}</option>
</select>
</td>
</tr>

View File

@@ -0,0 +1,54 @@
import { ComponentChildren } from "preact";
import { memo } from "preact/compat";
import AbstractBulkAction from "./abstract_bulk_action";
interface BulkActionProps {
label: string | ComponentChildren;
children?: ComponentChildren;
helpText?: ComponentChildren;
bulkAction: AbstractBulkAction;
}
// Define styles as constants to prevent recreation
const flexContainerStyle = { display: "flex", alignItems: "center" } as const;
const labelStyle = { marginRight: "10px" } as const;
const textStyle = { marginRight: "10px", marginLeft: "10px" } as const;
const BulkAction = memo(({ label, children, helpText, bulkAction }: BulkActionProps) => {
return (
<tr>
<td colSpan={2}>
<div style={flexContainerStyle}>
<div style={labelStyle} className="text-nowrap">{label}</div>
{children}
</div>
</td>
<td className="button-column">
{helpText && <div className="dropdown help-dropdown">
<span className="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div className="dropdown-menu dropdown-menu-right p-4">
{helpText}
</div>
</div>}
<span
className="bx bx-x icon-action action-conf-del"
onClick={() => bulkAction?.deleteAction()}
/>
</td>
</tr>
);
});
export default BulkAction;
export const BulkActionText = memo(({ text }: { text: string }) => {
return (
<div
style={textStyle}
className="text-nowrap">
{text}
</div>
);
});

View File

@@ -1,10 +1,9 @@
import { t } from "../../services/i18n.js";
import server from "../../services/server.js";
import ws from "../../services/ws.js";
import utils from "../../services/utils.js";
import type FAttribute from "../../entities/fattribute.js";
import { VNode } from "preact";
interface ActionDefinition {
export interface ActionDefinition {
script: string;
relationName: string;
targetNoteId: string;
@@ -27,26 +26,9 @@ export default abstract class AbstractBulkAction {
this.actionDef = actionDef;
}
render() {
try {
const $rendered = this.doRender();
$rendered
.find(".action-conf-del")
.on("click", () => this.deleteAction())
.attr("title", t("abstract_bulk_action.remove_this_search_action"));
utils.initHelpDropdown($rendered);
return $rendered;
} catch (e: any) {
logError(`Failed rendering search action: ${JSON.stringify(this.attribute.dto)} with error: ${e.message} ${e.stack}`);
return null;
}
}
// to be overridden
abstract doRender(): JQuery<HTMLElement>;
abstract doRender(): VNode;
static get actionName() {
return "";
}
@@ -66,9 +48,6 @@ export default abstract class AbstractBulkAction {
async deleteAction() {
await server.remove(`notes/${this.attribute.noteId}/attributes/${this.attribute.attributeId}`);
await ws.waitForMaxKnownEntityChangeId();
//await this.triggerCommand('refreshSearchDefinition');
}
}

View File

@@ -1,58 +0,0 @@
import { t } from "../../services/i18n.js";
import SpacedUpdate from "../../services/spaced_update.js";
import AbstractBulkAction from "./abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td>
${t("execute_script.execute_script")}
</td>
<td>
<input type="text"
class="form-control script"
placeholder="note.title = note.title + '- suffix';"/>
</td>
<td class="button-column">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
${t("execute_script.help_text")}
${t("execute_script.example_1")}
<pre>note.title = note.title + ' - suffix';</pre>
${t("execute_script.example_2")}
<pre>for (const attr of note.getOwnedAttributes) { attr.markAsDeleted(); }</pre>
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</div>
</td>
</tr>`;
export default class ExecuteScriptBulkAction extends AbstractBulkAction {
static get actionName() {
return "executeScript";
}
static get actionTitle() {
return t("execute_script.execute_script");
}
doRender() {
const $action = $(TPL);
const $script = $action.find(".script");
$script.val(this.actionDef.script || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({ script: $script.val() });
}, 1000);
$script.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,50 @@
import { useEffect, useState } from "preact/hooks";
import { t } from "../../services/i18n.js";
import FormTextBox from "../react/FormTextBox.jsx";
import AbstractBulkAction, { ActionDefinition } from "./abstract_bulk_action.js";
import BulkAction from "./BulkAction.jsx";
import { useSpacedUpdate } from "../react/hooks.jsx";
function ExecuteScriptBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
const [ script, setScript ] = useState(actionDef.script);
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ script }));
useEffect(() => spacedUpdate.scheduleUpdate(), [ script ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("execute_script.execute_script")}
helpText={<>
{t("execute_script.help_text")}
{t("execute_script.example_1")}
<pre>note.title = note.title + ' - suffix';</pre>
{t("execute_script.example_2")}
<pre>{"for (const attr of note.getOwnedAttributes) { attr.markAsDeleted(); }"}</pre>
</>}
>
<FormTextBox
placeholder="note.title = note.title + '- suffix';"
currentValue={script} onChange={setScript}
/>
</BulkAction>
);
}
export default class ExecuteScriptBulkAction extends AbstractBulkAction {
static get actionName() {
return "executeScript";
}
static get actionTitle() {
return t("execute_script.execute_script");
}
doRender() {
return <ExecuteScriptBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,70 +0,0 @@
import { t } from "../../../services/i18n.js";
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px;" class="text-nowrap">${t("add_label.add_label")}</div>
<input type="text"
class="form-control label-name"
placeholder="${t("add_label.label_name_placeholder")}"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("add_label.label_name_title")}"/>
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("add_label.to_value")}</div>
<input type="text" class="form-control label-value" placeholder="${t("add_label.new_value_placeholder")}"/>
</div>
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
<p>${t("add_label.help_text")}</p>
<ul>
<li>${t("add_label.help_text_item1")}</li>
<li>${t("add_label.help_text_item2")}</li>
</ul>
${t("add_label.help_text_note")}
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class AddLabelBulkAction extends AbstractBulkAction {
static get actionName() {
return "addLabel";
}
static get actionTitle() {
return t("add_label.add_label");
}
doRender() {
const $action = $(TPL);
const $labelName = $action.find(".label-name");
$labelName.val(this.actionDef.labelName || "");
const $labelValue = $action.find(".label-value");
$labelValue.val(this.actionDef.labelValue || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
labelName: $labelName.val(),
labelValue: $labelValue.val()
});
}, 1000);
$labelName.on("input", () => spacedUpdate.scheduleUpdate());
$labelValue.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,57 @@
import { useEffect, useState } from "preact/hooks";
import { t } from "../../../services/i18n";
import FormTextBox from "../../react/FormTextBox";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action";
import BulkAction, { BulkActionText } from "../BulkAction";
import { useSpacedUpdate } from "../../react/hooks";
function AddLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
const [ labelName, setLabelName ] = useState<string>(actionDef.labelName ?? "");
const [ labelValue, setLabelValue ] = useState<string>(actionDef.labelValue ?? "");
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName, labelValue }));
useEffect(() => spacedUpdate.scheduleUpdate(), [labelName, labelValue]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("add_label.add_label")}
helpText={<>
<p>{t("add_label.help_text")}</p>
<ul>
<li>{t("add_label.help_text_item1")}</li>
<li>{t("add_label.help_text_item2")}</li>
</ul>
{t("add_label.help_text_note")}
</>}
>
<FormTextBox
placeholder={t("add_label.label_name_placeholder")}
pattern="[\\p{L}\\p{N}_:]+"
title={t("add_label.label_name_title")}
currentValue={labelName} onChange={setLabelName}
/>
<BulkActionText text={t("add_label.to_value")} />
<FormTextBox
placeholder={t("add_label.new_value_placeholder")}
currentValue={labelValue} onChange={setLabelValue}
/>
</BulkAction>
)
}
export default class AddLabelBulkAction extends AbstractBulkAction {
doRender() {
return <AddLabelBulkActionComponent bulkAction={this} actionDef={this.actionDef} />;
}
static get actionName() {
return "addLabel";
}
static get actionTitle() {
return t("add_label.add_label");
}
}

View File

@@ -1,43 +0,0 @@
import { t } from "../../../services/i18n.js";
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td>
${t("delete_label.delete_label")}
</td>
<td>
<input type="text"
class="form-control label-name"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("delete_label.label_name_title")}"
placeholder="${t("delete_label.label_name_placeholder")}"/>
</td>
<td class="button-column">
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class DeleteLabelBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteLabel";
}
static get actionTitle() {
return t("delete_label.delete_label");
}
doRender() {
const $action = $(TPL);
const $labelName = $action.find(".label-name");
$labelName.val(this.actionDef.labelName || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({ labelName: $labelName.val() });
}, 1000);
$labelName.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,39 @@
import { useEffect, useState } from "preact/hooks";
import { t } from "../../../services/i18n.js";
import FormTextBox from "../../react/FormTextBox.jsx";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import { useSpacedUpdate } from "../../react/hooks.jsx";
import BulkAction from "../BulkAction.jsx";
function DeleteLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
const [ labelName, setLabelName ] = useState<string>(actionDef.labelName ?? "");
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName }));
useEffect(() => spacedUpdate.scheduleUpdate(), [labelName]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("delete_label.delete_label")}
>
<FormTextBox
pattern="[\\p{L}\\p{N}_:]+"
title={t("delete_label.label_name_title")}
placeholder={t("delete_label.label_name_placeholder")}
currentValue={labelName} onChange={setLabelName}
/>
</BulkAction>
);
}
export default class DeleteLabelBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteLabel";
}
static get actionTitle() {
return t("delete_label.delete_label");
}
doRender() {
return <DeleteLabelBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,60 +0,0 @@
import { t } from "../../../services/i18n.js";
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px; flex-shrink: 0;">${t("rename_label.rename_label_from")}</div>
<input type="text"
class="form-control old-label-name"
placeholder="${t("rename_label.old_name_placeholder")}"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("rename_label.name_title")}"/>
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("rename_label.to")}</div>
<input type="text"
class="form-control new-label-name"
placeholder="${t("rename_label.new_name_placeholder")}"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("rename_label.name_title")}"/>
</div>
</td>
<td class="button-column">
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class RenameLabelBulkAction extends AbstractBulkAction {
static get actionName() {
return "renameLabel";
}
static get actionTitle() {
return t("rename_label.rename_label");
}
doRender() {
const $action = $(TPL);
const $oldLabelName = $action.find(".old-label-name");
$oldLabelName.val(this.actionDef.oldLabelName || "");
const $newLabelName = $action.find(".new-label-name");
$newLabelName.val(this.actionDef.newLabelName || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
oldLabelName: $oldLabelName.val(),
newLabelName: $newLabelName.val()
});
}, 1000);
$oldLabelName.on("input", () => spacedUpdate.scheduleUpdate());
$newLabelName.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,49 @@
import { useEffect, useState } from "preact/hooks";
import { t } from "../../../services/i18n.js";
import FormTextBox from "../../react/FormTextBox.jsx";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
import { useSpacedUpdate } from "../../react/hooks.jsx";
function RenameLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
const [ oldLabelName, setOldLabelName ] = useState(actionDef.oldLabelName);
const [ newLabelName, setNewLabelName ] = useState(actionDef.newLabelName);
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ oldLabelName, newLabelName }));
useEffect(() => spacedUpdate.scheduleUpdate(), [ oldLabelName, newLabelName ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("rename_label.rename_label_from")}
>
<FormTextBox
placeholder={t("rename_label.old_name_placeholder")}
pattern="[\\p{L}\\p{N}_:]+"
title={t("rename_label.name_title")}
currentValue={oldLabelName} onChange={setOldLabelName}
/>
<BulkActionText text={t("rename_label.to")} />
<FormTextBox
placeholder={t("rename_label.new_name_placeholder")}
pattern="[\\p{L}\\p{N}_:]+"
title={t("rename_label.name_title")}
currentValue={newLabelName} onChange={setNewLabelName}
/>
</BulkAction>
)
}
export default class RenameLabelBulkAction extends AbstractBulkAction {
static get actionName() {
return "renameLabel";
}
static get actionTitle() {
return t("rename_label.rename_label");
}
doRender() {
return <RenameLabelBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,65 +0,0 @@
import { t } from "../../../services/i18n.js";
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px;" class="text-nowrap">${t("update_label_value.update_label_value")}</div>
<input type="text"
class="form-control label-name"
placeholder="${t("update_label_value.label_name_placeholder")}"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("update_label_value.label_name_title")}"/>
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("update_label_value.to_value")}</div>
<input type="text" class="form-control label-value" placeholder="${t("update_label_value.new_value_placeholder")}"/>
</div>
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
<p>${t("update_label_value.help_text")}</p>
${t("update_label_value.help_text_note")}
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class UpdateLabelValueBulkAction extends AbstractBulkAction {
static get actionName() {
return "updateLabelValue";
}
static get actionTitle() {
return t("update_label_value.update_label_value");
}
doRender() {
const $action = $(TPL);
const $labelName = $action.find(".label-name");
$labelName.val(this.actionDef.labelName || "");
const $labelValue = $action.find(".label-value");
$labelValue.val(this.actionDef.labelValue || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
labelName: $labelName.val(),
labelValue: $labelValue.val()
});
}, 1000);
$labelName.on("input", () => spacedUpdate.scheduleUpdate());
$labelValue.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,50 @@
import { t } from "../../../services/i18n.js";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import FormTextBox from "../../react/FormTextBox.jsx";
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
import { useSpacedUpdate } from "../../react/hooks.jsx";
import { useEffect, useState } from "preact/hooks";
function UpdateLabelValueComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
const [ labelName, setLabelName ] = useState<string>(actionDef.labelName ?? "");
const [ labelValue, setLabelValue ] = useState<string>(actionDef.labelValue ?? "");
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName, labelValue }));
useEffect(() => spacedUpdate.scheduleUpdate(), [labelName, labelValue]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("update_label_value.update_label_value")}
helpText={<>
<p>{t("update_label_value.help_text")}</p>
{t("update_label_value.help_text_note")}
</>}
>
<FormTextBox
placeholder={t("update_label_value.label_name_placeholder")}
pattern="[\\p{L}\\p{N}_:]+"
title={t("update_label_value.label_name_title")}
currentValue={labelName} onChange={setLabelName}
/>
<BulkActionText text={t("update_label_value.to_value")} />
<FormTextBox
placeholder={t("update_label_value.new_value_placeholder")}
currentValue={labelValue} onChange={setLabelValue}
/>
</BulkAction>
)
}
export default class UpdateLabelValueBulkAction extends AbstractBulkAction {
static get actionName() {
return "updateLabelValue";
}
static get actionTitle() {
return t("update_label_value.update_label_value");
}
doRender() {
return <UpdateLabelValueComponent bulkAction={this} actionDef={this.actionDef} />;
}
}

View File

@@ -1,38 +0,0 @@
import { t } from "../../../services/i18n.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<span class="bx bx-trash"></span>
${t("delete_note.delete_matched_notes")}
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
<p>${t("delete_note.delete_matched_notes_description")}</p>
<p>${t("delete_note.undelete_notes_instruction")}</p>
${t("delete_note.erase_notes_instruction")}
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class DeleteNoteBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteNote";
}
static get actionTitle() {
return t("delete_note.delete_note");
}
doRender() {
return $(TPL);
}
}

View File

@@ -0,0 +1,33 @@
import { t } from "../../../services/i18n.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
import BulkAction from "../BulkAction.jsx";
import Icon from "../../react/Icon.jsx";
function DeleteNoteBulkActionComponent({ bulkAction }: { bulkAction: AbstractBulkAction }) {
return (
<BulkAction
bulkAction={bulkAction}
label={<><Icon icon="bx bx-trash" /> {t("delete_note.delete_matched_notes")}</>}
helpText={<>
<p>{t("delete_note.delete_matched_notes_description")}</p>
<p>{t("delete_note.undelete_notes_instruction")}</p>
{t("delete_note.erase_notes_instruction")}
</>}
/>
);
}
export default class DeleteNoteBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteNote";
}
static get actionTitle() {
return t("delete_note.delete_note");
}
doRender() {
return <DeleteNoteBulkActionComponent bulkAction={this} />
}
}

View File

@@ -1,32 +0,0 @@
import { t } from "../../../services/i18n.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<span class="bx bx-trash"></span>
${t("delete_revisions.delete_note_revisions")}
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
${t("delete_revisions.all_past_note_revisions")}
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class DeleteRevisionsBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteRevisions";
}
static get actionTitle() {
return t("delete_revisions.delete_note_revisions");
}
doRender() {
return $(TPL);
}
}

View File

@@ -0,0 +1,28 @@
import { t } from "../../../services/i18n.js";
import Icon from "../../react/Icon.jsx";
import AbstractBulkAction from "../abstract_bulk_action.js";
import BulkAction from "../BulkAction.jsx";
function DeleteRevisionsBulkActionComponent({ bulkAction }: { bulkAction: AbstractBulkAction }) {
return (
<BulkAction
bulkAction={bulkAction}
label={<><Icon icon="bx bx-trash" /> {t("delete_revisions.delete_note_revisions")}</>}
helpText={t("delete_revisions.all_past_note_revisions")}
/>
)
}
export default class DeleteRevisionsBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteRevisions";
}
static get actionTitle() {
return t("delete_revisions.delete_note_revisions");
}
doRender() {
return <DeleteRevisionsBulkActionComponent bulkAction={this} />
}
}

View File

@@ -1,64 +0,0 @@
import { t } from "../../../services/i18n.js";
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
import noteAutocompleteService from "../../../services/note_autocomplete.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px;" class="text-nowrap">${t("move_note.move_note")}</div>
<div style="margin-right: 10px;" class="text-nowrap">${t("move_note.to")}</div>
<div class="input-group">
<input type="text" class="form-control target-parent-note" placeholder="${t("move_note.target_parent_note")}"/>
</div>
</div>
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
<p>${t("move_note.on_all_matched_notes")}:</p>
<ul style="margin-bottom: 0;">
<li>${t("move_note.move_note_new_parent")}</li>
<li>${t("move_note.clone_note_new_parent")}</li>
<li>${t("move_note.nothing_will_happen")}</li>
</ul>
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class MoveNoteBulkAction extends AbstractBulkAction {
static get actionName() {
return "moveNote";
}
static get actionTitle() {
return t("move_note.move_note");
}
doRender() {
const $action = $(TPL);
const $targetParentNote = $action.find(".target-parent-note");
noteAutocompleteService.initNoteAutocomplete($targetParentNote);
$targetParentNote.setNote(this.actionDef.targetParentNoteId);
$targetParentNote.on("autocomplete:closed", () => spacedUpdate.scheduleUpdate());
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
targetParentNoteId: $targetParentNote.getSelectedNoteId()
});
}, 1000);
$targetParentNote.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,50 @@
import { t } from "../../../services/i18n.js";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
import { useEffect, useState } from "preact/hooks";
import { useSpacedUpdate } from "../../react/hooks.jsx";
function MoveNoteBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
const [ targetParentNoteId, setTargetParentNoteId ] = useState<string>();
const spacedUpdate = useSpacedUpdate(() => {
return bulkAction.saveAction({ targetParentNoteId: targetParentNoteId })
});
useEffect(() => spacedUpdate.scheduleUpdate(), [ targetParentNoteId ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("move_note.move_note")}
helpText={<>
<p>{t("move_note.on_all_matched_notes")}:</p>
<ul style="margin-bottom: 0;">
<li>{t("move_note.move_note_new_parent")}</li>
<li>{t("move_note.clone_note_new_parent")}</li>
<li>{t("move_note.nothing_will_happen")}</li>
</ul>
</>}
>
<BulkActionText text={t("move_note.to")} />
<NoteAutocomplete
placeholder={t("move_note.target_parent_note")}
noteId={targetParentNoteId} noteIdChanged={setTargetParentNoteId}
/>
</BulkAction>
)
}
export default class MoveNoteBulkAction extends AbstractBulkAction {
static get actionName() {
return "moveNote";
}
static get actionTitle() {
return t("move_note.move_note");
}
doRender() {
return <MoveNoteBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,61 +0,0 @@
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
import { t } from "../../../services/i18n.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px; flex-shrink: 0;">${t("rename_note.rename_note_title_to")}</div>
<input type="text"
class="form-control new-title"
placeholder="${t("rename_note.new_note_title")}"
title="${t("rename_note.click_help_icon")}"/>
</div>
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
<p>${t("rename_note.evaluated_as_js_string")}</p>
<ul>
<li>${t("rename_note.example_note")}</li>
<li>${t("rename_note.example_new_title")}</li>
<li>${t("rename_note.example_date_prefix")}</li>
</ul>
${t("rename_note.api_docs")}
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class RenameNoteBulkAction extends AbstractBulkAction {
static get actionName() {
return "renameNote";
}
static get actionTitle() {
return t("rename_note.rename_note");
}
doRender() {
const $action = $(TPL);
const $newTitle = $action.find(".new-title");
$newTitle.val(this.actionDef.newTitle || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
newTitle: $newTitle.val()
});
}, 1000);
$newTitle.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,53 @@
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import { t } from "../../../services/i18n.js";
import BulkAction from "../BulkAction.jsx";
import FormTextBox from "../../react/FormTextBox.jsx";
import { useEffect, useState } from "preact/hooks";
import { useSpacedUpdate } from "../../react/hooks.jsx";
import RawHtml from "../../react/RawHtml.jsx";
function RenameNoteBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
const [ newTitle, setNewTitle ] = useState<string>(actionDef.newTitle ?? "");
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ newTitle }));
useEffect(() => spacedUpdate.scheduleUpdate(), [ newTitle ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("rename_note.rename_note_title_to")}
helpText={<>
<p>{t("rename_note.evaluated_as_js_string")}</p>
<ul>
<li><RawHtml html={t("rename_note.example_note")} /></li>
<li><RawHtml html={t("rename_note.example_new_title")} /></li>
<li><RawHtml html={t("rename_note.example_date_prefix")} /></li>
</ul>
<RawHtml html={t("rename_note.api_docs")} />
</>}
>
<FormTextBox
placeholder={t("rename_note.new_note_title")}
title={("rename_note.click_help_icon")}
currentValue={newTitle} onChange={setNewTitle}
/>
</BulkAction>
)
}
export default class RenameNoteBulkAction extends AbstractBulkAction {
static get actionName() {
return "renameNote";
}
static get actionTitle() {
return t("rename_note.rename_note");
}
doRender() {
return <RenameNoteBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,70 +0,0 @@
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
import noteAutocompleteService from "../../../services/note_autocomplete.js";
import { t } from "../../../services/i18n.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px;" class="text-nowrap">${t("add_relation.add_relation")}</div>
<input type="text"
class="form-control relation-name"
placeholder="${t("add_relation.relation_name")}"
pattern="[\\p{L}\\p{N}_:]+"
style="flex-shrink: 3"
title="${t("add_relation.allowed_characters")}"/>
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("add_relation.to")}</div>
<div class="input-group" style="flex-shrink: 2">
<input type="text" class="form-control target-note" placeholder="${t("add_relation.target_note")}"/>
</div>
</div>
</td>
<td class="button-column">
<div class="dropdown help-dropdown">
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
<div class="dropdown-menu dropdown-menu-right p-4">
${t("add_relation.create_relation_on_all_matched_notes")}
</div>
</div>
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class AddRelationBulkAction extends AbstractBulkAction {
static get actionName() {
return "addRelation";
}
static get actionTitle() {
return t("add_relation.add_relation");
}
doRender() {
const $action = $(TPL);
const $relationName = $action.find(".relation-name");
$relationName.val(this.actionDef.relationName || "");
const $targetNote = $action.find(".target-note");
noteAutocompleteService.initNoteAutocomplete($targetNote);
$targetNote.setNote(this.actionDef.targetNoteId);
$targetNote.on("autocomplete:closed", () => spacedUpdate.scheduleUpdate());
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
relationName: $relationName.val(),
targetNoteId: $targetNote.getSelectedNoteId()
});
}, 1000);
$relationName.on("input", () => spacedUpdate.scheduleUpdate());
$targetNote.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,53 @@
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import noteAutocompleteService from "../../../services/note_autocomplete.js";
import { t } from "../../../services/i18n.js";
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
import FormTextBox from "../../react/FormTextBox.jsx";
import { useEffect, useState } from "preact/hooks";
import { useSpacedUpdate } from "../../react/hooks.jsx";
function AddRelationBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
const [ relationName, setRelationName ] = useState<string>(actionDef.relationName);
const [ targetNoteId, setTargetNoteId ] = useState<string>(actionDef.targetNoteId);
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ relationName, targetNoteId }));
useEffect(() => spacedUpdate.scheduleUpdate(), [ relationName, targetNoteId ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("add_relation.add_relation")}
helpText={t("add_relation.create_relation_on_all_matched_notes")}
>
<FormTextBox
placeholder={t("add_relation.relation_name")}
pattern="[\\p{L}\\p{N}_:]+"
style={{ flexShrink: 3 }}
title={t("add_relation.allowed_characters")}
currentValue={relationName} onChange={setRelationName}
/>
<BulkActionText text={t("add_relation.to")} />
<NoteAutocomplete
placeholder={t("add_relation.target_note")}
noteId={targetNoteId} noteIdChanged={setTargetNoteId}
/>
</BulkAction>
)
}
export default class AddRelationBulkAction extends AbstractBulkAction {
static get actionName() {
return "addRelation";
}
static get actionTitle() {
return t("add_relation.add_relation");
}
doRender() {
return <AddRelationBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,45 +0,0 @@
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
import { t } from "../../../services/i18n.js";
const TPL = /*html*/`
<tr>
<td>
${t("delete_relation.delete_relation")}
</td>
<td>
<div style="display: flex; align-items: center">
<input type="text"
class="form-control relation-name"
pattern="[\\p{L}\\p{N}_:]+"
placeholder="${t("delete_relation.relation_name")}"
title="${t("delete_relation.allowed_characters")}"/>
</div>
</td>
<td class="button-column">
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class DeleteRelationBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteRelation";
}
static get actionTitle() {
return t("delete_relation.delete_relation");
}
doRender() {
const $action = $(TPL);
const $relationName = $action.find(".relation-name");
$relationName.val(this.actionDef.relationName || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({ relationName: $relationName.val() });
}, 1000);
$relationName.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,41 @@
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import { t } from "../../../services/i18n.js";
import BulkAction from "../BulkAction.jsx";
import FormTextBox from "../../react/FormTextBox.jsx";
import { useEffect, useState } from "preact/hooks";
import { useSpacedUpdate } from "../../react/hooks.jsx";
function DeleteRelationBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
const [ relationName, setRelationName ] = useState(actionDef.relationName);
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ relationName }));
useEffect(() => spacedUpdate.scheduleUpdate(), [ relationName ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("delete_relation.delete_relation")}
>
<FormTextBox
pattern="[\\p{L}\\p{N}_:]+"
placeholder={t("delete_relation.relation_name")}
title={t("delete_relation.allowed_characters")}
currentValue={relationName} onChange={setRelationName}
/>
</BulkAction>
)
}
export default class DeleteRelationBulkAction extends AbstractBulkAction {
static get actionName() {
return "deleteRelation";
}
static get actionTitle() {
return t("delete_relation.delete_relation");
}
doRender() {
return <DeleteRelationBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

View File

@@ -1,60 +0,0 @@
import SpacedUpdate from "../../../services/spaced_update.js";
import AbstractBulkAction from "../abstract_bulk_action.js";
import { t } from "../../../services/i18n.js";
const TPL = /*html*/`
<tr>
<td colspan="2">
<div style="display: flex; align-items: center">
<div style="margin-right: 10px; flex-shrink: 0;">${t("rename_relation.rename_relation_from")}</div>
<input type="text"
class="form-control old-relation-name"
placeholder="${t("rename_relation.old_name")}"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("rename_relation.allowed_characters")}"/>
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("rename_relation.to")}</div>
<input type="text"
class="form-control new-relation-name"
placeholder="${t("rename_relation.new_name")}"
pattern="[\\p{L}\\p{N}_:]+"
title="${t("rename_relation.allowed_characters")}"/>
</div>
</td>
<td class="button-column">
<span class="bx bx-x icon-action action-conf-del"></span>
</td>
</tr>`;
export default class RenameRelationBulkAction extends AbstractBulkAction {
static get actionName() {
return "renameRelation";
}
static get actionTitle() {
return t("rename_relation.rename_relation");
}
doRender() {
const $action = $(TPL);
const $oldRelationName = $action.find(".old-relation-name");
$oldRelationName.val(this.actionDef.oldRelationName || "");
const $newRelationName = $action.find(".new-relation-name");
$newRelationName.val(this.actionDef.newRelationName || "");
const spacedUpdate = new SpacedUpdate(async () => {
await this.saveAction({
oldRelationName: $oldRelationName.val(),
newRelationName: $newRelationName.val()
});
}, 1000);
$oldRelationName.on("input", () => spacedUpdate.scheduleUpdate());
$newRelationName.on("input", () => spacedUpdate.scheduleUpdate());
return $action;
}
}

View File

@@ -0,0 +1,49 @@
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
import { t } from "../../../services/i18n.js";
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
import FormTextBox from "../../react/FormTextBox.jsx";
import { useEffect, useState } from "preact/hooks";
import { useSpacedUpdate } from "../../react/hooks.jsx";
function RenameRelationBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
const [ oldRelationName, setOldRelationName ] = useState(actionDef.oldRelationName);
const [ newRelationName, setNewRelationName ] = useState(actionDef.newRelationName);
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ oldRelationName, newRelationName }));
useEffect(() => spacedUpdate.scheduleUpdate(), [ oldRelationName, newRelationName ]);
return (
<BulkAction
bulkAction={bulkAction}
label={t("rename_relation.rename_relation_from")}
>
<FormTextBox
placeholder={t("rename_relation.old_name")}
pattern="[\\p{L}\\p{N}_:]+"
title={t("rename_relation.allowed_characters")}
currentValue={oldRelationName} onChange={setOldRelationName}
/>
<BulkActionText text={t("rename_relation.to")} />
<FormTextBox
placeholder={t("rename_relation.new_name")}
pattern="[\\p{L}\\p{N}_:]+"
title={t("rename_relation.allowed_characters")}
currentValue={newRelationName} onChange={setNewRelationName}
/>
</BulkAction>
)
}
export default class RenameRelationBulkAction extends AbstractBulkAction {
static get actionName() {
return "renameRelation";
}
static get actionTitle() {
return t("rename_relation.rename_relation");
}
doRender() {
return <RenameRelationBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
}
}

Some files were not shown because too many files have changed in this diff Show More