diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index b4dfb29f7f..017e5b6205 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -186,6 +186,14 @@ When adding query parameters to ETAPI endpoints (`apps/server/src/etapi/`), main **Auth note**: ETAPI uses basic auth with tokens. Internal API endpoints trust the frontend. +### Adding New LLM Tools +Tools are defined using `defineTools()` in `apps/server/src/services/llm/tools/` and automatically registered for both the LLM chat and MCP server. + +1. Add the tool definition in the appropriate module (`note_tools.ts`, `attribute_tools.ts`, `hierarchy_tools.ts`) or create a new module +2. Each tool needs: `description`, `inputSchema` (Zod), `execute` function, and optionally `mutates: true` for write operations or `needsContext: true` for tools that need the current note context +3. If creating a new module, wrap tools in `defineTools({...})` and add the registry to `allToolRegistries` in `tools/index.ts` +4. Add a client-side friendly name in `apps/client/src/translations/en/translation.json` under `llm.tools.` — use **imperative tense** (e.g. "Search notes", "Create note", "Get attributes"), not present continuous + ### Database Migrations - Add scripts in `apps/server/src/migrations/YYMMDD_HHMM__description.sql` - Update schema in `apps/server/src/assets/db/schema.sql` @@ -213,6 +221,12 @@ When adding query parameters to ETAPI endpoints (`apps/server/src/etapi/`), main 10. **Attribute inheritance can be complex** - When checking for labels/relations, use `note.getOwnedAttribute()` for direct attributes or `note.getAttribute()` for inherited ones. Don't assume attributes are directly on the note. +## MCP Server +- Trilium exposes an MCP (Model Context Protocol) server at `http://localhost:8080/mcp`, configured in `.mcp.json` +- The MCP server is **only available when the Trilium server is running** (`pnpm run server:start`) +- It provides tools for reading, searching, and modifying notes directly from the AI assistant +- Use it to interact with actual note data when developing or debugging note-related features + ## TypeScript Configuration - **Project references**: Monorepo uses TypeScript project references (`tsconfig.json`) @@ -275,6 +289,12 @@ View types are configured via `#viewType` label (e.g., `#viewType=table`). Each - Register in `packages/ckeditor5/src/plugins.ts` - See `ckeditor5-admonition`, `ckeditor5-footnotes`, `ckeditor5-math`, `ckeditor5-mermaid` for examples +### Updating PDF.js +1. Update `pdfjs-dist` version in `packages/pdfjs-viewer/package.json` +2. Run `npx tsx scripts/update-viewer.ts` from that directory +3. Run `pnpm build` to verify success +4. Commit all changes including updated viewer files + ### Database Migrations - Add migration scripts in `apps/server/src/migrations/YYMMDD_HHMM__description.sql` - Update schema in `apps/server/src/assets/db/schema.sql` @@ -299,6 +319,8 @@ Trilium provides powerful user scripting capabilities: - Translation files in `apps/client/src/translations/` - Use translation system via `t()` function - Automatic pluralization: Add `_other` suffix to translation keys (e.g., `item` and `item_other` for singular/plural) +- When a translated string contains **interpolated components** (e.g. links, note references) whose order may vary across languages, use `` from `react-i18next` instead of `t()`. This lets translators reorder components freely (e.g. `" in "` vs `"in , "`) +- When adding a new locale, follow the step-by-step guide in `docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Adding a new locale.md` ## Testing Conventions diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 38d170903a..138fc39bc1 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -1,9 +1,13 @@ name: Dev on: push: - branches: [ main ] + branches: + - main + - "release/*" pull_request: - branches: [ main ] + branches: + - main + - "release/*" concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b3998e8365..c4ae22eb73 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -69,6 +69,8 @@ jobs: cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile + env: + npm_config_package_import_method: copy - name: Update nightly version run: pnpm run chore:ci-update-nightly-version - name: Run the build diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000000..9fd17b8d67 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "trilium": { + "type": "http", + "url": "http://localhost:8080/mcp" + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md index 5e70898951..56073acda4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -118,6 +118,16 @@ Trilium provides powerful user scripting capabilities: ### Internationalization - Translation files in `apps/client/src/translations/` - Supported languages: English, German, Spanish, French, Romanian, Chinese +- **Only add new translation keys to `en/translation.json`** — translations for other languages are managed via Weblate and will be contributed by the community +- Third-party components (e.g., mind-map context menu) should use i18next `t()` for their labels, with the English strings added to `en/translation.json` under a dedicated namespace (e.g., `"mind-map"`) +- When a translated string contains **interpolated components** (e.g. links, note references) whose order may vary across languages, use `` from `react-i18next` instead of `t()`. This lets translators reorder components freely (e.g. `" in "` vs `"in , "`) +- When adding a new locale, follow the step-by-step guide in `docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Adding a new locale.md` +- **Server-side translations** (e.g. hidden subtree titles) go in `apps/server/src/assets/translations/en/server.json`, not in the client `translation.json` + +### Electron Desktop App +- Desktop entry point: `apps/desktop/src/main.ts`, window management: `apps/server/src/services/window.ts` +- IPC communication: use `electron.ipcMain.on(channel, handler)` on server side, `electron.ipcRenderer.send(channel, data)` on client side +- Electron-only features should check `isElectron()` from `apps/client/src/services/utils.ts` (client) or `utils.isElectron` (server) ### Security Considerations - Per-note encryption with granular protected sessions @@ -125,6 +135,15 @@ Trilium provides powerful user scripting capabilities: - OpenID and TOTP authentication support - Sanitization of user-generated content +### Client-Side API Restrictions +- **Do not use `crypto.randomUUID()`** or other Web Crypto APIs that require secure contexts - Trilium can run over HTTP, not just HTTPS +- Use `randomString()` from `apps/client/src/services/utils.ts` for generating IDs instead + +### Shared Types Policy +- Types shared between client and server belong in `@triliumnext/commons` (`packages/commons/src/lib/`) +- Import shared types directly from `@triliumnext/commons` - do not re-export them from app-specific modules +- Keep app-specific types (e.g., `LlmProvider` for server, `StreamCallbacks` for client) in their respective apps + ## Common Development Tasks ### Adding New Note Types @@ -140,10 +159,51 @@ Trilium provides powerful user scripting capabilities: - Create new package in `packages/` following existing plugin structure - Register in `packages/ckeditor5/src/plugins.ts` +### Adding Hidden System Notes +The hidden subtree (`_hidden`) contains system notes with predictable IDs (prefixed with `_`). Defined in `apps/server/src/services/hidden_subtree.ts` via the `HiddenSubtreeItem` interface from `@triliumnext/commons`. + +1. Add the note definition to `buildHiddenSubtreeDefinition()` in `apps/server/src/services/hidden_subtree.ts` +2. Add a translation key for the title in `apps/server/src/assets/translations/en/server.json` under `"hidden-subtree"` +3. The note is auto-created on startup by `checkHiddenSubtree()` — uses deterministic IDs so all sync cluster instances generate the same structure +4. Key properties: `id` (must start with `_`), `title`, `type`, `icon` (format: `bx-icon-name` without `bx ` prefix), `attributes`, `children`, `content` +5. Use `enforceAttributes: true` to keep attributes in sync, `enforceBranches: true` for correct placement, `enforceDeleted: true` to remove deprecated notes +6. For launcher bar entries, see `hidden_subtree_launcherbar.ts`; for templates, see `hidden_subtree_templates.ts` + +### Writing to Notes from Server Services +- `note.setContent()` requires a CLS (Continuation Local Storage) context — wrap calls in `cls.init(() => { ... })` (from `apps/server/src/services/cls.ts`) +- Operations called from Express routes already have CLS context; standalone services (schedulers, Electron IPC handlers) do not + +### Adding New LLM Tools +Tools are defined using `defineTools()` in `apps/server/src/services/llm/tools/` and automatically registered for both the LLM chat and MCP server. + +1. Add the tool definition in the appropriate module (`note_tools.ts`, `attribute_tools.ts`, `attachment_tools.ts`, `hierarchy_tools.ts`) or create a new module +2. Each tool needs: `description`, `inputSchema` (Zod), `execute` function, and optionally `mutates: true` for write operations +3. If creating a new module, wrap tools in `defineTools({...})` and add the registry to `allToolRegistries` in `tools/index.ts` +4. Add a client-side friendly name in `apps/client/src/translations/en/translation.json` under `llm.tools.` — use **imperative tense** (e.g. "Search notes", "Create note", "Get attributes"), not present continuous +5. Use ETAPI (`apps/server/src/etapi/`) as inspiration for what fields to expose, but **do not import ETAPI mappers** — inline the field mappings directly in the tool so the LLM layer stays decoupled from the API layer + +### Updating PDF.js +1. Update `pdfjs-dist` version in `packages/pdfjs-viewer/package.json` +2. Run `npx tsx scripts/update-viewer.ts` from that directory +3. Run `pnpm build` to verify success +4. Commit all changes including updated viewer files + ### Database Migrations - Add migration scripts in `apps/server/src/migrations/` - Update schema in `apps/server/src/assets/db/schema.sql` +### Server-Side Static Assets +- Static assets (templates, SQL, translations, etc.) go in `apps/server/src/assets/` +- Access them at runtime via `RESOURCE_DIR` from `apps/server/src/services/resource_dir.ts` (e.g. `path.join(RESOURCE_DIR, "llm", "skills", "file.md")`) +- **Do not use `import.meta.url`/`fileURLToPath`** to resolve file paths — the server is bundled into CJS for production, so `import.meta.url` will not point to the source directory +- **Do not use `__dirname` with relative paths** from source files — after bundling, `__dirname` points to the bundle output, not the original source tree + +## MCP Server +- Trilium exposes an MCP (Model Context Protocol) server at `http://localhost:8080/mcp`, configured in `.mcp.json` +- The MCP server is **only available when the Trilium server is running** (`pnpm run server:start`) +- It provides tools for reading, searching, and modifying notes directly from the AI assistant +- Use it to interact with actual note data when developing or debugging note-related features + ## Build System Notes - Uses pnpm for monorepo management - Vite for fast development builds diff --git a/SECURITY.md b/SECURITY.md index 20c58fca16..befd061a74 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,13 +2,87 @@ ## Supported Versions -In the (still active) 0.X phase of the project only the latest stable minor release is getting bugfixes (including security ones). +Only the latest stable minor release receives security fixes. -So e.g. if the latest stable version is 0.42.3 and the latest beta version is 0.43.0-beta, then 0.42 line will still get security fixes but older versions (like 0.41.X) won't get any fixes. +For example, if the latest stable version is 0.92.3 and the latest beta is 0.93.0-beta, then only the 0.92.x line will receive security patches. Older versions (like 0.91.x) will not receive fixes. -Description above is a general rule and may be altered on case by case basis. +This policy may be altered on a case-by-case basis for critical vulnerabilities. ## Reporting a Vulnerability -* For low severity vulnerabilities, they can be reported as GitHub issues. -* For severe vulnerabilities, please report it using [GitHub Security Advisories](https://github.com/TriliumNext/Trilium/security/advisories). +**Please report all security vulnerabilities through [GitHub Security Advisories](https://github.com/TriliumNext/Notes/security/advisories/new).** + +We do not accept security reports via email, public issues, or other channels. GitHub Security Advisories allows us to: +- Discuss and triage vulnerabilities privately +- Coordinate fixes before public disclosure +- Credit reporters appropriately +- Publish advisories with CVE identifiers + +### What to Include + +When reporting, please provide: +- A clear description of the vulnerability +- Steps to reproduce or proof-of-concept +- Affected versions (if known) +- Potential impact assessment +- Any suggested mitigations or fixes + +### Response Timeline + +- **Initial response**: Within 7 days +- **Triage decision**: Within 14 days +- **Fix timeline**: Depends on severity and complexity + +## Scope + +### In Scope + +- Remote code execution +- Authentication/authorization bypass +- Cross-site scripting (XSS) that affects other users +- SQL injection +- Path traversal +- Sensitive data exposure +- Privilege escalation + +### Out of Scope (Won't Fix) + +The following are considered out of scope or accepted risks: + +#### Self-XSS / Self-Injection +Trilium is a personal knowledge base where users have full control over their own data. Users can intentionally create notes containing scripts, HTML, or other executable content. This is by design - Trilium's scripting system allows users to extend functionality with custom JavaScript. + +Vulnerabilities that require a user to inject malicious content into their own notes and then view it themselves are not considered security issues. + +#### Electron Architecture (nodeIntegration) +Trilium's desktop application runs with `nodeIntegration: true` to enable its powerful scripting features. This is an intentional design decision, similar to VS Code extensions having full system access. We mitigate risks by: +- Sanitizing content at input boundaries +- Fixing specific XSS vectors as they're discovered +- Using Electron fuses to prevent external abuse + +#### Authenticated User Actions +Actions that require valid authentication and only affect the authenticated user's own data are generally not vulnerabilities. + +#### Denial of Service via Resource Exhaustion +Creating extremely large notes or performing many operations is expected user behavior in a note-taking application. + +#### Missing Security Headers on Non-Sensitive Endpoints +We implement security headers where they provide meaningful protection, but may omit them on endpoints where they provide no practical benefit. + +## Coordinated Disclosure + +We follow a coordinated disclosure process: + +1. **Report received** - We acknowledge receipt and begin triage +2. **Fix developed** - We develop and test a fix privately +3. **Release prepared** - Security release is prepared with vague changelog +4. **Users notified** - Release is published, users encouraged to upgrade +5. **Advisory published** - After reasonable upgrade window (typically 2-4 weeks), full advisory is published + +We appreciate reporters allowing us time to fix issues before public disclosure. We aim to credit all reporters in published advisories unless they prefer to remain anonymous. + +## Security Updates + +Security fixes are released as patch versions (e.g., 0.92.1 → 0.92.2) to minimize upgrade friction. We recommend all users keep their installations up to date. + +Subscribe to GitHub releases or watch the repository to receive notifications of new releases. diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index aa4f56d489..fc61700eac 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -16,13 +16,11 @@ "license": "AGPL-3.0-only", "packageManager": "pnpm@10.33.0", "devDependencies": { - "@redocly/cli": "2.25.2", + "@redocly/cli": "2.25.4", "archiver": "7.0.1", "fs-extra": "11.3.4", "js-yaml": "4.1.1", - "react": "19.2.4", - "react-dom": "19.2.4", "typedoc": "0.28.18", - "typedoc-plugin-missing-exports": "4.1.2" + "typedoc-plugin-missing-exports": "4.1.3" } } diff --git a/apps/client/package.json b/apps/client/package.json index 8010438651..52738c71a9 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "@triliumnext/client", - "version": "0.102.1", + "version": "0.102.2", "description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)", "private": true, "license": "AGPL-3.0-only", @@ -27,7 +27,6 @@ "@maplibre/maplibre-gl-leaflet": "0.1.3", "@mermaid-js/layout-elk": "0.2.1", "@mind-elixir/node-menu": "5.0.1", - "@popperjs/core": "2.11.8", "@preact/signals": "2.9.0", "@triliumnext/ckeditor5": "workspace:*", "@triliumnext/codemirror": "workspace:*", @@ -35,26 +34,26 @@ "@triliumnext/highlightjs": "workspace:*", "@triliumnext/share-theme": "workspace:*", "@triliumnext/split.js": "workspace:*", - "@univerjs/preset-sheets-conditional-formatting": "0.18.0", - "@univerjs/preset-sheets-core": "0.18.0", - "@univerjs/preset-sheets-data-validation": "0.18.0", - "@univerjs/preset-sheets-filter": "0.18.0", - "@univerjs/preset-sheets-find-replace": "0.18.0", - "@univerjs/preset-sheets-note": "0.18.0", - "@univerjs/preset-sheets-sort": "0.18.0", - "@univerjs/presets": "0.18.0", - "@zumer/snapdom": "2.6.0", + "@univerjs/preset-sheets-conditional-formatting": "0.20.0", + "@univerjs/preset-sheets-core": "0.20.0", + "@univerjs/preset-sheets-data-validation": "0.20.0", + "@univerjs/preset-sheets-filter": "0.20.0", + "@univerjs/preset-sheets-find-replace": "0.20.0", + "@univerjs/preset-sheets-note": "0.20.0", + "@univerjs/preset-sheets-sort": "0.20.0", + "@univerjs/presets": "0.20.0", + "@zumer/snapdom": "2.7.0", "autocomplete.js": "0.38.1", "bootstrap": "5.3.8", "boxicons": "2.1.4", "clsx": "2.1.1", "color": "5.0.3", "debounce": "3.0.0", + "dompurify": "3.3.3", "draggabilly": "3.0.0", "force-graph": "1.51.2", - "globals": "17.4.0", - "i18next": "25.10.10", - "i18next-http-backend": "3.0.2", + "i18next": "26.0.3", + "i18next-http-backend": "3.0.4", "jquery": "4.0.0", "jquery.fancytree": "2.38.5", "jsplumb": "2.15.6", @@ -63,12 +62,11 @@ "leaflet-gpx": "2.2.0", "mark.js": "8.11.1", "marked": "17.0.5", - "mermaid": "11.13.0", - "mind-elixir": "5.9.3", - "normalize.css": "8.0.1", + "mermaid": "11.14.0", + "mind-elixir": "5.10.0", "panzoom": "9.4.4", - "preact": "10.29.0", - "react-i18next": "17.0.0", + "preact": "10.29.1", + "react-i18next": "17.0.2", "react-window": "2.2.7", "reveal.js": "6.0.0", "rrule": "2.8.1", @@ -89,6 +87,6 @@ "happy-dom": "20.8.9", "lightningcss": "1.32.0", "script-loader": "0.7.2", - "vite-plugin-static-copy": "3.4.0" + "vite-plugin-static-copy": "4.0.1" } } diff --git a/apps/client/src/components/app_context.ts b/apps/client/src/components/app_context.ts index 1c1389810a..7019617714 100644 --- a/apps/client/src/components/app_context.ts +++ b/apps/client/src/components/app_context.ts @@ -1,10 +1,11 @@ import type { CKTextEditor } from "@triliumnext/ckeditor5"; import type CodeMirror from "@triliumnext/codemirror"; -import { SqlExecuteResponse } from "@triliumnext/commons"; +import { type LOCALE_IDS, SqlExecuteResponse } from "@triliumnext/commons"; import type { NativeImage, TouchBar } from "electron"; import { ColumnComponent } from "tabulator-tables"; import type { Attribute } from "../services/attribute_parser.js"; +import bundleService from "../services/bundle.js"; import froca from "../services/froca.js"; import { initLocale, t } from "../services/i18n.js"; import keyboardActionsService from "../services/keyboard_actions.js"; @@ -302,6 +303,7 @@ export type CommandMappings = { ninthTab: CommandData; lastTab: CommandData; showNoteSource: CommandData; + showNoteOCRText: CommandData; showSQLConsole: CommandData; showBackendLog: CommandData; showCheatsheet: CommandData; @@ -508,7 +510,7 @@ type EventMappings = { contentSafeMarginChanged: { top: number; noteContext: NoteContext; - } + }; }; export type EventListener = { @@ -562,7 +564,7 @@ export class AppContext extends Component { */ async earlyInit() { await options.initializedPromise; - await initLocale(); + await initLocale((options.get("locale") || "en") as LOCALE_IDS); } setLayout(layout: Layout) { @@ -577,7 +579,6 @@ export class AppContext extends Component { this.tabManager.loadTabs(); - const bundleService = (await import("../services/bundle.js")).default; setTimeout(() => bundleService.executeStartupBundles(), 2000); } diff --git a/apps/client/src/components/root_command_executor.ts b/apps/client/src/components/root_command_executor.ts index 2aa5b90499..4560eafce6 100644 --- a/apps/client/src/components/root_command_executor.ts +++ b/apps/client/src/components/root_command_executor.ts @@ -148,6 +148,19 @@ export default class RootCommandExecutor extends Component { } } + async showNoteOCRTextCommand() { + const notePath = appContext.tabManager.getActiveContextNotePath(); + + if (notePath) { + await appContext.tabManager.openTabWithNoteWithHoisting(notePath, { + activate: true, + viewScope: { + viewMode: "ocr" + } + }); + } + } + async showAttachmentsCommand() { const notePath = appContext.tabManager.getActiveContextNotePath(); diff --git a/apps/client/src/desktop.ts b/apps/client/src/desktop.ts index 6f22d3fc7b..bb1f859809 100644 --- a/apps/client/src/desktop.ts +++ b/apps/client/src/desktop.ts @@ -54,7 +54,7 @@ function initOnElectron() { const currentWindow = electronRemote.getCurrentWindow(); const style = window.getComputedStyle(document.body); - initDarkOrLightMode(style); + initDarkOrLightMode(); initTransparencyEffects(style, currentWindow); initFullScreenDetection(currentWindow); @@ -119,11 +119,11 @@ function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Elec * * @param style the root CSS element to read variables from. */ -function initDarkOrLightMode(style: CSSStyleDeclaration) { +function initDarkOrLightMode() { let themeSource: typeof nativeTheme.themeSource = "system"; - const themeStyle = style.getPropertyValue("--theme-style"); - if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) { + const themeStyle = window.glob.getThemeStyle(); + if (themeStyle !== "auto") { themeSource = themeStyle; } diff --git a/apps/client/src/entities/fnote.ts b/apps/client/src/entities/fnote.ts index 4082671b87..5fe7caf33c 100644 --- a/apps/client/src/entities/fnote.ts +++ b/apps/client/src/entities/fnote.ts @@ -1,5 +1,6 @@ import { getNoteIcon } from "@triliumnext/commons"; +import bundleService from "../services/bundle.js"; import cssClassManager from "../services/css_class_manager.js"; import type { Froca } from "../services/froca-interface.js"; import noteAttributeCache from "../services/note_attribute_cache.js"; @@ -18,7 +19,7 @@ const RELATION = "relation"; * end user. Those types should be used only for checking against, they are * not for direct use. */ -export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "spreadsheet"; +export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "spreadsheet" | "llmChat"; export interface NotePathRecord { isArchived: boolean; @@ -1014,7 +1015,6 @@ export default class FNote { const env = this.getScriptEnv(); if (env === "frontend") { - const bundleService = (await import("../services/bundle.js")).default; return await bundleService.getAndExecuteBundle(this.noteId); } else if (env === "backend") { await server.post(`script/run/${this.noteId}`); diff --git a/apps/client/src/index.ts b/apps/client/src/index.ts index fba6e17d7e..720d3eb59c 100644 --- a/apps/client/src/index.ts +++ b/apps/client/src/index.ts @@ -1,3 +1,5 @@ +import { getThemeStyle } from "./services/theme"; + async function bootstrap() { showSplash(); await setupGlob(); @@ -38,6 +40,7 @@ async function setupGlob() { ...json, activeDialog: null }; + window.glob.getThemeStyle = getThemeStyle; } async function loadBootstrapCss() { @@ -49,31 +52,65 @@ async function loadBootstrapCss() { } } -function loadStylesheets() { - const { device, assetPath, themeCssUrl, themeUseNextAsBase } = window.glob; +type StylesheetRef = { + href: string; + media?: string; +}; - const cssToLoad: string[] = []; - if (device !== "print") { - cssToLoad.push(`${assetPath}/stylesheets/ckeditor-theme.css`); - cssToLoad.push(`api/fonts`); - cssToLoad.push(`${assetPath}/stylesheets/theme-light.css`); - if (themeCssUrl) { - cssToLoad.push(themeCssUrl); - } - if (themeUseNextAsBase === "next") { - cssToLoad.push(`${assetPath}/stylesheets/theme-next.css`); - } else if (themeUseNextAsBase === "next-dark") { - cssToLoad.push(`${assetPath}/stylesheets/theme-next-dark.css`); - } else if (themeUseNextAsBase === "next-light") { - cssToLoad.push(`${assetPath}/stylesheets/theme-next-light.css`); - } - cssToLoad.push(`${assetPath}/stylesheets/style.css`); +function getConfiguredThemeStylesheets(stylesheetsPath: string, theme: string, customThemeCssUrl?: string) { + if (theme === "auto") { + return [{ href: `${stylesheetsPath}/theme-dark.css`, media: "(prefers-color-scheme: dark)" }]; } - for (const href of cssToLoad) { + if (theme === "dark") { + return [{ href: `${stylesheetsPath}/theme-dark.css` }]; + } + + if (theme === "next") { + return [ + { href: `${stylesheetsPath}/theme-next-light.css` }, + { href: `${stylesheetsPath}/theme-next-dark.css`, media: "(prefers-color-scheme: dark)" } + ]; + } + + if (theme === "next-light") { + return [{ href: `${stylesheetsPath}/theme-next-light.css` }]; + } + + if (theme === "next-dark") { + return [{ href: `${stylesheetsPath}/theme-next-dark.css` }]; + } + + if (theme !== "light" && customThemeCssUrl) { + return [{ href: customThemeCssUrl }]; + } + + return []; +} + +function loadStylesheets() { + const { device, assetPath, theme, themeBase, customThemeCssUrl } = window.glob; + const stylesheetsPath = `${assetPath}/stylesheets`; + + const cssToLoad: StylesheetRef[] = []; + if (device !== "print") { + cssToLoad.push({ href: `${stylesheetsPath}/ckeditor-theme.css` }); + cssToLoad.push({ href: `api/fonts` }); + cssToLoad.push({ href: `${stylesheetsPath}/theme-light.css` }); + cssToLoad.push(...getConfiguredThemeStylesheets(stylesheetsPath, theme, customThemeCssUrl)); + if (themeBase) { + cssToLoad.push(...getConfiguredThemeStylesheets(stylesheetsPath, themeBase)); + } + cssToLoad.push({ href: `${stylesheetsPath}/style.css` }); + } + + for (const { href, media } of cssToLoad) { const linkEl = document.createElement("link"); linkEl.href = href; linkEl.rel = "stylesheet"; + if (media) { + linkEl.media = media; + } document.head.appendChild(linkEl); } } diff --git a/apps/client/src/menus/electron_context_menu.ts b/apps/client/src/menus/electron_context_menu.ts index 6baba6a951..a894cebfc3 100644 --- a/apps/client/src/menus/electron_context_menu.ts +++ b/apps/client/src/menus/electron_context_menu.ts @@ -1,12 +1,14 @@ -import utils from "../services/utils.js"; -import options from "../services/options.js"; -import zoomService from "../components/zoom.js"; -import contextMenu, { type MenuItem } from "./context_menu.js"; -import { t } from "../services/i18n.js"; -import server from "../services/server.js"; -import * as clipboardExt from "../services/clipboard_ext.js"; import type { BrowserWindow } from "electron"; -import type { CommandNames, AppContext } from "../components/app_context.js"; + +import type { CommandNames } from "../components/app_context.js"; +import appContext from "../components/app_context.js"; +import zoomService from "../components/zoom.js"; +import * as clipboardExt from "../services/clipboard_ext.js"; +import { t } from "../services/i18n.js"; +import options from "../services/options.js"; +import server from "../services/server.js"; +import utils from "../services/utils.js"; +import contextMenu, { type MenuItem } from "./context_menu.js"; function setupContextMenu() { const electron = utils.dynamicRequire("electron"); @@ -15,8 +17,6 @@ function setupContextMenu() { // FIXME: Remove typecast once Electron is properly integrated. const { webContents } = remote.getCurrentWindow() as BrowserWindow; - let appContext: AppContext; - webContents.on("context-menu", (event, params) => { const { editFlags } = params; const hasText = params.selectionText.trim().length > 0; @@ -38,7 +38,7 @@ function setupContextMenu() { items.push({ title: t("electron_context_menu.add-term-to-dictionary", { term: params.misspelledWord }), uiIcon: "bx bx-plus", - handler: () => webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord) + handler: () => electron.ipcRenderer.send("add-word-to-dictionary", params.misspelledWord) }); items.push({ kind: "separator" }); @@ -141,7 +141,7 @@ function setupContextMenu() { } // Replace the placeholder with the real search keyword. - let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText)); + const searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText)); items.push({ kind: "separator" }); @@ -155,10 +155,6 @@ function setupContextMenu() { title: t("electron_context_menu.search_in_trilium", { term: shortenedSelection }), uiIcon: "bx bx-search", handler: async () => { - if (!appContext) { - appContext = (await import("../components/app_context.js")).default; - } - await appContext.triggerCommand("searchNotes", { searchString: params.selectionText }); diff --git a/apps/client/src/print.tsx b/apps/client/src/print.tsx index dc7817d9b5..c943413c49 100644 --- a/apps/client/src/print.tsx +++ b/apps/client/src/print.tsx @@ -4,6 +4,7 @@ import { useCallback, useLayoutEffect, useRef } from "preact/hooks"; import FNote from "./entities/fnote"; import content_renderer from "./services/content_renderer"; import { applyInlineMermaid } from "./services/content_renderer_text"; +import froca from "./services/froca"; import { dynamicRequire, isElectron } from "./services/utils"; import { CustomNoteList, useNoteViewType } from "./widgets/collections/NoteList"; @@ -30,7 +31,6 @@ async function main() { if (!noteId) return; await import("./print.css"); - const froca = (await import("./services/froca")).default; const note = await froca.getNote(noteId); const bodyWrapper = document.createElement("div"); diff --git a/apps/client/src/services/bundle.ts b/apps/client/src/services/bundle.ts index 7cee01812b..fdee38ba34 100644 --- a/apps/client/src/services/bundle.ts +++ b/apps/client/src/services/bundle.ts @@ -26,7 +26,7 @@ type WithNoteId = T & { }; export type Widget = WithNoteId<(LegacyWidget | WidgetDefinitionWithType)>; -async function getAndExecuteBundle(noteId: string, originEntity = null, script = null, params = null) { +async function getAndExecuteBundle(noteId: string, originEntity: Entity | null = null, script: string | null = null, params: string | null = null) { const bundle = await server.post(`script/bundle/${noteId}`, { script, params diff --git a/apps/client/src/services/clipboard_ext.ts b/apps/client/src/services/clipboard_ext.ts index 9ab98af68f..16eea4ca49 100644 --- a/apps/client/src/services/clipboard_ext.ts +++ b/apps/client/src/services/clipboard_ext.ts @@ -1,3 +1,6 @@ +import { t } from "./i18n.js"; +import toast from "./toast.js"; + export function copyText(text: string) { if (!text) { return; @@ -6,29 +9,26 @@ export function copyText(text: string) { if (navigator.clipboard) { navigator.clipboard.writeText(text); return true; - } else { - // Fallback method: https://stackoverflow.com/a/72239825 - const textArea = document.createElement("textarea"); - textArea.value = text; - try { - document.body.appendChild(textArea); - textArea.focus(); - textArea.select(); - return document.execCommand('copy'); - } finally { - document.body.removeChild(textArea); - } + } + // Fallback method: https://stackoverflow.com/a/72239825 + const textArea = document.createElement("textarea"); + textArea.value = text; + try { + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + return document.execCommand('copy'); + } finally { + document.body.removeChild(textArea); } + } catch (e) { console.warn(e); return false; } } -export async function copyTextWithToast(text: string) { - const t = (await import("./i18n.js")).t; - const toast = (await import("./toast.js")).default; - +export function copyTextWithToast(text: string) { if (copyText(text)) { toast.showMessage(t("clipboard.copy_success")); } else { diff --git a/apps/client/src/services/content_renderer.ts b/apps/client/src/services/content_renderer.ts index ec29f094b5..e037383a73 100644 --- a/apps/client/src/services/content_renderer.ts +++ b/apps/client/src/services/content_renderer.ts @@ -1,6 +1,6 @@ import "./content_renderer.css"; -import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; +import { normalizeMimeTypeForCKEditor, type TextRepresentationResponse } from "@triliumnext/commons"; import { h, render } from "preact"; import WheelZoom from 'vanilla-js-wheel-zoom'; @@ -15,6 +15,7 @@ import openService from "./open.js"; import protectedSessionService from "./protected_session.js"; import protectedSessionHolder from "./protected_session_holder.js"; import renderService from "./render.js"; +import server from "./server.js"; import { applySingleBlockSyntaxHighlight } from "./syntax_highlight.js"; import utils, { getErrorMessage } from "./utils.js"; @@ -32,6 +33,7 @@ export interface RenderOptions { includeArchivedNotes?: boolean; /** Set of note IDs that have already been seen during rendering to prevent infinite recursion. */ seenNoteIds?: Set; + showTextRepresentation?: boolean; } const CODE_MIME_TYPES = new Set(["application/json"]); @@ -55,9 +57,9 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo } else if (type === "code") { await renderCode(entity, $renderedContent); } else if (["image", "canvas", "mindMap", "spreadsheet"].includes(type)) { - renderImage(entity, $renderedContent, options); + await renderImage(entity, $renderedContent, options); } else if (!options.tooltip && ["file", "pdf", "audio", "video"].includes(type)) { - await renderFile(entity, type, $renderedContent); + await renderFile(entity, type, $renderedContent, options); } else if (type === "mermaid") { await renderMermaid(entity, $renderedContent); } else if (type === "render" && entity instanceof FNote) { @@ -138,7 +140,7 @@ async function renderCode(note: FNote | FAttachment, $renderedContent: JQuery, options: RenderOptions = {}) { +async function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery, options: RenderOptions = {}) { const encodedTitle = encodeURIComponent(entity.title); let url; @@ -146,13 +148,14 @@ function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery`; + url = `api/attachments/${entity.attachmentId}/image/${encodedTitle}?${entity.utcDateModified}`; } $renderedContent // styles needed for the zoom to work well .css("display", "flex") .css("align-items", "center") - .css("justify-content", "center"); + .css("justify-content", "center") + .css("flex-direction", "column"); // OCR text is displayed below the image. const $img = $("") .attr("src", url || "") @@ -178,9 +181,35 @@ function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery) { +async function addOCRTextIfAvailable(note: FNote, $content: JQuery) { + try { + const data = await server.get(`ocr/notes/${note.noteId}/text`); + if (data.success && data.hasOcr && data.text) { + const $ocrSection = $(` +
+
+ ${t("ocr.extracted_text")} +
+
+
+ `); + + $ocrSection.find('.ocr-content').text(data.text); + $content.append($ocrSection); + } + } catch (error) { + // Silently fail if OCR API is not available + console.debug('Failed to fetch OCR text:', error); + } +} + +async function renderFile(entity: FNote | FAttachment, type: string, $renderedContent: JQuery, options: RenderOptions = {}) { let entityType, entityId; if (entity instanceof FNote) { @@ -220,6 +249,10 @@ async function renderFile(entity: FNote | FAttachment, type: string, $renderedCo $content.append($videoPreview); } + if (entity instanceof FNote && options.showTextRepresentation) { + await addOCRTextIfAvailable(entity, $content); + } + if (entityType === "notes" && "noteId" in entity) { // TODO: we should make this available also for attachments, but there's a problem with "Open externally" support // in attachment list diff --git a/apps/client/src/services/date_notes.ts b/apps/client/src/services/date_notes.ts index 21709b1bb0..f452e55dec 100644 --- a/apps/client/src/services/date_notes.ts +++ b/apps/client/src/services/date_notes.ts @@ -84,6 +84,55 @@ async function createSearchNote(opts = {}) { return await froca.getNote(note.noteId); } +async function createLlmChat() { + const note = await server.post("special-notes/llm-chat"); + + await ws.waitForMaxKnownEntityChangeId(); + + return await froca.getNote(note.noteId); +} + +/** + * Gets the most recently modified LLM chat. + * Returns null if no chat exists. + */ +async function getMostRecentLlmChat() { + const note = await server.get("special-notes/most-recent-llm-chat"); + + if (!note) { + return null; + } + + await ws.waitForMaxKnownEntityChangeId(); + + return await froca.getNote(note.noteId); +} + +/** + * Gets the most recent LLM chat, or creates a new one if none exists. + * Used by sidebar chat for persistent conversations across page refreshes. + */ +async function getOrCreateLlmChat() { + const note = await server.get("special-notes/get-or-create-llm-chat"); + + await ws.waitForMaxKnownEntityChangeId(); + + return await froca.getNote(note.noteId); +} + +export interface RecentLlmChat { + noteId: string; + title: string; + dateModified: string; +} + +/** + * Gets a list of recent LLM chats for the history popup. + */ +async function getRecentLlmChats(limit: number = 10): Promise { + return await server.get(`special-notes/recent-llm-chats?limit=${limit}`); +} + export default { getInboxNote, getTodayNote, @@ -94,5 +143,9 @@ export default { getMonthNote, getYearNote, createSqlConsole, - createSearchNote + createSearchNote, + createLlmChat, + getMostRecentLlmChat, + getOrCreateLlmChat, + getRecentLlmChats }; diff --git a/apps/client/src/services/dialog.ts b/apps/client/src/services/dialog.ts index 8711ec1751..6888870fc9 100644 --- a/apps/client/src/services/dialog.ts +++ b/apps/client/src/services/dialog.ts @@ -1,9 +1,11 @@ import { Modal } from "bootstrap"; + import appContext from "../components/app_context.js"; import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions, MessageType } from "../widgets/dialogs/confirm.js"; +import { InfoExtraProps } from "../widgets/dialogs/info.jsx"; import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js"; import { focusSavedElement, saveFocusedElement } from "./focus.js"; -import { InfoExtraProps } from "../widgets/dialogs/info.jsx"; +import keyboardActionsService from "./keyboard_actions.js"; export async function openDialog($dialog: JQuery, closeActDialog = true, config?: Partial) { if (closeActDialog) { @@ -25,7 +27,6 @@ export async function openDialog($dialog: JQuery, closeActDialog = } }); - const keyboardActionsService = (await import("./keyboard_actions.js")).default; keyboardActionsService.updateDisplayedShortcuts($dialog); return $dialog; diff --git a/apps/client/src/services/doc_renderer.spec.ts b/apps/client/src/services/doc_renderer.spec.ts new file mode 100644 index 0000000000..c36e3e80b9 --- /dev/null +++ b/apps/client/src/services/doc_renderer.spec.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; + +import { isValidDocName } from "./doc_renderer.js"; + +describe("isValidDocName", () => { + it("accepts valid docNames", () => { + expect(isValidDocName("launchbar_intro")).toBe(true); + expect(isValidDocName("User Guide/Quick Start")).toBe(true); + expect(isValidDocName("User Guide/User Guide/Quick Start")).toBe(true); + expect(isValidDocName("Quick Start Guide")).toBe(true); + expect(isValidDocName("quick_start_guide")).toBe(true); + expect(isValidDocName("quick-start-guide")).toBe(true); + }); + + it("rejects path traversal attacks", () => { + expect(isValidDocName("..")).toBe(false); + expect(isValidDocName("../etc/passwd")).toBe(false); + expect(isValidDocName("foo/../bar")).toBe(false); + expect(isValidDocName("../../../../api/notes/_malicious/open")).toBe(false); + expect(isValidDocName("..\\etc\\passwd")).toBe(false); + expect(isValidDocName("foo\\bar")).toBe(false); + }); + + it("rejects URL manipulation attacks", () => { + expect(isValidDocName("../../../../api/notes/_malicious/open?x=")).toBe(false); + expect(isValidDocName("foo#bar")).toBe(false); + expect(isValidDocName("%2e%2e")).toBe(false); + expect(isValidDocName("%2e%2e%2f%2e%2e%2fapi")).toBe(false); + }); +}); diff --git a/apps/client/src/services/doc_renderer.ts b/apps/client/src/services/doc_renderer.ts index 1ae60fb9ca..bb3bb996c2 100644 --- a/apps/client/src/services/doc_renderer.ts +++ b/apps/client/src/services/doc_renderer.ts @@ -3,22 +3,39 @@ import { applyReferenceLinks } from "../widgets/type_widgets/text/read_only_help import { getCurrentLanguage } from "./i18n.js"; import { formatCodeBlocks } from "./syntax_highlight.js"; +/** + * Validates a docName to prevent path traversal attacks. + * Allows forward slashes for subdirectories (e.g., "User Guide/Quick Start") + * but blocks traversal sequences and URL manipulation characters. + */ +export function isValidDocName(docName: string): boolean { + // Allow alphanumeric characters, spaces, underscores, hyphens, and forward slashes. + const validDocNameRegex = /^[a-zA-Z0-9_/\- ]+$/; + return validDocNameRegex.test(docName); +} + export default function renderDoc(note: FNote) { return new Promise>((resolve) => { - let docName = note.getLabelValue("docName"); + const docName = note.getLabelValue("docName"); const $content = $("
"); - if (docName) { - // find doc based on language - const url = getUrl(docName, getCurrentLanguage()); + // find doc based on language + const url = getUrl(docName, getCurrentLanguage()); + + if (url) { $content.load(url, async (response, status) => { // fallback to english doc if no translation available if (status === "error") { const fallbackUrl = getUrl(docName, "en"); - $content.load(fallbackUrl, async () => { - await processContent(fallbackUrl, $content) + + if (fallbackUrl) { + $content.load(fallbackUrl, async () => { + await processContent(fallbackUrl, $content); + resolve($content); + }); + } else { resolve($content); - }); + } return; } @@ -28,8 +45,6 @@ export default function renderDoc(note: FNote) { } else { resolve($content); } - - return $content; }); } @@ -39,7 +54,7 @@ async function processContent(url: string, $content: JQuery) { // Images are relative to the docnote but that will not work when rendered in the application since the path breaks. $content.find("img").each((i, el) => { const $img = $(el); - $img.attr("src", dir + "/" + $img.attr("src")); + $img.attr("src", `${dir}/${$img.attr("src")}`); }); formatCodeBlocks($content); @@ -48,10 +63,17 @@ async function processContent(url: string, $content: JQuery) { await applyReferenceLinks($content[0]); } -function getUrl(docNameValue: string, language: string) { +function getUrl(docNameValue: string | null, language: string) { + if (!docNameValue) return; + + if (!isValidDocName(docNameValue)) { + console.error(`Invalid docName: ${docNameValue}`); + return null; + } + // Cannot have spaces in the URL due to how JQuery.load works. docNameValue = docNameValue.replaceAll(" ", "%20"); - const basePath = window.glob.isDev ? window.glob.assetPath + "/.." : window.glob.assetPath; + const basePath = window.glob.isDev ? `${window.glob.assetPath }/..` : window.glob.assetPath; return `${basePath}/doc_notes/${language}/${docNameValue}.html`; } diff --git a/apps/client/src/services/experimental_features.ts b/apps/client/src/services/experimental_features.ts index 8cfbe126e8..d56836ef6b 100644 --- a/apps/client/src/services/experimental_features.ts +++ b/apps/client/src/services/experimental_features.ts @@ -13,6 +13,11 @@ export const experimentalFeatures = [ id: "new-layout", name: t("experimental_features.new_layout_name"), description: t("experimental_features.new_layout_description"), + }, + { + id: "llm", + name: t("experimental_features.llm_name"), + description: t("experimental_features.llm_description"), } ] as const satisfies ExperimentalFeature[]; diff --git a/apps/client/src/services/froca_updater.ts b/apps/client/src/services/froca_updater.ts index ca6c792746..8be1eceada 100644 --- a/apps/client/src/services/froca_updater.ts +++ b/apps/client/src/services/froca_updater.ts @@ -1,14 +1,16 @@ -import LoadResults from "./load_results.js"; -import froca from "./froca.js"; -import utils from "./utils.js"; -import options from "./options.js"; -import noteAttributeCache from "./note_attribute_cache.js"; -import FBranch, { type FBranchRow } from "../entities/fbranch.js"; -import FAttribute, { type FAttributeRow } from "../entities/fattribute.js"; +import type { OptionNames } from "@triliumnext/commons"; + +import appContext from "../components/app_context.js"; import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js"; +import FAttribute, { type FAttributeRow } from "../entities/fattribute.js"; +import FBranch, { type FBranchRow } from "../entities/fbranch.js"; import type { default as FNote, FNoteRow } from "../entities/fnote.js"; import type { EntityChange } from "../server_types.js"; -import type { OptionNames } from "@triliumnext/commons"; +import froca from "./froca.js"; +import LoadResults from "./load_results.js"; +import noteAttributeCache from "./note_attribute_cache.js"; +import options from "./options.js"; +import utils from "./utils.js"; async function processEntityChanges(entityChanges: EntityChange[]) { const loadResults = new LoadResults(entityChanges); @@ -63,7 +65,7 @@ async function processEntityChanges(entityChanges: EntityChange[]) { if (entityName === "branches" && !((entity as FBranchRow).parentNoteId in froca.notes)) { missingNoteIds.push((entity as FBranchRow).parentNoteId); } else if (entityName === "attributes") { - let attributeEntity = entity as FAttributeRow; + const attributeEntity = entity as FAttributeRow; if (attributeEntity.type === "relation" && (attributeEntity.name === "template" || attributeEntity.name === "inherit") && !(attributeEntity.value in froca.notes)) { missingNoteIds.push(attributeEntity.value); } @@ -79,7 +81,6 @@ async function processEntityChanges(entityChanges: EntityChange[]) { noteAttributeCache.invalidate(); } - const appContext = (await import("../components/app_context.js")).default; await appContext.triggerEvent("entitiesReloaded", { loadResults }); } } diff --git a/apps/client/src/services/frontend_script_api_preact.ts b/apps/client/src/services/frontend_script_api_preact.ts index 2829ca101e..9ce7a52e72 100644 --- a/apps/client/src/services/frontend_script_api_preact.ts +++ b/apps/client/src/services/frontend_script_api_preact.ts @@ -1,4 +1,4 @@ -import { Fragment, h, VNode } from "preact"; +import { createContext, Fragment, h, VNode } from "preact"; import * as hooks from "preact/hooks"; import ActionButton from "../widgets/react/ActionButton"; @@ -47,6 +47,7 @@ export const preactAPI = Object.freeze({ // Core h, Fragment, + createContext, /** * Method that must be run for widget scripts that run on Preact, using JSX. The method just returns the same definition, reserved for future typechecking and perhaps validation purposes. diff --git a/apps/client/src/services/i18n.ts b/apps/client/src/services/i18n.ts index c8bb9097d7..0743596731 100644 --- a/apps/client/src/services/i18n.ts +++ b/apps/client/src/services/i18n.ts @@ -1,21 +1,14 @@ -import options from "./options.js"; +import { LOCALE_IDS, LOCALES, setDayjsLocale } from "@triliumnext/commons"; import i18next from "i18next"; import i18nextHttpBackend from "i18next-http-backend"; -import server from "./server.js"; -import { LOCALE_IDS, setDayjsLocale, type Locale } from "@triliumnext/commons"; import { initReactI18next } from "react-i18next"; -let locales: Locale[] | null; - /** * A deferred promise that resolves when translations are initialized. */ -export let translationsInitializedPromise = $.Deferred(); +export const translationsInitializedPromise = $.Deferred(); -export async function initLocale() { - const locale = ((options.get("locale") as string) || "en") as LOCALE_IDS; - - locales = await server.get("options/locales"); +export async function initLocale(locale: LOCALE_IDS = "en") { i18next.use(initReactI18next); await i18next.use(i18nextHttpBackend).init({ @@ -24,8 +17,7 @@ export async function initLocale() { backend: { loadPath: `${window.glob.assetPath}/translations/{{lng}}/{{ns}}.json` }, - returnEmptyString: false, - showSupportNotice: false + returnEmptyString: false }); await setDayjsLocale(locale); @@ -33,11 +25,7 @@ export async function initLocale() { } export function getAvailableLocales() { - if (!locales) { - throw new Error("Tried to load list of locales, but localization is not yet initialized.") - } - - return locales; + return LOCALES; } /** @@ -48,7 +36,7 @@ export function getAvailableLocales() { */ export function getLocaleById(localeId: string | null | undefined) { if (!localeId) return null; - return locales?.find((l) => l.id === localeId) ?? null; + return LOCALES.find((l) => l.id === localeId) ?? null; } export const t = i18next.t; diff --git a/apps/client/src/services/in_app_help.ts b/apps/client/src/services/in_app_help.ts index ce4c0cdd15..4db04f3c4b 100644 --- a/apps/client/src/services/in_app_help.ts +++ b/apps/client/src/services/in_app_help.ts @@ -19,7 +19,8 @@ export const byNoteType: Record, string | null> = { search: null, text: null, webView: null, - spreadsheet: null + spreadsheet: null, + llmChat: null }; export const byBookType: Record = { diff --git a/apps/client/src/services/link.ts b/apps/client/src/services/link.ts index b74dd5f7b1..bee2ec09b7 100644 --- a/apps/client/src/services/link.ts +++ b/apps/client/src/services/link.ts @@ -28,7 +28,7 @@ async function getLinkIcon(noteId: string, viewMode: ViewMode | undefined) { return icon; } -export type ViewMode = "default" | "source" | "attachments" | "contextual-help" | "note-map"; +export type ViewMode = "default" | "source" | "attachments" | "contextual-help" | "note-map" | "ocr"; export interface ViewScope { /** diff --git a/apps/client/src/services/llm_chat.ts b/apps/client/src/services/llm_chat.ts new file mode 100644 index 0000000000..fa0a0279d3 --- /dev/null +++ b/apps/client/src/services/llm_chat.ts @@ -0,0 +1,114 @@ +import type { LlmChatConfig, LlmCitation, LlmMessage, LlmModelInfo,LlmUsage } from "@triliumnext/commons"; + +import server from "./server.js"; + +/** + * Fetch available models from all configured providers. + */ +export async function getAvailableModels(): Promise { + const response = await server.get<{ models?: LlmModelInfo[] }>("llm-chat/models"); + return response.models ?? []; +} + +export interface StreamCallbacks { + onChunk: (text: string) => void; + onThinking?: (text: string) => void; + onToolUse?: (toolName: string, input: Record) => void; + onToolResult?: (toolName: string, result: string, isError?: boolean) => void; + onCitation?: (citation: LlmCitation) => void; + onUsage?: (usage: LlmUsage) => void; + onError: (error: string) => void; + onDone: () => void; +} + +/** + * Stream a chat completion from the LLM API using Server-Sent Events. + */ +export async function streamChatCompletion( + messages: LlmMessage[], + config: LlmChatConfig, + callbacks: StreamCallbacks +): Promise { + const headers = await server.getHeaders(); + + const response = await fetch(`${window.glob.baseApiUrl}llm-chat/stream`, { + method: "POST", + headers: { + ...headers, + "Content-Type": "application/json" + } as HeadersInit, + body: JSON.stringify({ messages, config }) + }); + + if (!response.ok) { + callbacks.onError(`HTTP ${response.status}: ${response.statusText}`); + return; + } + + const reader = response.body?.getReader(); + if (!reader) { + callbacks.onError("No response body"); + return; + } + + const decoder = new TextDecoder(); + let buffer = ""; + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split("\n"); + buffer = lines.pop() || ""; + + for (const line of lines) { + if (line.startsWith("data: ")) { + try { + const data = JSON.parse(line.slice(6)); + + switch (data.type) { + case "text": + callbacks.onChunk(data.content); + break; + case "thinking": + callbacks.onThinking?.(data.content); + break; + case "tool_use": + callbacks.onToolUse?.(data.toolName, data.toolInput); + // Yield to force Preact to commit the pending tool call + // state before we process the result. + await new Promise((r) => setTimeout(r, 1)); + break; + case "tool_result": + callbacks.onToolResult?.(data.toolName, data.result, data.isError); + await new Promise((r) => setTimeout(r, 1)); + break; + case "citation": + if (data.citation) { + callbacks.onCitation?.(data.citation); + } + break; + case "usage": + if (data.usage) { + callbacks.onUsage?.(data.usage); + } + break; + case "error": + callbacks.onError(data.error); + break; + case "done": + callbacks.onDone(); + break; + } + } catch (e) { + console.error("Failed to parse SSE data line:", line, e); + } + } + } + } + } finally { + reader.releaseLock(); + } +} diff --git a/apps/client/src/services/note_types.ts b/apps/client/src/services/note_types.ts index 0047439c82..c99f04ae81 100644 --- a/apps/client/src/services/note_types.ts +++ b/apps/client/src/services/note_types.ts @@ -1,6 +1,7 @@ import type { NoteType } from "../entities/fnote.js"; import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js"; import type { TreeCommandNames } from "../menus/tree_context_menu.js"; +import { isExperimentalFeatureEnabled } from "./experimental_features.js"; import froca from "./froca.js"; import { t } from "./i18n.js"; import server from "./server.js"; @@ -41,6 +42,7 @@ export const NOTE_TYPES: NoteTypeMapping[] = [ { type: "relationMap", mime: "application/json", title: t("note_types.relation-map"), icon: "bxs-network-chart" }, // Misc note types + { type: "llmChat", mime: "application/json", title: t("note_types.llm-chat"), icon: "bx-message-square-dots", isBeta: true }, { type: "render", mime: "", title: t("note_types.render-note"), icon: "bx-extension" }, { type: "search", title: t("note_types.saved-search"), icon: "bx-file-find", static: true }, { type: "webView", mime: "", title: t("note_types.web-view"), icon: "bx-globe-alt" }, @@ -92,6 +94,7 @@ async function getNoteTypeItems(command?: TreeCommandNames) { function getBlankNoteTypes(command?: TreeCommandNames): MenuItem[] { return NOTE_TYPES .filter((nt) => !nt.reserved && nt.type !== "book") + .filter((nt) => nt.type !== "llmChat" || isExperimentalFeatureEnabled("llm")) .map((nt) => { const menuItem: MenuCommandItem = { title: nt.title, diff --git a/apps/client/src/services/server.ts b/apps/client/src/services/server.ts index d9b776babc..2d9d8273ae 100644 --- a/apps/client/src/services/server.ts +++ b/apps/client/src/services/server.ts @@ -1,3 +1,4 @@ +import { t } from "./i18n.js"; import utils, { isShare } from "./utils.js"; import ValidationError from "./validation_error.js"; @@ -32,8 +33,7 @@ async function getHeaders(headers?: Headers) { return {}; } - const appContext = (await import("../components/app_context.js")).default; - const activeNoteContext = appContext.tabManager ? appContext.tabManager.getActiveContext() : null; + const activeNoteContext = glob.appContext?.tabManager ? glob.appContext.tabManager.getActiveContext() : null; // headers need to be lowercase because node.js automatically converts them to lower case // also avoiding using underscores instead of dashes since nginx filters them out by default @@ -270,7 +270,11 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, opts } else if (opts.silentInternalServerError && jqXhr.status === 500) { // report nothing } else { - await reportError(method, url, jqXhr.status, jqXhr.responseText); + try { + await reportError(method, url, jqXhr.status, jqXhr.responseText); + } catch { + // reportError may throw (e.g. ValidationError); ensure rej() is still called below. + } } rej(jqXhr.responseText); @@ -340,6 +344,7 @@ async function reportError(method: string, url: string, statusCode: number, resp } catch (e) {} } + // Dynamic import to avoid circular dependency (toast → app_context → options → server). const toastService = (await import("./toast.js")).default; const messageStr = (typeof message === "string" ? message : JSON.stringify(message)) || "-"; @@ -353,7 +358,6 @@ async function reportError(method: string, url: string, statusCode: number, resp ...response }); } else { - const { t } = await import("./i18n.js"); if (statusCode === 400 && (url.includes("%23") || url.includes("%2F"))) { toastService.showPersistent({ id: "trafik-blocked", @@ -367,8 +371,7 @@ async function reportError(method: string, url: string, statusCode: number, resp t("server.unknown_http_error_content", { statusCode, method, url, message: messageStr }), 15_000); } - const { logError } = await import("./ws.js"); - logError(`${statusCode} ${method} ${url} - ${message}`); + window.logError(`${statusCode} ${method} ${url} - ${message}`); } } diff --git a/apps/client/src/services/theme.ts b/apps/client/src/services/theme.ts new file mode 100644 index 0000000000..9aa42c22ba --- /dev/null +++ b/apps/client/src/services/theme.ts @@ -0,0 +1,35 @@ +export function getThemeStyle(): "auto" | "light" | "dark" { + const configuredTheme = window.glob?.theme; + if (configuredTheme === "auto" || configuredTheme === "next") { + return "auto"; + } + + if (configuredTheme === "light" || configuredTheme === "dark") { + return configuredTheme; + } + + if (configuredTheme === "next-light") { + return "light"; + } + + if (configuredTheme === "next-dark") { + return "dark"; + } + + const style = window.getComputedStyle(document.body); + const themeStyle = style.getPropertyValue("--theme-style"); + if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) { + return themeStyle as "light" | "dark"; + } + + return "auto"; +} + +export function getEffectiveThemeStyle(): "light" | "dark" { + const themeStyle = getThemeStyle(); + if (themeStyle === "auto") { + return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; + } + + return themeStyle === "dark" ? "dark" : "light"; +} diff --git a/apps/client/src/services/utils.ts b/apps/client/src/services/utils.ts index bc35a0bd3f..67bbdd0e26 100644 --- a/apps/client/src/services/utils.ts +++ b/apps/client/src/services/utils.ts @@ -455,9 +455,7 @@ export function openInAppHelpFromUrl(inAppHelpPage: string) { export async function openInReusableSplit(targetNoteId: string, targetViewMode: ViewMode, openOpts: { hoistedNoteId?: string; } = {}) { - // Dynamic import to avoid import issues in tests. - const appContext = (await import("../components/app_context.js")).default; - const activeContext = appContext.tabManager.getActiveContext(); + const activeContext = glob.appContext?.tabManager?.getActiveContext(); if (!activeContext) { return; } @@ -467,7 +465,7 @@ export async function openInReusableSplit(targetNoteId: string, targetViewMode: if (!existingSubcontext) { // The target split is not already open, open a new split with it. const { ntxId } = subContexts[subContexts.length - 1]; - appContext.triggerCommand("openNewNoteSplit", { + glob.appContext?.triggerCommand("openNewNoteSplit", { ntxId, notePath: targetNoteId, hoistedNoteId: openOpts.hoistedNoteId, @@ -922,6 +920,7 @@ export default { parseDate, formatDateISO, formatDateTime, + formatTime, formatTimeInterval, formatSize, localNowDateTime, diff --git a/apps/client/src/services/ws.ts b/apps/client/src/services/ws.ts index 1002abe9f7..47ed90341b 100644 --- a/apps/client/src/services/ws.ts +++ b/apps/client/src/services/ws.ts @@ -1,13 +1,15 @@ -import utils from "./utils.js"; -import toastService from "./toast.js"; -import server from "./server.js"; -import options from "./options.js"; -import frocaUpdater from "./froca_updater.js"; -import appContext from "../components/app_context.js"; -import { t } from "./i18n.js"; -import type { EntityChange } from "../server_types.js"; import { WebSocketMessage } from "@triliumnext/commons"; + +import appContext from "../components/app_context.js"; +import type { EntityChange } from "../server_types.js"; +import bundleService from "./bundle.js"; +import froca from "./froca.js"; +import frocaUpdater from "./froca_updater.js"; +import { t } from "./i18n.js"; +import options from "./options.js"; +import server from "./server.js"; import toast from "./toast.js"; +import utils from "./utils.js"; type MessageHandler = (message: WebSocketMessage) => void; let messageHandlers: MessageHandler[] = []; @@ -126,20 +128,14 @@ async function handleMessage(event: MessageEvent) { } else if (message.type === "frontend-update") { await executeFrontendUpdate(message.data.entityChanges); } else if (message.type === "sync-hash-check-failed") { - toastService.showError(t("ws.sync-check-failed"), 60000); + toast.showError(t("ws.sync-check-failed"), 60000); } else if (message.type === "consistency-checks-failed") { - toastService.showError(t("ws.consistency-checks-failed"), 50 * 60000); + toast.showError(t("ws.consistency-checks-failed"), 50 * 60000); } else if (message.type === "api-log-messages") { appContext.triggerEvent("apiLogMessages", { noteId: message.noteId, messages: message.messages }); } else if (message.type === "toast") { - toastService.showMessage(message.message); + toast.showMessage(message.message); } else if (message.type === "execute-script") { - // TODO: Remove after porting the file - // @ts-ignore - const bundleService = (await import("./bundle.js")).default as any; - // TODO: Remove after porting the file - // @ts-ignore - const froca = (await import("./froca.js")).default as any; const originEntity = message.originEntityId ? await froca.getNote(message.originEntityId) : null; bundleService.getAndExecuteBundle(message.currentNoteId, originEntity, message.script, message.params); @@ -161,7 +157,7 @@ function waitForEntityChangeId(desiredEntityChangeId: number) { return new Promise((res, rej) => { entityChangeIdReachedListeners.push({ - desiredEntityChangeId: desiredEntityChangeId, + desiredEntityChangeId, resolvePromise: res, start: Date.now() }); @@ -205,7 +201,7 @@ async function consumeFrontendUpdateData() { } else { console.log("nonProcessedEntityChanges causing the timeout", nonProcessedEntityChanges); - toastService.showError(t("ws.encountered-error", { message: e.message })); + toast.showError(t("ws.encountered-error", { message: e.message })); } } diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index 5a462b9804..536db2d9b5 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -1750,10 +1750,13 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { justify-content: space-between; align-items: baseline; font-weight: bold; - text-transform: uppercase; color: var(--muted-text-color) !important; } +#right-pane .card-header-title { + text-transform: uppercase; +} + #right-pane .card-header-buttons { display: flex; transform: scale(0.9); @@ -2638,3 +2641,26 @@ iframe.print-iframe { min-height: 50px; align-items: center; } + +.ocr-text-section { + padding: 10px; + background: var(--accented-background-color); + border-left: 3px solid var(--main-border-color); + text-align: left; + width: 100%; +} + +.ocr-header { + font-weight: bold; + margin-bottom: 8px; + font-size: 0.9em; + color: var(--muted-text-color); +} + +.ocr-content { + max-height: 150px; + overflow-y: auto; + font-size: 0.9em; + line-height: 1.4; + white-space: pre-wrap; +} diff --git a/apps/client/src/stylesheets/theme-next.css b/apps/client/src/stylesheets/theme-next.css deleted file mode 100644 index 1c8a7d810d..0000000000 --- a/apps/client/src/stylesheets/theme-next.css +++ /dev/null @@ -1,11 +0,0 @@ -/* Import the light color scheme. - * This is the base color scheme, always active and overridden by the dark - * color scheme stylesheet when necessary. */ -@import url(./theme-next-light.css); - -/* Import the dark color scheme when the system preference is set to dark mode */ -@import url(./theme-next-dark.css) (prefers-color-scheme: dark); - -:root { - --theme-style-auto: true; -} diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 7bf9423138..c1d3cc3094 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -544,14 +544,11 @@ li.dropdown-item a.dropdown-item-button:focus-visible { vertical-align: middle; } -#toast-container .toast .toast-header .btn-close { +#toast-container .toast .toast-header .btn-close, +#toast-container .toast .toast-close .btn-close { margin: 0 0 0 12px; } -#toast-container .toast.no-title { - flex-direction: row; -} - #toast-container .toast .toast-body { flex-grow: 1; overflow: hidden; diff --git a/apps/client/src/stylesheets/theme-next/dialogs.css b/apps/client/src/stylesheets/theme-next/dialogs.css index 613fb94f36..94b6ff21a1 100644 --- a/apps/client/src/stylesheets/theme-next/dialogs.css +++ b/apps/client/src/stylesheets/theme-next/dialogs.css @@ -26,7 +26,8 @@ .modal .modal-header .btn-close, .modal .modal-header .help-button, .modal .modal-header .custom-title-bar-button, -#toast-container .toast .toast-header .btn-close { +#toast-container .toast .toast-header .btn-close, +#toast-container .toast .toast-close .btn-close { display: flex; justify-content: center; align-items: center; @@ -46,12 +47,14 @@ } .modal .modal-header .btn-close, -#toast-container .toast .toast-header .btn-close { +#toast-container .toast .toast-header .btn-close, +#toast-container .toast .toast-close .btn-close { --modal-control-button-hover-background: var(--modal-close-button-hover-background); } .modal .modal-header .btn-close::after, -#toast-container .toast .toast-header .btn-close::after { +#toast-container .toast .toast-header .btn-close::after, +#toast-container .toast .toast-close .btn-close::after { content: "\ec8d"; font-family: boxicons; } @@ -67,7 +70,8 @@ .modal .modal-header .btn-close:hover, .modal .modal-header .help-button:hover, .modal .modal-header .custom-title-bar-button:hover, -#toast-container .toast .toast-header .btn-close:hover { +#toast-container .toast .toast-header .btn-close:hover, +#toast-container .toast .toast-close .btn-close:hover { background: var(--modal-control-button-hover-background); color: var(--modal-control-button-hover-color); } @@ -75,19 +79,22 @@ .modal .modal-header .btn-close:active, .modal .modal-header .help-button:active, .modal .modal-header .custom-title-bar-button:active, -#toast-container .toast .toast-header .btn-close:active { +#toast-container .toast .toast-header .btn-close:active, +#toast-container .toast .toast-close .btn-close:active { transform: scale(.85); } .modal .modal-header .btn-close:focus, .modal .modal-header .help-button:focus, -#toast-container .toast .toast-header .btn-close:focus { +#toast-container .toast .toast-header .btn-close:focus, +#toast-container .toast .toast-close .btn-close:focus { box-shadow: none !important; } .modal .modal-header .btn-close:focus-visible, .modal .modal-header .help-button:focus-visible, -#toast-container .toast .toast-header .btn-close:focus-visible { +#toast-container .toast .toast-header .btn-close:focus-visible, +#toast-container .toast .toast-close .btn-close:focus-visible { outline: 2px solid var(--input-focus-outline-color); outline-offset: 2px; } diff --git a/apps/client/src/stylesheets/theme.css b/apps/client/src/stylesheets/theme.css deleted file mode 100644 index e99702d325..0000000000 --- a/apps/client/src/stylesheets/theme.css +++ /dev/null @@ -1,11 +0,0 @@ -/* Import the light color scheme. - * This is the base color scheme, always active and overridden by the dark - * color scheme stylesheet when necessary. */ -@import url(./theme-light.css); - -/* Import the dark color scheme when the system preference is set to dark mode */ -@import url(./theme-dark.css) (prefers-color-scheme: dark); - -:root { - --theme-style-auto: true; -} diff --git a/apps/client/src/translations/ar/translation.json b/apps/client/src/translations/ar/translation.json index 1e78b26f02..ad05b8b387 100644 --- a/apps/client/src/translations/ar/translation.json +++ b/apps/client/src/translations/ar/translation.json @@ -1130,9 +1130,7 @@ "spellcheck": { "title": "التدقيق الاملائي", "enable": "تفعيل التدقيق الاملائي", - "language_code_label": "رمز اللغة او رموز اللغات", - "available_language_codes_label": "رموز اللغات المتاحة:", - "language_code_placeholder": "على سبيل المثال \"en-US\", \"de-AI\"" + "language_code_label": "رمز اللغة او رموز اللغات" }, "note-map": { "button-link-map": "خريطة الروابط", diff --git a/apps/client/src/translations/cn/translation.json b/apps/client/src/translations/cn/translation.json index df59a5f866..8abc10324e 100644 --- a/apps/client/src/translations/cn/translation.json +++ b/apps/client/src/translations/cn/translation.json @@ -709,7 +709,8 @@ "advanced": "高级", "export_as_image": "导出为图像", "export_as_image_png": "PNG(栅格)", - "export_as_image_svg": "SVG(矢量图)" + "export_as_image_svg": "SVG(矢量图)", + "view_ocr_text": "查看 OCR 文本" }, "onclick_button": { "no_click_handler": "按钮组件'{{componentId}}'没有定义点击处理程序" @@ -1197,12 +1198,28 @@ }, "images": { "images_section_title": "图片", - "download_images_automatically": "自动下载图片以供离线使用。", - "download_images_description": "粘贴的 HTML 可能包含在线图片的引用,Trilium 会找到这些引用并下载图片,以便它们可以离线使用。", - "enable_image_compression": "启用图片压缩", - "max_image_dimensions": "图片的最大宽度/高度(超过此限制的图像将会被缩放)。", - "jpeg_quality_description": "JPEG 质量(10 - 最差质量,100 最佳质量,建议为 50 - 85)", - "max_image_dimensions_unit": "像素" + "download_images_automatically": "自动下载图片", + "download_images_description": "从粘贴的 HTML 代码中下载引用的在线图片,以便离线使用。", + "enable_image_compression": "图片压缩", + "max_image_dimensions": "最大图像尺寸", + "jpeg_quality_description": "建议范围为 50–85。较低的值可以减小文件大小,较高的值可以保留细节。", + "max_image_dimensions_unit": "像素", + "enable_image_compression_description": "上传或粘贴图片时,对其进行压缩和调整大小。", + "max_image_dimensions_description": "超过此尺寸的图片将自动调整大小。", + "jpeg_quality": "JPEG质量", + "ocr_section_title": "文本提取(OCR)", + "ocr_related_content_languages": "内容语言(用于文本提取)", + "ocr_auto_process": "自动处理新文件", + "ocr_auto_process_description": "自动从新上传或粘贴的文件中提取文本。", + "ocr_min_confidence": "最低置信度", + "ocr_confidence_description": "仅提取置信度高于此阈值的文本。较低的置信度阈值会包含更多文本,但可能准确性较低。", + "batch_ocr_title": "处理现有文件", + "batch_ocr_description": "从笔记中的所有现有图像、PDF 和 Office 文档中提取文本。这可能需要一些时间,具体取决于文件数量。", + "batch_ocr_start": "开始批量处理", + "batch_ocr_starting": "开始批量处理...", + "batch_ocr_progress": "正在处理 {{processed}} 个文件,共 {{total}} 个文件...", + "batch_ocr_completed": "批量处理完成!已处理 {{processed}} 个文件。", + "batch_ocr_error": "批量处理过程中出错:{{error}}" }, "attachment_erasure_timeout": { "attachment_erasure_timeout": "附件清理超时", @@ -1420,9 +1437,6 @@ "description": "这些选项仅适用于桌面版本,浏览器将使用其原生的拼写检查功能。", "enable": "启用拼写检查", "language_code_label": "语言代码", - "language_code_placeholder": "例如 \"en-US\", \"de-AT\"", - "multiple_languages_info": "多种语言可以用逗号分隔,例如 \"en-US, de-DE, cs\"。 ", - "available_language_codes_label": "可用的语言代码:", "restart-required": "拼写检查选项的更改将在应用重启后生效。" }, "sync_2": { @@ -1535,8 +1549,9 @@ "new-feature": "新建", "collections": "集合", "book": "集合", - "ai-chat": "AI聊天", - "spreadsheet": "电子表格" + "ai-chat": "AI对话", + "spreadsheet": "电子表格", + "llm-chat": "AI对话" }, "protect_note": { "toggle-on": "保护笔记", @@ -2046,7 +2061,9 @@ "title": "实验选项", "disclaimer": "这些选项处于实验阶段,可能导致系统不稳定。请谨慎使用。", "new_layout_name": "新布局", - "new_layout_description": "尝试全新布局,呈现更现代的外观并提升易用性。后续版本将进行重大调整。" + "new_layout_description": "尝试全新布局,呈现更现代的外观并提升易用性。后续版本将进行重大调整。", + "llm_name": "AI/大语言模型对话", + "llm_description": "启用由大语言模型驱动的 AI对话侧边栏和大语言模型对话笔记。" }, "tab_history_navigation_buttons": { "go-back": "返回前一笔记", @@ -2215,5 +2232,77 @@ "sample_venn": "韦恩图", "sample_ishikawa": "鱼骨图", "placeholder": "输入你的美人鱼图的内容,或者使用下面的示例图之一。" + }, + "llm_chat": { + "placeholder": "输入消息…", + "send": "发送", + "sending": "正在发送...", + "empty_state": "在下方输入消息,即可开始对话。", + "searching_web": "在网上搜索…", + "web_search": "联网搜索", + "sources": "来源", + "extended_thinking": "延伸思考", + "legacy_models": "传统模型", + "thinking": "正在思考...", + "thought_process": "思考过程", + "tool_calls": "{{count}} 次工具调用", + "input": "输入", + "result": "结果", + "error": "错误", + "tool_error": "失败", + "total_tokens": "{{total}} 个词元", + "tokens_detail": "{{prompt}} 提示词 + {{completion}} 补全", + "tokens_used": "{{prompt}} 提示词 + {{completion}} 补全 = {{total}} 个词元", + "tokens_used_with_cost": "{{prompt}} 提示词 + {{completion}} 补全 = {{total}} 个词元(约 ${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} 提示词 + {{completion}} 补全 = {{total}} 个词元", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} 提示词 + {{completion}} 补全 = {{total}} 个词元(约 ${{cost}})", + "tokens": "词元", + "context_used": "{{percentage}}% 使用率", + "note_context_enabled": "点击即可禁用笔记上下文:{{title}}", + "note_context_disabled": "点击即可将当前注释添加到上下文中", + "no_provider_message": "未配置人工智能提供商。添加一个即可开始对话。", + "add_provider": "添加人工智能提供商", + "note_tools": "笔记访问" + }, + "sidebar_chat": { + "title": "AI对话", + "launcher_title": "打开AI对话", + "new_chat": "开始新对话", + "save_chat": "将对话保存到笔记", + "empty_state": "开始对话", + "history": "对话历史", + "recent_chats": "最近对话", + "no_chats": "无历史对话" + }, + "ocr": { + "extracted_text": "提取文本(OCR)", + "extracted_text_title": "提取文本(OCR)", + "loading_text": "正在加载OCR文本...", + "no_text_available": "暂无OCR文本", + "no_text_explanation": "该笔记未进行 OCR 文本提取处理,或未找到文本。", + "failed_to_load": "OCR文本加载失败", + "process_now": "处理 OCR", + "processing": "正在处理...", + "processing_started": "OCR识别已开始。请稍候片刻并刷新页面。", + "processing_failed": "OCR处理启动失败", + "view_extracted_text": "查看提取的文本(OCR)" + }, + "mind-map": { + "addChild": "添加子节点", + "addParent": "添加父节点", + "addSibling": "添加同级节点", + "removeNode": "删除节点", + "focus": "专注模式", + "cancelFocus": "退出专注模式", + "moveUp": "上移", + "moveDown": "下移", + "link": "链接", + "linkBidirectional": "双向链接", + "clickTips": "请点击目标节点", + "summary": "总结" + }, + "llm": { + "settings_description": "配置人工智能和大语言模型集成。", + "add_provider": "添加提供商" } } diff --git a/apps/client/src/translations/cs/translation.json b/apps/client/src/translations/cs/translation.json index b5cb420326..5298bc48af 100644 --- a/apps/client/src/translations/cs/translation.json +++ b/apps/client/src/translations/cs/translation.json @@ -21,8 +21,17 @@ }, "bundle-error": { "title": "Načtení uživatelského skriptu selhalo", - "message": "Uživatelský skript z poznámky s ID \"{{id}}\" a názvem \"{{title}}\" nemohl být spuštěn z důvodu: \n\n{{message}}" - } + "message": "Skript nebylo možné spustit z následujícího důvodu:\n\n{{message}}" + }, + "widget-list-error": { + "title": "Nepodařilo se získat seznam widgetů ze serveru" + }, + "widget-render-error": { + "title": "Nepodařilo se vykreslit vlastní React widget" + }, + "widget-missing-parent": "Vlastní widget nemá definovanou povinnou vlastnost „{{property}}“.\n\nPokud má být tento skript spuštěn bez prvku uživatelského rozhraní, použijte místo toho „#run=frontendStartup“.", + "open-script-note": "Otevřít poznámku se skriptem", + "scripting-error": "Chyba vlastního skriptu: {{title}}" }, "add_link": { "add_link": "Přidat odkaz", @@ -111,8 +120,2262 @@ "note_cloned": "Poznámka „{{clonedTitle}}“ bylo naklonována do „{{targetTitle}}“" }, "zpetne_odkazy": { - "backlink_one": "{{count}} zpětný odkaz", - "backlink_few": "{{count}} zpětné odkazy", - "backlink_other": "{{count}} zpětných odkazů" + "backlink_one": "{{count}} Zpětný odkaz", + "backlink_few": "{{count}} Zpětné odkazy", + "backlink_other": "{{count}} Zpětných odkazů", + "relation": "vazba" + }, + "help": { + "title": "Rychlý přehled", + "editShortcuts": "Upravit klávesové zkratky", + "noteNavigation": "Navigace v poznámkách", + "goUpDown": "posunout nahoru/dolů v seznamu poznámek", + "collapseExpand": "sbalit/rozbalit uzel", + "notSet": "nenastaveno", + "goBackForwards": "jít zpět / vpřed v historii", + "showJumpToNoteDialog": "zobrazit dialog „Přejít na“", + "scrollToActiveNote": "posunout na aktivní poznámku", + "jumpToParentNote": "přejít na nadřazenou poznámku", + "collapseWholeTree": "sbalit celý strom poznámek", + "collapseSubTree": "sbalit podstrom", + "tabShortcuts": "Klávesové zkratky záložek", + "newTabNoteLink": "kliknutí na odkaz na poznámku otevře poznámku v nové záložce", + "newTabWithActivationNoteLink": "kliknutí na odkaz na poznámku otevře a aktivuje poznámku v nové záložce", + "onlyInDesktop": "Pouze na počítači (Electron build)", + "openEmptyTab": "otevřít prázdnou záložku", + "closeActiveTab": "zavřít aktivní záložku", + "activateNextTab": "aktivovat další záložku", + "activatePreviousTab": "aktivovat předchozí záložku", + "creatingNotes": "Vytváření poznámek", + "createNoteAfter": "vytvořit novou poznámku za aktivní poznámkou", + "createNoteInto": "vytvořit novou podpoznámku v aktivní poznámce", + "editBranchPrefix": "upravit předponu klonu aktivní poznámky", + "movingCloningNotes": "Přesouvání / klonování poznámtek", + "moveNoteUpDown": "přesunout poznámku nahoru/dolů v seznamu poznámek", + "moveNoteUpHierarchy": "přesunout poznámku výše v hierarchii", + "multiSelectNote": "vybrat více poznámek nad/pod", + "selectAllNotes": "vybrat všechny poznámky v aktuální úrovni", + "selectNote": "vybrat poznámku", + "copyNotes": "kopírovat aktivní poznámku (nebo aktuální výběr) do schránky (používá se pro klonování)", + "cutNotes": "vyříznout aktuální poznámky (nebo aktuální výběr) do schránky (používá se pro přesouvání poznámek)", + "pasteNotes": "vložit poznámku/poznámky jako podpoznámku do aktivní poznámky (což je buď přesun nebo klonování v závislosti na tom, zda byla do schránky zkopírována nebo vyříznuta)", + "deleteNotes": "smazat poznámku / podstrom", + "editingNotes": "Upravování poznámek", + "editNoteTitle": "V okně stromu přepne z okna stromu do názvu poznámky. Vstup z názvu poznámky přesune fokus do textového editoru. Ctrl+. přepne z editoru zpět do okna stromu.", + "createEditLink": "vytvořit / upravit externí odkaz", + "createInternalLink": "vytvořit interní odkaz", + "followLink": "sledovat odkaz pod kurzorem", + "insertDateTime": "vložit aktuální datum a čas na pozici kurzoru", + "jumpToTreePane": "přeskočit do okna stromu a posunout se k aktivní poznámce", + "markdownAutoformat": "Automatické formátování podobné ⟨Markdown⟩", + "headings": "##, ###, #### následované mezerou pro nadpisy", + "bulletList": "* nebo - následované mezerou pro odrážky", + "numberedList": "1. nebo 1) následované mezerou pro číslovaný seznam", + "blockQuote": "začněte řádek > následovaný mezerou pro blok citace", + "troubleshooting": "Řešení problémů", + "reloadFrontend": "znovu načíst ⟨Trilium⟩ ⟨frontend⟩", + "showDevTools": "zobrazit nástroje pro vývojáře", + "showSQLConsole": "zobrazit ⟨SQL⟩ konzoli", + "other": "Ostatní", + "quickSearch": "zaměřit se na rychlé vyhledávání", + "inPageSearch": "vyhledávání na stránce" + }, + "import": { + "importIntoNote": "Import do poznámky", + "chooseImportFile": "Vyberte soubor k importu", + "importDescription": "Obsah vybraných souborů bude importován jako dceřiné poznámky do", + "importZipRecommendation": "Při importu ZIP souboru bude hierarchie poznámek odrážet strukturu podadresářů v archivu.", + "options": "Nastavení", + "safeImportTooltip": "Exportované soubory Trilium .zip mohou obsahovat spustitelné skripty, které mohou mít škodlivé chování. Bezpečný import deaktivuje automatické spouštění všech importovaných skriptů. Zrušte zaškrtnutí \"Bezpečný import\" pouze v případě, že importovaný archiv má obsahovat spustitelné skripty a plně důvěřujete obsahu importovaného souboru.", + "safeImport": "Bezpečný import", + "explodeArchivesTooltip": "Pokud je toto zaškrtnuto, Trilium bude číst .zip, .enex a .opml soubory a vytvářet poznámky ze souborů uvnitř těchto archivů. Pokud není zaškrtnuto, Trilium připojí samotné archivy k poznámce.", + "explodeArchives": "Číst obsah archivů .zip, .enex a .opml.", + "shrinkImagesTooltip": "

Pokud zaškrtnete tuto možnost, Trilium se pokusí zmenšit importované obrázky škálováním a optimalizací, což může ovlivnit vnímanou kvalitu obrazu. Pokud není zaškrtnuto, obrázky budou importovány beze změn.

To se nevztahuje na importy .zip s metadaty, protože se předpokládá, že tyto soubory jsou již optimalizovány.

", + "shrinkImages": "Zmenšit obrázky", + "textImportedAsText": "Importovat HTML, Markdown a TXT jako textové poznámky, pokud to není z metadat zřejmé", + "codeImportedAsCode": "Importovat rozpoznané soubory s kódem (např. .json) jako poznámky s kódem, pokud to není z metadat zřejmé", + "replaceUnderscoresWithSpaces": "Nahradit podtržítka mezerami v názvech importovaných poznámek", + "import": "Import", + "failed": "Import selhal: {{message}}.", + "html_import_tags": { + "title": "HTML Import Tags", + "description": "Konfigurujte, které HTML tagy by měly být zachovány při importu poznámek. Tagy, které nejsou v tomto seznamu, budou během importu odstraněny. Některé tagy (jako 'script') jsou vždy odstraněny z bezpečnostních důvodů.", + "placeholder": "Zadejte HTML tagy, jeden na řádek", + "reset_button": "Obnovit do výchozího seznamu" + }, + "import-status": "Stav importu", + "in-progress": "Import probíhá: {{progress}}", + "successful": "Import byl úspěšně dokončen." + }, + "include_note": { + "dialog_title": "Zahrnout poznámku", + "label_note": "Poznámka", + "placeholder_search": "Hledat poznámku podle jejího názvu", + "box_size_prompt": "Velikost pole zahrnuté poznámky:", + "box_size_small": "Malý (~ 10 řádků)", + "box_size_medium": "Střední (~ 30 řádků)", + "box_size_full": "Úplný (pole zobrazuje kompletní text)", + "button_include": "Zahrnout poznámku" + }, + "info": { + "modalTitle": "Informační zpráva", + "closeButton": "Zavřít", + "okButton": "OK", + "copy_to_clipboard": "Kopírovat do schránky" + }, + "jump_to_note": { + "search_placeholder": "Hledat poznámku podle jména nebo typu > pro příkazy...", + "search_button": "Hledat v celém textu" + }, + "markdown_import": { + "dialog_title": "Markdown import", + "modal_body_text": "Vzhledem k omezením prohlížeče není možné přímo číst obsah schránky z JavaScriptu. Vložte prosím Markdown, který chcete importovat, do textového pole níže a klikněte na tlačítko Importovat", + "import_button": "Import", + "import_success": "Markdown obsah byl importován do dokumentu." + }, + "move_to": { + "dialog_title": "Přesunout poznámku do ...", + "notes_to_move": "Poznámky k přesunu", + "target_parent_note": "Cílová nadřazená poznámka", + "search_placeholder": "Hledat poznámku podle názvu", + "move_button": "Přesunout do vybrané poznámky", + "error_no_path": "Nebyla nalezena cesta pro přesun.", + "move_success_message": "Vybrané poznámky byly přesunuty do " + }, + "note_type_chooser": { + "change_path_prompt": "Změnit, kam se má nová poznámka vytvořit:", + "search_placeholder": "Hledat cestu podle názvu (výchozí, pokud je prázdná)", + "modal_title": "Vybrat typ poznámky", + "modal_body": "Vybrat typ poznámky / šablonu nové poznámky:", + "templates": "Šablony", + "builtin_templates": "Vestavěné šablony" + }, + "password_not_set": { + "title": "Heslo není nastaveno", + "body1": "Chráněné poznámky jsou šifrovány pomocí uživatelského hesla, ale heslo zatím nebylo nastaveno.", + "body2": "Pro možnost chránit poznámky klikněte na tlačítko níže a otevřete dialog Nastavení a nastavte své heslo.", + "go_to_password_options": "Přejít na možnosti hesla" + }, + "prompt": { + "title": "Výzva", + "ok": "OK", + "defaultTitle": "Výzva" + }, + "protected_session_password": { + "modal_title": "Chráněná relace", + "help_title": "Nápověda k chráněným poznámkám", + "close_label": "Zavřít", + "form_label": "Pro pokračování požadovanou akcí je třeba spustit chráněnou relaci zadáním hesla:", + "start_button": "Spustit chráněnou relaci" + }, + "recent_changes": { + "title": "Nedávné změny", + "erase_notes_button": "Vymazat smazané poznámky nyní", + "deleted_notes_message": "Smazané poznámky byly vymazány.", + "no_changes_message": "Zatím žádné změny...", + "undelete_link": "obnovit", + "confirm_undelete": "Chcete obnovit tuto poznámku a její podpoznámky?" + }, + "revisions": { + "note_revisions": "Revize poznámek", + "delete_all_revisions": "Smazat všechny revize této poznámky", + "delete_all_button": "Smazat všechny revize", + "help_title": "Nápověda k revizím poznámek", + "confirm_delete_all": "Chcete smazat všechny revize této poznámky?", + "no_revisions": "Ještě nejsou žádné revize pro tuto poznámku...", + "restore_button": "Obnovit", + "diff_on": "Zobrazit rozdíly", + "diff_off": "Zobrazit obsah", + "diff_on_hint": "Klikněte pro zobrazení rozdílů zdrojového kódu poznámky", + "diff_off_hint": "Klikněte pro zobrazení obsahu poznámky", + "diff_not_available": "Rozdíly nejsou dostupné.", + "confirm_restore": "Chcete obnovit tuto revizi? Tím se přepíše aktuální název a obsah poznámky s touto revizí.", + "delete_button": "Smazat", + "confirm_delete": "Chcete smazat tuto revizi?", + "revisions_deleted": "Revize poznámky byly smazány.", + "revision_restored": "Revize poznámky byla obnovena.", + "revision_deleted": "Revize poznámky byla smazána.", + "snapshot_interval": "Interval snímků revizí poznámky: {{seconds}}s.", + "maximum_revisions": "Limit snímků revizí poznámky: {{number}}.", + "settings": "Nastavení revizí poznámky", + "download_button": "Stáhnout", + "mime": "MIME: ", + "file_size": "Velikost souboru:", + "preview_not_available": "Náhled není dostupný pro tento typ poznámky." + }, + "sort_child_notes": { + "sort_children_by": "Seřadit dceřiné podle...", + "sorting_criteria": "Kritéria řazení", + "title": "název", + "date_created": "datum vytvoření", + "date_modified": "datum úpravy", + "sorting_direction": "Směr řazení", + "ascending": "vzestupně", + "descending": "sestupně", + "folders": "Složky", + "sort_folders_at_top": "řadit složky nahoře", + "natural_sort": "Přirozené řazení", + "sort_with_respect_to_different_character_sorting": "řadit s ohledem na různá pravidla řazení a kolace v různých jazycích nebo oblastech.", + "natural_sort_language": "Jazyk přirozeného řazení", + "the_language_code_for_natural_sort": "Jazykový kód pro přirozené řazení, např. \"zh-CN\" pro čínštinu.", + "sort": "Řazení" + }, + "upload_attachments": { + "upload_attachments_to_note": "Nahrát přílohy do poznámky", + "choose_files": "Vybrat soubory", + "files_will_be_uploaded": "Soubory budou nahrány jako přílohy do {{noteTitle}}", + "options": "Nastavení", + "shrink_images": "Zmenšit obrázky", + "upload": "Nahrát", + "tooltip": "Pokud tuto možnost zaškrtnete, Trilium se pokusí zmenšit nahrané obrázky škálováním a optimalizací, což může ovlivnit vnímanou kvalitu obrazu. Pokud není zaškrtnuta, obrázky budou nahrány beze změn." + }, + "attribute_detail": { + "attr_detail_title": "Detail Atributu", + "close_button_title": "Zrušit změny a zavřít", + "attr_is_owned_by": "Atribut je vlastněn", + "attr_name_title": "Název atributu může obsahovat pouze alfanumerické znaky, dvojtečku a podtržítko", + "name": "Název", + "value": "Hodnota", + "target_note_title": "Vazba je pojmenované spojení mezi zdrojovou poznámkou a cílovou poznámkou.", + "target_note": "Cílová poznámka", + "promoted_title": "Propagovaný atribut je zobrazen prominentně na poznámce.", + "promoted": "Propagováno", + "promoted_alias_title": "Název, který se má zobrazit v uživatelském rozhraní propagovaných atributů.", + "promoted_alias": "Alias", + "multiplicity_title": "Multiplicita definuje, kolik atributů se stejným názvem lze vytvořit – maximálně 1 nebo více než 1.", + "multiplicity": "Množnost", + "single_value": "Jedna hodnota", + "multi_value": "Více hodnot", + "label_type_title": "Typ štítku pomůže Trilium vybrat vhodné rozhraní pro zadání hodnoty štítku.", + "label_type": "Typ", + "text": "Text", + "textarea": "Víceřádkový text", + "number": "Číslo", + "boolean": "Boolean", + "date": "Datum", + "date_time": "Datum & Čas", + "time": "Čas", + "url": "URL", + "precision_title": "Kolik desetinných míst by mělo být k dispozici v rozhraní pro nastavení hodnoty.", + "precision": "Přesnost", + "digits": "číslice", + "inverse_relation_title": "Volitelné nastavení pro definování, ke které vazbě je tato inverzní. Příklad: Otec - Syn jsou inverzní vazby k sobě navzájem.", + "inverse_relation": "Inverzní vazba", + "inheritable_title": "Dědičný atribut bude zděděn všemi potomky pod tímto stromem.", + "inheritable": "Dědičný", + "save_and_close": "Uložit & zavřít Ctrl+Enter", + "delete": "Smazat", + "related_notes_title": "Další poznámky s tímto štítkem", + "more_notes": "Další poznámky", + "label": "Detail štítku", + "label_definition": "Detail definice štítku", + "relation": "Detail vazby", + "relation_definition": "Detail definice vazby", + "disable_versioning": "zakáže automatické verzování. Užitečné například pro velké, ale nepodstatné poznámky - například velké JavaScript knihovny používané pro scripting", + "calendar_root": "označí poznámku, která by měla být použita jako kořen pro denní poznámky. Pouze jedna by měla být takto označena.", + "archived": "Poznámky s tímto štítkem nebudou ve výchozím nastavení viditelné ve výsledcích vyhledávání (také v dialogových oknech Přeskočit na, Přidat odkaz atd.).", + "exclude_from_export": "Poznámky (včetně jejich podstromu) nebudou zahrnuty do žádného exportu poznámek", + "run": "Definuje, při kterých událostech se má skript spustit. Možné hodnoty jsou: \n
    \n
  • frontendStartup - když se spustí frontend Trilium (nebo se obnoví), ale ne na mobilních zařízeních.
  • \n
  • mobileStartup - když se spustí frontend Trilium (nebo se obnoví), na mobilních zařízeních.
  • \n
  • backendStartup - když se spustí backend Trilium.
  • \n
  • hourly - spustit jednou za hodinu. Můžete použít další štítek runAtHour pro určení hodiny.
  • \n
  • daily - spustit jednou denně.
  • \n
", + "run_on_instance": "Definujte, na které instanci Trilium se má toto spustit. Ve výchozím nastavení na všech instancích.", + "run_at_hour": "V kterou hodinu se má toto spustit. Mělo by se používat společně s #run=hourly. Lze definovat vícekrát pro více spuštění během dne.", + "disable_inclusion": "Skripty s tímto štítkem nebudou zahrnuty do spuštění nadřazeného skriptu.", + "sorted": "Udržuje podřízené poznámky seřazené podle názvu abecedně", + "sort_direction": "ASC (výchozí) nebo DESC", + "sort_folders_first": "Složky (poznámky s podřízenými položkami) by měly být řazeny nahoře", + "top": "Udržuje danou poznámku nahoře v rámci jejího nadřazeného (platí pouze pro seřazené nadřazené položky)", + "hide_promoted_attributes": "Skryje propagované atributy v této poznámce", + "read_only": "Editor je v režimu pouze pro čtení. Funguje pouze pro textové a kódové poznámky.", + "auto_read_only_disabled": "Textové/kódové poznámky se mohou automaticky nastavit do režimu pouze pro čtení, pokud jsou příliš velké. Toto chování můžete zakázat pro každou poznámku přidáním tohoto štítku do poznámky", + "app_css": "Označuje CSS poznámky, které jsou načteny do aplikace Trilium a mohou být tak použity k úpravě vzhledu Trilium.", + "app_theme": "Označuje CSS poznámky, které jsou kompletními motivy Trilium a jsou tak dostupné v možnostech Trilium.", + "app_theme_base": "nastavte na \"next\", \"next-light\" nebo \"next-dark\" pro použití odpovídajícího tématu TriliumNext (auto, světlé nebo tmavé) jako základu pro vlastní téma, namísto staršího.", + "css_class": "hodnota tohoto štítku je poté přidána jako CSS třída k uzlu reprezentujícímu danou poznámku ve stromu. To může být užitečné pro pokročilé tématizace. Lze použít v šablonových poznámkách.", + "icon_class": "hodnota tohoto štítku je přidána jako CSS třída k ikoně ve stromu, což může pomoci vizuálně odlišit poznámky ve stromu. Příkladem může být bx bx-home - ikony jsou převzaty z boxicons. Lze použít v šablonových poznámkách.", + "page_size": "počet položek na stránce v seznamu poznámek", + "custom_request_handler": "viz Vlastní zpracovatel požadavků", + "custom_resource_provider": "viz Vlastní zpracovatel požadavků", + "widget": "označí tuto poznámku jako vlastní widget, který bude přidán do stromu komponent Trilium", + "workspace": "označí tuto poznámku jako pracovní prostor, který umožňuje snadné zúžení zobrazení", + "workspace_icon_class": "definuje CSS třídu ikony box, která bude použita na záložce při zúžení zobrazení na tuto poznámku", + "workspace_tab_background_color": "CSS barva použitá na záložce při zúžení zobrazení na tuto poznámku", + "workspace_calendar_root": "Definuje kořenový kalendář pro pracovní prostor", + "workspace_template": "Tato poznámka se zobrazí ve výběru dostupných šablon při vytváření nové poznámky, ale pouze pokud je zúžena do pracovního prostoru obsahujícího tuto šablonu", + "search_home": "nové poznámky k vyhledávání budou vytvořeny jako podřízené položky této poznámky", + "workspace_search_home": "při přesunutí do některé nadřazené poznámky tohoto pracovního prostoru budou vytvořeny nové poznámky k vyhledávání jako podřízené této poznámky", + "inbox": "výchozí umístění schránky pro nové poznámky – pokud vytvoříte poznámku pomocí tlačítka „Nová poznámka“ v postranním panelu, poznámky se uloží jako podřízené poznámky k poznámce označené štítkem #inbox.", + "workspace_inbox": "výchozí umístění doručené pošty pro nové poznámky při přesunutí do některé nadřazené poznámky tohoto pracovního prostoru", + "sql_console_home": "výchozí umístění poznámky konzole SQL", + "bookmark_folder": "poznámka s tímto štítkem se zobrazí v záložkách jako složka (umožňuje přístup k jejím podřízeným poznámkám)", + "share_hidden_from_tree": "Tato poznámka je skrytá z levého navigačního stromu, ale je stále přístupná pomocí její URL", + "share_external_link": "poznámka bude fungovat jako odkaz na externí webovou stránku ve sdíleném stromu", + "share_alias": "definujte alias, pod kterým bude poznámka dostupná na https://your_trilium_host/share/[your_alias]", + "share_omit_default_css": "výchozí CSS stránky pro sdílení bude vynechána. Použijte, pokud provedete rozsáhlé změny stylu.", + "share_root": "Označuje poznámku, která je obsluhována z kořene /share.", + "share_description": "Definujte text, který má být přidán do meta tagu HTML pro popis", + "share_raw": "poznámka bude obsluhována v surovém formátu, bez obalu HTML", + "share_disallow_robot_indexing": "zakáže indexování této poznámky roboty pomocí hlavičky X-Robots-Tag: noindex", + "share_credentials": "Vyžaduje pověření pro přístup k této sdílené poznámce. Hodnota se očekává ve formátu 'username:password'. Nezapomeňte ji učinit dědičnou, aby se použila na podřízené poznámky/obrázky.", + "share_index": "poznámka s tímto štítkem zobrazí všechny kořeny sdílených poznámek", + "display_relations": "seznam jmen vazeb oddělených čárkami, které se mají zobrazit. Všechny ostatní budou skryté.", + "hide_relations": "Seznam jmen vazeb oddělených čárkami, které se mají skrýt. Všechny ostatní budou zobrazeny.", + "title_template": "výchozí název poznámek vytvořených jako podřízené této poznámce. Hodnota je vyhodnocena jako řetězec v JavaScriptu \n a lze ji tedy obohatit o dynamický obsah pomocí vložených proměnných now a parentNote. Příklady:\n \n
    \n
  • ${parentNote.getLabelValue(‚authorName‘)}ova literární díla
  • \n
  • Záznam pro ${now.format(‚YYYY-MM-DD HH:mm:ss‘)}
  • \n
\n \n Viz wiki s podrobnostmi, dokumentaci API pro parentNote a now pro podrobnosti.", + "template": "Tato poznámka se zobrazí ve výběru dostupných šablon při vytváření nové poznámky", + "toc": "#toc nebo #toc=show vynutí zobrazení Obsahu, #toc=hide vynutí jeho skrytí. Pokud štítek neexistuje, je respektováno globální nastavení", + "color": "Definuje barvu poznámky ve stromu poznámek, odkazech atd. Použijte jakoukoli platnou hodnotu CSS barvy, například 'red' nebo #a13d5f", + "keyboard_shortcut": "Definuje klávesovou zkratku, která okamžitě skočí na tuto poznámku. Příklad: 'ctrl+alt+e'. Pro projev změny je vyžadováno obnovení frontendu.", + "keep_current_hoisting": "Otevření tohoto odkazu nezmění zúžení zobrazení, i když poznámka není zobrazitelná v aktuálním zúženém podstromu.", + "execute_button": "Název tlačítka, které spustí aktuální poznámku s kódem", + "execute_description": "Delší popis aktuální poznámky s kódem zobrazený spolu s tlačítkem pro spuštění", + "exclude_from_note_map": "Poznámky s tímto štítkem budou skryté v Mapě poznámek", + "new_notes_on_top": "Nové poznámky budou vytvářeny nahoře nadřazené poznámky, nikoli dole.", + "hide_highlight_widget": "Skrýt Widget Seznam zvýraznění", + "run_on_note_creation": "spustí se při vytvoření poznámky na serveru. Tuto relaci použijte, pokud chcete skript spustit pro všechny poznámky vytvořené v rámci konkrétního podstromu. V takovém případě ji vytvořte na kořenové poznámce podstromu a nastavte ji jako dědičnou. Skript se spustí při vytvoření nové poznámky v rámci podstromu (v jakékoli úrovni).", + "run_on_child_note_creation": "provede se, když je pod poznámkou, ve které je tento vztah definován, vytvořena nová poznámka", + "run_on_note_title_change": "spustí se při změně názvu poznámky (včetně vytvoření poznámky)", + "run_on_note_content_change": "spustí se při změně obsahu poznámky (včetně jejího vytvoření).", + "run_on_note_change": "spustí se při změně noty (včetně jejího vytvoření). Nezahrnuje změny obsahu", + "run_on_note_deletion": "spustí se při mazání poznámky", + "run_on_branch_creation": "spustí se při vytvoření větve. Větev je propojení mezi nadřazenou a podřízenou poznámkou a vzniká například při klonování nebo přesouvání poznámky.", + "run_on_branch_change": "Spustí se při aktualizaci větve.", + "run_on_branch_deletion": "spustí se při smazání větve. Větev představuje propojení mezi nadřazenou a podřízenou poznámkou a je smazána např. při přesunu poznámky (původní větev/propojení je smazáno).", + "run_on_attribute_creation": "spustí se při vytvoření nového atributu pro poznámku, která definuje tuto vazbu", + "relation_template": "atributy poznámky budou zděděny i bez vztahu rodič-potomek; obsah poznámky a její podstrom budou přidány do instancí poznámek, pokud jsou prázdné. Podrobnosti najdete v dokumentaci.", + "inherit": "Atributy poznámky budou zděděny i bez vztahu rodič–potomek. Podobný koncept najdete v sekci „Vazby šablon“. Více informací najdete v dokumentaci v části „Dědičnost atributů“.", + "render_note": "Poznámky typu „zobrazit HTML poznámku“ budou zobrazeny pomocí kódové poznámky (HTML nebo skript) a je nutné pomocí této vazby určit, která poznámka se má zobrazit", + "widget_relation": "cíl této vazby bude proveden a zobrazen jako widget v postranním panelu", + "share_css": "CSS poznámka, která bude vložena do sdílené stránky. CSS poznámka musí být také v sdíleném podstromu. Zvažte použití 'share_hidden_from_tree' a 'share_omit_default_css'.", + "share_js": "JavaScript poznámka, která bude vložena do sdílené stránky. JS poznámka musí být také v sdíleném podstromu. Zvažte použití 'share_hidden_from_tree'.", + "share_template": "Vložená JavaScript poznámka, která bude použita jako šablona pro zobrazení sdílené poznámky. Vrací se k výchozí šabloně. Zvažte použití 'share_hidden_from_tree'.", + "share_favicon": "Poznámka s favicon, která bude nastavena na sdílené stránce. Obvykle ji chcete nastavit do kořene sdílení a učinit ji dědičnou. Favicon poznámka musí být také v sdíleném podstromu. Zvažte použití 'share_hidden_from_tree'.", + "is_owned_by_note": "je vlastněna poznámkou", + "other_notes_with_name": "Ostatní poznámky s {{attributeType}} názvem \"{{attributeName}}\"", + "and_more": "... a {{count}} dalších.", + "print_landscape": "Při exportu do ⟨PDF⟩ změní orientaci stránky na landscape místo portrait.", + "print_page_size": "Při exportu do ⟨PDF⟩ změní velikost stránky. Podporované hodnoty: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.", + "color_type": "Barva", + "run_on_attribute_change": " spustí se při změně atributu poznámky, která tuto vazbu definuje. Spustí se také při smazání tohoto atributu" + }, + "attribute_editor": { + "help_text_body1": "Pro přidání štítku stačí zadat např. #rock nebo pokud chcete přidat i hodnotu, např. #year = 2020", + "help_text_body2": "Pro vazbu zadejte ~author = @, což by mělo vyvolat automatické doplňování, kde můžete vyhledat požadovanou poznámku.", + "help_text_body3": "Případně můžete štítek a vazbu přidat pomocí tlačítka + na pravé straně.", + "save_attributes": "Uložit ⟨Atributy⟩ ", + "add_a_new_attribute": "Přidat nový ⟨Atribut⟩", + "add_new_label": "Přidat nový štítek ", + "add_new_relation": "Přidat novou vazbu ", + "add_new_label_definition": "Přidat novou definici štítku", + "add_new_relation_definition": "Přidat novou definici vazby", + "placeholder": "Zadejte štítky a vazby zde" + }, + "abstract_bulk_action": { + "remove_this_search_action": "Odebrat tuto akci hledání" + }, + "execute_script": { + "execute_script": "Spustit skript", + "help_text": "Můžete spustit jednoduché skripty na vybraných poznámkách.", + "example_1": "Například pro připojení řetězce k názvu poznámky použijte tento malý skript:", + "example_2": "Složitější příklad by bylo smazání všech atributů vybraných poznámek:" + }, + "add_label": { + "add_label": "Přidat štítek", + "label_name_placeholder": "Název štítku", + "label_name_title": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka.", + "to_value": "k hodnotě", + "new_value_placeholder": "nová hodnota", + "help_text": "Na všech odpovídajících poznámkách:", + "help_text_item1": "vytvořit daný štítek, pokud jej poznámka ještě nemá", + "help_text_item2": "nebo změnit hodnotu existujícího štítku", + "help_text_note": "Můžete také zavolat tuto metodu bez hodnoty, v takovém případě bude štítek přiřazen k poznámce bez hodnoty." + }, + "delete_label": { + "delete_label": "Smazat štítek", + "label_name_placeholder": "název štítku", + "label_name_title": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka." + }, + "rename_label": { + "rename_label": "Přejmenovat štítek", + "rename_label_from": "Přejmenovat štítek z", + "old_name_placeholder": "starý název", + "to": "Na", + "new_name_placeholder": "nový název", + "name_title": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka." + }, + "update_label_value": { + "update_label_value": "Aktualizovat hodnotu štítku", + "label_name_placeholder": "název štítku", + "label_name_title": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka.", + "to_value": "na hodnotu", + "new_value_placeholder": "nová hodnota", + "help_text": "U všech nalezených poznámek změňte hodnotu existujícího štítku.", + "help_text_note": "Tuto metodu můžete také zavolat bez hodnoty, v takovém případě bude štítek přiřazen k poznámce bez hodnoty." + }, + "delete_note": { + "delete_note": "Smazat poznámku", + "delete_matched_notes": "Smazat nalezené poznámky", + "delete_matched_notes_description": "Tímto se smažou nalezené poznámky.", + "undelete_notes_instruction": "Po smazání je lze obnovit z dialogu Recent Changes.", + "erase_notes_instruction": "Pro trvalé vymazání poznámek můžete po smazání přejít do Option -> Other a kliknout na tlačítko \"Vymazat smazané poznámky nyní\"." + }, + "delete_revisions": { + "delete_note_revisions": "Smazat revize poznámek", + "all_past_note_revisions": "Všechny minulé revize nalezených poznámek budou smazány. Poznámka samotná zůstane plně zachována. Jinými slovy, historie poznámky bude odstraněna." + }, + "move_note": { + "move_note": "Přesunout poznámku", + "to": "do", + "target_parent_note": "cílové nadřazené poznámky", + "on_all_matched_notes": "Na všech odpovídajících poznámkách", + "move_note_new_parent": "přesunout poznámku do nové nadřazené složky, pokud má poznámka pouze jednu nadřazenou složku (tj. stará větev je odstraněna a je vytvořena nová větev vedoucí do nové nadřazené složky)", + "clone_note_new_parent": "klonovat poznámku do novéhé nadřazené složky, pokud má poznámka více klonů/větví (není jasné, kterou větev by mělo odstranit)", + "nothing_will_happen": "nic se nestane, pokud nelze poznámku přesunout do cílové poznámky (tj. to by vytvořilo cyklus ve stromu)" + }, + "rename_note": { + "rename_note": "Přejmenovat poznámku", + "rename_note_title_to": "Přejmenovat název poznámky na", + "new_note_title": "nový název poznámky", + "click_help_icon": "Klikněte na ikonu nápovědy vpravo a zobrazte všechny možnosti", + "evaluated_as_js_string": "Zadaná hodnota je vyhodnocena jako JavaScript řetězec a může být tak obohacena o dynamický obsah pomocí vložené proměnné note (poznámka bude přejmenována). Příklady:", + "example_note": "Poznámka - všechny odpovídající poznámky jsou přejmenovány na 'Poznámka'", + "example_new_title": "NOVÝ: ${note.title} - názvy odpovídajících poznámek mají předponu 'NOVÝ: '", + "example_date_prefix": "${note.dateCreatedObj.format('MM-DD:')}: ${note.title} - před názvem nalezených poznámek je uvedeno datum a měsíc jejich vytvoření", + "api_docs": "Podrobnosti najdete v dokumentaci k API v poznámce a u jejích vlastností dateCreatedObj / utcDateCreatedObj." + }, + "add_relation": { + "add_relation": "Přidat vazbu", + "relation_name": "název vazby", + "allowed_characters": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka.", + "to": "do", + "target_note": "cílová poznámka", + "create_relation_on_all_matched_notes": "U všech shodných not vytvoř dannou vazbu." + }, + "delete_relation": { + "delete_relation": "Smazat vazbu", + "relation_name": "název vazby", + "allowed_characters": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka." + }, + "rename_relation": { + "rename_relation": "Přejmenovat vazbu", + "rename_relation_from": "Přejmenovat vazbu z", + "old_name": "starý název", + "to": "Na", + "new_name": "nový název", + "allowed_characters": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka." + }, + "update_relation_target": { + "update_relation": "Aktualizovat vazbu", + "relation_name": "název vazby", + "allowed_characters": "Povolené znaky jsou alfanumerické znaky, podtržítko a dvojtečka.", + "to": "do", + "target_note": "cílová poznámka", + "on_all_matched_notes": "Na všech odpovídajících poznámkách", + "change_target_note": "změnit cílovou poznámku existující vazby", + "update_relation_target": "Aktualizovat cílovou vazbu" + }, + "attachments_actions": { + "open_externally": "Otevřít externě", + "open_externally_title": "Soubor bude otevřen v externí aplikaci a sledován na změny. Poté budete moci nahrát upravenou verzi zpět do Trilium.", + "open_custom": "Otevřít vlastní", + "open_custom_title": "Soubor bude otevřen v externí aplikaci a sledován na změny. Poté budete moci nahrát upravenou verzi zpět do Trilium.", + "download": "Stáhnout", + "rename_attachment": "Přejmenovat přílohu", + "upload_new_revision": "Nahrát novou revizi", + "copy_link_to_clipboard": "Kopírovat odkaz do schránky", + "convert_attachment_into_note": "Převést přílohu na poznámku", + "delete_attachment": "Smazat přílohu", + "upload_success": "Nová revize přílohy byla nahrána.", + "upload_failed": "Nahrání nové revize přílohy selhalo.", + "open_externally_detail_page": "Otevření přílohy externě je dostupné pouze ze stránky s detaily, nejprve klikněte na detail přílohy a akci opakujte.", + "open_custom_client_only": "Vlastní otevření příloh lze provést pouze z desktop klienta.", + "delete_confirm": "Jste si jisti, že chcete smazat přílohu '{{title}}'?", + "delete_success": "Příloha '{{title}}' byla smazána.", + "convert_confirm": "Jste si jisti, že chcete převést přílohu '{{title}}' na samostatnou Poznámku?", + "convert_success": "Příloha '{{title}}' byla převedena na Poznámku.", + "enter_new_name": "Zadejte nový název přílohy" + }, + "calendar": { + "mon": "Po", + "tue": "Út", + "wed": "St", + "thu": "Čt", + "fri": "Pá", + "sat": "So", + "sun": "Ne", + "cannot_find_day_note": "Nelze najít denní poznámku", + "cannot_find_week_note": "Nelze najít týdenní poznámku", + "january": "Leden", + "february": "Únor", + "march": "Březen", + "april": "Duben", + "may": "Květen", + "june": "Červen", + "july": "Červenec", + "august": "Srpen", + "september": "Září", + "october": "Říjen", + "november": "Listopad", + "december": "Prosinec", + "week": "Týden", + "week_previous": "Předchozí týden", + "week_next": "Další týden", + "month": "Měsíc", + "month_previous": "Předchozí měsíc", + "month_next": "Další měsíc", + "year": "Rok", + "year_previous": "Předchozí rok", + "year_next": "Další rok", + "list": "Seznam", + "today": "Dnes" + }, + "close_pane_button": { + "close_this_pane": "Zavřít tento panel" + }, + "create_pane_button": { + "create_new_split": "Vytvořit nové rozdělení" + }, + "edit_button": { + "edit_this_note": "Upravit tuto poznámku" + }, + "show_toc_widget_button": { + "show_toc": "Zobrazit Obsah" + }, + "show_highlights_list_widget_button": { + "show_highlights_list": "Zobrazit Seznam zvýraznění" + }, + "global_menu": { + "menu": "Menu", + "options": "Nastavení", + "open_new_window": "Otevřít Nové Okno", + "switch_to_mobile_version": "Přepnout na Mobilní Verzi", + "switch_to_desktop_version": "Přepnout na Počítačovou Verzi", + "zoom": "Zoom", + "toggle_fullscreen": "Přepnout Celou Obrazovku", + "zoom_out": "Oddálit", + "reset_zoom_level": "Resetovat Úroveň Zoomu", + "zoom_in": "Přiblížit", + "configure_launchbar": "Konfigurovat Spouštěcí Lištu", + "show_shared_notes_subtree": "Zobrazit Podstrom Sdílených Poznámek", + "advanced": "Pokročilé", + "open_dev_tools": "Otevřít Nástroje pro vývojáře", + "open_sql_console": "Otevřít SQL Konzoli", + "open_sql_console_history": "Otevřít Historii SQL Konzole", + "open_search_history": "Otevřít Historii Hledání", + "show_backend_log": "Zobrazit Log Backendu", + "reload_hint": "Obnovení může pomoci s některými vizuálními chybami bez restartování celé aplikace.", + "reload_frontend": "Obnovit Frontend", + "show_hidden_subtree": "Zobrazit Skrytý Podstrom", + "show_help": "Zobrazit Nápovědu", + "about": "O Trilium Notes", + "logout": "Odhlásit se", + "show-cheatsheet": "Zobrazit Cheatsheet", + "toggle-zen-mode": "Zen Režim", + "new-version-available": "Je k dispozici nová aktualizace", + "download-update": "Získat verzi {{latestVersion}}", + "search_notes": "Hledání poznámek" + }, + "zen_mode": { + "button_exit": "Opustit Zen mód" + }, + "sync_status": { + "unknown": "

Stav synchronizace bude znám po spuštění dalšího pokusu o synchronizaci.

Klikněte pro spuštění synchronizace nyní.

", + "connected_with_changes": "

Připojeno k synchronizačnímu serveru.
Existují některé nedokončené změny, které je třeba synchronizovat.

Klikněte pro spuštění synchronizace.

", + "connected_no_changes": "

Připojeno k synchronizačnímu serveru.
Všechny změny již byly synchronizovány.

Klikněte pro spuštění synchronizace.

", + "disconnected_with_changes": "

Nepodařilo se navázat spojení se synchronizačním serverem.
Existují některé nedokončené změny, které je třeba synchronizovat.

Klikněte pro spuštění synchronizace.

", + "disconnected_no_changes": "

Nepodařilo se navázat spojení se synchronizačním serverem.
Všechny známé změny byly synchronizovány.

Klikněte pro spuštění synchronizace.

", + "in_progress": "Probíhá synchronizace se serverem." + }, + "left_pane_toggle": { + "show_panel": "Zobrazit panel", + "hide_panel": "Skrýt panel" + }, + "move_pane_button": { + "move_left": "Posunout vlevo", + "move_right": "Posunout vpravo" + }, + "note_actions": { + "convert_into_attachment": "Převést na přílohu", + "re_render_note": "Znovu vykreslit poznámku", + "search_in_note": "Hledat v poznámce", + "note_source": "Zdroj poznámky", + "note_attachments": "Přílohy poznámky", + "view_ocr_text": "Zobrazit text z OCR", + "open_note_externally": "Otevřít poznámku externě", + "open_note_externally_title": "Soubor bude otevřen v externí aplikaci a sledován na změny. Poté budete moci nahrát upravenou verzi zpět do Trilium.", + "open_note_custom": "Otevřít poznámku vlastním způsobem", + "open_note_on_server": "Otevřít poznámku na serveru", + "import_files": "Importovat soubory", + "export_note": "Exportovat poznámku", + "delete_note": "Smazat poznámku", + "print_note": "Vytisknout poznámku", + "view_revisions": "Revize poznámky...", + "save_revision": "Uložit revizi", + "advanced": "Pokročilé", + "convert_into_attachment_failed": "Konverze poznámky '{{title}}' selhala.", + "convert_into_attachment_successful": "Poznámka '{{title}}' byla převedena na přílohu.", + "convert_into_attachment_prompt": "Jste si jisti, že chcete převést poznámku '{{title}}' na přílohu nadřazené poznámky?", + "print_pdf": "Exportovat jako PDF...", + "export_as_image": "Exportovat jako obrázek", + "export_as_image_png": "PNG (raster)", + "export_as_image_svg": "SVG (vector)", + "note_map": "Mapa poznámek" + }, + "onclick_button": { + "no_click_handler": "Widget tlačítka '{{componentId}}' nemá definovaný obslužný program kliknutí" + }, + "protected_session_status": { + "active": "Chráněná relace je aktivní. Klikněte pro ukončení chráněné relace.", + "inactive": "Klikněte pro vstup do chráněné relace" + }, + "revisions_button": { + "note_revisions": "Revize poznámek" + }, + "update_available": { + "update_available": "Dostupná aktualizace" + }, + "note_launcher": { + "this_launcher_doesnt_define_target_note": "Tento spouštěč nedefinuje cílovou poznámku." + }, + "code_buttons": { + "execute_button_title": "Spustit skript", + "trilium_api_docs_button_title": "Otevřít dokumentaci Trilium API", + "save_to_note_button_title": "Uložit do poznámky", + "opening_api_docs_message": "Otevírám API dokumentaci...", + "sql_console_saved_message": "Poznámka SQL konzole byla uložena do {{note_path}}" + }, + "copy_image_reference_button": { + "button_title": "Kopírovat odkaz na obrázek do schránky, lze vložit do textové poznámky." + }, + "hide_floating_buttons_button": { + "button_title": "Skrýt tlačítka" + }, + "show_floating_buttons_button": { + "button_title": "Zobrazit tlačítka" + }, + "svg_export_button": { + "button_title": "Exportovat diagram jako SVG" + }, + "relation_map_buttons": { + "create_child_note_title": "Vytvořit dceřinou poznámku a přidat ji na mapu", + "reset_pan_zoom_title": "Resetovat posun & zoom na počáteční souřadnice a zvětšení", + "zoom_in_title": "Přiblížit", + "zoom_out_title": "Oddálit" + }, + "mobile_detail_menu": { + "insert_child_note": "Vložit dceřinou poznámku", + "delete_this_note": "Smazat tuto poznámku", + "note_revisions": "Revize poznámky", + "error_cannot_get_branch_id": "Nelze získat branchId pro cestu k poznámce '{{notePath}}'", + "error_unrecognized_command": "Nerozpoznaný příkaz {{command}}", + "backlinks": "Zpětné odkazy", + "content_language_switcher": "Jazyk obsahu: {{language}}" + }, + "note_icon": { + "change_note_icon": "Změnit ikonu poznámky", + "search": "Hledání:", + "search_placeholder_filtered": "Hledání {{number}} ikon v {{name}}", + "reset-default": "Obnovit na výchozí ikonu", + "filter": "Filtr", + "filter-none": "Všechny ikony", + "filter-default": "Výchozí ikony", + "icon_tooltip": "{{name}}\nBalíček ikon: {{iconPack}}", + "no_results": "Žádné ikony nenalezeny.", + "search_placeholder_one": "Najít {{number}} ikonu v {{count}} balíčcích", + "search_placeholder_few": "Najít {{number}} ikony v {{count}} balíčcích", + "search_placeholder_other": "Najít {{number}} ikon v {{count}} balíčcích" + }, + "basic_properties": { + "note_type": "Typ poznámky", + "editable": "Upravitelné", + "basic_properties": "Základní vlastnosti", + "language": "Jazyk", + "configure_code_notes": "Konfigurovat poznámky s kódem..." + }, + "book_properties": { + "view_type": "Typ zobrazení", + "grid": "Mřížka", + "list": "Seznam", + "collapse_all_notes": "Sbalit všechny poznámky", + "expand_tooltip": "Rozbalí přímé podprvky této kolekce (do hloubky jedné úrovně). Další možnosti zobrazíte kliknutím na šipku vpravo.", + "collapse": "Sbalit", + "expand": "Rozbalit", + "expand_first_level": "Rozbalit přímé potomky", + "expand_nth_level": "Rozbalit {{depth}} úrovně", + "expand_all_levels": "Rozbalit všechny úrovně", + "book_properties": "Vlastnosti kolekce", + "invalid_view_type": "Neplatný typ zobrazení '{{type}}'", + "calendar": "Kalendář", + "table": "Tabulka", + "geo-map": "Geomapa", + "board": "Tabule", + "presentation": "Prezentace", + "include_archived_notes": "Zobrazit archivované Poznámky", + "hide_child_notes": "Skrýt dceřiné Poznámky ve Stromu" + }, + "edited_notes": { + "no_edited_notes_found": "Zatím nebyly upraveny žádné Poznámky v tento den...", + "title": "Upravené Poznámky", + "deleted": "(smazáno)" + }, + "file_properties": { + "note_id": "ID Poznámky", + "original_file_name": "Původní název souboru", + "file_type": "Typ souboru", + "file_size": "Velikost souboru", + "download": "Stáhnout", + "open": "Otevřít externě", + "upload_new_revision": "Nahrát novou revizi", + "upload_success": "Nová revize souboru byla nahrána.", + "upload_failed": "Nahrání nové revize souboru selhalo.", + "title": "Soubor" + }, + "image_properties": { + "original_file_name": "Původní název souboru", + "file_type": "Typ souboru", + "file_size": "Velikost souboru", + "download": "Stáhnout", + "open": "Otevřít", + "copy_reference_to_clipboard": "Kopírovat referenci do schránky", + "upload_new_revision": "Nahrát novou revizi", + "upload_success": "Nová revize obrázku byla nahrána.", + "upload_failed": "Nahrání nové revize obrázku selhalo: {{message}}", + "title": "Obrázek" + }, + "inherited_attribute_list": { + "title": "Zděděné atributy", + "no_inherited_attributes": "Žádné zděděné atributy.", + "none": "žádný" + }, + "note_info_widget": { + "note_id": "ID Poznámky", + "created": "Vytvořeno", + "modified": "Upraveno", + "type": "Typ", + "mime": "MIME typ", + "note_size": "Velikost Poznámky", + "note_size_info": "Velikost Poznámky poskytuje hrubý odhad požadavků na úložiště pro tuto poznámku. Bere v úvahu obsah poznámky a obsah jejích revizí.", + "calculate": "vypočítat", + "subtree_size": "(velikost podstromu: {{size}} v {{count}} poznámkách)", + "title": "Informace o Poznámce", + "show_similar_notes": "Zobrazit podobné Poznámky" + }, + "note_map": { + "open_full": "Rozbalit na plnou velikost", + "collapse": "Sbalit na normální velikost", + "title": "Mapa poznámek", + "fix-nodes": "Opravit uzly", + "link-distance": "Vzdálenost propojení" + }, + "note_paths": { + "title": "Cesty k poznámkám", + "clone_button": "Klonovat poznámku na nové místo...", + "intro_placed": "Tato poznámka je umístěna v následujících cestách:", + "intro_not_placed": "Tato poznámka ještě nebyla umístěna do stromu poznámek.", + "outside_hoisted": "Tato cesta je mimo nadřazenou poznámku a bude nutné ji odnadřazit.", + "archived": "Archivováno", + "search": "Hledání" + }, + "note_properties": { + "this_note_was_originally_taken_from": "Tato poznámka byla původně pořízena z:", + "info": "Info" + }, + "owned_attribute_list": { + "owned_attributes": "Vlastní atributy" + }, + "promoted_attributes": { + "promoted_attributes": "Propagované atributy", + "unset-field-placeholder": "není nastaveno", + "url_placeholder": "http://website...", + "open_external_link": "Otevřít externí odkaz", + "unknown_label_type": "Neznámý typ štítku '{{type}}'", + "unknown_attribute_type": "Neznámý typ atributu '{{type}}'", + "add_new_attribute": "Přidat nový atribut", + "remove_this_attribute": "Odebrat tento atribut", + "remove_color": "Odebrat barevný štítek" + }, + "script_executor": { + "query": "Dotaz", + "script": "Skript", + "execute_query": "Spustit dotaz", + "execute_script": "Spustit skript" + }, + "search_definition": { + "add_search_option": "Přidat možnost hledání:", + "search_string": "vyhledávací řetězec", + "search_script": "skript pro hledání", + "ancestor": "předek", + "fast_search": "rychlé hledání", + "fast_search_description": "Možnost rychlého hledání vypne úplné textové prohledávání obsahu poznámek, což může urychlit hledání ve velkých databázích.", + "include_archived": "zahrnout archivované", + "include_archived_notes_description": "Archivované poznámky jsou ve výchozím nastavení vyloučeny z výsledků hledání, s touto možností budou zahrnuty.", + "order_by": "seřadit podle", + "limit": "limit", + "limit_description": "Omezit počet výsledků", + "debug": "ladění", + "debug_description": "Ladění vypíše do konzole další ladicí informace, které pomohou při ladění složitých dotazů", + "action": "akce", + "option": "možnost", + "search_button": "Hledání", + "search_execute": "Hledání & Spuštění akcí", + "save_to_note": "Uložit do poznámky", + "search_parameters": "Parametry hledání", + "unknown_search_option": "Neznámá možnost hledání {{searchOptionName}}", + "search_note_saved": "Hledání poznámky bylo uloženo do {{- notePathTitle}}", + "actions_executed": "Akce byly provedeny.", + "view_options": "Možnosti zobrazení:" + }, + "similar_notes": { + "title": "Podobné poznámky", + "no_similar_notes_found": "Nebyly nalezeny žádné podobné poznámky." + }, + "abstract_search_option": { + "remove_this_search_option": "Odebrat tuto možnost hledání", + "failed_rendering": "Selhalo vykreslení možnosti hledání: {{dto}} s chybou: {{error}} {{stack}}" + }, + "ancestor": { + "label": "Předek", + "placeholder": "hledat poznámku podle jejího názvu", + "depth_label": "hloubka", + "depth_doesnt_matter": "nezáleží na tom", + "depth_eq": "je přesně {{count}}", + "direct_children": "přímé děti", + "depth_gt": "je větší než {{count}}", + "depth_lt": "je menší než {{count}}" + }, + "debug": { + "debug": "Ladění", + "debug_info": "Ladění vypíše další ladicí informace do konzole, které pomohou při ladění složitých dotazů.", + "access_info": "Pro přístup k ladicím informacím spusťte dotaz a klikněte na \"Zobrazit backend log\" v levém horním rohu." + }, + "fast_search": { + "fast_search": "Rychlé hledání", + "description": "Možnost rychlého hledání vypne úplné prohledávání obsahu poznámek, což může urychlit hledání ve velkých databázích." + }, + "include_archived_notes": { + "include_archived_notes": "Zahrnout archivované poznámky" + }, + "limit": { + "limit": "Limit", + "take_first_x_results": "Zobrazí pouze prvních X zadaných výsledků." + }, + "order_by": { + "order_by": "Seřadit podle", + "relevancy": "Relevance (výchozí)", + "title": "Název", + "date_created": "Datum vytvoření", + "date_modified": "Datum poslední modifikace", + "content_size": "Velikost obsahu Poznámky", + "content_and_attachments_size": "Velikost obsahu Poznámky včetně Příloh", + "content_and_attachments_and_revisions_size": "Velikost obsahu Poznámky včetně Příloh a Revizí", + "revision_count": "Počet Revizí", + "children_count": "Počet Dceřiných Poznámek", + "parent_count": "Počet Klonů", + "owned_label_count": "Počet Štítků", + "owned_relation_count": "Počet Vazeb", + "target_relation_count": "Počet Vazeb cílených na Poznámku", + "random": "Náhodné pořadí", + "asc": "Vzestupně (výchozí)", + "desc": "Sestupně" + }, + "search_script": { + "title": "Skript pro hledání:", + "placeholder": "hledat Poznámku podle jejího názvu", + "description1": "Vyhledávací skript umožňuje definovat výsledky vyhledávání spuštěním skriptu. To poskytuje maximální flexibilitu v případech, kdy standardní vyhledávání nestačí.", + "description2": "Vyhledávací skript musí být typu „code“ a podtypu „JavaScript backend“. Skript musí vracet pole noteIds nebo notes.", + "example_title": "Podívejte se na tento příklad:", + "example_code": "// 1. Předběžné filtrování pomocí standardního vyhledávání\nconst candidateNotes = api.searchForNotes(„#journal“); \n\n// 2. Použití vlastních vyhledávacích kritérií\nconst matchedNotes = candidateNotes\n .filter(note => note.title.match(/[0-9]{1,2}\\. ?[0-9]{1,2}\\. ?[0-9]{4}/));\n\nreturn matchedNotes;", + "note": "Upozorňujeme, že vyhledávací skript a vyhledávací řetězec nelze vzájemně kombinovat." + }, + "search_string": { + "title_column": "Vyhledávací řetězec:", + "placeholder": "fulltext klíčová slova, #tag = hodnota...", + "search_syntax": "Syntaxe vyhledávání", + "also_see": "také viz", + "complete_help": "kompletní nápověda k syntaxi vyhledávání", + "full_text_search": "Stačí zadat jakýkoli text pro fulltextové vyhledávání", + "label_abc": "vrací poznámky se stítkem abc", + "label_year": "vyhledá poznámky, u nichž má štítek roku hodnotu 2019", + "label_rock_pop": "vyhledá poznámky, které mají štítek rock i pop", + "label_rock_or_pop": "stačí, aby byl přítomen jeden ze štítků", + "label_year_comparison": "numerické porovnání (také >, >=, <).", + "label_date_created": "poznámky vytvořené za poslední měsíc", + "error": "Chyba vyhledávání: {{error}}", + "search_prefix": "Hledání:" + }, + "attachment_detail": { + "open_help_page": "Otevřít nápovědu k přílohám", + "owning_note": "Vlastní poznámka: ", + "you_can_also_open": ", můžete také otevřít ", + "list_of_all_attachments": "Seznam všech příloh", + "attachment_deleted": "Tato příloha byla smazána." + }, + "attachment_list": { + "open_help_page": "Otevřít nápovědu k přílohám", + "owning_note": "Vlastní poznámka: ", + "upload_attachments": "Nahrát přílohy", + "no_attachments": "Tato poznámka nemá žádné přílohy." + }, + "book": { + "no_children_help": "Tato kolekce nemá žádné dceřiné poznámky, takže není co zobrazit.", + "drag_locked_title": "Uzamčeno pro úpravy", + "drag_locked_message": "Přetahování není povoleno, protože kolekce je uzamčena pro úpravy." + }, + "editable_code": { + "placeholder": "Zadejte obsah své poznámky s kódem zde..." + }, + "editable_text": { + "placeholder": "Zadejte obsah své poznámky zde...", + "editor_crashed_title": "Editor textu havaroval", + "editor_crashed_content": "Váš obsah byl úspěšně obnoven, ale několik vašich posledních změn nemuselo být uloženo.", + "editor_crashed_details_button": "Zobrazit více detailů...", + "editor_crashed_details_intro": "Pokud se tato chyba vyskytne několikrát, zvažte její nahlášení na GitHub vložením informací níže.", + "editor_crashed_details_title": "Technické informace", + "auto-detect-language": "Automaticky detekováno", + "keeps-crashing": "Komponenta pro úpravy opakovaně havaruje. Zkuste restartovat Trilium. Pokud problém přetrvává, zvažte vytvoření hlášení o chybě." + }, + "empty": { + "open_note_instruction": "Otevřete poznámku zadáním názvu poznámky do pole níže nebo vyberte poznámku ve stromu.", + "search_placeholder": "hledat poznámku podle jejího názvu", + "enter_workspace": "Vstup do pracovního prostoru {{title}}" + }, + "file": { + "file_preview_not_available": "Náhled souboru není dostupný pro tento formát souboru.", + "too_big": "Náhled zobrazuje pouze prvních {{maxNumChars}} znaků souboru z důvodu výkonu. Stáhněte si soubor a otevřete jej externě, abyste mohli zobrazit celý obsah." + }, + "media": { + "play": "Přehrát (Space)", + "pause": "Pozastavit (Space)", + "back-10s": "Zpět o 10s (Šipka doleva)", + "forward-30s": "Dopředu o 30s", + "mute": "Ztlumit (M)", + "unmute": "Zrušit ztlumení (M)", + "playback-speed": "Rychlost přehrávání", + "loop": "Cyklus", + "disable-loop": "Zakázat cyklus", + "rotate": "Otočit", + "picture-in-picture": "Obraz v obraze", + "exit-picture-in-picture": "Ukončit obraz v obraze", + "fullscreen": "Celá obrazovka (F)", + "exit-fullscreen": "Ukončit celou obrazovku", + "unsupported-format": "Náhled médií není dostupný pro tento formát souboru:\n {{mime}}", + "zoom-to-fit": "Přiblížit do šířky", + "zoom-reset": "Obnovit přiblížení do šířky" + }, + "protected_session": { + "enter_password_instruction": "Zobrazení chráněné poznámky vyžadující zadání hesla:", + "start_session_button": "Spustit chráněnou relaci", + "started": "Chráněná relace byla spuštěna.", + "wrong_password": "Nesprávné heslo.", + "protecting-finished-successfully": "Ochrana proběhla úspěšně.", + "unprotecting-finished-successfully": "Ochrana byla úspěšně zrušena.", + "protecting-in-progress": "Probíhá ochrana: {{count}}", + "unprotecting-in-progress-count": "Probíhá odchrana: {{count}}", + "protecting-title": "Stav ochrany", + "unprotecting-title": "Stav odchrany" + }, + "relation_map": { + "remove_note": "Odstranit poznámku", + "edit_title": "Upravit název", + "rename_note": "Přejmenovat poznámku", + "enter_new_title": "Zadejte nový název poznámky:", + "remove_relation": "Odstranit vazbu", + "confirm_remove_relation": "Jste si jisti, že chcete odstranit vazbu?", + "specify_new_relation_name": "Zadejte nový název vazby (povolené znaky: alfanumerické, dvojtečka a podtržítko):", + "connection_exists": "Připojení '{{name}}' mezi těmito poznámkami již existuje.", + "start_dragging_relations": "Začněte táhnout vazby odsud a přetáhněte je na jinou poznámku.", + "note_not_found": "Poznámka {{noteId}} nebyla nalezena!", + "cannot_match_transform": "Nelze porovnat transformaci: {{transform}}", + "note_already_in_diagram": "Poznámka \"{{title}}\" je již v diagramu.", + "enter_title_of_new_note": "Zadejte název nové poznámky", + "default_new_note_title": "nová poznámka", + "click_on_canvas_to_place_new_note": "Klikněte na plátno pro umístění nové poznámky" + }, + "render": { + "setup_title": "Zobrazit vlastní HTML nebo Preact JSX uvnitř této poznámky", + "setup_create_sample_preact": "Vytvořit ukázkovou poznámku s Preact", + "setup_create_sample_html": "Vytvořit ukázkovou poznámku s HTML", + "setup_sample_created": "Jako dceřiná poznámka byla vytvořena ukázková poznámka.", + "disabled_description": "Tato poznámka pro vykreslení pochází z externího zdroje. Abychom vás ochránili před škodlivým obsahem, není ve výchozím nastavení povolena. Ujistěte se, že zdroji důvěřujete, než ji povolíte.", + "disabled_button_enable": "Povolit poznámku pro vykreslení" + }, + "web_view_setup": { + "title": "Vytvořte živý pohled na webovou stránku přímo v Trilium", + "url_placeholder": "Zadejte nebo vložte webovou adresu, například https://triliumnotes.org", + "create_button": "Vytvořit Webový Pohled", + "invalid_url_title": "Neplatná adresa", + "invalid_url_message": "Vložte platnou webovou adresu, například https://triliumnotes.org.", + "disabled_description": "Tento webový pohled byl importován z externího zdroje. Abychom vás ochránili před phishingem nebo škodlivým obsahem, nenačítá se automaticky. Můžete jej povolit, pokud zdroji důvěřujete.", + "disabled_button_enable": "Povolit webový pohled" + }, + "backend_log": { + "refresh": "Obnovit" + }, + "consistency_checks": { + "title": "Kontroly konzistence", + "find_and_fix_button": "Najděte a opravte problémy s konzistencí", + "finding_and_fixing_message": "Hledání a oprava problémů s konzistencí...", + "issues_fixed_message": "Všechny nalezené problémy s konzistencí byly nyní opraveny." + }, + "database_anonymization": { + "title": "Anonymizace Databáze", + "full_anonymization": "Úplná Anonymizace", + "full_anonymization_description": "Tato akce vytvoří novou kopii databáze a anonymizuje ji (odstraní veškerý obsah poznámek a ponechá pouze strukturu a některá nesenzitivní metadata) pro sdílení online pro účely ladění bez obav z úniku vašich osobních údajů.", + "save_fully_anonymized_database": "Uložit plně anonymizovanou databázi", + "light_anonymization": "Částečná Anonymizace", + "light_anonymization_description": "Tato akce vytvoří novou kopii databáze a provede v ní částečnou anonymizaci — konkrétně budou odstraněny pouze obsahy všech poznámek, zatímco názvy a atributy zůstanou zachovány. Zachovány zůstanou také vlastní skripty poznámek v JS pro frontend i backend a vlastní widgety. To poskytuje více kontextu pro ladění problémů.", + "choose_anonymization": "Můžete se sami rozhodnout, zda chcete poskytnout plně nebo částečně anonymizovanou databázi. I plně anonymizovaná databáze je velmi užitečná, ale v některých případech může částečně anonymizovaná databáze urychlit proces identifikace a opravy chyb.", + "save_lightly_anonymized_database": "Uložit částečně anonymizovanou databázi", + "existing_anonymized_databases": "Existující anonymizované databáze", + "creating_fully_anonymized_database": "Vytváření plně anonymizované databáze...", + "creating_lightly_anonymized_database": "Vytváření částečně anonymizované databáze...", + "error_creating_anonymized_database": "Nepodařilo se vytvořit anonymizovanou databázi, podrobnosti najdete v protokolech backendu", + "successfully_created_fully_anonymized_database": "Vytvořena plně anonymizovaná databáze v {{anonymizedFilePath}}", + "successfully_created_lightly_anonymized_database": "Vytvořena částečně anonymizovaná databáze v {{anonymizedFilePath}}", + "no_anonymized_database_yet": "Zatím žádná anonymizovaná databáze." + }, + "database_integrity_check": { + "title": "Kontrola integrity databáze", + "description": "Toto zkontroluje, zda databáze není poškozena na úrovni SQLite. Může to chvíli trvat v závislosti na velikosti databáze.", + "check_button": "Zkontrolovat integritu databáze", + "checking_integrity": "Probíhá kontrola integrity databáze...", + "integrity_check_succeeded": "Kontrola integrity proběhla úspěšně - nebyly nalezeny žádné problémy.", + "integrity_check_failed": "Kontrola integrity selhala: {{results}}" + }, + "sync": { + "title": "Synchronizace", + "force_full_sync_button": "Vynutit úplnou synchronizaci", + "fill_entity_changes_button": "Naplnit záznamy změn entit", + "full_sync_triggered": "Spuštěna úplná synchronizace", + "filling_entity_changes": "Probíhá naplňování řádků změn entit...", + "sync_rows_filled_successfully": "Řádky synchronizace byly úspěšně naplněny", + "finished-successfully": "Synchronizace proběhla úspěšně.", + "failed": "Synchronizace selhala: {{message}}" + }, + "vacuum_database": { + "title": "Vyčistit databázi (Vacuum)", + "description": "Tímto se provede rekonstrukce databáze, což obvykle povede k menšímu souboru databáze. Žádná data nebudou ve skutečnosti změněna.", + "button_text": "Vyčistit databázi", + "vacuuming_database": "Probíhá čištění databáze...", + "database_vacuumed": "Databáze byla vyčištěna" + }, + "experimental_features": { + "title": "Experimentální Nastavení", + "disclaimer": "Tato nastavení jsou experimentální a mohou způsobit nestabilitu. Používejte s opatrností.", + "new_layout_name": "Nové Rozložení", + "new_layout_description": "Vyzkoušejte nové rozložení pro modernější vzhled a lepší použitelnost. Podléhá velkým změnám v nadcházejících verzích.", + "llm_name": "AI / LLM Chat", + "llm_description": "Povolte postranní panel AI chatu a poznámky LLM chatu poháněné velkými jazykovými modely." + }, + "fonts": { + "theme_defined": "Definované téma", + "fonts": "Písma", + "main_font": "Hlavní písmo", + "font_family": "Rodina písma", + "size": "Velikost", + "note_tree_font": "Font stromu poznámek", + "note_detail_font": "Font detailu poznámky", + "monospace_font": "Monospace (kód) Font", + "note_tree_and_detail_font_sizing": "Upozorňujeme, že velikost fontu stromu a detailu je relativní k hlavnímu nastavení velikosti fontu.", + "not_all_fonts_available": "Ne všechny uvedené fonty nemusí být dostupné ve vašem systému.", + "apply_font_changes": "Pro použití změn fontu klikněte na", + "reload_frontend": "obnovení frontendu", + "generic-fonts": "Obecné fonty", + "sans-serif-system-fonts": "Systémové sans-serif fonty", + "serif-system-fonts": "Systémové serif fonty", + "monospace-system-fonts": "Systémové monospace fonty", + "handwriting-system-fonts": "Systémové fonty pro psaní rukou", + "serif": "Serif", + "sans-serif": "Sans Serif", + "monospace": "Monospace", + "system-default": "Výchozí systémové nastavení" + }, + "max_content_width": { + "title": "Šířka obsahu", + "default_description": "Trilium ve výchozím nastavení omezuje maximální šířku obsahu pro zlepšení čitelnosti na maximalizovaných obrazovkách na širokých monitorech.", + "max_width_label": "Maximální šířka obsahu", + "max_width_unit": "pixelů", + "centerContent": "Udržovat obsah centrováný" + }, + "native_title_bar": { + "title": "Nativní panel titulku (vyžaduje restart aplikace)", + "enabled": "zapnuto", + "disabled": "vypnuto" + }, + "ribbon": { + "widgets": "Widgety pásu karet", + "promoted_attributes_message": "Záložka „Propagované Atributy“ se automaticky otevře, pokud jsou v poznámce přítomny povýšené atributy", + "edited_notes_message": "Záložka Upravené poznámky na pásu karet se automaticky otevře u denních poznámek" + }, + "theme": { + "title": "Vzhled aplikace", + "theme_label": "Vzhled", + "override_theme_fonts_label": "Přepsat písma vzhledu", + "auto_theme": "Starší (Sledovat barevné schéma systému)", + "light_theme": "Starší (Světlé)", + "dark_theme": "Starší (Tmavé)", + "triliumnext": "Trilium (Sledovat barevné schéma systému)", + "triliumnext-light": "Trilium (Světlé)", + "triliumnext-dark": "Trilium (Tmavé)", + "layout": "Rozložení", + "layout-vertical-title": "Vertikální", + "layout-horizontal-title": "Horizontální", + "layout-vertical-description": "panel spouštěčů je vlevo (výchozí nastavení)", + "layout-horizontal-description": "panel spouštěčů je pod záložkou, záložka je nyní celá šířka." + }, + "ui-performance": { + "title": "Výkon", + "enable-motion": "Povolit přechody a animace", + "enable-shadows": "Povolit stíny", + "enable-backdrop-effects": "Povolit efekty pozadí pro nabídky, vyskakovací okna a panely", + "enable-smooth-scroll": "Povolit plynulé rolování", + "app-restart-required": "(restart aplikace je nutný pro projev změny)" + }, + "zoom_factor": { + "title": "Faktor zoomu (pouze desktop verze)", + "description": "Zoom lze ovládat i pomocí klávesových zkratek CTRL+- a CTRL+=." + }, + "code_auto_read_only_size": { + "title": "Automatická velikost pro režim Pouze pro čtení", + "description": "Automatická velikost poznámky pro režim Pouze pro čtení určuje velikost, po které se poznámky zobrazí v režimu Pouze pro čtení (z důvodu výkonu).", + "label": "Automatická velikost pro režim Pouze pro čtení (kódové poznámky)", + "unit": "znaků" + }, + "code-editor-options": { + "title": "Editor" + }, + "code_mime_types": { + "title": "Dostupné MIME typy v rozbalovací nabídce", + "tooltip_syntax_highlighting": "Zvýrazňování syntaxe", + "tooltip_code_block_syntax": "Kódové bloky v Textových poznámkách", + "tooltip_code_note_syntax": "Kódové poznámky" + }, + "vim_key_bindings": { + "use_vim_keybindings_in_code_notes": "Klávesové zkratky Vim", + "enable_vim_keybindings": "Povolit klávesové zkratky Vim v kódových poznámkách (bez ex módu)" + }, + "wrap_lines": { + "wrap_lines_in_code_notes": "Zabalit řádky v kódových poznámkách", + "enable_line_wrap": "Povolit zalomení řádků (změna může vyžadovat obnovení frontendu, aby se projevila)" + }, + "images": { + "images_section_title": "Obrázky", + "download_images_automatically": "Automaticky stahovat obrázky", + "download_images_description": "Automaticky stahovat obrázky odkazované v vloženém HTML, aby byly dostupné offline.", + "enable_image_compression": "Komprese obrázků", + "enable_image_compression_description": "Komprimovat a změnit velikost obrázků při nahrávání nebo vkládání.", + "max_image_dimensions": "Maximální rozměry obrázku", + "max_image_dimensions_description": "Obrázky překračující tuto velikost budou automaticky změněny.", + "max_image_dimensions_unit": "pixelů", + "jpeg_quality": "Kvalita JPEG", + "jpeg_quality_description": "Doporučený rozsah je 50–85. Nižší hodnoty snižují velikost souboru, vyšší hodnoty zachovávají detaily.", + "ocr_section_title": "Extrakce textu (OCR)", + "ocr_related_content_languages": "Jazyky obsahu (používané pro extrakci textu)", + "ocr_auto_process": "Automaticky zpracovávat nové soubory", + "ocr_auto_process_description": "Automaticky extrahovat text z nově nahraných nebo vložených souborů.", + "ocr_min_confidence": "Minimální spolehlivost", + "ocr_confidence_description": "Extrahovat pouze text nad touto hranicí spolehlivosti. Nižší hodnoty zahrnují více textu, ale mohou být méně přesné.", + "batch_ocr_title": "Zpracovat existující soubory", + "batch_ocr_description": "Extrahovat text ze všech existujících obrázků, PDF a Office dokumentů ve vašich poznámkách. To může trvat nějaký čas v závislosti na počtu souborů.", + "batch_ocr_start": "Spustit dávkové zpracování", + "batch_ocr_starting": "Spuštění dávkového zpracování...", + "batch_ocr_progress": "Zpracovávám {{processed}} z {{total}} souborů...", + "batch_ocr_completed": "Dávkové zpracování dokončeno! Zpracováno {{processed}} souborů.", + "batch_ocr_error": "Chyba během dávkového zpracování: {{error}}" + }, + "attachment_erasure_timeout": { + "attachment_erasure_timeout": "Časový limit pro vymazání příloh", + "attachment_auto_deletion_description": "Přílohy jsou automaticky smazány (a vymazány), pokud nejsou po definovaném časovém limitu odkazovány jejich poznámkách.", + "erase_attachments_after": "Vymazat nepoužité přílohy po:", + "manual_erasing_description": "Můžete také spustit vymazání ručně (bez ohledu na výše definovaný časový limit):", + "erase_unused_attachments_now": "Vymazat nepoužité přílohy nyní", + "unused_attachments_erased": "Nepoužívané přílohy byly vymazány." + }, + "network_connections": { + "network_connections_title": "Síťová připojení", + "check_for_updates": "Automaticky kontrolovat aktualizace" + }, + "note_erasure_timeout": { + "note_erasure_timeout_title": "Časový limit pro vymazání Poznámky", + "note_erasure_description": "Odstraněné poznámky (a atributy, revize...) jsou zpočátku pouze označeny jako odstraněné a lze je obnovit v dialogovém okně „Poslední poznámky“. Po uplynutí určité doby jsou odstraněné poznámky „vymazány“, což znamená, že jejich obsah již nelze obnovit. Toto nastavení vám umožňuje určit dobu, která uplyne mezi odstraněním a vymazáním poznámky.", + "erase_notes_after": "Vymazat Poznámky po:", + "manual_erasing_description": "Můžete také spustit vymazání ručně (bez ohledu na výše uvedený časový limit):", + "erase_deleted_notes_now": "Vymazat smazané Poznámky nyní", + "deleted_notes_erased": "Smazané Poznámky byly vymazány." + }, + "revisions_snapshot_interval": { + "note_revisions_snapshot_interval_title": "Interval snímků revizí Poznámky", + "note_revisions_snapshot_description": "Interval snímků revizí Poznámky je doba po které bude vytvořen nový snímek revize Poznámky. Více informací naleznete v wiki.", + "snapshot_time_interval_label": "Časový interval snímků revizí Poznámky:" + }, + "revisions_snapshot_limit": { + "note_revisions_snapshot_limit_title": "Limit snímků revizí Poznámky", + "note_revisions_snapshot_limit_description": "Limit počtu snímků revizí Poznámky se týká maximálního počtu revizí, které lze uložit pro každou Poznámku. Hodnota -1 znamená žádný limit, 0 znamená smazat všechny revize. Můžete nastavit maximální počet revizí pro jednu Poznámku pomocí štítku #versioningLimit.", + "snapshot_number_limit_label": "Limit počtu snímků revizí Poznámky:", + "snapshot_number_limit_unit": "snímky", + "erase_excess_revision_snapshots": "Vymazat nadbytečné snímky revizí nyní", + "erase_excess_revision_snapshots_prompt": "Nadbytečné snímky revizí byly vymazány." + }, + "search_engine": { + "title": "Vyhledávač", + "custom_search_engine_info": "Vlastní vyhledávač vyžaduje nastavení jak názvu, tak URL. Pokud některý z nich není nastaven, bude použit DuckDuckGo jako výchozí vyhledávač.", + "predefined_templates_label": "Předdefinované šablony vyhledávačů", + "bing": "Bing", + "baidu": "Baidu", + "duckduckgo": "DuckDuckGo", + "google": "Google", + "custom_name_label": "Název vlastního vyhledávače", + "custom_name_placeholder": "Přizpůsobit název vyhledávače", + "custom_url_label": "URL vlastního vyhledávače by měl obsahovat {keyword} jako zástupný symbol pro vyhledávací výraz.", + "custom_url_placeholder": "Přizpůsobit URL vyhledávače", + "save_button": "Uložit" + }, + "tray": { + "title": "Systémová informační oblast", + "enable_tray": "Povolit informační oblast (pro zavedení této změny je nutné Trilium restartovat)" + }, + "heading_style": { + "title": "Styl nadpisu", + "plain": "Prostý", + "underline": "Podtržení", + "markdown": "Ve stylu Markdown" + }, + "highlights_list": { + "title": "Seznam zvýraznění", + "description": "V pravém panelu můžete upravit seznam zvýraznění:", + "bold": "Tučné písmo", + "italic": "Kurzíva", + "underline": "Podtržený text", + "color": "Barevný text", + "bg_color": "Text s barvou pozadí", + "visibility_title": "Viditelnost seznamu zvýraznění", + "visibility_description": "Widget zvýraznění můžete pro jednotlivé poznámky skrýt přidáním štítku #hideHighlightWidget.", + "shortcut_info": "Můžete nakonfigurovat klávesovou zkratku pro rychlé přepínání pravého panelu (včetně zvýraznění) v Nastavení -> Zkratky (název 'toggleRightPane')." + }, + "table_of_contents": { + "title": "Obsah", + "description": "Obsah se zobrazí v textových Poznámkách, pokud Poznámka obsahuje více než definovaný počet nadpisů. Můžete si přizpůsobit tento počet:", + "unit": "nadpisů", + "disable_info": "Můžete také použít tuto možnost pro efektivní vypnutí TOC nastavením velmi vysokého čísla.", + "shortcut_info": "Můžete nakonfigurovat klávesovou zkratku pro rychlé přepínání pravého panelu (včetně TOC) v Nastavení -> Zkratky (název 'toggleRightPane')." + }, + "text_auto_read_only_size": { + "title": "Automatická velikost pro Pouze pro čtení", + "description": "Automatická velikost Poznámky pro Pouze pro čtení je velikost, po které se Poznámky zobrazí v režimu Pouze pro čtení (z důvodu výkonu).", + "label": "Automatická velikost pro Pouze pro čtení (textové Poznámky)", + "unit": "znaků" + }, + "custom_date_time_format": { + "title": "Vlastní formát data/času", + "description": "Přizpůsobte formát data a času vloženého pomocí nebo panelu nástrojů. Podívejte se na dokumentaci Day.js pro dostupné tokeny formátu.", + "format_string": "Řetězec formátu:", + "formatted_time": "Formátované datum/čas:" + }, + "i18n": { + "title": "Lokalizace", + "language": "Čeština", + "first-day-of-the-week": "První den v týdnu", + "monday": "Pondělí", + "tuesday": "Úterý", + "wednesday": "Středa", + "thursday": "Čtvrtek", + "friday": "Pátek", + "saturday": "Sobota", + "sunday": "Neděle", + "first-week-of-the-year": "První týden v roce", + "first-week-contains-first-day": "První týden obsahuje první den v roce", + "first-week-contains-first-thursday": "První týden obsahuje první čtvrtek v roce", + "first-week-has-minimum-days": "První týden má minimální počet dní", + "min-days-in-first-week": "Minimální počet dní v prvním týdnu", + "first-week-info": "První týden obsahuje první čtvrtek v roce je založen na ISO 8601 standardu.", + "first-week-warning": "Změna možností prvního týdne může způsobit duplikaci se stávajícími Týdenními Poznámkami a stávající Týdenní Poznámky nebudou odpovídajícím způsobem aktualizovány.", + "formatting-locale": "Formát data & čísel", + "formatting-locale-auto": "Na základě jazyka aplikace" + }, + "backup": { + "automatic_backup": "Automatické zálohování", + "automatic_backup_description": "Trilium může automaticky zálohovat databázi:", + "enable_daily_backup": "Povolit denní zálohování", + "enable_weekly_backup": "Povolit týdenní zálohování", + "enable_monthly_backup": "Povolit měsíční zálohování", + "backup_recommendation": "Doporučuje se ponechat zálohování zapnuté, ale to může zpomalit spuštění aplikace s velkými databázemi a/nebo pomalými úložnými zařízeními.", + "backup_now": "Zálohovat nyní", + "backup_database_now": "Zálohovat databázi nyní", + "existing_backups": "Existující zálohy", + "date-and-time": "Datum & čas", + "path": "Cesta", + "database_backed_up_to": "Databáze byla zálohována do {{backupFilePath}}", + "no_backup_yet": "Zatím neexistuje žádná záloha" + }, + "etapi": { + "title": "ETAPI", + "description": "ETAPI je REST API používané pro programatický přístup k instanci Trilium bez uživatelského rozhraní.", + "create_token": "Vytvořit nový ETAPI token", + "existing_tokens": "Existující tokeny", + "no_tokens_yet": "Zatím neexistují žádné tokeny. Klikněte na tlačítko výše a vytvořte jeden.", + "token_name": "Název tokenu", + "created": "Vytvořeno", + "actions": "Akce", + "new_token_title": "Nový ETAPI token", + "new_token_message": "Zadejte název nového tokenu", + "default_token_name": "nový token", + "error_empty_name": "Název tokenu nemůže být prázdný", + "token_created_title": "ETAPI token vytvořen", + "token_created_message": "Zkopírujte vytvořený token do schránky. Trilium token ukládá hashovaný a toto je poslední možnost, jak jej uvidíte.", + "rename_token": "Přejmenovat tento token", + "delete_token": "Smazat / deaktivovat tento token", + "rename_token_title": "Přejmenovat token", + "rename_token_message": "Zadejte nový název tokenu", + "delete_token_confirmation": "Jste si jisti, že chcete smazat ETAPI token \"{{name}}\"?" + }, + "options_widget": { + "options_status": "Stav Nastavení", + "options_change_saved": "Změny v Nastavení byly uloženy." + }, + "password": { + "heading": "Heslo", + "alert_message": "Dávejte pozor, abyste si zapamatovali své nové heslo. Heslo se používá pro přihlášení do webového rozhraní a pro šifrování chráněných Poznámek. Pokud heslo zapomenete, všechny vaše chráněné Poznámky budou navždy ztraceny.", + "reset_link": "Klikněte zde pro jeho resetování.", + "old_password": "Staré heslo", + "new_password": "Nové heslo", + "new_password_confirmation": "Potvrzení nového hesla", + "change_password": "Změnit heslo", + "protected_session_timeout": "Časový limit pro Chráněná relace", + "protected_session_timeout_description": "Časový limit chráněné relace je doba, po které se chráněná relace vymaže z paměti prohlížeče. Měří se od poslední interakce s chráněnými poznámkami. Viz", + "wiki": "wiki", + "for_more_info": "pro více informací.", + "protected_session_timeout_label": "Časový limit chráněné relace:", + "reset_confirmation": "Resetováním hesla navždy ztratíte přístup ke všem svým existujícím chráněným poznámkám. Opravdu chcete heslo resetovat?", + "reset_success_message": "Heslo bylo resetováno. Nastavte nové heslo", + "change_password_heading": "Změnit heslo", + "set_password_heading": "Nastavit heslo", + "set_password": "Nastavit heslo", + "password_mismatch": "Nová hesla se neshodují.", + "password_changed_success": "Heslo bylo změněno. Trilium se po stisknutí OK znovu načte." + }, + "multi_factor_authentication": { + "title": "Vícefaktorová autentizace", + "description": "Vícefaktorová autentizace (MFA) přidává další vrstvu zabezpečení k vašemu účtu. Místo pouhého zadání hesla pro přihlášení MFA vyžaduje, abyste poskytli jeden nebo více dalších důkazů pro ověření vaší identity. Tímto způsobem, i když se někdo dostane k vašemu heslu, nemůže se k vašemu účtu dostat bez druhého kusu informace. Je to jako přidání dalšího zámku ke dveřím, což ztěžuje vniknutí kohokoli jiného.

Postupujte podle pokynů níže a povolte MFA. Pokud to nenakonfigurujete správně, přihlášení se vrátí pouze k heslu.", + "mfa_enabled": "Povolit vícefaktorovou autentizaci", + "mfa_method": "Metoda MFA", + "electron_disabled": "Multifaktorová autentizace není v desktop verzi aktuálně podporována.", + "totp_title": "Časově založené jednorázové heslo (TOTP)", + "totp_description": "TOTP (Časově založené jednorázové heslo) je bezpečnostní funkce, která generuje jedinečný, dočasný kód, který se mění každých 30 sekund. Tento kód spolu s vaším heslem použijete k přihlášení do svého účtu, což ztěžuje přístup k němu pro kohokoli jiného.", + "totp_secret_title": "Generovat TOTP tajný klíč", + "totp_secret_generate": "Generovat TOTP tajný klíč", + "totp_secret_regenerate": "Regenerovat TOTP tajný klíč", + "no_totp_secret_warning": "Pro povolení TOTP je nejprve nutné vygenerovat TOTP tajný klíč.", + "totp_secret_description_warning": "Po vygenerování nového TOTP tajného klíče budete muset znovu přihlásit pomocí nového TOTP tajného klíče.", + "totp_secret_generated": "TOTP tajný klíč vygenerován", + "totp_secret_warning": "Uložte vygenerovaný tajný klíč na bezpečném místě. Nebude znovu zobrazen.", + "totp_secret_regenerate_confirm": "Jste si jisti, že chcete regenerovat TOTP tajný klíč? Tím se zneplatní předchozí TOTP tajný klíč a všechny existující záchranné kódy.", + "recovery_keys_title": "Záchranné klíče pro jednotné přihlašování", + "recovery_keys_description": "Záchranné klíče pro jednotné přihlašování se používají k přihlášení v případě, že nemáte přístup ke svým autentifikačním kódům.", + "recovery_keys_description_warning": "Záchranné klíče nebudou po opuštění stránky znovu zobrazeny, uchovejte je na bezpečném místě. Po použití záchranného klíče jej nelze znovu použít.", + "recovery_keys_error": "Chyba při generování záchranných kódů", + "recovery_keys_no_key_set": "Nebyly nastaveny žádné záchranné kódy", + "recovery_keys_generate": "Generovat záchranné kódy", + "recovery_keys_regenerate": "Regenerovat záchranné kódy", + "recovery_keys_used": "Použito: {{date}}", + "recovery_keys_unused": "Záchranný kód {{index}} nebyl použit", + "oauth_title": "OAuth/OpenID", + "oauth_description": "OpenID je standardizovaný způsob, jak se přihlásit na webové stránky pomocí účtu z jiné služby, jako je Google, pro ověření vaší identity. Výchozí vydavatel je Google, ale můžete jej změnit na jakéhokoli jiného ⟨OpenID provider⟩. Podrobnosti naleznete zde. Postupujte podle těchto instrukcí pro nastavení služby OpenID přes Google.", + "oauth_description_warning": "Pro povolení OAuth/OpenID musíte nastavit základní ⟨URL⟩ OAuth/OpenID, ID klienta a tajný klíč klienta v souboru config.ini a restartovat aplikaci. Pokud chcete nastavit z proměnných prostředí, nastavte TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID a TRILIUM_OAUTH_CLIENT_SECRET.", + "oauth_missing_vars": "Chybějící nastavení: {{-variables}}", + "oauth_user_account": "Uživatelský účet: ", + "oauth_user_email": "Uživatelský e-mail: ", + "oauth_user_not_logged_in": "Není přihlášen!" + }, + "shortcuts": { + "keyboard_shortcuts": "Klávesové zkratky", + "multiple_shortcuts": "Více zkratek pro stejnou akci lze oddělit čárkou.", + "electron_documentation": "Dostupné modifikátory a kódy kláves naleznete v dokumentaci Electronu.", + "type_text_to_filter": "Napište text pro filtrování zkratek...", + "action_name": "Název akce", + "shortcuts": "Zkratky", + "default_shortcuts": "Výchozí zkratky", + "description": "Popis", + "reload_app": "Načtěte aplikaci pro použití změn", + "set_all_to_default": "Nastavte všechny zkratky na výchozí", + "confirm_reset": "Opravdu chcete resetovat všechny klávesové zkratky na výchozí?", + "no_results": "Nebyly nalezeny žádné zkratky odpovídající '{{filter}}'" + }, + "spellcheck": { + "title": "Kontrola pravopisu", + "description": "Tato nastavení platí pouze pro ⟨desktop⟩ verze, prohlížeče budou používat vlastní nativní kontrolu pravopisu.", + "enable": "Povolit kontrolu pravopisu", + "language_code_label": "Kód jazyka(ů)", + "restart-required": "Změny v nastavení kontroly pravopisu se projeví po restartu aplikace." + }, + "sync_2": { + "config_title": "Konfigurace Synchronizace", + "server_address": "Adresa instance serveru", + "timeout": "Časový limit synchronizace", + "timeout_unit": "milisekund", + "proxy_label": "Proxy server pro synchronizaci (volitelné)", + "note": "Poznámka", + "note_description": "Pokud ponecháte nastavení proxy prázdné, bude použit systémový proxy (platí pouze pro desktop/electron build).", + "special_value_description": "Další speciální hodnota je noproxy, která vynutí ignorování i systémového proxy a respektuje NODE_TLS_REJECT_UNAUTHORIZED.", + "save": "Uložit", + "help": "Nápověda", + "test_title": "Test Synchronizace", + "test_description": "Tím se otestuje připojení a handshake se serverem synchronizace. Pokud server synchronizace není inicializován, nastaví se pro synchronizaci s lokálním dokumentem.", + "test_button": "Test synchronizace", + "handshake_failed": "Selhání handshake se serverem pro synchronizaci, chyba: {{message}}" + }, + "api_log": { + "close": "Zavřít" + }, + "attachment_detail_2": { + "will_be_deleted_in": "Tato příloha bude automaticky smazána za {{time}}", + "will_be_deleted_soon": "Tato příloha bude brzy automaticky smazána", + "deletion_reason": ", protože příloha není propojena s obsahem poznámky. Aby se smazání zabránilo, vložte odkaz na přílohu zpět do obsahu nebo převeďte přílohu na poznámku.", + "role_and_size": "Role: {{role}}, velikost: {{size}}, MIME: {{- mimeType}}", + "link_copied": "Odkaz na přílohu byl zkopírován do schránky.", + "unrecognized_role": "Nerozpoznaná role přílohy '{{role}}'." + }, + "bookmark_switch": { + "bookmark": "Záložka (oblíbená)", + "bookmark_this_note": "Přidejte tuto poznámku do záložek na levém panelu", + "remove_bookmark": "Odebrat záložku" + }, + "editability_select": { + "auto": "Automaticky", + "read_only": "Pouze pro čtení", + "always_editable": "Vždy upravitelná", + "note_is_editable": "Poznámka je upravitelná, pokud není příliš dlouhá.", + "note_is_read_only": "Poznámka je pouze pro čtení, ale lze ji upravit kliknutím na tlačítko.", + "note_is_always_editable": "Poznámka je vždy editovatelná, bez ohledu na její délku." + }, + "note-map": { + "button-link-map": "Mapa odkazů", + "button-tree-map": "Mapa stromu" + }, + "tree-context-menu": { + "open-in-a-new-tab": "Otevřít v nové záložce", + "open-in-a-new-split": "Otevřít v novém rozdělení", + "open-in-a-new-window": "Otevřít v novém okně", + "insert-note-after": "Vložit poznámku za", + "insert-child-note": "Vložit dceřinou poznámku", + "archive": "Archivovat", + "unarchive": "Obnovit z archivu", + "delete": "Smazat", + "search-in-subtree": "Hledat v podstromu", + "hoist-note": "Přesunout poznámku nahoru", + "unhoist-note": "Přesunout poznámku dolů", + "edit-branch-prefix": "Upravit předponu větve", + "advanced": "Pokročilé", + "expand-subtree": "Rozbalit podstrom", + "collapse-subtree": "Sbalit podstrom", + "hide-subtree": "Skrýt podstrom", + "show-subtree": "Zobrazit podstrom", + "sort-by": "Seřadit podle...", + "recent-changes-in-subtree": "Nedávné změny v podstromu", + "convert-to-attachment": "Převést na přílohu", + "copy-note-path-to-clipboard": "Kopírovat cestu poznámky do schránky", + "protect-subtree": "Chránit podstrom", + "unprotect-subtree": "Zrušit ochranu podstromu", + "copy-clone": "Kopírovat / klonovat", + "clone-to": "Klonovat do...", + "cut": "Vyjmout", + "move-to": "Přesunout do...", + "paste-into": "Vložit do", + "paste-after": "Vložit za", + "duplicate": "Duplikovat", + "export": "Export", + "import-into-note": "Importovat do Poznámky", + "apply-bulk-actions": "Použít hromadné akce", + "converted-to-attachments": "{{count}} Poznámek bylo převedeno na Přílohy.", + "convert-to-attachment-confirm": "Jste si jisti, že chcete převést vybrané Poznámky na Přílohy jejich nadřazených Poznámek? Tato operace se vztahuje pouze na Poznámky typu Obrázek, ostatní Poznámky budou přeskočeny.", + "open-in-popup": "Rychlá úprava" + }, + "shared_info": { + "shared_publicly": "Tato Poznámka je veřejně Sdílena na {{- link}}.", + "shared_locally": "Tato Poznámka je lokálně Sdílena na {{- link}}.", + "help_link": "Pro pomoc navštivte wiki." + }, + "read-only-info": { + "read-only-note": "Zobrazujete Poznámku pouze pro čtení.", + "auto-read-only-note": "Tato Poznámka je zobrazena v režimu Pouze pro čtení pro rychlejší načítání.", + "edit-note": "Upravit Poznámku" + }, + "note_types": { + "text": "Text", + "code": "Kód", + "saved-search": "Uložené vyhledávání", + "relation-map": "Mapa Vazeb", + "note-map": "Mapa Poznámek", + "render-note": "Poznámka pro vykreslení", + "book": "Kolekce", + "mermaid-diagram": "Mermaid Diagram", + "canvas": "Plátno", + "web-view": "Webový pohled", + "mind-map": "Mentální mapa", + "file": "Soubor", + "image": "Obrázek", + "launcher": "Spouštěč", + "doc": "Dokument", + "widget": "Widget", + "confirm-change": "Nedoporučuje se měnit typ poznámky, pokud není prázdná. Chcete pokračovat?", + "geo-map": "Geomapa", + "beta-feature": "Beta", + "ai-chat": "AI Chat", + "llm-chat": "AI Chat", + "task-list": "Seznam úkolů", + "new-feature": "Nový", + "collections": "Kolekce", + "spreadsheet": "Tabulka" + }, + "protect_note": { + "toggle-on": "Zabezpečit poznámku", + "toggle-off": "Zrušit zabezpečení poznámky", + "toggle-on-hint": "Poznámka není zabezpečená, klikněte pro její zabezpečení", + "toggle-off-hint": "Poznámka je zabezpečená, klikněte pro zrušení zabezpečení" + }, + "llm_chat": { + "placeholder": "Napište zprávu...", + "send": "Odeslat", + "sending": "Odesílání...", + "empty_state": "Zahajte konverzaci napsáním zprávy níže.", + "searching_web": "Hledání na webu...", + "web_search": "Vyhledávání na webu", + "note_tools": "Přístup k Poznámce", + "sources": "Zdroje", + "sources_summary": "{{count}} zdrojů z {{sites}} webů", + "extended_thinking": "Rozšířené myšlení", + "legacy_models": "Starší modely", + "thinking": "Přemýšlím...", + "thought_process": "Myšlenkový proces", + "tool_calls": "{{count}} volání nástroje(ů)", + "input": "Vstup", + "result": "Výsledek", + "error": "Chyba", + "tool_error": "selhalo", + "total_tokens": "{{total}} tokenů", + "tokens_detail": "{{prompt}} prompt + {{completion}} completion", + "tokens_used": "{{prompt}} prompt + {{completion}} completion = {{total}} tokenů", + "tokens_used_with_cost": "{{prompt}} prompt + {{completion}} completion = {{total}} tokenů (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} prompt + {{completion}} completion = {{total}} tokenů", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} prompt + {{completion}} completion = {{total}} tokenů (~${{cost}})", + "tokens": "tokenů", + "context_used": "{{percentage}}% použito", + "note_context_enabled": "Kliknutím zakažte kontext poznámky: {{title}}", + "note_context_disabled": "Kliknutím zahrňte aktuální Poznámku do kontextu", + "no_provider_message": "Nebyl nakonfigurován žádný AI poskytovatel. Přidejte jeden pro zahájení chatu.", + "add_provider": "Přidat AI Poskytovatele" + }, + "sidebar_chat": { + "title": "AI Chat", + "launcher_title": "Otevřít AI Chat", + "new_chat": "Zahájit nový chat", + "save_chat": "Uložit chat do poznámek", + "empty_state": "Zahájit konverzaci", + "history": "Historie chatu", + "recent_chats": "Nedávné chaty", + "no_chats": "Žádné předchozí chaty" + }, + "shared_switch": { + "shared": "Sdíleno", + "toggle-on-title": "Sdílet poznámku", + "toggle-off-title": "Zrušit sdílení poznámky", + "shared-branch": "Tato poznámka existuje pouze jako sdílená poznámka, zrušení sdílení by ji smazalo. Chcete pokračovat a tímto poznámku smazat?", + "inherited": "Poznámku nelze zde zrušit sdílení, protože je sdílena dědičně z nadřazené poznámky." + }, + "template_switch": { + "template": "Šablona", + "toggle-on-hint": "Udělat z poznámky šablonu", + "toggle-off-hint": "Odstranit poznámku jako šablonu" + }, + "open-help-page": "Otevřít stránku nápovědy", + "find": { + "case_sensitive": "Rozlišovat malá a velká písmena", + "match_words": "Shoda slov", + "find_placeholder": "Najít v textu...", + "replace_placeholder": "Nahradit pomocí...", + "replace": "Nahradit", + "replace_all": "Nahradit vše" + }, + "highlights_list_2": { + "title": "Seznam zvýraznění", + "options": "Nastavení", + "modal_title": "Konfigurovat seznam zvýraznění", + "menu_configure": "Konfigurovat seznam zvýraznění...", + "no_highlights": "Nebyla nalezena žádná zvýraznění.", + "title_with_count_one": "{{count}} zvýraznění", + "title_with_count_few": "{{count}} zvýraznění", + "title_with_count_other": "{{count}} zvýraznění" + }, + "quick-search": { + "placeholder": "Rychlé hledání", + "searching": "Hledání...", + "no-results": "Nebyla nalezena žádná výsledná", + "more-results": "... a dalších {{number}} výsledků.", + "show-in-full-search": "Zobrazit v úplném vyhledávání" + }, + "note_tree": { + "collapse-title": "Sbalit strom poznámek", + "scroll-active-title": "Posunout k aktivní poznámce", + "tree-settings-title": "Nastavení stromu", + "hide-archived-notes": "Skrýt archivované poznámky", + "automatically-collapse-notes": "Automaticky sbalovat poznámky", + "automatically-collapse-notes-title": "Poznámky budou po období nečinnosti sbaleny, aby se strom nepřehltil.", + "save-changes": "Uložit a použít změny", + "auto-collapsing-notes-after-inactivity": "Automatické sbalování poznámek po nečinnosti...", + "saved-search-note-refreshed": "Uložené vyhledávání poznámky bylo obnoveno.", + "hoist-this-note-workspace": "Vyvýšit tuto poznámku (pracovní plocha)", + "refresh-saved-search-results": "Obnovit výsledky uloženého vyhledávání", + "create-child-note": "Vytvořit dceřinnou poznámku", + "unhoist": "Unhoist", + "toggle-sidebar": "Přepnout boční panel", + "dropping-not-allowed": "Do této polohy nelze poznámky přesouvat.", + "clone-indicator-tooltip": "Tato poznámka má {{- count}} rodičů: {{- parents}}", + "clone-indicator-tooltip-single": "Tato poznámka je klonována (1 další rodič: {{- parent}})", + "shared-indicator-tooltip": "Tato poznámka je sdílena veřejně", + "shared-indicator-tooltip-with-url": "Tato poznámka je sdílena veřejně na: {{- url}}", + "subtree-hidden-moved-title": "Přidáno do {{title}}", + "subtree-hidden-moved-description-collection": "Tato kolekce skrývá své dceřiné poznámky ve stromu.", + "subtree-hidden-moved-description-other": "Dceřiné poznámky jsou pro tuto poznámku skryty ve stromu.", + "subtree-hidden-tooltip_one": "{{count}} podřízená poznámka, která je ve stromu skrytá", + "subtree-hidden-tooltip_few": "{{count}} podřízené poznámky, které jsou ve stromu skryté", + "subtree-hidden-tooltip_other": "{{count}} podřízených poznámek, které jsou ve stromu skryté" + }, + "title_bar_buttons": { + "window-on-top": "Připítnout okno na horní část obrazovky" + }, + "note_detail": { + "could_not_find_typewidget": "Nebyl nalezen typeWidget pro typ '{{type}}'", + "printing": "Tisknutí probíhá...", + "printing_pdf": "Exportování do PDF probíhá...", + "print_report_title": "Vytisknout sestavu", + "print_report_error_title": "Tisk se nezdařil", + "print_report_stack_trace": "Stack trace", + "print_report_collection_details_button": "Zobrazit podrobnosti", + "print_report_collection_details_ignored_notes": "Ignorované poznámky", + "print_report_collection_content_one": "{{count}} poznámka ve sbírce nebyla možná vytisknout, protože není podporována nebo je chráněna.", + "print_report_collection_content_few": "{{count}} poznámky ve sbírce nebylo možné vytisknout, protože nejsou podporovány nebo jsou chráněny.", + "print_report_collection_content_other": "{{count}} poznámek ve sbírce nebylo možné vytisknout, protože nejsou podporovány nebo jsou chráněny." + }, + "note_title": { + "placeholder": "Zde napište název poznámky...", + "created_on": "Vytvořeno dne ", + "last_modified": "Upraveno dne ", + "note_type_switcher_label": "Přepnout z {{type}} na:", + "note_type_switcher_others": "Jiný typ poznámky", + "note_type_switcher_templates": "Šablona", + "note_type_switcher_collection": "Kolekce", + "edited_notes": "Poznámky upravené v tento den", + "promoted_attributes": "Propagované atributy" + }, + "search_result": { + "no_notes_found": "Pro zadané parametry hledání nebyly nalezeny žádné poznámky.", + "search_not_executed": "Hledání ještě nebylo provedeno.", + "search_now": "Hledat nyní" + }, + "spacer": { + "configure_launchbar": "Konfigurovat Launchbar" + }, + "sql_result": { + "not_executed": "Dotaz ještě nebyl proveden.", + "no_rows": "Pro tento dotaz nebyly vráceny žádné řádky", + "failed": "Provádění SQL dotazu selhalo", + "statement_result": "Výsledek příkazu", + "execute_now": "Spustit nyní" + }, + "sql_table_schemas": { + "tables": "Tabulky" + }, + "tab_row": { + "close_tab": "Zavřít záložku", + "add_new_tab": "Přidat novou záložku", + "close": "Zavřít", + "close_other_tabs": "Zavřít ostatní záložky", + "close_right_tabs": "Zavřít záložky vpravo", + "close_all_tabs": "Zavřít všechny záložky", + "reopen_last_tab": "Znovu otevřít poslední zavřenou záložku", + "move_tab_to_new_window": "Přesunout tuto záložku do nového okna", + "copy_tab_to_new_window": "Zkopírovat tuto záložku do nového okna", + "new_tab": "Nová záložka" + }, + "toc": { + "table_of_contents": "Obsah", + "options": "Nastavení", + "no_headings": "Žádné nadpisy." + }, + "watched_file_update_status": { + "file_last_modified": "Soubor byl naposledy upraven .", + "upload_modified_file": "Nahrát upravený soubor", + "ignore_this_change": "Ignorovat tuto změnu" + }, + "app_context": { + "please_wait_for_save": "Počkejte prosím několik sekund, dokud se dokončí ukládání, poté můžete zkusit znovu." + }, + "note_create": { + "duplicated": "Poznámka \"{{title}}\" byla duplikována." + }, + "image": { + "copied-to-clipboard": "Odkaz na obrázek byl zkopírován do schránky. Lze jej vložit do jakékoli textové poznámky.", + "cannot-copy": "Odkaz na obrázek nebylo možné zkopírovat do schránky." + }, + "clipboard": { + "cut": "Poznámka/poznámky byly vyříznuty do schránky.", + "copied": "Poznámka/poznámky byly zkopírovány do schránky.", + "copy_failed": "Nelze zkopírovat do schránky kvůli problémům s oprávněním.", + "copy_success": "Zkopírováno do schránky." + }, + "entrypoints": { + "note-revision-created": "Revize poznámky byla vytvořena.", + "note-executed": "Poznámka byla spuštěna.", + "sql-error": "Při provádění SQL dotazu došlo k chybě: {{message}}" + }, + "branches": { + "cannot-move-notes-here": "Poznámky sem nelze přesunout.", + "delete-status": "Stav mazání", + "delete-notes-in-progress": "Probíhá mazání poznámek: {{count}}", + "delete-finished-successfully": "Mazání proběhlo úspěšně.", + "undeleting-notes-in-progress": "Probíhá obnovování poznámek: {{count}}", + "undeleting-notes-finished-successfully": "Obnovení poznámek proběhlo úspěšně." + }, + "frontend_script_api": { + "async_warning": "Předáváte asynchronní funkci do `api.runOnBackend()`, což pravděpodobně nebude fungovat tak, jak jste zamýšleli.\\nBuď udělejte funkci synchronní (odstraněním klíčového slova `async`), nebo použijte `api.runAsyncOnBackendWithManualTransactionHandling()`.", + "sync_warning": "Předáváte synchronní funkci do `api.runAsyncOnBackendWithManualTransactionHandling()`,\\nzatímco byste pravděpodobně měli místo toho použít `api.runOnBackend()`." + }, + "ws": { + "sync-check-failed": "Kontrola synchronizace selhala!", + "consistency-checks-failed": "Kontroly konzistence selhaly! Podrobnosti najdete v protokolech.", + "encountered-error": "Došlo k chybě \"{{message}}\", podívejte se do konzole.", + "lost-websocket-connection-title": "Ztraceno připojení ke serveru", + "lost-websocket-connection-message": "Zkontrolujte konfiguraci svého reverzního proxy (např. nginx nebo Apache), zda jsou připojení WebSocket správně povolena a nejsou blokována." + }, + "hoisted_note": { + "confirm_unhoisting": "Požadovaná poznámka '{{requestedNote}}' se nachází mimo podstrom zúžené poznámky '{{hoistedNote}}' a pro k jejímu přístupu musíte provést zúžení zrušit. Chcete pokračovat v uvolnění zobrazení?" + }, + "launcher_context_menu": { + "reset_launcher_confirm": "Opravdu chcete resetovat \"{{title}}\"? Všechna data / nastavení v této poznámce (a jejích dceřiných poznámkách) budou ztracena a spouštěč se vrátí na své původní místo.", + "add-note-launcher": "Přidat spouštěč poznámky", + "add-script-launcher": "Přidat spouštěč skriptu", + "add-custom-widget": "Přidat vlastní widget", + "add-spacer": "Přidat oddělovač", + "delete": "Smazat ", + "reset": "Resetovat", + "move-to-visible-launchers": "Přesunout do viditelných spouštěčů", + "move-to-available-launchers": "Přesunout do dostupných spouštěčů", + "duplicate-launcher": "Duplikovat spouštěč " + }, + "highlighting": { + "title": "Bloky kódu", + "description": "Ovládá zvýrazňování syntaxe pro bloky kódu v textových poznámkách, poznámky kódu se tím nebudou dotýkat.", + "color-scheme": "Barevné schéma" + }, + "code_block": { + "word_wrapping": "Zalomování slov", + "theme_none": "Žádné zvýrazňování syntaxe", + "theme_group_light": "Světlé motivy", + "theme_group_dark": "Tmavé motivy", + "copy_title": "Kopírovat do schránky" + }, + "classic_editor_toolbar": { + "title": "Formátování" + }, + "editor": { + "title": "Editor" + }, + "editing": { + "editor_type": { + "label": "Lišta pro formátování", + "floating": { + "title": "Plovoucí", + "description": "nástroje pro úpravy se zobrazí u kurzoru;" + }, + "fixed": { + "title": "Fixní", + "description": "nástroje pro úpravu se zobrazují na záložce „Formátování“ v pásu karet." + }, + "multiline-toolbar": "Zobrazit panel nástrojů v několika řádcích, pokud se nevejde." + } + }, + "electron_context_menu": { + "add-term-to-dictionary": "Přidat „{{term}}“ do slovníku", + "cut": "Vyříznout", + "copy": "Kopírovat", + "copy-as-markdown": "Kopírovat jako Markdown", + "copy-link": "Kopírovat odkaz", + "paste": "Vložit", + "paste-as-plain-text": "Vložit jako prostý text", + "search_in_trilium": "Hledat „{{term}}“ v Trilium", + "search_online": "Hledat „{{term}}“ pomocí {{searchEngine}}" + }, + "image_context_menu": { + "copy_reference_to_clipboard": "Kopírovat referenci do schránky", + "copy_image_to_clipboard": "Kopírovat obrázek do schránky" + }, + "link_context_menu": { + "open_note_in_new_tab": "Otevřít poznámku v nové záložce", + "open_note_in_new_split": "Otevřít poznámku v novém rozdělení", + "open_note_in_other_split": "Otevřít poznámku v druhém rozdělení", + "open_note_in_new_window": "Otevřít poznámku v novém okně", + "open_note_in_popup": "Rychlá úprava" + }, + "electron_integration": { + "desktop-application": "Počítačová aplikace", + "native-title-bar": "Nativní názevku okna", + "native-title-bar-description": "Pro Windows a macOS vede vypnutí nativního názvu okna k kompaktnějšímu vzhledu aplikace. Na Linuxu lepší integraci s ostatní částí systému zajistí zapnutý nativní název okna.", + "background-effects": "Povolit efekty pozadí", + "background-effects-description": "Přidává rozmazané, stylové pozadí do oken aplikace, čímž vytváří hloubku a moderní vzhled. Musí být vypnutá funkce „Nativní název okna“.", + "restart-app-button": "Restartujte aplikaci pro zobrazení změn", + "zoom-factor": "Míra přiblížení" + }, + "note_autocomplete": { + "search-for": "Hledat \"{{term}}\"", + "create-note": "Vytvořit a propojit dceřinnou poznámku \"{{term}}\"", + "insert-external-link": "Vložit externí odkaz na \"{{term}}\"", + "clear-text-field": "Vymazat textové pole", + "show-recent-notes": "Zobrazit nedávné poznámky", + "full-text-search": "Vyhledávání v celém textu" + }, + "note_tooltip": { + "note-has-been-deleted": "Poznámka byla smazána.", + "quick-edit": "Rychlá úprava" + }, + "geo-map": { + "create-child-note-title": "Vytvořit novou dceřinou poznámku a přidat ji do mapy", + "create-child-note-text": "Přidat značku", + "create-child-note-instruction": "Kliknutím na mapu vytvoříte novou poznámku na daném místě nebo stisknutím klávesy Escape jej zavřete.", + "unable-to-load-map": "Nelze načíst mapu." + }, + "geo-map-context": { + "open-location": "Otevřít polohu", + "remove-from-map": "Odebrat z mapy", + "add-note": "Přidat značku na toto místo" + }, + "help-button": { + "title": "Otevřít příslušnou nápovědu" + }, + "duration": { + "seconds": "Sekundy", + "minutes": "Minuty", + "hours": "Hodiny", + "days": "Dny" + }, + "share": { + "title": "Nastavení sdílení", + "redirect_bare_domain": "Přesměrovat hlavní doménu na stránku sdílení", + "redirect_bare_domain_description": "Přesměrovat anonymní uživatele na stránku sdílení místo zobrazení přihlášení", + "show_login_link": "Zobrazit odkaz na přihlášení ve tématu sdílení", + "show_login_link_description": "Přidat odkaz na přihlášení do zápatí stránky sdílení", + "check_share_root": "Kontrola stavu kořenové poznámky sdílení", + "share_root_found": "Kořenová poznámka sdílení '{{noteTitle}}' je připravena", + "share_root_not_found": "Nebyla nalezena žádná poznámka se štítkem #shareRoot", + "share_root_not_shared": "Poznámka '{{noteTitle}}' má štítek #shareRoot, ale není sdílena" + }, + "time_selector": { + "invalid_input": "Zadaná hodnota času není platné číslo.", + "minimum_input": "Zadaná hodnota času musí být alespoň {{minimumSeconds}} sekund." + }, + "tasks": { + "due": { + "today": "Dnes", + "tomorrow": "Zítra", + "yesterday": "Včera" + } + }, + "content_widget": { + "unknown_widget": "Neznámý widget pro \"{{id}}\"." + }, + "note_language": { + "not_set": "Jazyk není nastaven", + "configure-languages": "Konfigurovat jazyky...", + "help-on-languages": "Nápověda k jazykům obsahu..." + }, + "content_language": { + "title": "Jazyky obsahu", + "description": "Vyberte jeden nebo více jazyků, které by měly být zobrazeny v výběru jazyka v části Základní vlastnosti poznámky typu pouze pro čtení nebo k editaci. To umožní funkce jako kontrola pravopisu, podpora písma zprava doleva a extrakce textu (OCR)." + }, + "switch_layout_button": { + "title_vertical": "Přesunout panel úprav na dolní část", + "title_horizontal": "Přesunout panel úpráv nalevo" + }, + "toggle_read_only_button": { + "unlock-editing": "Odemknout úpravy", + "lock-editing": "Uzamknout úpravy" + }, + "png_export_button": { + "button_title": "Exportovat diagram jako PNG" + }, + "svg": { + "export_to_png": "Diagram nebylo možné exportovat do PNG.", + "export_to_svg": "Diagram nebylo možné exportovat do SVG." + }, + "code_theme": { + "title": "Vzhled", + "word_wrapping": "Zalomování textu", + "color-scheme": "Barevné schéma" + }, + "cpu_arch_warning": { + "title": "Prosím stáhněte si verzi ARM64", + "message_macos": "TriliumNext momentálně běží pod překladem Rosetta 2, což znamená, že na Macu s Apple Silicon používáte verzi Intel (x64). To bude mít výrazný dopad na výkon a výdrž baterie.", + "message_windows": "TriliumNext momentálně běží v režimu emulace, což znamená, že na zařízení Windows pro ARM používáte verzi Intel (x64). To bude mít výrazný dopad na výkon a výdrž baterie.", + "recommendation": "Pro nejlepší zážitek si prosím stáhněte nativní verzi ARM64 aplikace TriliumNext z naší stránky s vydáními.", + "download_link": "Stáhnout nativní verzi", + "continue_anyway": "Pokračovat i tak", + "dont_show_again": "Toto varování již nezobrazovat" + }, + "editorfeatures": { + "title": "Funkce", + "emoji_completion_enabled": "Povolit automatické doplňování emoji", + "emoji_completion_description": "Pokud je tato funkce povolena, do textu lze snadno vkládat emoji napsáním symbolu `:`, následovaného názvem emoji.", + "note_completion_enabled": "Povolit automatické doplňování poznámek", + "note_completion_description": "Pokud je tato funkce povolena, lze vytvářet odkazy na poznámky napsáním symbolu `@`, následovaného názvem poznámky.", + "slash_commands_enabled": "Povolit lomítkové příkazy (slash commands)", + "slash_commands_description": "Pokud je tato funkce povolena, lze přepínat editační příkazy, jako je vkládání zalomení řádku nebo nadpisů, napsáním `/`." + }, + "table_view": { + "new-row": "Nový řádek", + "new-column": "Nový sloupec", + "sort-column-by": "Řadit podle \"{{title}}\"", + "sort-column-ascending": "Vzestupně", + "sort-column-descending": "Sestupně", + "sort-column-clear": "Vymazat řazení", + "hide-column": "Skrýt sloupec \"{{title}}\"", + "show-hide-columns": "Zobrazit/skrýt sloupce", + "row-insert-above": "Vložit řádek nad", + "row-insert-below": "Vložit řádek pod", + "row-insert-child": "Vložit dceřinnou poznámku", + "add-column-to-the-left": "Přidat sloupec vlevo", + "add-column-to-the-right": "Přidat sloupec vpravo", + "edit-column": "Upravit sloupec", + "delete_column_confirmation": "Opravdu chcete tento sloupec smazat? Odpovídající atribut bude odstraněn ze všech poznámek.", + "delete-column": "Odstranit sloupec", + "new-column-label": "Štítek", + "new-column-relation": "Vazba" + }, + "book_properties_config": { + "hide-weekends": "Skrýt víkendy", + "display-week-numbers": "Zobrazovat čísla týdnů", + "map-style": "Styl mapy", + "max-nesting-depth": "Maximální hloubka vnoření:", + "raster": "Raster", + "vector_light": "Vektor (Světlý)", + "vector_dark": "Vektor (Tmavý)", + "show-scale": "Zobrazit měřítko", + "show-labels": "Zobrazovat názvy značek" + }, + "table_context_menu": { + "delete_row": "Odstranit řádek" + }, + "board_view": { + "delete-note": "Odstranit poznámku...", + "remove-from-board": "Odebrat z tabule", + "archive-note": "Archivovat poznámku", + "unarchive-note": "Odarchivovat poznámku", + "move-to": "Přesunout do", + "insert-above": "Vložit nad", + "insert-below": "Vložit pod", + "delete-column": "Odstranit sloupec", + "delete-column-confirmation": "Opravdu chcete tento sloupec odstranit? Odstraněny budou i odpovídající atributy v poznámkách pod tímto sloupcem.", + "new-item": "Nová položka", + "new-item-placeholder": "Zadejte název poznámky...", + "add-column": "Přidat sloupec", + "add-column-placeholder": "Zadejte název sloupce...", + "edit-note-title": "Kliknutím upravíte název poznámky", + "edit-column-title": "Kliknutím upravíte název sloupce", + "column-already-exists": "Tento sloupec již na tabuli existuje." + }, + "presentation_view": { + "edit-slide": "Upravit tento snímek", + "start-presentation": "Spustit prezentaci", + "slide-overview": "Přepnout zobrazení přehledu snímků" + }, + "calendar_view": { + "delete_note": "Smazat poznámku..." + }, + "ocr": { + "extracted_text": "Extraktovaný text (OCR)", + "extracted_text_title": "Extraktovaný text (OCR)", + "loading_text": "Načítání OCR textu...", + "no_text_available": "Žádný OCR text není k dispozici", + "no_text_explanation": "Tato poznámka nebyla zpracována pro extrakci OCR textu, nebo nebyl nalezen žádný text.", + "failed_to_load": "Nepodařilo se načíst OCR text", + "process_now": "Zpracovat OCR", + "processing": "Zpracovávání...", + "processing_started": "Zpracování OCR bylo zahájeno. Počkejte chvíli a obnovte stránku.", + "processing_failed": "Nepodařilo se zahájit zpracování OCR", + "view_extracted_text": "Zobrazit extraktovaný text (OCR)", + "processing_complete": "Zpracování pomocí OCR bylo dokončeno.", + "text_filtered_low_confidence": "OCR rozpoznal text s jistotou {{confidence}} %, ale výsledek byl vyřazen, protože vaše minimální prahová hodnota je {{threshold}} %.", + "open_media_settings": "Otevřít Nastavení" + }, + "command_palette": { + "tree-action-name": "Strom: {{name}}", + "export_note_title": "Exportovat poznámku", + "export_note_description": "Exportovat aktuální poznámku", + "show_attachments_title": "Zobrazit přílohy", + "show_attachments_description": "Zobrazit přílohy poznámky", + "search_notes_title": "Hledat poznámky", + "search_notes_description": "Otevřít pokročilé hledání", + "search_subtree_title": "Hledat v podstromu", + "search_subtree_description": "Hledat v aktuálním podstromu", + "search_history_title": "Zobrazit historii hledání", + "search_history_description": "Zobrazit předchozí hledání", + "configure_launch_bar_title": "Konfigurovat Launch Bar", + "configure_launch_bar_description": "Otevřít konfiguraci Launch Baru pro přidání nebo odebrání položek." + }, + "content_renderer": { + "open_externally": "Otevřít externě" + }, + "modal": { + "close": "Zavřít", + "help_title": "Zobrazit více informací o této obrazovce" + }, + "call_to_action": { + "next_theme_title": "Vyzkoušejte nové téma Trilium", + "next_theme_message": "Momentálně používáte staré téma, chcete vyzkoušet nové téma?", + "next_theme_button": "Vyzkoušet nové téma", + "background_effects_title": "Efekty pozadí jsou nyní stabilní", + "background_effects_message": "Na zařízeních Windows a macOS jsou efekty pozadí nyní stabilní. Efekty pozadí přidávají uživatelskému rozhraní nádech barvy rozostřením pozadí za ním.", + "background_effects_button": "Povolit efekty pozadí", + "new_layout_title": "Nové rozvržení", + "new_layout_message": "Pro Trilium jsme zavedli modernizované rozvržení. Pás karet byl odstraněn a plynule integrovan do hlavního rozhraní, přičemž nové stavové řádky a rozšiřitelné sekce (jako jsou propagované atributy) převzaly klíčové funkce. \n\nNové rozvržení je padrãoně zapnuté a lze jej dočasně vypnout přes Nastavení → Vzhled.", + "new_layout_button": "Více informací", + "dismiss": "Zavřít" + }, + "settings": { + "related_settings": "Související nastavení" + }, + "settings_appearance": { + "related_code_blocks": "Barevné schéma pro bloky kódu v textových poznámkách", + "related_code_notes": "Barevné schéma pro poznámky kódu", + "ui": "Uživatelské rozhraní", + "ui_old_layout": "Staré rozvržení", + "ui_new_layout": "Nové rozvržení" + }, + "units": { + "percentage": "%" + }, + "pagination": { + "total_notes": "{{count}} poznámek", + "prev_page": "Předchozí stránka", + "next_page": "Další stránka" + }, + "collections": { + "rendering_error": "Obsah nelze zobrazit kvůli chybě." + }, + "note-color": { + "clear-color": "Odstranit barvu poznámky", + "set-color": "Nastavit barvu poznámky", + "set-custom-color": "Nastavit vlastní barvu poznámky" + }, + "popup-editor": { + "maximize": "Přepnout na plný editor" + }, + "server": { + "unknown_http_error_title": "Chyba komunikace se serverem", + "unknown_http_error_content": "Stavový kód: {{statusCode}} \nURL: {{method}} {{url}} \nZpráva: {{message}}", + "traefik_blocks_requests": "Pokud používáte reverzní proxy Traefik, došlo k wprowadzeniu zásadní změny, která ovlivňuje komunikaci se serverem." + }, + "tab_history_navigation_buttons": { + "go-back": "Přejít na předchozí poznámku", + "go-forward": "Přejít na další poznámku" + }, + "breadcrumb": { + "hoisted_badge": "Vyvýšené", + "hoisted_badge_title": "Odstranit z horní části", + "workspace_badge": "Pracovní plocha", + "scroll_to_top_title": "Skočit na začátek poznámky", + "create_new_note": "Vytvořit novou dceřinnou poznámku", + "empty_hide_archived_notes": "Skrýt archivované poznámky" + }, + "breadcrumb_badges": { + "read_only_explicit": "Pouze pro čtení", + "read_only_explicit_description": "Tato poznámka byla ručně nastavena jako pouze pro čtení.\nKliknutím ji můžete dočasně upravit.", + "read_only_auto": "Automatické pouze pro čtení", + "read_only_auto_description": "Tato poznámka byla automaticky nastavena do režimu pouze pro čtení z důvodu výkonu. Toto automatické omezení lze upravit v nastavení.\n\nKliknutím ji můžete dočasně upravit.", + "read_only_temporarily_disabled": "Dočasně upravitelné", + "read_only_temporarily_disabled_description": "Tato poznámka je nyní upravitelná, ale normálně je pouze pro čtení. Jakmile přejdete na jinou poznámku, vrátí se do režimu pouze pro čtení.\n\nKliknutím znovu aktivujete režim pouze pro čtení.", + "shared_publicly": "Veřejně sdílené", + "shared_locally": "Lokálně sdílené", + "shared_copy_to_clipboard": "Kopírovat odkaz do schránky", + "shared_open_in_browser": "Otevřít odkaz v prohlížeči", + "shared_unshare": "Zrušit sdílení", + "clipped_note": "Webový výřez", + "clipped_note_description": "Tato poznámka byla původně převzata z {{url}}.\n\nKliknutím přejdete na zdrojovou webovou stránku.", + "execute_script": "Spustit skript", + "execute_script_description": "Tato poznámka obsahuje skript. Kliknutím jej spustíte.", + "execute_sql": "Spustit SQL", + "execute_sql_description": "Tato poznámka obsahuje SQL dotaz. Kliknutím jej spustíte.", + "save_status_saved": "Uloženo", + "save_status_saving": "Ukládání...", + "save_status_unsaved": "Neuloženo", + "save_status_error": "Uložení selhalo", + "save_status_saving_tooltip": "Změny se ukládají.", + "save_status_unsaved_tooltip": "Neexistují uložené změny. Za chvíli budou uloženy automaticky.", + "save_status_error_tooltip": "Při ukládání poznámky došlo k chybě. Pokud je to možné, zkuste obsah poznámky zkopírovat jinam a aplikaci znovu načíst." + }, + "status_bar": { + "language_title": "Změnit jazyk obsahu", + "note_info_title": "Zobrazit informace o poznámce (např. datum, velikost poznámky)", + "attributes_title": "Vlastní atributy a zděděné atributy", + "note_paths_title": "Cesty poznámky", + "code_note_switcher": "Změnit režim jazyka", + "backlinks_one": "{{count}} zpětný odkaz", + "backlinks_few": "{{count}} zpětné odkazy", + "backlinks_other": "{{count}} zpětných odkazů", + "backlinks_title_one": "Zobrazit zpětný odkaz", + "backlinks_title_few": "Zobrazit zpětné odkazy", + "backlinks_title_other": "Zobrazení zpětných odkazu", + "attachments_one": "{{count}} příloha", + "attachments_few": "{{count}} přílohy", + "attachments_other": "{{count}} příloh", + "attachments_title_one": "Zobrazit přílohu v nové záložce", + "attachments_title_few": "Zobrazit přílohy v nové záložce", + "attachments_title_other": "Zobrazit přílohy v nové záložce", + "attributes_one": "{{count}} atribut", + "attributes_few": "{{count}} atributy", + "attributes_other": "{{count}} atributů", + "note_paths_one": "{{count}} cesta", + "note_paths_few": "{{count}} cesty", + "note_paths_other": "{{count}} cest" + }, + "attributes_panel": { + "title": "Atributy poznámky" + }, + "right_pane": { + "empty_message": "Pro tuto poznámku není nic k zobrazení", + "empty_button": "Skrýt panel", + "toggle": "Přepnout pravý panel", + "custom_widget_go_to_source": "Přejít do zdrojového kódu" + }, + "pdf": { + "pages_alt": "Strana {{pageNumber}}", + "pages_loading": "Načítání...", + "attachments_one": "{{count}} příloha", + "attachments_few": "{{count}} přílohy", + "attachments_other": "{{count}} příloh", + "layers_one": "{{count}} vrstva", + "layers_few": "{{count}} vrstvy", + "layers_other": "{{count}} vrstev", + "pages_one": "{{count}} stránka", + "pages_few": "{{count}} stránky", + "pages_other": "{{count}} stran" + }, + "platform_indicator": { + "available_on": "Dostupné na {{platform}}" + }, + "mobile_tab_switcher": { + "more_options": "Další nastavení", + "title_one": "{{count}} záložka", + "title_few": "{{count}} záložky", + "title_other": "{{count}} záložek" + }, + "bookmark_buttons": { + "bookmarks": "Záložky (oblíbené)" + }, + "active_content_badges": { + "type_icon_pack": "Sada ikon", + "type_backend_script": "Backend skript", + "type_frontend_script": "Frontend skript", + "type_widget": "Widget", + "type_app_css": "Vlastní CSS", + "type_render_note": "Poznámka pro vykreslení", + "type_web_view": "Webové zobrazení", + "type_app_theme": "Vlastní téma", + "toggle_tooltip_enable_tooltip": "Kliknutím tuto {{type}} zapnete.", + "toggle_tooltip_disable_tooltip": "Kliknutím tuto {{type}} vypnete.", + "menu_docs": "Otevřít dokumentaci", + "menu_execute_now": "Spustit skript nyní", + "menu_run": "Spustit automaticky", + "menu_run_disabled": "Ručně", + "menu_run_backend_startup": "Při spuštění backendu", + "menu_run_hourly": "Hodinově", + "menu_run_daily": "Denně", + "menu_run_frontend_startup": "Při spuštění desktop frontend", + "menu_run_mobile_startup": "Při spuštění mobilního rozhraní", + "menu_change_to_widget": "Změnit na widget", + "menu_change_to_frontend_script": "Změnit na frontend skript", + "menu_theme_base": "Základ motivu" + }, + "setup_form": { + "more_info": "Dozvědět se více" + }, + "mermaid": { + "placeholder": "Napište obsah svého Mermaid diagramu nebo použijte jeden z ukázkových diagramů níže.", + "sample_diagrams": "Ukázkové diagramy:", + "sample_flowchart": "Tokový diagram", + "sample_class": "Třída", + "sample_sequence": "Sekvence", + "sample_entity_relationship": "Relace entit", + "sample_state": "Stav", + "sample_mindmap": "Myšlenková mapa", + "sample_architecture": "Architektura", + "sample_block": "Blok", + "sample_c4": "C4", + "sample_gantt": "Gantt", + "sample_git": "Git", + "sample_kanban": "Kanban", + "sample_packet": "Paket", + "sample_pie": "Koláčový graf", + "sample_quadrant": "Čtvrrtinový graf", + "sample_radar": "Radarový graf", + "sample_requirement": "Požadavek", + "sample_sankey": "Sankey", + "sample_timeline": "Osa času", + "sample_treemap": "Stromový graf", + "sample_user_journey": "Cesta uživatele", + "sample_xy": "XY", + "sample_venn": "Vennův diagram", + "sample_ishikawa": "Ishikawa", + "sample_treeview": "Stromové zobrazení", + "sample_wardley": "Wardleyho mapa" + }, + "mind-map": { + "addChild": "Přidat dceřiný", + "addParent": "Přidat rodiče", + "addSibling": "Přidat sourozence", + "removeNode": "Odebrat uzel", + "focus": "Režim soustředění", + "cancelFocus": "Ukončit režim soustředění", + "moveUp": "Posunout nahoru", + "moveDown": "Posunout dolů", + "link": "Odkaz", + "linkBidirectional": "Obousměrný odkaz", + "clickTips": "Klikněte prosím na cílový uzel", + "summary": "Shrnutí" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "Konfigurovat integrace AI a Large Language Model.", + "feature_not_enabled": "Povolte experimentální funkci LLM v Nastavení → Pokročilé → Experimentální funkce pro použití integrací AI.", + "add_provider": "Přidat poskytovatele", + "add_provider_title": "Přidat poskytovatele AI", + "configured_providers": "Konfigurovaní poskytovatelé", + "no_providers_configured": "Ještě nejsou nakonfigurováni žádní poskytovatelé.", + "provider_name": "Název", + "provider_type": "Poskytovatel", + "actions": "Akce", + "delete_provider": "Odstranit", + "delete_provider_confirmation": "Opravdu chcete odstranit poskytovatele \"{{name}}\"?", + "api_key": "API klíč", + "api_key_placeholder": "Zadejte svůj API klíč", + "cancel": "Zrušit", + "mcp_title": "MCP (Model Context Protocol)", + "mcp_enabled": "MCP server", + "mcp_enabled_description": "Zpřístupněte endpoint Model Context Protocol (MCP), aby si AI asistenti pro kódování (např. Claude Code, GitHub Copilot) mohli číst a upravovat vaše poznámky. Endpoint je přístupný pouze z localhost.", + "mcp_endpoint_title": "URL endpointu", + "mcp_endpoint_description": "Přidejte tuto URL adresu do konfigurace MCP svého AI asistenta", + "tools": { + "search_notes": "Hledat poznámky", + "get_note": "Získat poznámku", + "get_note_content": "Získat obsah poznámky", + "update_note_content": "Aktualizovat obsah poznámky", + "append_to_note": "Připojit k poznámce", + "create_note": "Vytvořit poznámku", + "get_attributes": "Získat atributy", + "get_attribute": "Získat atribut", + "set_attribute": "Nastavit atribut", + "delete_attribute": "Odstranit atribut", + "get_child_notes": "Získat dceřiné poznámky", + "get_subtree": "Získat podstrom", + "load_skill": "Načíst dovednost", + "web_search": "Webové hledání", + "note_in_parent": " v ", + "get_attachment": "Získat přílohu", + "get_attachment_content": "Přečíst obsah přílohy" + } } } diff --git a/apps/client/src/translations/de/translation.json b/apps/client/src/translations/de/translation.json index 1275af9825..358c92cf38 100644 --- a/apps/client/src/translations/de/translation.json +++ b/apps/client/src/translations/de/translation.json @@ -1386,9 +1386,6 @@ "description": "Diese Optionen gelten nur für Desktop-Builds. Browser verwenden ihre eigene native Rechtschreibprüfung.", "enable": "Aktiviere die Rechtschreibprüfung", "language_code_label": "Sprachcode(s)", - "language_code_placeholder": "zum Beispiel \"en-US\", \"de-AT\"", - "multiple_languages_info": "Mehrere Sprachen können mit einem Komma getrennt werden z.B. \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Verfügbare Sprachcodes:", "restart-required": "Änderungen an den Rechtschreibprüfungsoptionen werden nach dem Neustart der Anwendung wirksam." }, "sync_2": { diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 9aeddac20a..6006d665e4 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -369,7 +369,7 @@ "calendar_root": "marks note which should be used as root for day notes. Only one should be marked as such.", "archived": "notes with this label won't be visible by default in search results (also in Jump To, Add Link dialogs etc).", "exclude_from_export": "notes (with their sub-tree) won't be included in any note export", - "run": "defines on which events script should run. Possible values are:\n
    \n
  • frontendStartup - when Trilium frontend starts up (or is refreshed), but not on mobile.
  • \n
  • mobileStartup - when Trilium frontend starts up (or is refreshed), on mobile.
  • \n
  • backendStartup - when Trilium backend starts up
  • \n
  • hourly - run once an hour. You can use additional label runAtHour to specify at which hour.
  • \n
  • daily - run once a day
  • \n
", + "run": "defines on which events script should run. Possible values are:\n
    \n
  • frontendStartup - when Trilium frontend starts up (or is refreshed), but not on mobile.
  • \n
  • mobileStartup - when Trilium frontend starts up (or is refreshed), on mobile.
  • \n
  • backendStartup - when Trilium backend starts up.
  • \n
  • hourly - run once an hour. You can use additional label runAtHour to specify at which hour.
  • \n
  • daily - run once a day.
  • \n
", "run_on_instance": "Define which trilium instance should run this on. Default to all instances.", "run_at_hour": "On which hour should this run. Should be used together with #run=hourly. Can be defined multiple times for more runs during the day.", "disable_inclusion": "scripts with this label won't be included into parent script execution.", @@ -691,6 +691,7 @@ "search_in_note": "Search in note", "note_source": "Note source", "note_attachments": "Note attachments", + "view_ocr_text": "View OCR text", "open_note_externally": "Open note externally", "open_note_externally_title": "File will be open in an external application and watched for changes. You'll then be able to upload the modified version back to Trilium.", "open_note_custom": "Open note custom", @@ -1073,6 +1074,7 @@ "edit_title": "Edit title", "rename_note": "Rename note", "enter_new_title": "Enter new note title:", + "rename_relation": "Rename relation", "remove_relation": "Remove relation", "confirm_remove_relation": "Are you sure you want to remove the relation?", "specify_new_relation_name": "Specify new relation name (allowed characters: alphanumeric, colon and underscore):", @@ -1157,7 +1159,9 @@ "title": "Experimental Options", "disclaimer": "These options are experimental and may cause instability. Use with caution.", "new_layout_name": "New Layout", - "new_layout_description": "Try out the new layout for a more modern look and improved usability. Subject to heavy change in the upcoming releases." + "new_layout_description": "Try out the new layout for a more modern look and improved usability. Subject to heavy change in the upcoming releases.", + "llm_name": "AI / LLM Chat", + "llm_description": "Enable the AI chat sidebar and LLM chat notes powered by large language models." }, "fonts": { "theme_defined": "Theme defined", @@ -1252,12 +1256,28 @@ }, "images": { "images_section_title": "Images", - "download_images_automatically": "Download images automatically for offline use.", - "download_images_description": "Pasted HTML can contain references to online images, Trilium will find those references and download the images so that they are available offline.", - "enable_image_compression": "Enable image compression", - "max_image_dimensions": "Max width / height of an image (image will be resized if it exceeds this setting).", + "download_images_automatically": "Download images automatically", + "download_images_description": "Download referenced online images from pasted HTML so they are available offline.", + "enable_image_compression": "Image compression", + "enable_image_compression_description": "Compress and resize images when they are uploaded or pasted.", + "max_image_dimensions": "Max image dimensions", + "max_image_dimensions_description": "Images exceeding this size will be resized automatically.", "max_image_dimensions_unit": "pixels", - "jpeg_quality_description": "JPEG quality (10 - worst quality, 100 - best quality, 50 - 85 is recommended)" + "jpeg_quality": "JPEG quality", + "jpeg_quality_description": "Recommended range is 50–85. Lower values reduce file size, higher values preserve detail.", + "ocr_section_title": "Text Extraction (OCR)", + "ocr_related_content_languages": "Content languages (used for text extraction)", + "ocr_auto_process": "Auto-process new files", + "ocr_auto_process_description": "Automatically extract text from newly uploaded or pasted files.", + "ocr_min_confidence": "Minimum confidence", + "ocr_confidence_description": "Only extract text above this confidence threshold. Lower values include more text but may be less accurate.", + "batch_ocr_title": "Process Existing Files", + "batch_ocr_description": "Extract text from all existing images, PDFs, and Office documents in your notes. This may take some time depending on the number of files.", + "batch_ocr_start": "Start Batch Processing", + "batch_ocr_starting": "Starting batch processing...", + "batch_ocr_progress": "Processing {{processed}} of {{total}} files...", + "batch_ocr_completed": "Batch processing completed! Processed {{processed}} files.", + "batch_ocr_error": "Error during batch processing: {{error}}" }, "attachment_erasure_timeout": { "attachment_erasure_timeout": "Attachment Erasure Timeout", @@ -1303,7 +1323,7 @@ "custom_name_label": "Custom search engine name", "custom_name_placeholder": "Customize search engine name", "custom_url_label": "Custom search engine URL should include {keyword} as a placeholder for the search term.", - "custom_url_placeholder": "Customize search engine url", + "custom_url_placeholder": "Customize search engine URL", "save_button": "Save" }, "tray": { @@ -1480,12 +1500,15 @@ "spellcheck": { "title": "Spell Check", "description": "These options apply only for desktop builds, browsers will use their own native spell check.", - "enable": "Enable spellcheck", - "language_code_label": "Language code(s)", - "language_code_placeholder": "for example \"en-US\", \"de-AT\"", - "multiple_languages_info": "Multiple languages can be separated by comma, e.g. \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Available language codes:", - "restart-required": "Changes to the spell check options will take effect after application restart." + "enable": "Check spelling", + "language_code_label": "Spell Check Languages", + "restart-required": "Changes to the spell check options will take effect after application restart.", + "custom_dictionary_title": "Custom Dictionary", + "custom_dictionary_description": "Words added to the dictionary are synced across all your devices.", + "custom_dictionary_edit": "Custom words", + "custom_dictionary_edit_description": "Edit the list of words that should not be flagged by the spell checker. Changes will be visible after a restart.", + "custom_dictionary_open": "Edit dictionary", + "related_description": "Configure spell check languages and custom dictionary." }, "sync_2": { "config_title": "Sync Configuration", @@ -1600,6 +1623,7 @@ "geo-map": "Geo Map", "beta-feature": "Beta", "ai-chat": "AI Chat", + "llm-chat": "AI Chat", "task-list": "Task List", "new-feature": "New", "collections": "Collections", @@ -1611,6 +1635,48 @@ "toggle-on-hint": "Note is not protected, click to make it protected", "toggle-off-hint": "Note is protected, click to make it unprotected" }, + "llm_chat": { + "placeholder": "Type a message...", + "send": "Send", + "sending": "Sending...", + "empty_state": "Start a conversation by typing a message below.", + "searching_web": "Searching the web...", + "web_search": "Web search", + "note_tools": "Note access", + "sources": "Sources", + "sources_summary": "{{count}} sources from {{sites}} sites", + "extended_thinking": "Extended thinking", + "legacy_models": "Legacy models", + "thinking": "Thinking...", + "thought_process": "Thought process", + "tool_calls": "{{count}} tool call(s)", + "input": "Input", + "result": "Result", + "error": "Error", + "tool_error": "failed", + "total_tokens": "{{total}} tokens", + "tokens_detail": "{{prompt}} prompt + {{completion}} completion", + "tokens_used": "{{prompt}} prompt + {{completion}} completion = {{total}} tokens", + "tokens_used_with_cost": "{{prompt}} prompt + {{completion}} completion = {{total}} tokens (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} prompt + {{completion}} completion = {{total}} tokens", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} prompt + {{completion}} completion = {{total}} tokens (~${{cost}})", + "tokens": "tokens", + "context_used": "{{percentage}}% used", + "note_context_enabled": "Click to disable note context: {{title}}", + "note_context_disabled": "Click to include current note in context", + "no_provider_message": "No AI provider configured. Add one to start chatting.", + "add_provider": "Add AI Provider" + }, + "sidebar_chat": { + "title": "AI Chat", + "launcher_title": "Open AI Chat", + "new_chat": "Start new chat", + "save_chat": "Save chat to notes", + "empty_state": "Start a conversation", + "history": "Chat history", + "recent_chats": "Recent chats", + "no_chats": "No previous chats" + }, "shared_switch": { "shared": "Shared", "toggle-on-title": "Share the note", @@ -1922,7 +1988,7 @@ }, "content_language": { "title": "Content languages", - "description": "Select one or more languages that should appear in the language selection in the Basic Properties section of a read-only or editable text note. This will allow features such as spell-checking or right-to-left support." + "description": "Select one or more languages that should appear in the language selection in the Basic Properties section of a read-only or editable text note. This will allow features such as spell-checking, right-to-left support and text extraction (OCR)." }, "switch_layout_button": { "title_vertical": "Move editing pane to the bottom", @@ -2022,6 +2088,22 @@ "calendar_view": { "delete_note": "Delete note..." }, + "ocr": { + "extracted_text": "Extracted Text (OCR)", + "extracted_text_title": "Extracted Text (OCR)", + "loading_text": "Loading OCR text...", + "no_text_available": "No OCR text available", + "no_text_explanation": "This note has not been processed for OCR text extraction or no text was found.", + "failed_to_load": "Failed to load OCR text", + "process_now": "Process OCR", + "processing": "Processing...", + "processing_started": "OCR processing has been started. Please wait a moment and refresh.", + "processing_complete": "OCR processing complete.", + "processing_failed": "Failed to start OCR processing", + "text_filtered_low_confidence": "OCR detected text with {{confidence}}% confidence, but it was discarded because your minimum threshold is {{threshold}}%.", + "open_media_settings": "Open Settings", + "view_extracted_text": "View extracted text (OCR)" + }, "command_palette": { "tree-action-name": "Tree: {{name}}", "export_note_title": "Export Note", @@ -2230,6 +2312,63 @@ "sample_user_journey": "User Journey", "sample_xy": "XY", "sample_venn": "Venn", - "sample_ishikawa": "Ishikawa" + "sample_ishikawa": "Ishikawa", + "sample_treeview": "TreeView", + "sample_wardley": "Wardley Map" + }, + "mind-map": { + "addChild": "Add child", + "addParent": "Add parent", + "addSibling": "Add sibling", + "removeNode": "Remove node", + "focus": "Focus Mode", + "cancelFocus": "Cancel Focus Mode", + "moveUp": "Move up", + "moveDown": "Move down", + "link": "Link", + "linkBidirectional": "Bidirectional Link", + "clickTips": "Please click the target node", + "summary": "Summary" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "Configure AI and Large Language Model integrations.", + "feature_not_enabled": "Enable the LLM experimental feature in Settings → Advanced → Experimental features to use AI integrations.", + "add_provider": "Add Provider", + "add_provider_title": "Add AI Provider", + "configured_providers": "Configured Providers", + "no_providers_configured": "No providers configured yet.", + "provider_name": "Name", + "provider_type": "Provider", + "actions": "Actions", + "delete_provider": "Delete", + "delete_provider_confirmation": "Are you sure you want to delete the provider \"{{name}}\"?", + "api_key": "API Key", + "api_key_placeholder": "Enter your API key", + "cancel": "Cancel", + "mcp_title": "MCP (Model Context Protocol)", + "mcp_enabled": "MCP server", + "mcp_enabled_description": "Expose a Model Context Protocol (MCP) endpoint so that AI coding assistants (e.g. Claude Code, GitHub Copilot) can read and modify your notes. The endpoint is only accessible from localhost.", + "mcp_endpoint_title": "Endpoint URL", + "mcp_endpoint_description": "Add this URL to your AI assistant's MCP configuration", + "tools": { + "search_notes": "Search notes", + "get_note": "Get note", + "get_note_content": "Get note content", + "update_note_content": "Update note content", + "append_to_note": "Append to note", + "create_note": "Create note", + "get_attributes": "Get attributes", + "get_attribute": "Get attribute", + "set_attribute": "Set attribute", + "delete_attribute": "Delete attribute", + "get_child_notes": "Get child notes", + "get_subtree": "Get subtree", + "load_skill": "Load skill", + "web_search": "Web search", + "note_in_parent": " in ", + "get_attachment": "Get attachment", + "get_attachment_content": "Read attachment content" + } } } diff --git a/apps/client/src/translations/es/translation.json b/apps/client/src/translations/es/translation.json index 800d71d32c..22717f2625 100644 --- a/apps/client/src/translations/es/translation.json +++ b/apps/client/src/translations/es/translation.json @@ -1433,9 +1433,6 @@ "description": "Estas opciones se aplican sólo para compilaciones de escritorio; los navegadores utilizarán su corrector ortográfico nativo.", "enable": "Habilitar corrector ortográfico", "language_code_label": "Código(s) de idioma", - "language_code_placeholder": "por ejemplo \"en-US\", \"de-AT\"", - "multiple_languages_info": "Múltiples idiomas se pueden separar por coma, por ejemplo \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Códigos de idioma disponibles:", "restart-required": "Los cambios en las opciones de corrección ortográfica entrarán en vigor después del reinicio de la aplicación." }, "sync_2": { diff --git a/apps/client/src/translations/fr/translation.json b/apps/client/src/translations/fr/translation.json index be019eaa16..590c4e184d 100644 --- a/apps/client/src/translations/fr/translation.json +++ b/apps/client/src/translations/fr/translation.json @@ -28,7 +28,10 @@ }, "widget-render-error": { "title": "Rendu impossible d'un widget React custom" - } + }, + "widget-missing-parent": "Le widget personnalisé ne comprend pas de propriété '{{property}}' définie\n\nSi ce script est prévu pour être exécuté sans fonctionnalité UI, utilisez '#run=frontendStartup' plutôt.", + "open-script-note": "Ouvrir une note script", + "scripting-error": "Échec du script personnalisé : {{title}}" }, "add_link": { "add_link": "Ajouter un lien", @@ -46,7 +49,7 @@ "prefix": "Préfixe : ", "save": "Sauvegarder", "branch_prefix_saved": "Le préfixe de la branche a été enregistré.", - "edit_branch_prefix_multiple": "Modifier le préfixe de branche pour {{count}} branches", + "edit_branch_prefix_multiple": "Modifier le préfixe pour {{count}} branches", "branch_prefix_saved_multiple": "Le préfixe de la branche a été sauvegardé pour {{count}} branches.", "affected_branches": "Branches impactées ({{count}}):" }, @@ -114,7 +117,7 @@ "export_in_progress": "Exportation en cours : {{progressCount}}", "export_finished_successfully": "L'exportation s'est terminée avec succès.", "format_pdf": "PDF - pour l'impression ou le partage de documents.", - "share-format": "HTML pour la publication Web - utilise le même thème que celui utilisé pour les notes partagées, mais peut être publié sous forme de site Web statique." + "share-format": "HTML pour la publication Web : utilise le même thème que celui utilisé pour les notes partagées, mais peut être publié sous forme de site Web statique." }, "help": { "noteNavigation": "Navigation dans les notes", @@ -443,7 +446,8 @@ "and_more": "... et {{count}} plus.", "print_landscape": "Lors de l'exportation en PDF, change l'orientation de la page en paysage au lieu de portrait.", "print_page_size": "Lors de l'exportation en PDF, change la taille de la page. Valeurs supportées : A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.", - "color_type": "Couleur" + "color_type": "Couleur", + "textarea": "Texte multiligne" }, "attribute_editor": { "help_text_body1": "Pour ajouter un label, tapez simplement par ex. #rock, ou si vous souhaitez également ajouter une valeur, tapez par ex. #année = 2020", @@ -659,7 +663,8 @@ "show-cheatsheet": "Afficher l'aide rapide", "toggle-zen-mode": "Zen Mode", "new-version-available": "Nouvelle mise à jour disponible", - "download-update": "Obtenir la version {{latestVersion}}" + "download-update": "Obtenir la version {{latestVersion}}", + "search_notes": "Rechercher notes" }, "zen_mode": { "button_exit": "Sortir du Zen mode" @@ -703,7 +708,8 @@ "advanced": "Avancé", "export_as_image": "Exporter en tant qu'image", "export_as_image_png": "PNG", - "export_as_image_svg": "SVG (vectoriel)" + "export_as_image_svg": "SVG (vectoriel)", + "note_map": "Note Carte" }, "onclick_button": { "no_click_handler": "Le widget bouton '{{componentId}}' n'a pas de gestionnaire de clic défini" @@ -741,23 +747,25 @@ "button_title": "Exporter le diagramme au format SVG" }, "relation_map_buttons": { - "create_child_note_title": "Créer une nouvelle note enfant et l'ajouter à cette carte de relation", + "create_child_note_title": "Créer une note enfant et l'ajouter à la carte", "reset_pan_zoom_title": "Réinitialiser le panoramique et le zoom aux coordonnées et à la position initiales", "zoom_in_title": "Zoomer", "zoom_out_title": "Zoom arrière" }, "zpetne_odkazy": { "relation": "relation", - "backlink_one": "{{count}} Lien inverse", - "backlink_many": "", - "backlink_other": "{{count}} Liens inverses" + "backlink_one": "{{count}} Rétrolien", + "backlink_many": "{{count}} Rétroliens", + "backlink_other": "{{count}} Rétrolien" }, "mobile_detail_menu": { "insert_child_note": "Insérer une note enfant", "delete_this_note": "Supprimer cette note", "error_cannot_get_branch_id": "Impossible d'obtenir branchId pour notePath '{{notePath}}'", "error_unrecognized_command": "Commande non reconnue {{command}}", - "note_revisions": "Révision de la note" + "note_revisions": "Révision de la note", + "backlinks": "Rétro-liens", + "content_language_switcher": "Langue du contenu: {{language}}" }, "note_icon": { "change_note_icon": "Changer l'icône de note", @@ -766,7 +774,12 @@ "filter": "Filtre", "filter-none": "Toutes les icônes", "filter-default": "Icônes par défaut", - "icon_tooltip": "{{name}}\nPack d'icônes : {{iconPack}}" + "icon_tooltip": "{{name}}\nPack d'icônes : {{iconPack}}", + "no_results": "Aucune icône trouvée.", + "search_placeholder_one": "{{number}} icône recherchées parmi {{count}} packs.", + "search_placeholder_many": "{{number}} icônes recherchées parmi {{count}} packs.", + "search_placeholder_other": "{{number}} icônes recherchées parmi {{count}} packs.", + "search_placeholder_filtered": "Rechercher {{number}} icônes dans {{name}}" }, "basic_properties": { "note_type": "Type de note", @@ -782,7 +795,7 @@ "collapse_all_notes": "Réduire toutes les notes", "collapse": "Réduire", "expand": "Développer", - "invalid_view_type": "Type de vue non valide '{{type}}'", + "invalid_view_type": "Type de vue '{{type}}' non valide", "calendar": "Calendrier", "book_properties": "Propriétés de la collection", "table": "Tableau", @@ -793,7 +806,8 @@ "expand_tooltip": "Développe les éléments enfants directs de cette collection (à un niveau). Pour plus d'options, appuyez sur la flèche à droite.", "expand_first_level": "Développer les enfants directs", "expand_nth_level": "Développer sur {{depth}} niveaux", - "expand_all_levels": "Développer tous les niveaux" + "expand_all_levels": "Développer tous les niveaux", + "hide_child_notes": "Masquer les notes enfants dans l’arborescence" }, "edited_notes": { "no_edited_notes_found": "Aucune note modifiée ce jour-là...", @@ -806,7 +820,7 @@ "file_type": "Type de fichier", "file_size": "Taille du fichier", "download": "Télécharger", - "open": "Ouvrir", + "open": "Ouvrir dans une nouvelle fenêtre", "upload_new_revision": "Téléverser une nouvelle version", "upload_success": "Une nouvelle version de fichier a été téléversée.", "upload_failed": "Le téléversement d'une nouvelle version de fichier a échoué.", @@ -826,7 +840,8 @@ }, "inherited_attribute_list": { "title": "Attributs hérités", - "no_inherited_attributes": "Aucun attribut hérité." + "no_inherited_attributes": "Aucun attribut hérité.", + "none": "aucun" }, "note_info_widget": { "note_id": "Identifiant de la note", @@ -903,7 +918,8 @@ "unknown_search_option": "Option de recherche inconnue {{searchOptionName}}", "search_note_saved": "La note de recherche a été enregistrée dans {{- notePathTitle}}", "actions_executed": "Les actions ont été exécutées.", - "view_options": "Afficher les options:" + "view_options": "Afficher les options:", + "option": "option" }, "similar_notes": { "title": "Notes similaires", @@ -997,7 +1013,7 @@ "no_attachments": "Cette note ne contient aucune pièce jointe." }, "book": { - "no_children_help": "Cette note de type Livre n'a aucune note enfant, donc il n'y a rien à afficher. Consultez le wiki pour plus de détails.", + "no_children_help": "Cette collection ne contient pas de notes enfants, il n'y a donc rien à afficher.", "drag_locked_title": "Edition verrouillée", "drag_locked_message": "Le glisser-déposer n'est pas autorisé car l'édition de cette collection est verrouillé." }, @@ -1171,8 +1187,8 @@ }, "code_mime_types": { "title": "Types MIME disponibles dans la liste déroulante", - "tooltip_syntax_highlighting": "Souligner la syntaxe", - "tooltip_code_block_syntax": "Blocs de code dans les notes de texte", + "tooltip_syntax_highlighting": "Mise en évidence de la syntaxe", + "tooltip_code_block_syntax": "Blocs de code dans les notes textuelles", "tooltip_code_note_syntax": "Notes de code" }, "vim_key_bindings": { @@ -1367,16 +1383,14 @@ "description": "Description", "reload_app": "Recharger l'application pour appliquer les modifications", "set_all_to_default": "Réinitialiser aux valeurs par défaut", - "confirm_reset": "Voulez-vous vraiment réinitialiser tous les raccourcis clavier par défaut ?" + "confirm_reset": "Voulez-vous vraiment réinitialiser tous les raccourcis clavier par défaut ?", + "no_results": "Aucun raccourci correspondant à '{{filter}}'" }, "spellcheck": { "title": "Vérification orthographique", "description": "Ces options s'appliquent uniquement aux versions de bureau, les navigateurs utiliseront leur propre vérification orthographique native.", "enable": "Activer la vérification orthographique", "language_code_label": "Code(s) de langue", - "language_code_placeholder": "par exemple \"fr-FR\", \"en-US\", \"de-AT\"", - "multiple_languages_info": "Plusieurs langues peuvent être séparées par une virgule, par ex. \"fr-FR, en-US, de-DE, cs\". ", - "available_language_codes_label": "Codes de langue disponibles :", "restart-required": "Les modifications apportées aux options de vérification orthographique prendront effet après le redémarrage de l'application." }, "sync_2": { @@ -1402,7 +1416,7 @@ "will_be_deleted_in": "Cette pièce jointe sera automatiquement supprimée dans {{time}}", "will_be_deleted_soon": "Cette pièce jointe sera bientôt supprimée automatiquement", "deletion_reason": ", car la pièce jointe n'est pas liée dans le contenu de la note. Pour empêcher la suppression, ajoutez à nouveau le lien de la pièce jointe dans le contenu d'une note ou convertissez la pièce jointe en note.", - "role_and_size": "Rôle : {{role}}, Taille : {{size}}", + "role_and_size": "Rôle : {{role}}, Taille : {{size}}, MIME: {{- mimeType}}", "link_copied": "Lien de pièce jointe copié dans le presse-papiers.", "unrecognized_role": "Rôle de pièce jointe « {{role}} » non reconnu." }, @@ -1453,10 +1467,13 @@ "import-into-note": "Importer dans la note", "apply-bulk-actions": "Appliquer des Actions groupées", "converted-to-attachments": "Les notes {{count}} ont été converties en pièces jointes.", - "convert-to-attachment-confirm": "Êtes-vous sûr de vouloir convertir les notes sélectionnées en pièces jointes de leurs notes parentes ?", + "convert-to-attachment-confirm": "Êtes-vous sûr de vouloir convertir les notes sélectionnées en pièces jointes de leurs notes parentales ? Cette opération s'applique uniquement aux notes d'image, les autres notes seront ignorées.", "archive": "Archive", "unarchive": "Désarchiver", - "open-in-popup": "Modification rapide" + "open-in-popup": "Modification rapide", + "open-in-a-new-window": "Ouvrir dans une nouvelle fenêtre", + "hide-subtree": "Masquer le sous-arbre", + "show-subtree": "Afficher le sous-arbre" }, "shared_info": { "shared_publicly": "Cette note est partagée publiquement sur {{- link}}.", @@ -1485,7 +1502,10 @@ "task-list": "Liste de tâches", "book": "Collection", "new-feature": "Nouveau", - "collections": "Collections" + "collections": "Collections", + "ai-chat": "Chat IA", + "llm-chat": "Chat AI", + "spreadsheet": "Feuille de calcul" }, "protect_note": { "toggle-on": "Protéger la note", @@ -1516,7 +1536,13 @@ }, "highlights_list_2": { "title": "Accentuations", - "options": "Options" + "options": "Options", + "title_with_count_one": "{{count}} mise en évidence", + "title_with_count_many": "{{count}} mises en évidence", + "title_with_count_other": "{{count}} mises en évidence", + "modal_title": "Configurer les mises en évidence", + "menu_configure": "Configuration des mises en évidence...", + "no_highlights": "Aucune mise en évidence." }, "quick-search": { "placeholder": "Recherche rapide", @@ -1540,7 +1566,17 @@ "create-child-note": "Créer une note enfant", "unhoist": "Désactiver le focus", "toggle-sidebar": "Basculer la barre latérale", - "dropping-not-allowed": "Lâcher des notes à cet endroit n'est pas autorisé" + "dropping-not-allowed": "Déplacer des notes à cet emplacement n'est pas autorisé.", + "clone-indicator-tooltip": "Cette note a {{- count}} parents: {{- parents}}", + "clone-indicator-tooltip-single": "Cette note est clonée (1 parent supplémentaire: {{- parent}})", + "shared-indicator-tooltip": "Cette note est partagée publiquement", + "shared-indicator-tooltip-with-url": "Cette note est partagée publiquement sur: {{- url}}", + "subtree-hidden-tooltip_one": "{{count}} note enfant cachée de l'arbre", + "subtree-hidden-tooltip_many": "{{count}} notes enfants cachées de l'arbre", + "subtree-hidden-tooltip_other": "{{count}} notes enfants cachées de l'arbre", + "subtree-hidden-moved-title": "Ajouté à {{title}}", + "subtree-hidden-moved-description-collection": "Cette collection cache ses notes enfants dans l'arbre.", + "subtree-hidden-moved-description-other": "Les notes enfants sont cachées dans l'arbre pour cette note." }, "title_bar_buttons": { "window-on-top": "Épingler cette fenêtre au premier plan" @@ -1551,7 +1587,12 @@ "printing_pdf": "Export au format PDF en cours...", "print_report_title": "Imprimer le rapport", "print_report_collection_details_button": "Consulter les détails", - "print_report_collection_details_ignored_notes": "Notes ignorées" + "print_report_collection_details_ignored_notes": "Notes ignorées", + "print_report_error_title": "Échec de l'impression", + "print_report_stack_trace": "Trace de la pile", + "print_report_collection_content_one": "La {{count}} note de la collection n'a pas pu être imprimée car elle n'est pas prises en charge ou est protégée.", + "print_report_collection_content_many": "Les {{count}} notes de la collection n'ont pas pu être imprimées car elles ne sont pas prises en charge ou sont protégées.", + "print_report_collection_content_other": "Les {{count}} notes de la collection n'ont pas pu être imprimées car elles ne sont pas prises en charge ou sont protégées." }, "note_title": { "placeholder": "saisir le titre de la note ici...", @@ -1560,17 +1601,24 @@ "note_type_switcher_label": "Basculer de {{type}} à :", "note_type_switcher_others": "Autre type de note", "note_type_switcher_templates": "Modèle", - "note_type_switcher_collection": "Collection" + "note_type_switcher_collection": "Collection", + "edited_notes": "Notes éditées ce jour", + "promoted_attributes": "Attributs promus" }, "search_result": { "no_notes_found": "Aucune note n'a été trouvée pour les paramètres de recherche donnés.", - "search_not_executed": "La recherche n'a pas encore été exécutée. Cliquez sur le bouton \"Rechercher\" ci-dessus pour voir les résultats." + "search_not_executed": "La recherche n'a pas encore été exécutée.", + "search_now": "Recherche maintenant" }, "spacer": { "configure_launchbar": "Configurer la Barre de raccourcis" }, "sql_result": { - "no_rows": "Aucune ligne n'a été renvoyée pour cette requête" + "no_rows": "Aucune ligne n'a été renvoyée pour cette requête", + "not_executed": "La requête n'a pas encore été exécutée.", + "failed": "L'exécution de requêtes SQL a échoué", + "statement_result": "Résultat de la déclaration", + "execute_now": "Exécuter maintenant" }, "sql_table_schemas": { "tables": "Tableaux" @@ -1693,7 +1741,7 @@ "paste": "Coller", "paste-as-plain-text": "Coller comme texte brut", "search_online": "Rechercher «{{term}}» avec {{searchEngine}}", - "search_in_trilium": "Rechercher \"{{term}}\" dans Trilium" + "search_in_trilium": "Rechercher « {{term}} » dans Trilium" }, "image_context_menu": { "copy_reference_to_clipboard": "Copier la référence dans le presse-papiers", @@ -1703,14 +1751,15 @@ "open_note_in_new_tab": "Ouvrir la note dans un nouvel onglet", "open_note_in_new_split": "Ouvrir la note dans une nouvelle division", "open_note_in_new_window": "Ouvrir la note dans une nouvelle fenêtre", - "open_note_in_popup": "Édition rapide" + "open_note_in_popup": "Édition rapide", + "open_note_in_other_split": "Ouvrir la note dans l'autre volet" }, "electron_integration": { "desktop-application": "Application de bureau", "native-title-bar": "Barre de titre native", "native-title-bar-description": "Sous Windows et macOS, désactiver la barre de titre native rend l'application plus compacte. Sous Linux, le maintien de la barre de titre native permet une meilleure intégration avec le reste du système.", - "background-effects": "Activer les effets d'arrière-plan (Windows 11 uniquement)", - "background-effects-description": "L'effet Mica ajoute un fond flou et élégant aux fenêtres de l'application, créant une profondeur et un style moderne.", + "background-effects": "Activer les effets d'arrière-plan", + "background-effects-description": "Ajoute un arrière-plan flou et élégant aux fenêtres d'application, créant de la profondeur et un style moderne. La « barre de titre native » doit être désactivée.", "restart-app-button": "Redémarrez l'application pour afficher les modifications", "zoom-factor": "Facteur de zoom" }, @@ -1729,7 +1778,8 @@ "geo-map": { "create-child-note-title": "Créer une nouvelle note enfant et l'ajouter à la carte", "create-child-note-instruction": "Cliquez sur la carte pour créer une nouvelle note à cet endroit ou appuyez sur Échap pour la supprimer.", - "unable-to-load-map": "Impossible de charger la carte." + "unable-to-load-map": "Impossible de charger la carte.", + "create-child-note-text": "Ajouter le marqueur" }, "geo-map-context": { "open-location": "Ouvrir la position", @@ -1834,12 +1884,13 @@ "book_properties_config": { "hide-weekends": "Masquer les week-ends", "display-week-numbers": "Afficher les numéros de semaine", - "map-style": "Style de carte :", + "map-style": "Style de carte", "max-nesting-depth": "Profondeur d'imbrication maximale :", "raster": "Trame", "vector_light": "Vecteur (clair)", "vector_dark": "Vecteur (foncé)", - "show-scale": "Afficher l'échelle" + "show-scale": "Afficher l'échelle", + "show-labels": "Afficher les noms des marqueurs" }, "table_context_menu": { "delete_row": "Supprimer la ligne" @@ -1860,7 +1911,7 @@ "add-column-placeholder": "Entrez le nom de la colonne...", "edit-note-title": "Cliquez pour modifier le titre de la note", "edit-column-title": "Cliquez pour modifier le titre de la colonne", - "column-already-exists": "Cette colonne existe déjà dans le tableau." + "column-already-exists": "Cette colonne existe déjà sur le tableau." }, "presentation_view": { "edit-slide": "Modifier cette diapositive", @@ -1890,22 +1941,30 @@ "next_theme_message": "Vous utilisez actuellement le thème hérité de l'ancienne version, souhaitez-vous essayer le nouveau thème ?", "next_theme_button": "Essayez le nouveau thème", "background_effects_title": "Les effets d'arrière-plan sont désormais stables", - "background_effects_message": "Sur les appareils Windows, les effets d'arrière-plan sont désormais parfaitement stables. Ils ajoutent une touche de couleur à l'interface utilisateur en floutant l'arrière-plan. Cette technique est également utilisée dans d'autres applications comme l'Explorateur Windows.", + "background_effects_message": "Sur les appareils Windows et macOS les effets d'arrière-plan sont désormais stables. Ils ajoutent une touche de couleur à l'interface utilisateur en floutant l'arrière-plan.", "background_effects_button": "Activer les effets d'arrière-plan", - "dismiss": "Rejeter" + "dismiss": "Rejeter", + "new_layout_title": "Nouvelle mise en page", + "new_layout_message": "Nous avons introduit une mise en page modernisée pour Trilium. Le ruban a été supprimé et intégré de manière transparente dans l'interface principale, avec une nouvelle barre d'état et des sections extensibles (telles que les attributs promus) reprenant les fonctions clés.\n\nLa nouvelle mise en page est activée par défaut et peut être temporairement désactivée via Options → Apparence.", + "new_layout_button": "Plus d'infos" }, "settings": { "related_settings": "Paramètres associés" }, "settings_appearance": { "related_code_blocks": "Schéma de coloration syntaxique pour les blocs de code dans les notes de texte", - "related_code_notes": "Schéma de couleurs pour les notes de code" + "related_code_notes": "Schéma de couleurs pour les notes de code", + "ui": "Interface utilisateur", + "ui_old_layout": "Ancienne mise en page", + "ui_new_layout": "Nouvelle mise en page" }, "units": { "percentage": "%" }, "pagination": { - "total_notes": "{{count}} notes" + "total_notes": "{{count}} notes", + "prev_page": "Page précédente", + "next_page": "Page suivante" }, "collections": { "rendering_error": "Impossible d'afficher le contenu en raison d'une erreur." @@ -1924,8 +1983,9 @@ "unknown_widget": "Widget inconnu pour « {{id}} »." }, "note_language": { - "not_set": "Non défini", - "configure-languages": "Configurer les langues..." + "not_set": "Langage non défini", + "configure-languages": "Configurer les langues...", + "help-on-languages": "Aide sur les langues de contenu..." }, "content_language": { "title": "Contenu des langues", @@ -1973,14 +2033,288 @@ "title": "Options expérimentales", "disclaimer": "Ces options sont expérimentales et peuvent provoquer une instabilité. Utilisez avec prudence.", "new_layout_name": "Nouvelle mise en page", - "new_layout_description": "Essayez la nouvelle mise en page pour un look plus moderne et un usage améliorée. Sous réserve de changements importants dans les prochaines versions." + "new_layout_description": "Essayez la nouvelle mise en page pour un look plus moderne et un usage améliorée. Sous réserve de changements importants dans les prochaines versions.", + "llm_name": "AI / LLM Chat", + "llm_description": "Activer la barre de chat AI et les notes de chat LLM alimentées par de grands modèles de langage." }, "read-only-info": { "read-only-note": "Vous consultez actuellement une note en lecture seule.", "auto-read-only-note": "Cette note s'affiche en mode lecture seule pour un chargement plus rapide.", - "edit-note": "Editer la note" + "edit-note": "Modifier la note" }, "calendar_view": { - "delete_note": "Effacer la note..." + "delete_note": "Supprimer la note..." + }, + "media": { + "play": "Lire (Espace)", + "pause": "Pause (Espace)", + "back-10s": "Retour arrière 10s (flèche gauche)", + "forward-30s": "Avance 30s", + "mute": "Silence (M)", + "unmute": "Réactiver le son (M)", + "playback-speed": "Vitesse de lecture", + "loop": "Boucle", + "disable-loop": "Désactiver la boucle", + "rotate": "Rotation", + "picture-in-picture": "Image dans l'image", + "exit-picture-in-picture": "Sortir de Image dans l'image", + "fullscreen": "Plein-écran (F)", + "exit-fullscreen": "Sortir du mode plein-écran", + "unsupported-format": "L'aperçu multimédia n'est pas disponible pour ce format de fichier:\n{{mime}}", + "zoom-to-fit": "Zoom pour remplir", + "zoom-reset": "Annuler zoom pour remplir" + }, + "render": { + "setup_title": "Afficher du HTML personnalisé ou Preact JSX dans cette note", + "setup_create_sample_preact": "Créer un exemple de note avec Preact", + "setup_create_sample_html": "Créer un exemple de note avec HTML", + "setup_sample_created": "Un exemple de note a été créé en tant que note enfant.", + "disabled_description": "Ces notes de rendu proviennent d'une source externe. Pour vous protéger de contenu malveillant, elle n'est pas activée par défaut. Assurez-vous de faire confiance à la source avant de l’activer.", + "disabled_button_enable": "Activer la note de rendu" + }, + "web_view_setup": { + "title": "Créez la vue de la page Web directement dans Trilium", + "url_placeholder": "Entrez ou collez l'adresse du site Web, par exemple https://triliumnotes.org", + "create_button": "Créer une vue Web", + "invalid_url_title": "Adresse invalide", + "invalid_url_message": "Insérer une adresse Web valide, par exemple https://triliumnotes.org.", + "disabled_description": "Cette vue Web a été importée à partir d'une source externe. Pour vous protéger du phishing ou du contenu malveillant, elle ne se charge pas automatiquement. Vous pouvez l'activer si vous faites confiance à la source.", + "disabled_button_enable": "Activer la vue Web" + }, + "llm_chat": { + "placeholder": "Tapez un message...", + "send": "Envoyer", + "sending": "Envoi...", + "empty_state": "Démarrez une conversation en tapant un message ci-dessous.", + "searching_web": "Recherche sur le Web...", + "web_search": "Recherche sur le Web", + "note_tools": "Accès aux notes", + "sources": "Sources", + "extended_thinking": "Réflexion étendue", + "legacy_models": "Modèles hérités", + "thinking": "Réflexion...", + "thought_process": "Processus de réflexion", + "tool_calls": "{{count}} appel(s) d'outil", + "input": "Entrée", + "result": "Résultat", + "error": "Erreur", + "tool_error": "échoué", + "total_tokens": "{{total}} jetons", + "tokens_detail": "{{prompt}} prompt + {{completion}} achèvement", + "tokens_used": "{{prompt}} prompt + {{completion}} achèvement = {{total}} jetons", + "tokens_used_with_cost": "{{prompt}} prompt + {{completion}} achèvement = {{total}} jetons (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} prompt + {{completion}} achèvement = {{total}} jetons", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} prompt + {{completion}} achèvement = {{total}} jetons (~${{cost}})", + "tokens": "jetons", + "context_used": "{{percentage}}% utilisé", + "note_context_enabled": "Cliquez pour désactiver le contexte de la note : {{title}}", + "note_context_disabled": "Cliquez pour inclure la note actuelle dans le contexte", + "no_provider_message": "Aucun fournisseur d'IA configuré. Ajoutez en un pour commencer à discuter.", + "add_provider": "Ajouter un fournisseur d'IA" + }, + "sidebar_chat": { + "title": "discussion IA", + "launcher_title": "Ouvrir la discussion IA", + "new_chat": "Démarrer une nouvelle discussion", + "save_chat": "Enregistrer la discussion dans les notes", + "empty_state": "Démarrer une conversation", + "history": "Historique des discussions", + "recent_chats": "Discussions récentes", + "no_chats": "Pas de discussions précédentes" + }, + "note-color": { + "clear-color": "Retirer la couleur de la note", + "set-color": "Définir la couleur de la note", + "set-custom-color": "Définir la couleur personnalisée de la note" + }, + "popup-editor": { + "maximize": "Basculer sur l'éditeur complet" + }, + "server": { + "unknown_http_error_title": "Erreur de communication avec le serveur", + "unknown_http_error_content": "Code de statut: {{statusCode}}\nURL: {{method}} {{url}}\nMessage: {{message}}", + "traefik_blocks_requests": "Si vous utilisez le reverse proxy Traefik, celui-ci a introduit un changement de rupture qui affecte la communication avec le serveur." + }, + "tab_history_navigation_buttons": { + "go-back": "Revenir à la note précédente", + "go-forward": "Aller vers la note suivante" + }, + "breadcrumb": { + "hoisted_badge": "Remonté", + "hoisted_badge_title": "Redescendu", + "workspace_badge": "Espace de travail", + "scroll_to_top_title": "Aller au début de la note", + "create_new_note": "Créer une nouvelle note enfant", + "empty_hide_archived_notes": "Cacher les notes archivées" + }, + "breadcrumb_badges": { + "read_only_explicit": "Lecture seule", + "read_only_explicit_description": "Cette note a été paramétrée manuellement en lecture seule.\nCliquer pour temporairement l'éditer.", + "read_only_auto": "Lecture seule automatique", + "read_only_auto_description": "Cette note a été réglée automatiquement en mode lecture seule pour des raisons de performances. Cette limite automatique est réglable à partir des paramètres.\n\nCliquez pour la modifier temporairement.", + "read_only_temporarily_disabled": "Temporairement modifiable", + "read_only_temporarily_disabled_description": "Cette note est actuellement modifiable, mais elle est normalement en lecture seule. La note redeviendra en lecture seule dès que vous accéderez à une autre note.\n\nCliquez pour réactiver le mode lecture seule.", + "shared_publicly": "Partagés publiquement", + "shared_locally": "Partagé localement", + "shared_copy_to_clipboard": "Copier le lien vers le presse-papier", + "shared_open_in_browser": "Ouvrir le lien dans le navigateur", + "shared_unshare": "Supprimer le partage", + "clipped_note": "Clip Web", + "clipped_note_description": "Cette note a été initialement construite depuis l'url {{url}}.\n\nCliquez pour accéder à la page Web source.", + "execute_script": "Exécuter le script", + "execute_script_description": "Cette note est une note de script. Cliquez pour exécuter le script.", + "execute_sql": "Exécuter la commande SQL", + "execute_sql_description": "Cette note est une note SQL. Cliquer pour exécuter la requête SQL.", + "save_status_saved": "Enregister", + "save_status_saving": "Enregistrement...", + "save_status_unsaved": "Non sauvée", + "save_status_error": "La sauvegarde a échoué", + "save_status_saving_tooltip": "Les modifications sont enregistrées.", + "save_status_unsaved_tooltip": "Il y a des changements non enregistrés. Ils seront enregistrés automatiquement dans un instant.", + "save_status_error_tooltip": "Une erreur s'est produite lors de l'enregistrement de la note. Si possible, essayez de copier le contenu de la note ailleurs et de recharger l'application." + }, + "right_pane": { + "toggle": "Basculer le panneau de droite", + "custom_widget_go_to_source": "Aller sur le code source", + "empty_message": "Rien à afficher pour cette note", + "empty_button": "Cacher le panneau" + }, + "pdf": { + "attachments_one": "{{count}} pièce jointe", + "attachments_many": "{{count}} pièces jointes", + "attachments_other": "{{count}} pièces jointes", + "layers_one": "{{count}} couche", + "layers_many": "{{count}} couches", + "layers_other": "{{count}} couches", + "pages_one": "{{count}} page", + "pages_many": "{{count}} pages", + "pages_other": "{{count}} pages", + "pages_alt": "Page {{pageNumber}}", + "pages_loading": "Chargement..." + }, + "platform_indicator": { + "available_on": "Disponible sur {{platform}}" + }, + "mobile_tab_switcher": { + "title_one": "{{count}} onglet", + "title_many": "{{count}} onglets", + "title_other": "{{count}} onglets", + "more_options": "Autres options" + }, + "bookmark_buttons": { + "bookmarks": "Signets" + }, + "active_content_badges": { + "type_icon_pack": "pack d'icônes", + "type_backend_script": "Script backend", + "type_frontend_script": "Script frontend", + "type_widget": "Widget", + "type_app_css": "CSS personnalisé", + "type_render_note": "Note de rendu", + "type_web_view": "Vue Web", + "type_app_theme": "Thème personnalisé", + "toggle_tooltip_enable_tooltip": "Cliquer pour activer {{type}}.", + "toggle_tooltip_disable_tooltip": "Cliquer pour désactiver ce {{type}}.", + "menu_docs": "Ouvrir la documentation", + "menu_execute_now": "Exécuter le script maintenant", + "menu_run": "Démarrer automatiquement", + "menu_run_disabled": "Manuellement", + "menu_run_backend_startup": "Lorsque le backend commence", + "menu_run_hourly": "Horaire", + "menu_run_daily": "Quotidien", + "menu_run_frontend_startup": "Lorsque le frontend du bureau démarre", + "menu_run_mobile_startup": "Lorsque le frontend mobile démarre", + "menu_change_to_widget": "Passer au widget", + "menu_change_to_frontend_script": "Passer au script frontend", + "menu_theme_base": "Thème de base" + }, + "setup_form": { + "more_info": "En savoir plus" + }, + "mermaid": { + "placeholder": "Tapez le contenu de votre diagramme Mermaid ou utilisez l'un des diagrammes de l'échantillon ci-dessous.", + "sample_diagrams": "Diagrammes d 'exemple:", + "sample_flowchart": "Organigramme", + "sample_class": "Classe", + "sample_sequence": "Séquence", + "sample_entity_relationship": "Entité relationnelle", + "sample_state": "État", + "sample_mindmap": "Carte mentale", + "sample_architecture": "Architecture", + "sample_block": "Bloc", + "sample_c4": "C4", + "sample_gantt": "Gantt", + "sample_git": "Git", + "sample_kanban": "Kanban", + "sample_packet": "Paquet", + "sample_pie": "Camembert", + "sample_quadrant": "Quadrant", + "sample_radar": "Radar", + "sample_requirement": "Exigence", + "sample_sankey": "Sankey", + "sample_timeline": "Chronologie", + "sample_treemap": "Arborescence", + "sample_user_journey": "Utilisateur Journey", + "sample_xy": "XY", + "sample_venn": "Venn", + "sample_ishikawa": "Ishikawa" + }, + "mind-map": { + "addChild": "Ajouter un enfant", + "addParent": "Ajouter parent", + "addSibling": "Ajouter un frère", + "removeNode": "Supprimer le nœud", + "focus": "Mode Focus", + "cancelFocus": "Annuler le mode Focus", + "moveUp": "Monter", + "moveDown": "Descendre", + "link": "Lien", + "linkBidirectional": "Lien bidirectionnel", + "clickTips": "Cliquer sur le nœud cible", + "summary": "Résumé" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "Configurer les intégrations AI et les LLM (Large Language Model).", + "add_provider": "Ajouter le fournisseur", + "add_provider_title": "Ajouter le fournisseur d'IA", + "configured_providers": "Fournisseurs configurés", + "no_providers_configured": "Aucun fournisseur n'est encore configuré.", + "provider_name": "Nom", + "provider_type": "Fournisseur", + "actions": "Actions", + "delete_provider": "Supprimer", + "delete_provider_confirmation": "Êtes-vous sûr de vouloir supprimer le fournisseur \"{{name}}\" ?", + "api_key": "Clé API", + "api_key_placeholder": "Entrer votre clé API", + "cancel": "Annuler" + }, + "status_bar": { + "language_title": "Changer de langue", + "note_info_title": "Afficher les informations sur les notes (par exemple, dates, taille des notes)", + "backlinks_one": "{{count}} rétrolien", + "backlinks_many": "{{count}} rétroliens", + "backlinks_other": "{{count}} rétroliens", + "backlinks_title_one": "voir le rétrolien", + "backlinks_title_many": "voir les rétroliens", + "backlinks_title_other": "voir les rétroliens", + "attachments_one": "{{count}} pièce-jointe", + "attachments_many": "{{count}} pièces-jointes", + "attachments_other": "{{count}} pièces-jointes", + "attachments_title_one": "Voir la pièce-jointe dans un nouvel onglet", + "attachments_title_many": "Voir les pièces-jointes dans un nouvel onglet", + "attachments_title_other": "Voir les pièces-jointes dans un nouvel onglet", + "attributes_one": "{{count}} attribut", + "attributes_many": "{{count}} attributs", + "attributes_other": "{{count}} attributs", + "attributes_title": "Attributs propres et attributs hérités", + "note_paths_one": "{{count}} chemin", + "note_paths_many": "{{count}} chemins", + "note_paths_other": "{{count}} chemins", + "note_paths_title": "Chemins de la note", + "code_note_switcher": "Changer de langue" + }, + "attributes_panel": { + "title": "Attributs de la note" } } diff --git a/apps/client/src/translations/ga/translation.json b/apps/client/src/translations/ga/translation.json index d0f41408ce..d4653932ad 100644 --- a/apps/client/src/translations/ga/translation.json +++ b/apps/client/src/translations/ga/translation.json @@ -399,7 +399,7 @@ "calendar_root": "nóta marcáilte ar cheart a úsáid mar fhréamh do nótaí lae. Níor cheart ach ceann amháin a mharcáil mar sin.", "archived": "Ní bheidh nótaí leis an lipéad seo le feiceáil de réir réamhshocraithe i dtorthaí cuardaigh (i ndialóga Léim Chuig, Cuir Nasc Leis srl. chomh maith).", "exclude_from_export": "ní chuirfear nótaí (lena bhfo-chrann) san áireamh in aon onnmhairiú nótaí", - "run": "Sainmhíníonn sé seo cé na himeachtaí ar cheart don script rith orthu. Is iad seo a leanas na luachanna féideartha:\n
    \n
  • frontendStartup - nuair a thosaíonn (nó a athnuachan) tosaigh Trilium, ach ní ar fhóin phóca.
  • \n
  • mobileStartup - nuair a thosaíonn (nó a athnuachan) tosaigh Trilium, ar fhóin phóca.
  • \n
  • backendStartup - nuair a thosaíonn cúltaca Trilium
  • \n
  • uair an chloig - rith uair san uair. Is féidir leat lipéad breise runAtHour a úsáid chun a shonrú cén uair a ritheann sé.
  • \n
  • daily - rith uair sa lá
  • \n
", + "run": "Sainmhíníonn sé seo cé na himeachtaí ar cheart don script rith orthu. Is iad seo a leanas na luachanna féideartha:\n
    \n
  • frontendStartup - nuair a thosaíonn (nó a athnuachan) tosaigh Trilium, ach ní ar fhóin phóca.
  • \n
  • mobileStartup - nuair a thosaíonn (nó a athnuachan) tosaigh Trilium, ar fhóin phóca.
  • \n
  • backendStartup - nuair a thosaíonn cúltaca Trilium.
  • \n
  • hourly - rith uair san uair. Is féidir leat lipéad breise runAtHour a úsáid chun a shonrú cén uair a ritheann sé.
  • \n
  • daily - rith uair sa lá.
  • \n
", "run_on_instance": "Sainmhínigh cén sampla de Trilium ba chóir é seo a rith air. Réamhshocrú do gach sampla.", "run_at_hour": "Cén uair ar cheart é seo a rith? Ba cheart é a úsáid i dteannta #run=hourly. Is féidir é seo a shainiú arís agus arís eile le haghaidh níos mó ritheanna i rith an lae.", "disable_inclusion": "Ní chuirfear scripteanna leis an lipéad seo san áireamh i bhforghníomhú an scripte tuismitheora.", @@ -709,7 +709,8 @@ "export_as_image": "Easpórtáil mar íomhá", "export_as_image_png": "PNG (rastar)", "export_as_image_svg": "SVG (veicteoir)", - "note_map": "Léarscáil nótaí" + "note_map": "Léarscáil nótaí", + "view_ocr_text": "Féach ar théacs OCR" }, "onclick_button": { "no_click_handler": "Níl aon láimhseálaí cliceáil sainithe ag an ngiuirléid cnaipe '{{componentId}}'" @@ -1127,7 +1128,9 @@ "title": "Roghanna Turgnamhacha", "disclaimer": "Is roghanna turgnamhacha iad seo agus d’fhéadfadh éagobhsaíocht a bheith mar thoradh orthu. Bain úsáid astu go cúramach.", "new_layout_name": "Leagan Amach Nua", - "new_layout_description": "Bain triail as an leagan amach nua le haghaidh cuma níos nua-aimseartha agus inúsáidteachta feabhsaithe. Tá sé faoi réir athruithe móra sna heisiúintí atá le teacht." + "new_layout_description": "Bain triail as an leagan amach nua le haghaidh cuma níos nua-aimseartha agus inúsáidteachta feabhsaithe. Tá sé faoi réir athruithe móra sna heisiúintí atá le teacht.", + "llm_name": "Comhrá AI / LLM", + "llm_description": "Cumasaigh an taobhbharra comhrá AI agus nótaí comhrá LLM faoi thiomáint ag samhlacha teanga móra." }, "fonts": { "theme_defined": "Téama sainmhínithe", @@ -1222,12 +1225,28 @@ }, "images": { "images_section_title": "Íomhánna", - "download_images_automatically": "Íoslódáil íomhánna go huathoibríoch le húsáid as líne.", - "download_images_description": "Is féidir tagairtí d’íomhánna ar líne a bheith i HTML greamaithe, aimseoidh Trilium na tagairtí sin agus íoslódálfaidh sé na híomhánna ionas go mbeidh siad ar fáil as líne.", - "enable_image_compression": "Cumasaigh comhbhrú íomhá", - "max_image_dimensions": "Uasleithead/airde íomhá (athrófar méid na híomhá má sháraíonn sí an socrú seo).", + "download_images_automatically": "Íomhánna a íoslódáil go huathoibríoch", + "download_images_description": "Íoslódáil íomhánna tagartha ar líne ó HTML greamaithe ionas go mbeidh siad ar fáil as líne.", + "enable_image_compression": "Comhbhrú íomhá", + "max_image_dimensions": "Uasmhéid toisí íomhá", "max_image_dimensions_unit": "picteilíní", - "jpeg_quality_description": "Cáilíocht JPEG (10 - an caighdeán is measa, 100 - an caighdeán is fearr, moltar 50 - 85)" + "jpeg_quality_description": "Is é an raon molta ná 50–85. Laghdaíonn luachanna níos ísle méid an chomhaid, agus coinníonn luachanna níos airde sonraí.", + "enable_image_compression_description": "Comhbhrúigh agus athraigh méid íomhánna nuair a uaslódálfar nó a ghreamaítear iad.", + "max_image_dimensions_description": "Athrófar méid íomhánna a sháraíonn an méid seo go huathoibríoch.", + "jpeg_quality": "Cáilíocht JPEG", + "ocr_section_title": "Eastóscadh Téacs (OCR)", + "ocr_related_content_languages": "Teangacha ábhair (a úsáidtear le haghaidh eastóscadh téacs)", + "ocr_auto_process": "Próiseáil comhaid nua go huathoibríoch", + "ocr_auto_process_description": "Bain téacs go huathoibríoch as comhaid atá uaslódáilte nó greamaithe le déanaí.", + "ocr_min_confidence": "Íosmhuinín", + "ocr_confidence_description": "Ná bain ach téacs os cionn an tairsí muiníne seo. Cuimsíonn luachanna níos ísle níos mó téacs ach d'fhéadfadh siad a bheith níos lú cruinn.", + "batch_ocr_title": "Próiseáil Comhaid atá ann cheana", + "batch_ocr_description": "Bain téacs as na híomhánna, na PDFanna agus na doiciméid Office go léir atá i do nótaí. D’fhéadfadh sé seo roinnt ama a thógáil ag brath ar líon na gcomhad.", + "batch_ocr_start": "Tosaigh Próiseáil Bhaisc", + "batch_ocr_starting": "Ag tosú próiseáil bhaisc...", + "batch_ocr_progress": "Ag próiseáil {{processed}} de {{total}} comhad...", + "batch_ocr_completed": "Próiseáil bhaisc críochnaithe! Próiseáladh {{processed}} comhad.", + "batch_ocr_error": "Earráid le linn próiseála baisce: {{error}}" }, "attachment_erasure_timeout": { "attachment_erasure_timeout": "Am Teorann Scriosadh Ceangaltáin", @@ -1273,7 +1292,7 @@ "custom_name_label": "Ainm innill chuardaigh saincheaptha", "custom_name_placeholder": "Saincheap ainm an innill chuardaigh", "custom_url_label": "Ba chóir go mbeadh {keyword} san áireamh mar áitchoinneálaí don téarma cuardaigh i URL inneall cuardaigh saincheaptha.", - "custom_url_placeholder": "Saincheap url an innill chuardaigh", + "custom_url_placeholder": "Saincheap URL an innill chuardaigh", "save_button": "Sábháil" }, "tray": { @@ -1451,9 +1470,6 @@ "description": "Ní bhaineann na roghanna seo ach le leaganacha deisce, úsáidfidh brabhsálaithe a seiceáil litrithe dúchasach féin.", "enable": "Cumasaigh seiceáil litrithe", "language_code_label": "Cód(anna) teanga", - "language_code_placeholder": "mar shampla \"en-US\", \"de-AT\"", - "multiple_languages_info": "Is féidir camóg a úsáid chun teangacha iolracha a dheighilt óna chéile, m.sh. \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Cóid teanga atá ar fáil:", "restart-required": "Tiocfaidh athruithe ar na roghanna seiceála litrithe i bhfeidhm tar éis atosú an fheidhmchláir." }, "sync_2": { @@ -1572,7 +1588,8 @@ "task-list": "Liosta Tascanna", "new-feature": "Nua", "collections": "Bailiúcháin", - "spreadsheet": "Scarbhileog" + "spreadsheet": "Scarbhileog", + "llm-chat": "Comhrá AI" }, "protect_note": { "toggle-on": "Cosain an nóta", @@ -1900,7 +1917,7 @@ }, "content_language": { "title": "Teangacha ábhair", - "description": "Roghnaigh teanga amháin nó níos mó ar cheart dóibh a bheith le feiceáil sa rogha teanga sa rannán Airíonna Bunúsacha de nóta téacs inléite amháin nó in-eagarthóireachta. Ceadóidh sé seo gnéithe ar nós seiceáil litrithe nó tacaíocht ó dheis go clé." + "description": "Roghnaigh teanga amháin nó níos mó ar cheart dóibh a bheith le feiceáil sa rogha teanga sa rannán Airíonna Bunúsacha de nóta téacs inléite amháin nó in-eagarthóireachta. Ceadaíonn sé seo gnéithe ar nós seiceáil litrithe, tacaíocht ó dheis go clé agus eastóscadh téacs (OCR)." }, "switch_layout_button": { "title_vertical": "Bog an painéal eagarthóireachta go dtí an bun", @@ -2275,5 +2292,115 @@ "sample_xy": "XY", "sample_venn": "Venn", "sample_ishikawa": "Ishikawa" + }, + "llm_chat": { + "placeholder": "Clóscríobh teachtaireacht...", + "send": "Seol", + "sending": "Ag seoladh...", + "empty_state": "Tosaigh comhrá trí theachtaireacht a chlóscríobh thíos.", + "searching_web": "Ag cuardach an ghréasáin...", + "web_search": "Cuardach gréasáin", + "note_tools": "Rochtain nótaí", + "sources": "Foinsí", + "extended_thinking": "Smaointeoireacht leathnaithe", + "legacy_models": "Samhlacha oidhreachta", + "thinking": "Ag smaoineamh...", + "thought_process": "Próiseas smaointeoireachta", + "tool_calls": "{{count}} glao(í) uirlisí", + "input": "Ionchur", + "result": "Toradh", + "error": "Earráid", + "tool_error": "theip", + "total_tokens": "{{total}} comharthaí", + "tokens_detail": "leid {{prompt}} + críochnú {{completion}}", + "tokens_used": "{{prompt}} leid + {{completion}} críochnú = {{total}} comharthaí", + "tokens_used_with_cost": "{{prompt}} leid + {{completion}} críochnú = {{total}} comharthaí (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} leid + {{completion}} críochnú = {{total}} comharthaí", + "tokens_used_with_model_and_cost": "{{model}}: leid {{prompt}} + críochnú {{completion}} = {{total}} comharthaí (~${{cost}})", + "tokens": "comharthaí", + "context_used": "Úsáideadh {{percentage}}%", + "note_context_enabled": "Cliceáil chun comhthéacs nótaí a dhíchumasú: {{title}}", + "note_context_disabled": "Cliceáil chun an nóta reatha a chur san áireamh i gcomhthéacs", + "no_provider_message": "Níl aon soláthraí AI cumraithe. Cuir ceann leis chun comhrá a thosú.", + "add_provider": "Cuir Soláthraí AI leis", + "sources_summary": "{{count}} foinsí ó {{sites}} suíomhanna" + }, + "sidebar_chat": { + "title": "Comhrá AI", + "launcher_title": "Oscail Comhrá AI", + "new_chat": "Tosaigh comhrá nua", + "save_chat": "Sábháil comhrá sna nótaí", + "empty_state": "Tosaigh comhrá", + "history": "Stair chomhrá", + "recent_chats": "Comhráite le déanaí", + "no_chats": "Gan aon chomhráite roimhe seo" + }, + "mind-map": { + "addChild": "Cuir páiste leis", + "addParent": "Cuir tuismitheoir leis", + "addSibling": "Cuir deartháir nó deirfiúr leis", + "removeNode": "Bain nód", + "focus": "Mód Fócais", + "cancelFocus": "Cealaigh Mód Fócais", + "moveUp": "Bog suas", + "moveDown": "Bog síos", + "link": "Nasc", + "linkBidirectional": "Nasc Déthreoch", + "clickTips": "Cliceáil ar an nód sprice le do thoil", + "summary": "Achoimre" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "Cumraigh comhtháthú idir Intleacht Shaorga agus Múnla Teanga Mór.", + "add_provider": "Cuir Soláthraí leis", + "add_provider_title": "Cuir Soláthraí AI leis", + "configured_providers": "Soláthraithe Cumraithe", + "no_providers_configured": "Níl aon soláthraithe cumraithe fós.", + "provider_name": "Ainm", + "provider_type": "Soláthraí", + "actions": "Gníomhartha", + "delete_provider": "Scrios", + "delete_provider_confirmation": "An bhfuil tú cinnte gur mian leat an soláthraí \"{{name}}\" a scriosadh?", + "api_key": "Eochair API", + "api_key_placeholder": "Cuir isteach d'eochair API", + "cancel": "Cealaigh", + "feature_not_enabled": "Cumasaigh an ghné turgnamhach LLM i Socruithe → Ardleibhéil → Gnéithe turgnamhacha chun comhtháthú AI a úsáid.", + "mcp_title": "MCP (Prótacal Comhthéacs Múnla)", + "mcp_enabled": "Freastalaí MCP", + "mcp_enabled_description": "Nochtaigh críochphointe Prótacal Comhthéacs Múnla (MCP) ionas gur féidir le cúntóirí códaithe AI (m.sh. Claude Code, GitHub Copilot) do nótaí a léamh agus a mhodhnú. Ní féidir rochtain a fháil ar an gcríochphointe ach ó localhost.", + "mcp_endpoint_title": "URL críochphointe", + "mcp_endpoint_description": "Cuir an URL seo le cumraíocht MCP do chúntóra AI", + "tools": { + "search_notes": "Cuardaigh nótaí", + "get_note": "Faigh nóta", + "get_note_content": "Faigh ábhar nótaí", + "update_note_content": "Nuashonraigh ábhar an nóta", + "append_to_note": "Cuir leis an nóta", + "create_note": "Cruthaigh nóta", + "get_attributes": "Faigh tréithe", + "get_attribute": "Faigh tréith", + "set_attribute": "Socraigh tréith", + "delete_attribute": "Scrios tréith", + "get_child_notes": "Faigh nótaí leanaí", + "get_subtree": "Faigh fo-chrann", + "load_skill": "Luchtaigh scileanna", + "web_search": "Cuardach gréasáin", + "note_in_parent": " i ", + "get_attachment": "Faigh ceangaltán", + "get_attachment_content": "Léigh ábhar an cheangail" + } + }, + "ocr": { + "extracted_text": "Téacs Bainte (OCR)", + "extracted_text_title": "Téacs Bainte (OCR)", + "loading_text": "Ag lódáil téacs OCR...", + "no_text_available": "Níl aon téacs OCR ar fáil", + "no_text_explanation": "Níor próiseáladh an nóta seo le haghaidh eastóscadh téacs OCR nó níor aimsíodh aon téacs.", + "failed_to_load": "Theip ar lódáil téacs OCR", + "process_now": "Próiseas OCR", + "processing": "Ag próiseáil...", + "processing_started": "Tá próiseáil OCR tosaithe. Fan nóiméad agus athnuachan le do thoil.", + "processing_failed": "Theip ar phróiseáil OCR a thosú", + "view_extracted_text": "Féach ar théacs eastósctha (OCR)" } } diff --git a/apps/client/src/translations/hi/translation.json b/apps/client/src/translations/hi/translation.json index b11e731125..deb3456638 100644 --- a/apps/client/src/translations/hi/translation.json +++ b/apps/client/src/translations/hi/translation.json @@ -1461,9 +1461,6 @@ "description": "ये विकल्प सिर्फ़ डेस्कटॉप वर्जन के लिए हैं, ब्राउज़र अपना स्पेल चेक इस्तेमाल करेंगे।", "enable": "स्पेल चेक चालू करें", "language_code_label": "भाषा कोड (Language code)", - "language_code_placeholder": "जैसे \"en-US\", \"hi-IN\"", - "multiple_languages_info": "कई भाषाओं को कॉमा से अलग किया जा सकता है, जैसे \"en-US, hi-IN\"। ", - "available_language_codes_label": "उपलब्ध भाषा कोड:", "restart-required": "स्पेल चेक में बदलाव ऐप रीस्टार्ट करने के बाद ही दिखेंगे।" }, "sync_2": { diff --git a/apps/client/src/translations/it/translation.json b/apps/client/src/translations/it/translation.json index ef4e0295a2..e46cc571a5 100644 --- a/apps/client/src/translations/it/translation.json +++ b/apps/client/src/translations/it/translation.json @@ -520,7 +520,7 @@ "custom_name_label": "Nome del motore di ricerca personalizzato", "custom_name_placeholder": "Personalizza il nome del motore di ricerca", "custom_url_label": "L'URL del motore di ricerca personalizzato deve includere {keyword} come segnaposto per il termine di ricerca.", - "custom_url_placeholder": "Personalizza indirizzo url del motore di ricerca" + "custom_url_placeholder": "Personalizza indirizzo URL del motore di ricerca" }, "sql_table_schemas": { "tables": "Tabelle" @@ -538,12 +538,12 @@ "new_tab": "Nuova scheda" }, "toc": { - "table_of_contents": "Sommario", + "table_of_contents": "Tabella dei Contenuti", "options": "Opzioni", "no_headings": "Nessun titolo." }, "table_of_contents": { - "title": "Sommario", + "title": "Tabella dei Contenuti", "description": "L'indice apparirà nelle note di testo quando la nota contiene più di un numero definito di titoli. È possibile personalizzare questo numero:", "unit": "titoli", "disable_info": "È anche possibile utilizzare questa opzione per disattivare efficacemente l'indice impostando un numero molto alto.", @@ -853,7 +853,7 @@ "archived": "Le note con questa etichetta non saranno visibili per impostazione predefinita nei risultati di ricerca (anche nelle finestre di dialogo Vai a, Aggiungi collegamento ecc.).", "run_on_instance": "Definire su quale istanza di Trilium eseguire questa operazione. L'impostazione predefinita è tutte le istanze.", "exclude_from_export": "le note (con la loro sottostruttura) non saranno incluse in nessuna esportazione di note", - "run": "definisce su quali eventi deve essere eseguito lo script. I valori possibili sono:\n
    \n
  • frontendStartup - quando il frontend Trilium viene avviato (o aggiornato), ma non su dispositivi mobili.
  • \n
  • mobileStartup - quando il frontend Trilium viene avviato (o aggiornato) su dispositivi mobili.
  • \n
  • backendStartup - quando viene avviato il backend Trilium
  • \n
  • hourly - eseguire una volta all'ora. È possibile utilizzare l'etichetta aggiuntiva runAtHour per specificare a che ora.
  • \n
  • daily - eseguire una volta al giorno
  • \n
", + "run": "definisce su quali eventi deve essere eseguito lo script. I valori possibili sono:\n
    \n
  • frontendStartup - quando il frontend Trilium viene avviato (o aggiornato), ma non su dispositivi mobili.
  • \n
  • mobileStartup - quando il frontend Trilium viene avviato (o aggiornato) su dispositivi mobili.
  • \n
  • backendStartup - quando viene avviato il backend Trilium.
  • \n
  • hourly - eseguire una volta all'ora. È possibile utilizzare l'etichetta aggiuntiva runAtHour per specificare a che ora.
  • \n
  • daily - eseguire una volta al giorno.
  • \n
", "run_at_hour": "A che ora deve essere eseguito. Deve essere utilizzato insieme a #run=hourly. Può essere definito più volte per più esecuzioni durante il giorno.", "disable_inclusion": "gli script con questa etichetta non saranno inclusi nell'esecuzione dello script principale.", "sorted": "mantiene le note figlie ordinate alfabeticamente per titolo", @@ -1149,7 +1149,8 @@ "export_as_image": "Esporta come immagine", "export_as_image_png": "PNG (raster)", "export_as_image_svg": "SVG (vector)", - "note_map": "Mappa" + "note_map": "Mappa", + "view_ocr_text": "Visualizza il testo OCR" }, "onclick_button": { "no_click_handler": "Il widget pulsante '{{componentId}}' non ha un gestore di clic definito" @@ -1541,12 +1542,28 @@ }, "images": { "images_section_title": "Immagini", - "download_images_automatically": "Scarica automaticamente le immagini per l'utilizzo offline.", - "download_images_description": "L'HTML incollato può contenere riferimenti a immagini online; Trilium troverà tali riferimenti e scaricherà le immagini in modo che siano disponibili offline.", - "enable_image_compression": "Abilita la compressione delle immagini", - "max_image_dimensions": "Larghezza/altezza massima di un'immagine (l'immagine verrà ridimensionata se supera questa impostazione).", + "download_images_automatically": "Scarica automaticamente le immagini", + "download_images_description": "Scarica le immagini online a cui si fa riferimento nel codice HTML incollato, in modo che siano disponibili offline.", + "enable_image_compression": "Compressione delle immagini", + "max_image_dimensions": "Dimensioni massime dell'immagine", "max_image_dimensions_unit": "pixel", - "jpeg_quality_description": "Qualità JPEG (10 - qualità peggiore, 100 - qualità migliore, 50 - 85 è consigliato)" + "jpeg_quality_description": "Il range consigliato è compreso tra 50 e 85. Valori più bassi riducono le dimensioni del file, mentre valori più alti preservano i dettagli.", + "enable_image_compression_description": "Comprimi e ridimensiona le immagini al momento del caricamento o dell'inserimento.", + "max_image_dimensions_description": "Le immagini che superano queste dimensioni verranno ridimensionate automaticamente.", + "jpeg_quality": "Qualità JPEG", + "ocr_section_title": "Estrazione di testo (OCR)", + "ocr_related_content_languages": "Lingue dei contenuti (utilizzate per l'estrazione del testo)", + "ocr_auto_process": "Elaborazione automatica dei nuovi file", + "ocr_auto_process_description": "Estrai automaticamente il testo dai file appena caricati o incollati.", + "ocr_min_confidence": "Livello minimo di confidenza", + "ocr_confidence_description": "Estrai solo il testo che supera questa soglia di affidabilità. Valori inferiori includono più testo, ma potrebbero risultare meno accurati.", + "batch_ocr_title": "Elabora i file esistenti", + "batch_ocr_description": "Estrai il testo da tutte le immagini, i PDF e i documenti Office presenti nei tuoi appunti. L'operazione potrebbe richiedere un po' di tempo a seconda del numero di file.", + "batch_ocr_start": "Avvia l'elaborazione in batch", + "batch_ocr_starting": "Avvio dell'elaborazione in batch...", + "batch_ocr_progress": "Elaborazione di {{processed}} su {{total}} file...", + "batch_ocr_completed": "Elaborazione in batch completata! Sono stati elaborati {{processed}} file.", + "batch_ocr_error": "Errore durante l'elaborazione in batch: {{error}}" }, "attachment_erasure_timeout": { "attachment_erasure_timeout": "Timeout cancellazione allegato", @@ -1656,9 +1673,6 @@ "description": "Queste opzioni sono valide solo per le versioni desktop; i browser utilizzeranno il proprio controllo ortografico nativo.", "enable": "Abilita il controllo ortografico", "language_code_label": "Codice/i della lingua", - "language_code_placeholder": "ad esempio \"en-US\", \"de-AT\"", - "multiple_languages_info": "È possibile separare più lingue con una virgola, ad esempio \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Codici lingua disponibili:", "restart-required": "Le modifiche alle opzioni di controllo ortografico avranno effetto dopo il riavvio dell'applicazione." }, "api_log": { @@ -1718,7 +1732,8 @@ "new-feature": "Nuovo", "collections": "Collezioni", "ai-chat": "Chat con IA", - "spreadsheet": "Foglio di calcolo" + "spreadsheet": "Foglio di calcolo", + "llm-chat": "Chat con IA" }, "protect_note": { "toggle-on": "Proteggi la nota", @@ -1939,7 +1954,7 @@ }, "content_language": { "title": "Lingue dei contenuti", - "description": "Seleziona una o più lingue che desideri visualizzare nella sezione \"Proprietà di base\" di una nota di testo di sola lettura o modificabile. Ciò consentirà funzionalità come il controllo ortografico o il supporto per la scrittura da destra a sinistra." + "description": "Seleziona una o più lingue che devono comparire nell'elenco di selezione delle lingue nella sezione \"Proprietà di base\" di una nota di testo in sola lettura o modificabile. Ciò consentirà di utilizzare funzioni quali il controllo ortografico, il supporto per la scrittura da destra a sinistra e l'estrazione del testo (OCR)." }, "switch_layout_button": { "title_vertical": "Sposta il riquadro di modifica in basso", @@ -2051,7 +2066,9 @@ "title": "Opzioni sperimentali", "disclaimer": "Queste opzioni sono sperimentali e potrebbero causare instabilità. Usare con cautela.", "new_layout_name": "Nuovo layout", - "new_layout_description": "Prova il nuovo layout per un look più moderno e una maggiore usabilità. Soggetto a modifiche significative nelle prossime versioni." + "new_layout_description": "Prova il nuovo layout per un look più moderno e una maggiore usabilità. Soggetto a modifiche significative nelle prossime versioni.", + "llm_name": "Chat con IA / LLM", + "llm_description": "Attiva la barra laterale della chat con IA e le note della chat LLM basate su modelli linguistici di grandi dimensioni." }, "server": { "unknown_http_error_title": "Errore di comunicazione con il server", @@ -2244,6 +2261,121 @@ "sample_user_journey": "Percorso dell'utente", "sample_xy": "XY", "sample_venn": "Venn", - "sample_ishikawa": "Ishikawa" + "sample_ishikawa": "Ishikawa", + "sample_treeview": "TreeView", + "sample_wardley": "Mappa di Wardley" + }, + "llm_chat": { + "placeholder": "Scrivi un messaggio...", + "send": "Invia", + "sending": "Invio in corso...", + "empty_state": "Inizia una conversazione scrivendo un messaggio qui sotto.", + "searching_web": "Ricerca sul web...", + "web_search": "Ricerca sul web", + "note_tools": "Nota di accesso", + "sources": "Fonti", + "extended_thinking": "Riflessioni approfondite", + "legacy_models": "Modelli precedenti", + "thinking": "Sto riflettendo...", + "thought_process": "Processo mentale", + "tool_calls": "{{count}} chiamata/e di funzione", + "input": "Dati in ingresso", + "result": "Risultato", + "error": "Errore", + "tool_error": "fallito", + "total_tokens": "{{total}} gettoni", + "tokens_detail": "{{prompt}} prompt + {{completion}} completamento", + "tokens_used": "{{prompt}} prompt + {{completion}} completamento = {{total}} token", + "tokens_used_with_cost": "{{prompt}} prompt + {{completion}} completamento = {{total}} token (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} prompt + {{completion}} completamento = {{total}} token", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} prompt + {{completion}} completamento = {{total}} token (~${{cost}})", + "tokens": "tokens", + "context_used": "{{percentage}}% utilizzato", + "note_context_enabled": "Clicca qui per disattivare il contesto della nota: {{title}}", + "note_context_disabled": "Clicca per includere la nota corrente nel contesto", + "no_provider_message": "Non è stato configurato alcun fornitore di IA. Aggiungine uno per iniziare a chattare.", + "add_provider": "Aggiungi un fornitore di IA", + "sources_summary": "{{count}} fonti provenienti da {{sites}} siti" + }, + "sidebar_chat": { + "title": "Chat AI", + "launcher_title": "Apri Chat AI", + "new_chat": "Inizia una nuova chat", + "save_chat": "Salva la chat negli appunti", + "empty_state": "Avvia una conversazione", + "history": "Cronologia delle chat", + "recent_chats": "Conversazioni recenti", + "no_chats": "Nessuna conversazione precedente" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "Configurare le integrazioni con l'intelligenza artificiale e i modelli linguistici di grandi dimensioni.", + "add_provider": "Aggiungi fornitore", + "add_provider_title": "Aggiungi un fornitore di IA", + "configured_providers": "Fornitori configurati", + "no_providers_configured": "Non sono stati ancora configurati fornitori.", + "provider_name": "Nome", + "provider_type": "Fornitore", + "actions": "Azioni", + "delete_provider": "Elimina", + "delete_provider_confirmation": "Sei sicuro di voler eliminare il provider \"{{name}}\"?", + "api_key": "Chiave API", + "api_key_placeholder": "Inserisci la tua chiave API", + "cancel": "Annulla", + "feature_not_enabled": "Abilita la funzione sperimentale LLM in Impostazioni → Avanzate → Funzioni sperimentali per utilizzare le integrazioni basate sull'intelligenza artificiale.", + "mcp_title": "MCP (Model Context Protocol)", + "mcp_enabled": "Server MCP", + "mcp_enabled_description": "Rendi pubblico un endpoint MCP (Model Context Protocol) in modo che gli assistenti di programmazione basati sull'intelligenza artificiale (ad esempio Claude Code, GitHub Copilot) possano leggere e modificare le tue note. L'endpoint è accessibile solo da localhost.", + "mcp_endpoint_title": "URL dell'endpoint", + "mcp_endpoint_description": "Aggiungi questo URL alla configurazione MCP del tuo assistente AI", + "tools": { + "search_notes": "Cerca nelle note", + "get_note": "Prendi nota", + "get_note_content": "Visualizza il contenuto della nota", + "update_note_content": "Aggiorna il contenuto della nota", + "append_to_note": "Aggiungi alla nota", + "create_note": "Crea nota", + "get_attributes": "Recupera gli attributi", + "get_attribute": "Ottieni attributo", + "set_attribute": "Imposta attributo", + "delete_attribute": "Elimina attributo", + "get_child_notes": "Recupera le note relative ai figli", + "get_subtree": "Ottieni sottostruttura", + "load_skill": "Carica skill", + "web_search": "Ricerca sul web", + "note_in_parent": " in ", + "get_attachment": "Scarica l'allegato", + "get_attachment_content": "Leggi il contenuto dell'allegato" + } + }, + "ocr": { + "extracted_text": "Testo estratto (OCR)", + "extracted_text_title": "Testo estratto (OCR)", + "loading_text": "Caricamento del testo OCR in corso...", + "no_text_available": "Non è disponibile alcun testo OCR", + "no_text_explanation": "Questo documento non è stato sottoposto a elaborazione OCR per l'estrazione del testo oppure non è stato trovato alcun testo.", + "failed_to_load": "Impossibile caricare il testo OCR", + "process_now": "Elaborazione OCR", + "processing": "Elaborazione in corso...", + "processing_started": "L'elaborazione OCR è stata avviata. Attendere qualche istante e aggiorna.", + "processing_complete": "Elaborazione OCR completata.", + "processing_failed": "Impossibile avviare l'elaborazione OCR", + "text_filtered_low_confidence": "L'OCR ha rilevato il testo con un livello di affidabilità del {{confidence}}%, ma è stato scartato perché la soglia minima impostata è del {{threshold}}%.", + "open_media_settings": "Apri Impostazioni", + "view_extracted_text": "Visualizza il testo estratto (OCR)" + }, + "mind-map": { + "addChild": "Aggiungi figlio", + "addParent": "Aggiungi genitore", + "addSibling": "Aggiungi un fratello o una sorella", + "removeNode": "Rimuovi nodo", + "focus": "Modalità Focus", + "cancelFocus": "Annulla modalità Focus", + "moveUp": "Sposta su", + "moveDown": "Sposta giù", + "link": "Collegamento", + "linkBidirectional": "Collegamento bidirezionale", + "clickTips": "Clicca sul nodo di destinazione", + "summary": "Sommario" } } diff --git a/apps/client/src/translations/ja/translation.json b/apps/client/src/translations/ja/translation.json index a7e959998b..b3ddcb6e6d 100644 --- a/apps/client/src/translations/ja/translation.json +++ b/apps/client/src/translations/ja/translation.json @@ -486,7 +486,8 @@ "advanced": "高度", "export_as_image": "画像としてエクスポート", "export_as_image_png": "PNG (raster)", - "export_as_image_svg": "SVG (vector)" + "export_as_image_svg": "SVG (vector)", + "view_ocr_text": "OCR テキストを表示" }, "command_palette": { "export_note_title": "ノートをエクスポート", @@ -601,7 +602,8 @@ "new-feature": "New", "collections": "コレクション", "ai-chat": "AI チャット", - "spreadsheet": "スプレッドシート" + "spreadsheet": "スプレッドシート", + "llm-chat": "AI チャット" }, "edited_notes": { "no_edited_notes_found": "この日の編集されたノートはまだありません...", @@ -897,12 +899,28 @@ }, "images": { "images_section_title": "画像", - "download_images_automatically": "画像を自動的にダウンロードしてオフラインで使用可能にする。", - "download_images_description": "貼り付けられたHTMLにはオンライン画像への参照が含まれていることがありますが、Triliumはそれらの参照を見つけて画像をダウンロードし、オフラインで利用できるようにします。", - "enable_image_compression": "画像の圧縮を有効にする", - "max_image_dimensions": "画像の最大幅/高さ(この設定を超えると画像はリサイズされます)。", + "download_images_automatically": "画像を自動的にダウンロードする。", + "download_images_description": "貼り付けた HTML 内の参照画像をダウンロードし、オフラインでも利用できるようにする。", + "enable_image_compression": "画像の圧縮", + "max_image_dimensions": "画像の最大サイズ", "max_image_dimensions_unit": "ピクセル", - "jpeg_quality_description": "JPEGの品質(10 - 最低品質、100 - 最高品質、50 - 80を推奨)" + "jpeg_quality_description": "推奨範囲は50~85です。値が低いほどファイルサイズが小さくなり、値が高いほどディテールが保持されます。", + "enable_image_compression_description": "画像をアップロードまたは貼り付ける際に、画像を圧縮およびサイズ変更します。", + "max_image_dimensions_description": "このサイズを超える画像は自動的にサイズ変更されます", + "jpeg_quality": "JPEG 画質", + "ocr_section_title": "テキスト抽出(OCR)", + "ocr_related_content_languages": "コンテンツ言語(テキスト抽出に使用)", + "ocr_auto_process": "新しいファイルを自動処理", + "ocr_auto_process_description": "新しくアップロードまたは貼り付けられたファイルからテキストを自動的に抽出します。", + "ocr_min_confidence": "最低限の信頼度", + "ocr_confidence_description": "この信頼度閾値以上のテキストのみを抽出します。信頼度が低いほど抽出されるテキストの量は増えますが、精度が低下する可能性があります。", + "batch_ocr_title": "既存ファイルの処理", + "batch_ocr_description": "ノート内の既存の画像、PDF、Office 文書からテキストを抽出します。ファイル数によっては時間がかかる場合があります。", + "batch_ocr_start": "バッチ処理を開始します", + "batch_ocr_starting": "バッチ処理を開始しています...", + "batch_ocr_progress": "{{total}} ファイルのうち {{processed}} ファイルを処理中...", + "batch_ocr_completed": "バッチ処理が完了しました!{{processed}} ファイルを処理しました。", + "batch_ocr_error": "バッチ処理中にエラーが発生しました: {{error}}" }, "search_engine": { "title": "検索エンジン", @@ -915,7 +933,7 @@ "custom_name_label": "カスタム検索エンジンの名前", "custom_name_placeholder": "カスタム検索エンジンの名前", "custom_url_label": "カスタム検索エンジンのURLには、検索語句のプレースホルダーとして {keyword} を含める必要があります。", - "custom_url_placeholder": "カスタム検索エンジンのurl", + "custom_url_placeholder": "検索エンジンの URL をカスタマイズ", "save_button": "保存" }, "tray": { @@ -1011,9 +1029,6 @@ "description": "これらのオプションはデスクトップビルドにのみ適用され、ブラウザはそれぞれのネイティブスペルチェックを使用します。", "enable": "スペルチェックを有効", "language_code_label": "言語コード", - "language_code_placeholder": "例えば \"en-US\", \"de-AT\"", - "multiple_languages_info": "複数の言語はカンマで区切ることができます。例: \"en-US, de-DE, cs\"。 ", - "available_language_codes_label": "使用可能な言語コード:", "restart-required": "スペルチェックオプションの変更は、アプリケーションの再起動後に有効になります。" }, "sync_2": { @@ -1102,7 +1117,7 @@ "calendar_root": "dayノートのルートとして使用するノートをマークします。このようにマークできるのは 1 つだけです。", "archived": "このラベルの付いたノートは、デフォルトでは検索結果に表示されません (ジャンプ先、リンクの追加ダイアログなどにも表示されません)。", "exclude_from_export": "ノート(サブツリーを含む)はノートのエクスポートには含まれません", - "run": "どのイベントでスクリプトを実行するかを定義します。可能な値は次の通り:\n
    \n
  • frontendStartup - Trilium フロントエンドが起動(または更新)されたとき。モバイルは除く
  • \n
  • mobileStartup - モバイルで Trilium フロントエンドが起動(または更新)されたとき。
  • \n
  • backendStartup - Trilium バックエンドが起動したとき
  • \n
  • hourly - 1時間に1回実行します。 runAtHour というラベルを追加して、実行時刻を指定できます。
  • \n
  • daily - 1日に1回実行
  • \n
", + "run": "スクリプトを実行するイベントを定義します。指定可能な値は以下の通りです:\n
    \n
  • frontendStartup - Trilium フロントエンドの起動時(または更新時)に実行されます。モバイルでは実行されません。
  • \n
  • mobileStartup - モバイルでの Trilium フロントエンドの起動時(または更新時)に実行されます。
  • \n
  • backendStartup - Trilium バックエンドの起動時。
  • \n
  • hourly - 1時間ごとに実行。 runAtHour というラベルを追加することで、実行時刻を指定できます。
  • \n
  • daily - 1日に1回実行。
  • \n
", "run_on_instance": "どの Trilium インスタンスでこれを実行するかを定義します。デフォルトはすべてのインスタンスです。", "run_at_hour": "何時に実行するかを指定します。 #run=hourly と併用してください。1日に複数回実行したい場合は、複数回定義できます。", "disable_inclusion": "このラベルが付いたスクリプトは親スクリプトの実行には含まれません。", @@ -1390,7 +1405,7 @@ }, "content_language": { "title": "コンテンツの言語", - "description": "読み取り専用または編集可能なテキストノートの基本プロパティセクションの言語選択に表示する言語を 1 つ以上選択します。これにより、スペルチェックや右から左へのサポートなどの機能が利用できるようになります。" + "description": "読み取り専用または編集可能なテキストノートの基本プロパティセクションの言語選択に表示する言語を 1 つ以上選択してください。これにより、スペルチェック、右から左へのサポート、テキスト抽出(OCR)などの機能が利用できるようになります。" }, "png_export_button": { "button_title": "図をPNG形式でエクスポート" @@ -2050,7 +2065,9 @@ "title": "実験オプション", "disclaimer": "これらのオプションは試験的なもので、動作が不安定になる可能性があります。注意してご使用ください。", "new_layout_name": "新しいレイアウト", - "new_layout_description": "よりモダンな外観と使いやすさが向上した新しいレイアウトをお試しください。今後のリリースで大幅な変更が加えられる可能性があります。" + "new_layout_description": "よりモダンな外観と使いやすさが向上した新しいレイアウトをお試しください。今後のリリースで大幅な変更が加えられる可能性があります。", + "llm_name": "AI / LLM チャット", + "llm_description": "大規模言語モデルを活用した AI チャットサイドバーと LLM チャットノートを有効にします。" }, "breadcrumb_badges": { "read_only_explicit": "読み取り専用", @@ -2215,5 +2232,115 @@ "sample_xy": "XY チャート", "sample_venn": "ベン図", "sample_ishikawa": "石川図" + }, + "llm_chat": { + "placeholder": "メッセージを入力してください…", + "send": "送信", + "sending": "送信中...", + "empty_state": "下記にメッセージを入力して会話を始めましょう。", + "searching_web": "ウェブ検索中…", + "web_search": "ウェブ検索", + "note_tools": "ノートへのアクセス", + "sources": "ソース", + "extended_thinking": "思考を拡張", + "legacy_models": "レガシーモデル", + "thinking": "思考中...", + "thought_process": "思考プロセス", + "tool_calls": "{{count}} 回のツール呼び出し", + "input": "入力", + "result": "結果", + "error": "エラー", + "tool_error": "失敗", + "total_tokens": "{{total}} トークン", + "tokens_detail": "{{prompt}} プロンプト + {{completion}} コンプリーション", + "tokens_used": "{{prompt}} プロンプト + {{completion}} コンプリーション = {{total}} トークン", + "tokens_used_with_cost": "{{prompt}} プロンプト + {{completion}} コンプリーション = {{total}} トークン (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} プロンプト + {{completion}} コンプリーション = {{total}} トークン", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} プロンプト + {{completion}} コンプリーション = {{total}} トークン (~${{cost}})", + "tokens": "トークン", + "context_used": "{{percentage}} % 使用済み", + "note_context_enabled": "クリックしてノートのコンテキストを無効にする: {{title}}", + "note_context_disabled": "クリックして現在のノートをコンテキストに含める", + "no_provider_message": "AI プロバイダーが設定されていません。チャットを開始するには、プロバイダーを追加してください。", + "add_provider": "AI プロバイダーを追加", + "sources_summary": "{{count}} 件のソースを {{sites}} サイトから取得" + }, + "sidebar_chat": { + "title": "AI チャット", + "launcher_title": "AI チャットを開く", + "new_chat": "新しいチャットを開始", + "save_chat": "チャットをノートに保存", + "empty_state": "会話を開始", + "history": "チャット履歴", + "recent_chats": "最近のチャット", + "no_chats": "過去のチャットはありません" + }, + "mind-map": { + "addChild": "子ノードを追加", + "addParent": "親ノードを追加", + "addSibling": "兄弟ノードを追加", + "removeNode": "ノードを削除", + "focus": "フォーカスモード", + "cancelFocus": "フォーカスモードを解除", + "moveUp": "上に移動", + "moveDown": "下に移動", + "link": "リンク", + "linkBidirectional": "双方向リンク", + "clickTips": "対象ノードをクリックしてください", + "summary": "概要" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "AI と大規模言語モデルの連携設定をします。", + "add_provider": "プロバイダーを追加", + "add_provider_title": "AI プロバイダーを追加", + "configured_providers": "設定済みプロバイダー", + "no_providers_configured": "まだプロバイダーが設定されていません。", + "provider_name": "名前", + "provider_type": "プロバイダー", + "actions": "アクション", + "delete_provider": "削除", + "delete_provider_confirmation": "プロバイダー \"{{name}}\" を削除してもよろしいですか?", + "api_key": "API キー", + "api_key_placeholder": "API キーを入力してください", + "cancel": "キャンセル", + "feature_not_enabled": "AI 連携機能を使用するには、「設定」→「高度」→「実験的機能」で LLM 実験的機能を有効にしてください。", + "mcp_title": "MCP(モデル コンテキスト プロトコル)", + "mcp_enabled": "MCP サーバー", + "mcp_enabled_description": "AI コーディングアシスタント(例:Claude Code、GitHub Copilot)がノートを読み取って変更できるように、モデルコンテキストプロトコル(MCP)エンドポイントを公開します。このエンドポイントは localhost からのみアクセス可能です。", + "mcp_endpoint_title": "エンドポイント URL", + "mcp_endpoint_description": "この URL を AI アシスタントの MCP 設定に追加してください", + "tools": { + "search_notes": "ノートを検索", + "get_note": "ノートを取得", + "get_note_content": "ノートの内容を取得", + "update_note_content": "ノートの内容を更新", + "append_to_note": "ノートに追記", + "create_note": "ノートを作成", + "get_attributes": "複数の属性を取得", + "get_attribute": "属性を取得", + "set_attribute": "属性を設定", + "delete_attribute": "属性を削除", + "get_child_notes": "子ノートを取得", + "get_subtree": "サブツリーを取得", + "load_skill": "スキルを読み込む", + "web_search": "Web 検索", + "note_in_parent": "", + "get_attachment": "添付ファイルを取得", + "get_attachment_content": "添付ファイルの内容を読み取る" + } + }, + "ocr": { + "extracted_text": "抽出されたテキスト(OCR)", + "extracted_text_title": "抽出されたテキスト(OCR)", + "loading_text": "OCR テキストを読み込んでいます…", + "no_text_available": "OCR テキストが見つかりません", + "no_text_explanation": "このノートは OCR テキスト抽出処理が行われなかったか、テキストが見つかりませんでした。", + "failed_to_load": "OCR テキストの読み込みに失敗しました", + "process_now": "OCR 処理", + "processing": "処理中…", + "processing_started": "OCR 処理が開始されました。しばらくお待ちいただき、ページを更新してください。", + "processing_failed": "OCR 処理の開始に失敗しました", + "view_extracted_text": "抽出されたテキスト(OCR)を表示" } } diff --git a/apps/client/src/translations/pl/translation.json b/apps/client/src/translations/pl/translation.json index 3cd2d35be3..2cf8aa62f4 100644 --- a/apps/client/src/translations/pl/translation.json +++ b/apps/client/src/translations/pl/translation.json @@ -1665,9 +1665,6 @@ "description": "Te opcje dotyczą tylko wersji desktopowych, przeglądarki będą używać własnego natywnego sprawdzania pisowni.", "enable": "Włącz sprawdzanie pisowni", "language_code_label": "Kod(y) języka", - "language_code_placeholder": "na przykład \"pl-PL\", \"en-US\"", - "multiple_languages_info": "Wiele języków można oddzielić przecinkiem, np. \"en-US, de-DE, pl\". ", - "available_language_codes_label": "Dostępne kody języków:", "restart-required": "Zmiany w opcjach sprawdzania pisowni wejdą w życie po ponownym uruchomieniu aplikacji." }, "sync_2": { diff --git a/apps/client/src/translations/pt/translation.json b/apps/client/src/translations/pt/translation.json index b28d38e414..095e38c257 100644 --- a/apps/client/src/translations/pt/translation.json +++ b/apps/client/src/translations/pt/translation.json @@ -1435,9 +1435,6 @@ "description": "Estas opções aplicam-se apenas às versões desktop; os navegadores usarão a sua própria verificação ortográfica nativa.", "enable": "Ativar verificação ortográfica", "language_code_label": "Código(s) de idioma", - "language_code_placeholder": "por exemplo \"en-US\", \"de-AT\", \"pt-BR\"", - "multiple_languages_info": "Múltiplos idiomas podem ser separados por vírgula, por exemplo: \"en-US, de-DE, pt-BR, cs\". ", - "available_language_codes_label": "Códigos de idioma disponíveis:", "restart-required": "As alterações nas opções de verificação ortográfica terão efeito após reiniciar a aplicação." }, "sync_2": { diff --git a/apps/client/src/translations/pt_br/translation.json b/apps/client/src/translations/pt_br/translation.json index 24c896984f..bd7183f2f7 100644 --- a/apps/client/src/translations/pt_br/translation.json +++ b/apps/client/src/translations/pt_br/translation.json @@ -1944,9 +1944,6 @@ "description": "Estas opções se aplicam apenas às versões desktop; os navegadores usarão sua própria verificação ortográfica nativa.", "enable": "Habilitar verificação ortográfica", "language_code_label": "Código(s) de idioma", - "language_code_placeholder": "por exemplo \"en-US\", \"de-AT\", \"pt-BR\"", - "multiple_languages_info": "Múltiplos idiomas podem ser separados por vírgula, por exemplo: \"en-US, de-DE, pt-BR, cs\". ", - "available_language_codes_label": "Códigos de idioma disponíveis:", "restart-required": "As alterações nas opções de verificação ortográfica terão efeito após reiniciar o aplicativo." }, "sync_2": { diff --git a/apps/client/src/translations/ro/translation.json b/apps/client/src/translations/ro/translation.json index 9e12892d38..49c4601581 100644 --- a/apps/client/src/translations/ro/translation.json +++ b/apps/client/src/translations/ro/translation.json @@ -875,7 +875,7 @@ "print_note": "Imprimare notiță", "re_render_note": "Reinterpretare notiță", "save_revision": "Salvează o nouă revizie", - "advanced": "Advansat", + "advanced": "Avansat", "search_in_note": "Caută în notiță", "convert_into_attachment_failed": "Nu s-a putut converti notița „{{title}}”.", "convert_into_attachment_successful": "Notița „{{title}}” a fost convertită în atașament.", @@ -1237,12 +1237,9 @@ "title": "titlu" }, "spellcheck": { - "available_language_codes_label": "Coduri de limbă disponibile:", "description": "Aceste opțiuni se aplică doar pentru aplicația de desktop, navigatoarele web folosesc propriile corectoare ortografice.", "enable": "Activează corectorul ortografic", "language_code_label": "Codurile de limbă", - "language_code_placeholder": "de exemplu „en-US”, „de-AT”", - "multiple_languages_info": "Mai multe limbi pot fi separate prin virgulă, e.g. \"en-US, de-DE, cs\". ", "title": "Corector ortografic", "restart-required": "Schimbările asupra setărilor corectorului ortografic vor fi aplicate după restartarea aplicației." }, diff --git a/apps/client/src/translations/ru/translation.json b/apps/client/src/translations/ru/translation.json index 818297e172..780e5cfcef 100644 --- a/apps/client/src/translations/ru/translation.json +++ b/apps/client/src/translations/ru/translation.json @@ -194,7 +194,7 @@ "row-insert-child": "Создать дочернюю заметку", "row-insert-below": "Добавить строку ниже", "row-insert-above": "Добавить строку выше", - "new-column-relation": "Связь" + "new-column-relation": "Отношение" }, "add_label": { "add_label": "Добавить метку", @@ -465,13 +465,13 @@ "related_notes_title": "Другие заметки с этой меткой", "label": "Метка", "label_definition": "Определение метки", - "relation": "Отношение", + "relation": "Детали отношения", "relation_definition": "Определение отношения", "disable_versioning": "отключает автоматическое версионирование. Полезно, например, для больших, но неважных заметок, например, для больших JS-библиотек, используемых для написания скриптов", "calendar_root": "отмечает заметку, которая должна использоваться в качестве корневой для заметок дня. Только одна должна быть отмечена как таковая.", "archived": "заметки с этой меткой не будут отображаться в результатах поиска по умолчанию (а также в диалоговых окнах «Перейти к», «Добавить ссылку» и т. д.).", "exclude_from_export": "заметки (с их поддеревьями) не будут включены ни в один экспорт заметок", - "run": "определяет, при каких событиях должен запускаться скрипт. Возможные значения:
    \n
  • frontendStartup — при запуске (или обновлении) фронтенда Trilium, но не на мобильном устройстве.
  • \n
  • mobileStartup — при запуске (или обновлении) фронтенда Trilium на мобильном устройстве.
  • \n
  • backendStartup — при запуске бэкенда Trilium.
  • \n
  • hourly — запускать каждый час. Для указания времени можно использовать дополнительную метку runAtHour.
  • \n
  • daily — запускать раз в день.
", + "run": "определяет, при каких событиях должен запускаться скрипт. Возможные значения:\n
    \n
  • frontendStartup — при запуске (или обновлении) фронтенда Trilium, но не на мобильном устройстве.
  • \n
  • mobileStartup — при запуске (или обновлении) фронтенда Trilium на мобильном устройстве.
  • \n
  • backendStartup — при запуске бэкенда Trilium.
  • \n
  • hourly — запускать каждый час. Для указания времени можно использовать дополнительную метку runAtHour.
  • \n
  • daily — запускать раз в день.
  • \n
", "run_on_instance": "Определить, на каком экземпляре Trilium это должно выполняться. По умолчанию — для всех экземпляров.", "run_at_hour": "В какой час это должно выполняться? Следует использовать вместе с #run=hourly. Можно задать несколько раз для большего количества запусков в течение дня.", "disable_inclusion": "скрипты с этой меткой не будут включены в выполнение родительского скрипта.", @@ -495,7 +495,7 @@ "is_owned_by_note": "принадлежит заметке", "and_more": "... и ещё {{count}}.", "app_theme": "отмечает заметки CSS, которые являются полноценными темами Trilium и, таким образом, доступны в опциях Trilium.", - "title_template": "Заголовок по умолчанию для заметок, создаваемых как дочерние элементы данной заметки. Значение вычисляется как строка JavaScript\n и, таким образом, может быть дополнено динамическим контентом с помощью внедренных переменных now и parentNote. Примеры:\n \n
    \n
  • Литературные произведения ${parentNote.getLabelValue('authorName')}
  • \n
  • Лог для ${now.format('YYYY-MM-DD HH:mm:ss')}
  • \n
\n \n Подробности см. в вики, документации API для parentNote и now.", + "title_template": "заголовок по умолчанию для заметок, создаваемых как дочерние элементы текущей. Значение вычисляется как строка JavaScript \n и может быть дополнено динамическим контентом с помощью внедренных переменных now и parentNote. Например:\n \n
    \n
  • Литературные произведения ${parentNote.getLabelValue('authorName')}
  • \n
  • Лог для ${now.format('YYYY-MM-DD HH:mm:ss')}
  • \n
\n \n Подробности см. в вики, документации API для parentNote и now.", "icon_class": "значение этой метки добавляется в виде CSS-класса к значку в дереве, что помогает визуально различать заметки в дереве. Примером может служить bx bx-home — значки берутся из boxicons. Может использоваться в шаблонах заметок.", "share_favicon": "Заметка о фавиконе должна быть размещена на странице общего доступа. Обычно её назначают корневой папке общего доступа и делают наследуемой. Заметка о фавиконе также должна находиться в поддереве общего доступа. Рассмотрите возможность использования атрибута 'share_hidden_from_tree'.", "inbox": "расположение папки «Входящие» по умолчанию для новых заметок — при создании заметки с помощью кнопки «Новая заметка» на боковой панели заметки будут созданы как дочерние заметки в заметке, помеченной меткой #inbox.", @@ -548,7 +548,8 @@ "render_note": "заметки типа «Рендер HTML» будут отображаться с использованием кодовой заметки (HTML или скрипта), и необходимо указать с помощью этой связи, какую заметку следует отобразить", "widget_relation": "заметка, на которую ссылается отношение будет выполнена и отображена как виджет на боковой панели", "share_js": "JavaScript-заметка, которая будет добавлена на страницу общего доступа. JavaScript-заметка также должна находиться в общем поддереве. Рекомендуется использовать 'share_hidden_from_tree'.", - "other_notes_with_name": "Другие заметки с {{attributeType}} названием \"{{attributeName}}\"" + "other_notes_with_name": "Другие заметки с {{attributeType}} названием \"{{attributeName}}\"", + "textarea": "Многострочный текст" }, "command_palette": { "configure_launch_bar_description": "Откройте конфигурацию панели запуска, чтобы добавить или удалить элементы.", @@ -835,7 +836,8 @@ "task-list": "Список задач", "confirm-change": "Не рекомендуется менять тип заметки, если её содержимое не пустое. Вы всё равно хотите продолжить?", "ai-chat": "Чат с ИИ", - "spreadsheet": "Электронная таблица" + "spreadsheet": "Электронная таблица", + "llm-chat": "Чат с ИИ" }, "tree-context-menu": { "open-in-popup": "Быстрое редактирование", @@ -1015,7 +1017,7 @@ "open_sql_console_history": "Открыть историю консоли SQL", "show_shared_notes_subtree": "Поддерево общедоступных заметок", "switch_to_mobile_version": "Перейти на мобильную версию", - "switch_to_desktop_version": "Переключиться на версию для ПК", + "switch_to_desktop_version": "Переключиться на версию для компьютера", "new-version-available": "Доступно обновление", "download-update": "Обновить до {{latestVersion}}", "search_notes": "Поиск заметок" @@ -1637,11 +1639,11 @@ "start_dragging_relations": "Начните перетягивать отношения отсюда на другую заметку." }, "vacuum_database": { - "title": "Сжатие базы данных", - "description": "Это приведет к перестройке базы данных, что, как правило, приводит к уменьшению размера файла базы данных. Данные затронуты не будут.", - "button_text": "Сжать базу данных", - "vacuuming_database": "Сжатие БД...", - "database_vacuumed": "База данных была сжата" + "title": "Уменьшение размера файла базы данных", + "description": "Это приведет к перестройке базы данных, что, скорее всего, уменьшит размер её файла. Данные не будут изменены.", + "button_text": "Уменьшить размер файла базы данных", + "vacuuming_database": "Уменьшение размера файла базы данных...", + "database_vacuumed": "База данных была перестроена" }, "vim_key_bindings": { "use_vim_keybindings_in_code_notes": "Сочетания клавиш Vim", @@ -1677,10 +1679,7 @@ "title": "Проверка орфографии", "enable": "Включить проверку орфографии", "language_code_label": "Код(ы) языков", - "multiple_languages_info": "Несколько языков можно разделять запятой, например, \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Доступные коды языков:", "restart-required": "Изменения параметров проверки орфографии вступят в силу после перезапуска приложения.", - "language_code_placeholder": "например \"en-US\", \"de-AT\"", "description": "Эти параметры применимы только для десктопных сборок, браузеры будут использовать собственную встроенную проверку орфографии." }, "attribute_editor": { @@ -1763,8 +1762,8 @@ "database_integrity_check": { "title": "Проверка целостности базы данных", "description": "Это позволит проверить базу данных на предмет повреждений на уровне SQLite. Это может занять некоторое время в зависимости от размера базы данных.", - "check_button": "Проверить целостность БД", - "checking_integrity": "Проверка целостности БД...", + "check_button": "Проверить целостность базы данных", + "checking_integrity": "Проверка целостности базы данных...", "integrity_check_succeeded": "Проверка целостности прошла успешно - проблем не обнаружено.", "integrity_check_failed": "Проверка целостности завершена с ошибками: {{results}}" }, @@ -2115,7 +2114,9 @@ "new_layout_description": "Попробуйте новый современный и удобный дизайн. В будущих обновлениях возможны его существенные изменения.", "new_layout_name": "Новый дизайн", "title": "Экспериментальные параметры", - "disclaimer": "Эти параметры экспериментальные и могут повлиять на стабильность. Используйте с осторожностью." + "disclaimer": "Эти параметры экспериментальные и могут повлиять на стабильность. Используйте с осторожностью.", + "llm_name": "ИИ / LLM чат", + "llm_description": "Включить боковую панель чата с ИИ и заметки, созданные на основе больших языковых моделей (LLM)." }, "popup-editor": { "maximize": "Переключить на полный редактор" @@ -2197,5 +2198,123 @@ }, "setup_form": { "more_info": "Узнать больше" + }, + "media": { + "play": "Воспроизвести (пробел)", + "pause": "Пауза (пробел)", + "back-10s": "Назад на 10 секунд (стрелка влево)", + "forward-30s": "Вперёд на 30 секунд", + "mute": "Выключить звук (M)", + "unmute": "Включить звук (M)", + "playback-speed": "Скорость проигрывания", + "loop": "Зациклить", + "disable-loop": "Отключить зацикливание", + "rotate": "Повернуть", + "picture-in-picture": "Картинка в картинке", + "exit-picture-in-picture": "Выйти из режима \"картинка в картинке\"", + "fullscreen": "Режим полного экрана (F)", + "exit-fullscreen": "Выйти из режима полного экрана", + "unsupported-format": "Предпросмотр недоступен для данного формата файла:\n{{mime}}", + "zoom-to-fit": "Заполнить путём масштабирования", + "zoom-reset": "Сбросить заполнение путём масштабирования" + }, + "llm_chat": { + "placeholder": "Введите сообщение...", + "send": "Отправить", + "sending": "Отправка...", + "empty_state": "Начните общение, написав сообщение в поле ниже.", + "searching_web": "Поиск в сети...", + "web_search": "Поиск в сети", + "note_tools": "Доступ к заметке", + "sources": "Источники", + "extended_thinking": "Расширенное мышление", + "legacy_models": "Устаревшие модели", + "thinking": "Обработка...", + "thought_process": "Процесс обработки", + "tool_calls": "{{count}} вызов(а/ов) инструмента", + "input": "Ввод", + "result": "Результат", + "error": "Ошибка", + "tool_error": "ошибка", + "total_tokens": "{{total}} токен(а/ов)", + "tokens": "токены", + "context_used": "{{percentage}}% использовано", + "note_context_enabled": "Нажмите, чтобы отключить контекст заметки: {{title}}", + "note_context_disabled": "Нажмите, чтобы включить текущую заметку в контекст", + "no_provider_message": "Не выбран провайдер ИИ. Добавьте его для начала общения.", + "add_provider": "Добавить провайдера ИИ", + "tokens_detail": "{{prompt}} (промт) + {{completion}} (ответ)", + "tokens_used": "{{prompt}} (промт) + {{completion}} (ответ) = {{total}} токен(а/ов)", + "tokens_used_with_cost": "{{prompt}} (промт) + {{completion}} (ответ) = {{total}} токен(а/ов) (~${{cost}})", + "tokens_used_with_model": "{{model}}: {{prompt}} (промт) + {{completion}} (ответ) = {{total}} токен(а/ов)", + "tokens_used_with_model_and_cost": "{{model}}: {{prompt}} (промт) + {{completion}} (ответ) = {{total}} токен(а/ов) (~${{cost}})" + }, + "sidebar_chat": { + "title": "Чат с ИИ", + "launcher_title": "Чат с Open AI", + "new_chat": "Начать новый чат", + "save_chat": "Сохранить чат в заметках", + "empty_state": "Начать общение", + "history": "История чата", + "recent_chats": "Недавние чаты", + "no_chats": "Нет предыдущих чатов" + }, + "mermaid": { + "placeholder": "Введите содержимое вашей Mermaid диаграммы или используйте один из примеров ниже.", + "sample_diagrams": "Примеры диаграм:", + "sample_flowchart": "Блок-схема", + "sample_class": "Диаграмма классов", + "sample_sequence": "Диаграмма последовательностей", + "sample_entity_relationship": "Диаграмма \"Сущность — связь\"", + "sample_state": "Диаграмма состояний", + "sample_mindmap": "Ментальная карта", + "sample_architecture": "Архитектурная схема", + "sample_block": "Структурная схема", + "sample_gantt": "Диаграмма Ганта", + "sample_git": "Git", + "sample_kanban": "Канбан", + "sample_ishikawa": "Диаграмма Исикавы", + "sample_c4": "C4", + "sample_packet": "Диаграмма сетевых пакетов", + "sample_pie": "Круговая диаграмма", + "sample_quadrant": "Квадрантная диаграмма", + "sample_radar": "Радиолокационная схема", + "sample_requirement": "Диаграмма зависимостей", + "sample_sankey": "Диаграмма Сэнки", + "sample_timeline": "Временная диаграмма", + "sample_treemap": "Древовидная диаграмма", + "sample_user_journey": "Карта пользовательского пути", + "sample_xy": "XY", + "sample_venn": "Диаграмма Венна" + }, + "mind-map": { + "addChild": "Добавить дочерний элемент", + "addParent": "Добавить родительский элемент", + "addSibling": "Добавить элемент на том же уровне", + "removeNode": "Удалить узел", + "focus": "Режим фокусировки", + "cancelFocus": "Отключить режим фокусировки", + "moveUp": "Передвинуть выше", + "moveDown": "Передвинуть ниже", + "link": "Связь", + "linkBidirectional": "Двусторонняя связь", + "clickTips": "Пожалуйста, нажмите на целевой узел", + "summary": "Сводка" + }, + "llm": { + "settings_title": "ИИ / LLM", + "settings_description": "Настроить интеграции ИИ и больших языковых моделей.", + "add_provider": "Добавить провайдера", + "add_provider_title": "Добавить провайдера ИИ", + "configured_providers": "Настроенные провайдеры", + "no_providers_configured": "Ещё нет настроенных провайдеров.", + "provider_name": "Название", + "provider_type": "Провайдер", + "actions": "Действия", + "delete_provider": "Удалить", + "delete_provider_confirmation": "Вы уверены, что желаете удалить провайдера \"{{name}}\"?", + "api_key": "Ключ API", + "api_key_placeholder": "Введите ваш ключ API", + "cancel": "Отмена" } } diff --git a/apps/client/src/translations/tr/translation.json b/apps/client/src/translations/tr/translation.json index 2f534ba12e..397675e76b 100644 --- a/apps/client/src/translations/tr/translation.json +++ b/apps/client/src/translations/tr/translation.json @@ -23,10 +23,33 @@ "close": "Kapat", "delete_notes_preview": "Not önizlemesini sil", "delete_all_clones_description": "Tüm klonları da sil (son değişikliklerden geri alınabilir)", - "erase_notes_description": "Normal (yazılımsal) silme işlemi, notları yalnızca silinmiş olarak işaretler ve belirli bir süre içinde (son değişiklikler iletişim kutusunda) geri alınabilir. Bu seçeneği işaretlemek, notları hemen siler ve notların geri alınması mümkün olmaz." + "erase_notes_description": "Normal (yazılımsal) silme işlemi, notları yalnızca silinmiş olarak işaretler ve belirli bir süre içinde (son değişiklikler iletişim kutusunda) geri alınabilir. Bu seçeneği işaretlemek, notları hemen siler ve notların geri alınması mümkün olmaz.", + "erase_notes_warning": "Notları, tüm kopyaları da dahil olmak üzere kalıcı olarak silin (geri alınamaz). Bu işlem, uygulamanın yeniden yüklenmesine neden olacaktır.", + "notes_to_be_deleted": "Aşağıdaki notlar silinecektir. ({{notesCount}})", + "no_note_to_delete": "Hiçbir not silinmeyecek (sadece kopyaları silinecek).", + "broken_relations_to_be_deleted": "Aşağıdaki ilişkiler koparılacak ve silinecektir ({{ relationCount}})", + "cancel": "İptal", + "ok": "Tamam", + "deleted_relation_text": "{{- note}} (silinecek) notu, {{- source}} kaynağından kaynaklanan {{- relation}} ilişkisi tarafından referans alınmaktadır." }, "export": { - "close": "Kapat" + "close": "Kapat", + "export_note_title": "Notu dışa aktar", + "export_type_subtree": "Bu not ve tüm torunları", + "format_html": "HTML - tüm biçimlendirmeyi koruduğu için önerilir", + "format_html_zip": "ZIP arşivindeki HTML dosyaları - tüm biçimlendirmeyi koruduğu için bu yöntem önerilir.", + "format_markdown": "Markdown - bu, biçimlendirmenin büyük kısmını korur.", + "format_opml": "OPML - yalnızca metin için anahat değişim biçimi. Biçimlendirme, resimler ve dosyalar dahil edilmez.", + "opml_version_1": "OPML v1.0 - yalnızca düz metin", + "opml_version_2": "OPML v2.0 - HTML de destekler", + "export_type_single": "Yalnızca bu not, alt öğeleri olmadan", + "export": "Dışa aktar", + "choose_export_type": "Lütfen önce dışa aktarma türünü seçin", + "export_status": "Dışa aktarma durumu", + "export_in_progress": "Dışa aktarma devam ediyor: {{progressCount}}", + "export_finished_successfully": "Dışa aktarma başarıyla tamamlandı.", + "format_pdf": "PDF - yazdırma veya paylaşım amaçları için.", + "share-format": "Web yayını için HTML - paylaşılan notlarda kullanılan temayı kullanır, ancak statik bir web sitesi olarak yayınlanabilir." }, "import": { "chooseImportFile": "İçe aktarım dosyası", @@ -58,7 +81,9 @@ "widget-render-error": { "title": "Özel React widget'ı çizilirken sorun yaşandı" }, - "scripting-error": "Kullanıcı tanımlı betik hatası: {{title}}" + "scripting-error": "Kullanıcı tanımlı betik hatası: {{title}}", + "widget-missing-parent": "Özel widget'ın zorunlu '{{property}}' özelliği tanımlanmamıştır.\n\nBu komut dosyasının bir kullanıcı arayüzü öğesi olmadan çalıştırılması gerekiyorsa, bunun yerine '#run=frontendStartup' kullanın.", + "open-script-note": "Komut dosyası notunu aç" }, "add_link": { "add_link": "Bağlantı ekle", @@ -103,5 +128,15 @@ "are_you_sure_remove_note": "\"{{title}}\" notunu ilişki haritasından kaldırmak istediğinize emin misiniz?. ", "also_delete_note": "Notu da sil", "if_you_dont_check": "Bunu işaretlemezseniz, not yalnızca ilişki haritasından kaldırılacaktır." + }, + "help": { + "title": "Özet tablo", + "editShortcuts": "Klavye kısayollarını düzenle", + "noteNavigation": "Not içinde gezinme", + "goUpDown": "Notlar listesinde yukarı/aşağı gitmek", + "collapseExpand": "düğümü daralt/genişlet", + "notSet": "ayarlanmamış", + "goBackForwards": "tarihte geri/ileri git", + "showJumpToNoteDialog": "\"Şuraya Git\" iletişim kutusunu göster" } } diff --git a/apps/client/src/translations/tw/translation.json b/apps/client/src/translations/tw/translation.json index 35c8dbff1b..33076b3332 100644 --- a/apps/client/src/translations/tw/translation.json +++ b/apps/client/src/translations/tw/translation.json @@ -368,7 +368,7 @@ "calendar_root": "標記應用作為每日筆記的根。只應標記一個筆記。", "archived": "含有此標籤的筆記預設在搜尋結果中不可見(也適用於跳轉至、新增連結對話方塊等)。", "exclude_from_export": "筆記(及其子階層)不會包含在任何匯出的筆記中", - "run": "定義腳本應運行的事件。可能的值包括:\n
    \n
  • frontendStartup - Trilium前端啟動時(或重新整理時),但不會在移動端執行。
  • \n
  • mobileStartup - Trilium前端啟動時(或重新整理時), 在行動端會執行。
  • \n
  • backendStartup - Trilium後端啟動時
  • \n
  • hourly - 每小時運行一次。您可以使用附加標籤runAtHour指定小時。
  • \n
  • daily - 每天運行一次
  • \n
", + "run": "定義腳本應運行的事件。可能的值包括:\n
    \n
  • frontendStartup - Trilium前端啟動時(或重新整理時),但不會在移動端執行。
  • \n
  • mobileStartup - Trilium前端啟動時(或重新整理時), 在行動端會執行。
  • \n
  • backendStartup - Trilium後端啟動時。
  • \n
  • hourly - 每小時運行一次。您可以使用附加標籤runAtHour指定小時。
  • \n
  • daily - 每天運行一次。
  • \n
", "run_on_instance": "定義應在哪個 Trilium 實例上運行。預設為所有實例。", "run_at_hour": "應在哪個小時運行。應與#run=hourly一起使用。可以多次定義,以便一天內運行多次。", "disable_inclusion": "含有此標籤的腳本不會包含在父腳本執行中。", @@ -706,7 +706,8 @@ "export_as_image": "匯出為圖片", "export_as_image_png": "PNG (點陣)", "export_as_image_svg": "SVG (向量)", - "note_map": "筆記地圖" + "note_map": "筆記地圖", + "view_ocr_text": "顯示 OCR 文字" }, "onclick_button": { "no_click_handler": "按鈕元件'{{componentId}}'沒有定義點擊時的處理方式" @@ -1196,12 +1197,28 @@ }, "images": { "images_section_title": "圖片", - "download_images_automatically": "自動下載圖片以供離線使用。", - "download_images_description": "貼上的 HTML 可能包含線上圖片的引用,Trilium 會找到這些引用並下載圖片,以便它們可以離線使用。", - "enable_image_compression": "啟用圖片壓縮", - "max_image_dimensions": "圖片的最大寬度 / 高度(超過此限制的圖片將會被縮放)。", - "jpeg_quality_description": "JPEG 質量(10 - 最差質量,100 最佳質量,建議為 50 - 85)", - "max_image_dimensions_unit": "像素" + "download_images_automatically": "自動下載圖片", + "download_images_description": "從貼上的 HTML 下載引用的線上圖片以便離線使用。", + "enable_image_compression": "圖片壓縮", + "max_image_dimensions": "最大圖片尺寸", + "jpeg_quality_description": "建議範圍為 50–85。較低的數值可縮小檔案大小,較高的數值則能保留更多細節。", + "max_image_dimensions_unit": "像素", + "enable_image_compression_description": "在上傳或貼上圖片時壓縮並調整圖片大小。", + "max_image_dimensions_description": "超過此尺寸的圖片將會自動調整大小。", + "jpeg_quality": "JPEG 品質", + "ocr_section_title": "文字擷取(OCR)", + "ocr_related_content_languages": "內容語言(用於文字擷取)", + "ocr_auto_process": "自動處理新檔案", + "ocr_auto_process_description": "自動從新上傳或貼上的檔案中擷取文字。", + "ocr_min_confidence": "最低信賴度", + "ocr_confidence_description": "僅提取高於此信賴度閾值的文字。較低的閾值雖能包含更多文字,但準確度可能較低。", + "batch_ocr_title": "處理現有檔案", + "batch_ocr_description": "從筆記中的所有現有圖片、PDF 檔案及 Office 文件中擷取文字。根據檔案數量多寡,此過程可能需要一些時間。", + "batch_ocr_start": "開始批次處理", + "batch_ocr_starting": "開始批次處理…", + "batch_ocr_progress": "正在處理 {{processed}} 個檔案,共 {{total}} 個檔案…", + "batch_ocr_completed": "批次處理完成!已處理 {{processed}} 個檔案。", + "batch_ocr_error": "批次處理期間發生錯誤:{{error}}" }, "attachment_erasure_timeout": { "attachment_erasure_timeout": "附件清理超時", @@ -1381,9 +1398,6 @@ "description": "這些選項僅適用於桌面版,瀏覽器將使用其原生的拼寫檢查功能。", "enable": "啟用拼寫檢查", "language_code_label": "語言代碼", - "language_code_placeholder": "例如 \"en-US\", \"de-AT\"", - "multiple_languages_info": "多種語言可以用逗號分隔,例如 \"en-US, de-DE, cs\"。 ", - "available_language_codes_label": "可用的語言代碼:", "restart-required": "拼寫檢查選項的更改將在應用重啟後生效。" }, "sync_2": { @@ -1497,7 +1511,8 @@ "new-feature": "新增", "collections": "集合", "ai-chat": "AI 聊天", - "spreadsheet": "試算表" + "spreadsheet": "試算表", + "llm-chat": "AI 對話" }, "protect_note": { "toggle-on": "保護筆記", @@ -1866,7 +1881,7 @@ }, "content_language": { "title": "內文語言", - "description": "選擇一種或多種語言作為唯讀或可編輯文字筆記的可選基本屬性,這將支援拼寫檢查或從右向左之類的功能。" + "description": "選擇一種或多種語言作為唯讀或可編輯文字筆記的可選基本屬性,這將支援拼寫檢查、從右向左及文字擷取 (OCR) 等功能。" }, "switch_layout_button": { "title_vertical": "將編輯面板移至底部", @@ -2046,7 +2061,9 @@ "title": "實驗性選項", "disclaimer": "這些選項屬實驗性質,可能導致系統不穩定。請謹慎使用。", "new_layout_name": "新版面配置", - "new_layout_description": "體驗全新版面配置,呈現更現代的外觀與更佳的使用體驗。在未來版本將進行大幅調整。" + "new_layout_description": "體驗全新版面配置,呈現更現代的外觀與更佳的使用體驗。在未來版本將進行大幅調整。", + "llm_name": "AI / LLM 對話", + "llm_description": "啟用由大語言模型驅動的 AI 聊天側邊欄及 LLM 聊天筆記。" }, "server": { "unknown_http_error_title": "與伺服器通訊錯誤", @@ -2229,6 +2246,121 @@ "sample_user_journey": "使用者旅程", "sample_xy": "XY 圖表", "sample_venn": "韋恩圖", - "sample_ishikawa": "魚骨圖" + "sample_ishikawa": "魚骨圖", + "sample_treeview": "樹狀視圖", + "sample_wardley": "沃德利地圖" + }, + "llm_chat": { + "placeholder": "輸入訊息…", + "send": "送出", + "sending": "正在送出…", + "empty_state": "請在下方輸入訊息,開啟對話。", + "searching_web": "正在搜尋網頁…", + "web_search": "網頁搜尋", + "note_tools": "筆記存取", + "sources": "來源", + "sources_summary": "來自 {{sites}} 個網站的 {{count}} 個來源", + "extended_thinking": "延伸思考", + "legacy_models": "傳統模型", + "thinking": "正在思考…", + "thought_process": "思考過程", + "tool_calls": "{{count}} 次工具調用", + "input": "輸入", + "result": "結果", + "error": "錯誤", + "tool_error": "失敗", + "total_tokens": "{{total}} 個詞元", + "tokens_detail": "{{prompt}} 提示詞 + {{completion}} 補全", + "tokens_used": "{{prompt}} 提示詞 + {{completion}} 補全 = {{total}} 個詞元", + "tokens_used_with_cost": "{{prompt}} 提示詞 + {{completion}} 補全 = {{total}} 個詞元(約 ${{cost}})", + "tokens_used_with_model": "{{model}}:{{prompt}} 提示詞 + {{completion}} 補全 = {{total}} 個詞元", + "tokens_used_with_model_and_cost": "{{model}}:{{prompt}} 提示詞 + {{completion}} 補全 = {{total}} 個詞元(約 ${{cost}})", + "tokens": "詞元", + "context_used": "已使用 {{percentage}}%", + "note_context_enabled": "點擊以禁用筆記上下文:{{title}}", + "note_context_disabled": "點擊將當前筆記納入上下文", + "no_provider_message": "尚未設定任何 AI 服務提供者。請新增一個以開始聊天。", + "add_provider": "新增 AI 提供者" + }, + "ocr": { + "processing_complete": "OCR 處理已完成。", + "processing_failed": "無法啟動 OCR 處理", + "text_filtered_low_confidence": "OCR 偵測到的信賴度為 {{confidence}}%,但因您的最低閾值設定為 {{threshold}}%,故該結果已被捨棄。", + "open_media_settings": "開啟設定", + "view_extracted_text": "檢視擷取的文字 (OCR)", + "extracted_text": "已擷取的文字 (OCR)", + "extracted_text_title": "已擷取的文字 (OCR)", + "loading_text": "正在載入 OCR 文字…", + "no_text_available": "無 OCR 文字可用", + "no_text_explanation": "此筆記尚未經過 OCR 文字擷取處理,或未找到任何文字。", + "failed_to_load": "載入 OCR 文字失敗", + "process_now": "處理 OCR", + "processing": "正在處理…", + "processing_started": "OCR 處理已開始。請稍候片刻並重新整理頁面。" + }, + "mind-map": { + "addChild": "新增子節點", + "addParent": "新增父節點", + "addSibling": "新增同級節點", + "removeNode": "刪除節點", + "focus": "專注模式", + "cancelFocus": "退出專注模式", + "moveUp": "上移", + "moveDown": "下移", + "link": "連結", + "linkBidirectional": "雙向連結", + "clickTips": "請點擊目標節點", + "summary": "摘要" + }, + "llm": { + "settings_title": "AI / LLM", + "settings_description": "設定 AI 及大型語言模型整合。", + "feature_not_enabled": "請前往「設定」→「進階」→「實驗性功能」啟用 LLM 實驗性功能,即可使用 AI 整合。", + "add_provider": "新增提供者", + "add_provider_title": "新增 AI 提供者", + "configured_providers": "已設定的提供者", + "no_providers_configured": "尚未設定任何提供者。", + "provider_name": "名稱", + "provider_type": "提供者", + "actions": "動作", + "delete_provider": "刪除", + "delete_provider_confirmation": "您確定要刪除提供者 \"{{name}}\" 嗎?", + "api_key": "API 金鑰", + "api_key_placeholder": "請輸入您的 API 金鑰", + "cancel": "取消", + "mcp_title": "MCP(模型上下文協定)", + "mcp_enabled": "MCP 伺服器", + "mcp_enabled_description": "公開一個模型上下文協定 (MCP) 端點,以便人工智慧編程助手(例如 Claude Code、GitHub Copilot)能夠讀取並修改您的筆記。此端點僅限從 localhost 存取。", + "mcp_endpoint_title": "端點網址", + "mcp_endpoint_description": "將此網址新增至您的 AI 助理的 MCP 設定中", + "tools": { + "search_notes": "搜尋筆記", + "get_note": "取得筆記", + "get_note_content": "取得筆記內容", + "update_note_content": "更新筆記內容", + "append_to_note": "追加至筆記", + "create_note": "建立筆記", + "get_attributes": "取得屬性", + "get_attribute": "取得屬性", + "set_attribute": "設定屬性", + "delete_attribute": "移除屬性", + "get_child_notes": "取得子筆記", + "get_subtree": "取得子階層", + "load_skill": "載入技能", + "web_search": "網頁搜尋", + "note_in_parent": "", + "get_attachment": "取得附件", + "get_attachment_content": "讀取附件內容" + } + }, + "sidebar_chat": { + "title": "AI 對話", + "launcher_title": "打開 AI 對話", + "new_chat": "開始新對話", + "save_chat": "將對話保存至筆記", + "empty_state": "開始會話", + "history": "對話歷史", + "recent_chats": "最近的對話", + "no_chats": "無先前的對話記錄" } } diff --git a/apps/client/src/translations/uk/translation.json b/apps/client/src/translations/uk/translation.json index 75c890ffbf..252100847a 100644 --- a/apps/client/src/translations/uk/translation.json +++ b/apps/client/src/translations/uk/translation.json @@ -1744,9 +1744,6 @@ "description": "Ці параметри застосовуються лише для збірок для ПК, браузери використовуватимуть власну вбудовану перевірку орфографії.", "enable": "Увімкнути перевірку орфографії", "language_code_label": "Код(и) мови", - "language_code_placeholder": "наприклад, \"en-US\", \"de-AT\"", - "multiple_languages_info": "Кілька мов можна розділяти комами, наприклад, \"en-US, de-DE, cs\". ", - "available_language_codes_label": "Доступні коди мови:", "restart-required": "Зміни в параметрах перевірки орфографії набудуть чинності після перезапуску програми." }, "sync_2": { diff --git a/apps/client/src/types-lib.d.ts b/apps/client/src/types-lib.d.ts index 4f942b8cb6..8d3c9296d1 100644 --- a/apps/client/src/types-lib.d.ts +++ b/apps/client/src/types-lib.d.ts @@ -66,6 +66,7 @@ declare module "preact" { interface ElectronWebViewElement extends JSX.HTMLAttributes { src: string; class: string; + key?: string | number; } interface IntrinsicElements { diff --git a/apps/client/src/types.d.ts b/apps/client/src/types.d.ts index f7673901c1..6e2196eab9 100644 --- a/apps/client/src/types.d.ts +++ b/apps/client/src/types.d.ts @@ -24,6 +24,7 @@ interface CustomGlobals { getReferenceLinkTitle: (href: string) => Promise; getReferenceLinkTitleSync: (href: string) => string; getActiveContextNote: () => FNote | null; + getThemeStyle: () => "auto" | "light" | "dark"; ESLINT: Library; appContext: AppContext; froca: Froca; @@ -51,8 +52,9 @@ interface CustomGlobals { isElectron: boolean; isRtl: boolean; iconRegistry: IconRegistry; - themeCssUrl: string; - themeUseNextAsBase?: "next" | "next-light" | "next-dark"; + theme: string; + themeBase?: "next" | "next-light" | "next-dark"; + customThemeCssUrl?: string; iconPackCss: string; headingStyle: "plain" | "underline" | "markdown"; layoutOrientation: "vertical" | "horizontal"; diff --git a/apps/client/src/widgets/NoteDetail.tsx b/apps/client/src/widgets/NoteDetail.tsx index ea43851359..40ae3e49e9 100644 --- a/apps/client/src/widgets/NoteDetail.tsx +++ b/apps/client/src/widgets/NoteDetail.tsx @@ -336,6 +336,8 @@ export async function getExtendedWidgetType(note: FNote | null | undefined, note if (noteContext?.viewScope?.viewMode === "source") { resultingType = "readOnlyCode"; + } else if (noteContext.viewScope?.viewMode === "ocr") { + resultingType = "readOnlyOCRText"; } else if (noteContext.viewScope?.viewMode === "attachments") { resultingType = noteContext.viewScope.attachmentId ? "attachmentDetail" : "attachmentList"; } else if (noteContext.viewScope?.viewMode === "note-map") { diff --git a/apps/client/src/widgets/Toast.css b/apps/client/src/widgets/Toast.css index b58e6a13ab..95b9f69157 100644 --- a/apps/client/src/widgets/Toast.css +++ b/apps/client/src/widgets/Toast.css @@ -28,9 +28,10 @@ overflow: hidden; } -.toast.no-title { +.toast.no-title .toast-main-row { display: flex; flex-direction: row; + align-items: center; } .toast.no-title .toast-icon { @@ -40,22 +41,26 @@ } .toast.no-title .toast-body { - padding-inline-start: 0; - padding-inline-end: 0; + flex: 1; + padding-block: var(--bs-toast-padding-y); + padding-inline: 0; } -.toast.no-title .toast-header { - background-color: unset !important; +.toast.no-title .toast-close { + display: flex; + align-items: center; + padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); } .toast { .toast-buttons { - padding: 0 1em 1em 1em; + padding: 0 var(--bs-toast-padding-x) var(--bs-toast-padding-y) var(--bs-toast-padding-x); display: flex; - gap: 1em; - justify-content: space-between; + flex-direction: column; + gap: 0.5em; .btn { + width: 100%; color: var(--bs-toast-color); background: var(--modal-control-button-background); diff --git a/apps/client/src/widgets/Toast.tsx b/apps/client/src/widgets/Toast.tsx index 9630836e1b..c251b900a3 100644 --- a/apps/client/src/widgets/Toast.tsx +++ b/apps/client/src/widgets/Toast.tsx @@ -5,7 +5,6 @@ import { useEffect } from "preact/hooks"; import { removeToastFromStore, ToastOptionsWithRequiredId, toasts } from "../services/toast"; import Icon from "./react/Icon"; -import { RawHtmlBlock } from "./react/RawHtml"; import Button from "./react/Button"; export default function ToastContainer() { @@ -43,21 +42,24 @@ function Toast({ id, title, timeout, progress, message, icon, buttons }: ToastOp id={`toast-${id}`} > {title ? ( -
- - {toastIcon} - {title} - - {closeButton} -
+ <> +
+ + {toastIcon} + {title} + + {closeButton} +
+
{message}
+ ) : ( -
{toastIcon}
+
+
{toastIcon}
+
{message}
+
{closeButton}
+
)} - - - {!title &&
{closeButton}
} - {buttons && (
{buttons.map(({ text, onClick }) => ( diff --git a/apps/client/src/widgets/collections/NoteList.tsx b/apps/client/src/widgets/collections/NoteList.tsx index 0b864ace25..0c37c4a08a 100644 --- a/apps/client/src/widgets/collections/NoteList.tsx +++ b/apps/client/src/widgets/collections/NoteList.tsx @@ -25,6 +25,7 @@ interface NoteListProps { viewType: ViewTypeOptions | undefined; onReady?: (data: PrintReport) => void; onProgressChanged?(progress: number): void; + showTextRepresentation?: boolean; } type LazyLoadedComponent = ((props: ViewModeProps) => VNode | undefined); @@ -67,7 +68,7 @@ export default function NoteList(props: Pick) { const viewType = useNoteViewType(props.note); - return ; + return ; } export function CustomNoteList({ note, viewType, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId, onReady, onProgressChanged, ...restProps }: NoteListProps) { diff --git a/apps/client/src/widgets/collections/board/data.spec.ts b/apps/client/src/widgets/collections/board/data.spec.ts index 83a36ac0e6..b8f0f50341 100644 --- a/apps/client/src/widgets/collections/board/data.spec.ts +++ b/apps/client/src/widgets/collections/board/data.spec.ts @@ -1,8 +1,9 @@ -import { it, describe, expect } from "vitest"; -import { buildNote } from "../../../test/easy-froca"; -import { getBoardData } from "./data"; +import { describe, expect,it } from "vitest"; + import FBranch from "../../../entities/fbranch"; import froca from "../../../services/froca"; +import { buildNote } from "../../../test/easy-froca"; +import { getBoardData } from "./data"; describe("Board data", () => { it("deduplicates cloned notes", async () => { diff --git a/apps/client/src/widgets/collections/calendar/index.css b/apps/client/src/widgets/collections/calendar/index.css index df93910b50..51ff05e032 100644 --- a/apps/client/src/widgets/collections/calendar/index.css +++ b/apps/client/src/widgets/collections/calendar/index.css @@ -1,20 +1,9 @@ -:root { - /* Default values to be overridden by themes */ - --calendar-coll-event-background-lightness: 95%; - --calendar-coll-event-background-saturation: 80%; - --calendar-coll-event-background-color: var(--accented-background-color); - --calendar-coll-event-text-color: var(--main-text-color); - --calendar-coll-event-hover-filter: none; - --callendar-coll-event-archived-sripe-color: #00000013; - --calendar-coll-today-background-color: var(--more-accented-background-color); -} - .calendar-view { - --fc-event-border-color: var(--calendar-coll-event-text-color); - --fc-event-bg-color: var(--calendar-coll-event-background-color); - --fc-event-text-color: var(--calendar-coll-event-text-color); + --fc-event-border-color: var(--calendar-coll-event-text-color, var(--main-text-color)); + --fc-event-bg-color: var(--calendar-coll-event-background-color, var(--accented-background-color)); + --fc-event-text-color: var(--calendar-coll-event-text-color, var(--main-text-color)); --fc-event-selected-overlay-color: transparent; - --fc-today-bg-color: var(--calendar-coll-today-background-color); + --fc-today-bg-color: var(--calendar-coll-today-background-color, var(--more-accented-background-color)); overflow: hidden; position: relative; @@ -123,7 +112,7 @@ z-index: -1; --c1: transparent; - --c2: var(--callendar-coll-event-archived-sripe-color); + --c2: var(--callendar-coll-event-archived-sripe-color, #00000013); background: repeating-linear-gradient(45deg, var(--c1), var(--c1) 8px, var(--c2) 8px, var(--c2) 16px); @@ -153,8 +142,8 @@ --fc-event-text-color: var(--custom-color); --fc-event-bg-color: hsl(var(--custom-color-hue), - var(--calendar-coll-event-background-saturation), - var(--calendar-coll-event-background-lightness)) !important; + var(--calendar-coll-event-background-saturation, 80%), + var(--calendar-coll-event-background-lightness, 95%)) !important; } .calendar-view a.fc-timegrid-event:focus-visible, @@ -171,7 +160,7 @@ .calendar-view a.fc-timegrid-event:hover, .calendar-view a.fc-daygrid-event:hover { - filter: var(--calendar-coll-event-hover-filter); + filter: var(--calendar-coll-event-hover-filter, none); border-color: var(--fc-event-text-color); text-decoration: none; color: currentColor; diff --git a/apps/client/src/widgets/collections/calendar/index.tsx b/apps/client/src/widgets/collections/calendar/index.tsx index 349d666e6c..4bde4b6350 100644 --- a/apps/client/src/widgets/collections/calendar/index.tsx +++ b/apps/client/src/widgets/collections/calendar/index.tsx @@ -82,6 +82,7 @@ export const LOCALE_MAPPINGS: Record Promise<{ de hi: () => import("@fullcalendar/core/locales/hi"), ga: null, cn: () => import("@fullcalendar/core/locales/zh-cn"), + cs: () => import("@fullcalendar/core/locales/cs"), tw: () => import("@fullcalendar/core/locales/zh-tw"), ro: () => import("@fullcalendar/core/locales/ro"), ru: () => import("@fullcalendar/core/locales/ru"), diff --git a/apps/client/src/widgets/collections/interface.ts b/apps/client/src/widgets/collections/interface.ts index 4a965588df..15acbfa8e2 100644 --- a/apps/client/src/widgets/collections/interface.ts +++ b/apps/client/src/widgets/collections/interface.ts @@ -21,4 +21,5 @@ export interface ViewModeProps { media: ViewModeMedia; onReady(data: PrintReport): void; onProgressChanged?: ProgressChangedFn; + showTextRepresentation?: boolean; } diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 238817d978..0e3d7d5add 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -23,7 +23,7 @@ import { ComponentChildren, TargetedMouseEvent } from "preact"; const contentSizeObserver = new ResizeObserver(onContentResized); -export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { +export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens, showTextRepresentation }: ViewModeProps<{}>) { const expandDepth = useExpansionDepth(note); const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); @@ -37,13 +37,14 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } key={childNote.noteId} note={childNote} parentNote={note} expandDepth={expandDepth} highlightedTokens={highlightedTokens} - currentLevel={1} includeArchived={includeArchived} /> + currentLevel={1} includeArchived={includeArchived} + showTextRepresentation={showTextRepresentation} /> ))} ; } -export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { +export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens, showTextRepresentation }: ViewModeProps<{}>) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); @@ -56,7 +57,8 @@ export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens } note={childNote} parentNote={note} highlightedTokens={highlightedTokens} - includeArchived={includeArchived} /> + includeArchived={includeArchived} + showTextRepresentation={showTextRepresentation} /> ))}
@@ -91,13 +93,14 @@ function NoteList(props: NoteListProps) {
} -function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived }: { +function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived, showTextRepresentation }: { note: FNote, parentNote: FNote, currentLevel: number, expandDepth: number, highlightedTokens: string[] | null | undefined; includeArchived: boolean; + showTextRepresentation?: boolean; }) { const [ isExpanded, setExpanded ] = useState(currentLevel <= expandDepth); @@ -113,7 +116,8 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan + includeArchivedNotes={includeArchived} + showTextRepresentation={showTextRepresentation} /> ); @@ -201,12 +207,13 @@ function NoteAttributes({ note }: { note: FNote }) { return ; } -export function NoteContent({ note, trim, noChildrenList, highlightedTokens, includeArchivedNotes }: { +export function NoteContent({ note, trim, noChildrenList, highlightedTokens, includeArchivedNotes, showTextRepresentation }: { note: FNote; trim?: boolean; noChildrenList?: boolean; highlightedTokens: string[] | null | undefined; includeArchivedNotes: boolean; + showTextRepresentation?: boolean; }) { const contentRef = useRef(null); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); @@ -230,7 +237,8 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc trim, noChildrenList, noIncludedNotes: true, - includeArchivedNotes + includeArchivedNotes, + showTextRepresentation }) .then(({ $renderedContent, type }) => { if (!contentRef.current) return; diff --git a/apps/client/src/widgets/launch_bar/LauncherContainer.tsx b/apps/client/src/widgets/launch_bar/LauncherContainer.tsx index 79de559c98..d5d443084b 100644 --- a/apps/client/src/widgets/launch_bar/LauncherContainer.tsx +++ b/apps/client/src/widgets/launch_bar/LauncherContainer.tsx @@ -1,6 +1,7 @@ import { useCallback, useLayoutEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; +import { isExperimentalFeatureEnabled } from "../../services/experimental_features"; import froca from "../../services/froca"; import { isDesktop, isMobile } from "../../services/utils"; import TabSwitcher from "../mobile_widgets/TabSwitcher"; @@ -12,6 +13,7 @@ import HistoryNavigationButton from "./HistoryNavigation"; import { LaunchBarContext } from "./launch_bar_widgets"; import { CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions"; import ProtectedSessionStatusWidget from "./ProtectedSessionStatusWidget"; +import SidebarChatButton from "./SidebarChatButton"; import SpacerWidget from "./SpacerWidget"; import SyncStatus from "./SyncStatus"; @@ -98,6 +100,8 @@ function initBuiltinWidget(note: FNote, isHorizontalLayout: boolean) { return ; case "mobileTabSwitcher": return ; + case "sidebarChat": + return isExperimentalFeatureEnabled("llm") ? : undefined; default: console.warn(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`); } diff --git a/apps/client/src/widgets/launch_bar/SidebarChatButton.tsx b/apps/client/src/widgets/launch_bar/SidebarChatButton.tsx new file mode 100644 index 0000000000..15bcfbb525 --- /dev/null +++ b/apps/client/src/widgets/launch_bar/SidebarChatButton.tsx @@ -0,0 +1,24 @@ +import { useCallback } from "preact/hooks"; + +import appContext from "../../components/app_context"; +import { t } from "../../services/i18n"; +import { LaunchBarActionButton } from "./launch_bar_widgets"; + +/** + * Launcher button to open the sidebar (which contains the chat). + * The chat widget is always visible in the sidebar for non-chat notes. + */ +export default function SidebarChatButton() { + const handleClick = useCallback(() => { + // Open right pane if hidden, or toggle it if visible + appContext.triggerEvent("toggleRightPane", {}); + }, []); + + return ( + + ); +} diff --git a/apps/client/src/widgets/layout/NoteTypeSwitcher.tsx b/apps/client/src/widgets/layout/NoteTypeSwitcher.tsx index e345249add..cf685828aa 100644 --- a/apps/client/src/widgets/layout/NoteTypeSwitcher.tsx +++ b/apps/client/src/widgets/layout/NoteTypeSwitcher.tsx @@ -5,6 +5,7 @@ import { useEffect, useMemo, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; import attributes from "../../services/attributes"; +import { isExperimentalFeatureEnabled } from "../../services/experimental_features"; import froca from "../../services/froca"; import { t } from "../../services/i18n"; import { NOTE_TYPES, NoteTypeMapping } from "../../services/note_types"; @@ -28,6 +29,7 @@ export default function NoteTypeSwitcher() { const restNoteTypes: NoteTypeMapping[] = []; for (const noteType of NOTE_TYPES) { if (noteType.reserved || noteType.static || noteType.type === "book") continue; + if (noteType.type === "llmChat" && !isExperimentalFeatureEnabled("llm")) continue; if (SWITCHER_PINNED_NOTE_TYPES.has(noteType.type)) { pinnedNoteTypes.push(noteType); } else { diff --git a/apps/client/src/widgets/mobile_widgets/TabSwitcher.tsx b/apps/client/src/widgets/mobile_widgets/TabSwitcher.tsx index ff92b6512e..32f21b94ab 100644 --- a/apps/client/src/widgets/mobile_widgets/TabSwitcher.tsx +++ b/apps/client/src/widgets/mobile_widgets/TabSwitcher.tsx @@ -27,6 +27,7 @@ const VIEW_MODE_ICON_MAPPINGS: Record, string> = { "contextual-help": "bx bx-help-circle", "note-map": "bx bxs-network-chart", attachments: "bx bx-paperclip", + ocr: "bx bx-text" }; export default function TabSwitcher() { diff --git a/apps/client/src/widgets/note_map/NoteMap.tsx b/apps/client/src/widgets/note_map/NoteMap.tsx index 12e15202d2..2677e4aa59 100644 --- a/apps/client/src/widgets/note_map/NoteMap.tsx +++ b/apps/client/src/widgets/note_map/NoteMap.tsx @@ -1,18 +1,21 @@ -import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import "./NoteMap.css"; -import { getThemeStyle, MapType, NoteMapWidgetMode, rgb2hex } from "./utils"; -import { RefObject } from "preact"; -import FNote from "../../entities/fnote"; -import { useElementSize, useNoteLabel } from "../react/hooks"; + import ForceGraph from "force-graph"; +import { RefObject } from "preact"; +import { useEffect, useMemo, useRef, useState } from "preact/hooks"; + +import appContext from "../../components/app_context"; +import FNote from "../../entities/fnote"; +import link_context_menu from "../../menus/link_context_menu"; +import hoisted_note from "../../services/hoisted_note"; +import { t } from "../../services/i18n"; +import { getEffectiveThemeStyle } from "../../services/theme"; +import ActionButton from "../react/ActionButton"; +import { useElementSize, useNoteLabel } from "../react/hooks"; +import Slider from "../react/Slider"; import { loadNotesAndRelations, NoteMapLinkObject, NoteMapNodeObject, NotesAndRelationsData } from "./data"; import { CssData, setupRendering } from "./rendering"; -import ActionButton from "../react/ActionButton"; -import { t } from "../../services/i18n"; -import link_context_menu from "../../menus/link_context_menu"; -import appContext from "../../components/app_context"; -import Slider from "../react/Slider"; -import hoisted_note from "../../services/hoisted_note"; +import { MapType, NoteMapWidgetMode, rgb2hex } from "./utils"; interface NoteMapProps { note: FNote; @@ -40,9 +43,9 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) { return hoisted_note.getHoistedNoteId(); } else if (mapRootIdLabel) { return mapRootIdLabel; - } else { - return appContext.tabManager.getActiveContext()?.parentNoteId ?? null; } + return appContext.tabManager.getActiveContext()?.parentNoteId ?? null; + }, [ note ]); // Build the note graph instance. @@ -67,7 +70,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) { noteIdToSizeMap: notesAndRelations.noteIdToSizeMap, cssData, notesAndRelations, - themeStyle: getThemeStyle(), + themeStyle: getEffectiveThemeStyle(), widgetMode, mapType }); @@ -113,7 +116,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) { node.fx = undefined; node.fy = undefined; } - }) + }); }, [ fixNodes, mapType ]); return ( @@ -159,7 +162,7 @@ function MapTypeSwitcher({ icon, text, type, currentMapType, setMapType }: { onClick={() => setMapType(type)} frame /> - ) + ); } function getCssData(container: HTMLElement, styleResolver: HTMLElement): CssData { @@ -170,5 +173,5 @@ function getCssData(container: HTMLElement, styleResolver: HTMLElement): CssData fontFamily: containerStyle.fontFamily, textColor: rgb2hex(containerStyle.color), mutedTextColor: rgb2hex(styleResolverStyle.color) - } + }; } diff --git a/apps/client/src/widgets/note_map/utils.ts b/apps/client/src/widgets/note_map/utils.ts index d551ea235b..923b5cb001 100644 --- a/apps/client/src/widgets/note_map/utils.ts +++ b/apps/client/src/widgets/note_map/utils.ts @@ -27,7 +27,3 @@ export function generateColorFromString(str: string, themeStyle: "light" | "dark return color; } -export function getThemeStyle() { - const documentStyle = window.getComputedStyle(document.documentElement); - return documentStyle.getPropertyValue("--theme-style")?.trim() as "light" | "dark"; -} diff --git a/apps/client/src/widgets/note_types.tsx b/apps/client/src/widgets/note_types.tsx index b80d4d545e..f2f17dd590 100644 --- a/apps/client/src/widgets/note_types.tsx +++ b/apps/client/src/widgets/note_types.tsx @@ -12,7 +12,7 @@ import { TypeWidgetProps } from "./type_widgets/type_widget"; * A `NoteType` altered by the note detail widget, taking into consideration whether the note is editable or not and adding special note types such as an empty one, * for protected session or attachment information. */ -export type ExtendedNoteType = Exclude | "empty" | "readOnlyCode" | "readOnlyText" | "editableText" | "editableCode" | "attachmentDetail" | "attachmentList" | "protectedSession" | "sqlConsole"; +export type ExtendedNoteType = Exclude | "empty" | "readOnlyCode" | "readOnlyText" | "readOnlyOCRText" | "editableText" | "editableCode" | "attachmentDetail" | "attachmentList" | "protectedSession" | "sqlConsole" | "llmChat"; export type TypeWidget = ((props: TypeWidgetProps) => VNode | JSX.Element | undefined); type NoteTypeView = () => (Promise<{ default: TypeWidget } | TypeWidget> | TypeWidget); @@ -78,6 +78,11 @@ export const TYPE_MAPPINGS: Record = { className: "note-detail-readonly-code", printable: true }, + readOnlyOCRText: { + view: () => import("./type_widgets/ReadOnlyTextRepresentation"), + className: "note-detail-ocr-text", + printable: true + }, editableCode: { view: async () => (await import("./type_widgets/code/Code")).EditableCode, className: "note-detail-code", @@ -147,5 +152,11 @@ export const TYPE_MAPPINGS: Record = { className: "note-detail-spreadsheet", printable: true, isFullHeight: true + }, + llmChat: { + view: () => import("./type_widgets/llm_chat/LlmChat"), + className: "note-detail-llm-chat", + printable: true, + isFullHeight: true } }; diff --git a/apps/client/src/widgets/quick_search.ts b/apps/client/src/widgets/quick_search.ts index cc326df983..df0edb2a90 100644 --- a/apps/client/src/widgets/quick_search.ts +++ b/apps/client/src/widgets/quick_search.ts @@ -1,13 +1,14 @@ -import BasicWidget from "./basic_widget.js"; -import server from "../services/server.js"; -import linkService from "../services/link.js"; -import froca from "../services/froca.js"; -import utils, { handleRightToLeftPlacement } from "../services/utils.js"; -import appContext from "../components/app_context.js"; -import shortcutService, { isIMEComposing } from "../services/shortcuts.js"; -import { t } from "../services/i18n.js"; import { Dropdown, Tooltip } from "bootstrap"; +import appContext from "../components/app_context.js"; +import froca from "../services/froca.js"; +import { t } from "../services/i18n.js"; +import linkService from "../services/link.js"; +import server from "../services/server.js"; +import shortcutService, { isIMEComposing } from "../services/shortcuts.js"; +import utils, { handleRightToLeftPlacement } from "../services/utils.js"; +import BasicWidget from "./basic_widget.js"; + const TPL = /*html*/`